Skip to content

Latest commit

 

History

History
337 lines (252 loc) · 9.02 KB

rpc-methods.md

File metadata and controls

337 lines (252 loc) · 9.02 KB

RPC Reference

Endpoints

Type Mainnet Testnet
HTTP https://mainnet.megaeth.com/rpc https://carrot.megaeth.com/rpc
WebSocket wss://mainnet.megaeth.com/ws wss://carrot.megaeth.com/ws

Third-party providers: Alchemy, QuickNode (recommended for geo-distributed access)

MegaETH-Specific Methods

Instant Transaction Receipts

MegaETH supports synchronous transaction submission — get your receipt in <10ms instead of polling.

Two equivalent methods:

Method Origin Status
realtime_sendRawTransaction MegaETH original Supported
eth_sendRawTransactionSync EIP-7966 standard Supported (proxied)

History: MegaETH created realtime_sendRawTransaction first. Later, eth_sendRawTransactionSync was standardized as EIP-7966. MegaETH now proxies both — they are functionally identical. Use whichever you prefer; eth_sendRawTransactionSync is recommended for cross-chain compatibility.

# Both work identically:
curl -X POST https://mainnet.megaeth.com/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransactionSync",
    "params": ["0x...signedTx"],
    "id": 1
  }'

# Or use the original:
curl -X POST https://mainnet.megaeth.com/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "realtime_sendRawTransaction",
    "params": ["0x...signedTx"],
    "id": 1
  }'

Response: Full transaction receipt (same schema as eth_getTransactionReceipt)

Corner cases on retry:

  • Tx still in pool: "already known" error
  • Tx already executed: "nonce too low" error (future: will return receipt directly)

eth_getLogsWithCursor

Paginated log queries for large result sets:

const response = await client.request({
  method: 'eth_getLogsWithCursor',
  params: [{
    address: '0x...',
    topics: ['0x...'],
    fromBlock: '0x0',
    toBlock: 'latest'
  }]
});
// Returns { logs: [...], cursor: "..." }
// Use cursor in next request to continue

Mini-Block Subscription

{
  "jsonrpc": "2.0",
  "method": "eth_subscribe",
  "params": ["miniBlocks"],
  "id": 1
}

Mini-block schema:

{
  "payload_id": "0x...",
  "block_number": 12345,
  "index": 0,
  "tx_offset": 0,
  "log_offset": 0,
  "gas_offset": 0,
  "timestamp": 1704067200000,
  "gas_used": 21000,
  "transactions": [...],
  "receipts": [...]
}

Mini-blocks are ephemeral — cannot be fetched via RPC after assembly into blocks.

WebSocket Guidelines

Keepalive Required

Send eth_chainId every 30 seconds to prevent disconnection:

const ws = new WebSocket('wss://mainnet.megaeth.com/ws');

const keepalive = setInterval(() => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_chainId',
    params: [],
    id: Date.now()
  }));
}, 30000);

ws.on('close', () => clearInterval(keepalive));

Limits

  • 50 WebSocket connections per VIP endpoint
  • 10 subscriptions per connection (+1 on subscribe, -1 on unsubscribe)

Supported Methods on WS

  • eth_sendRawTransaction
  • eth_sendRawTransactionSync
  • eth_subscribe / eth_unsubscribe
  • eth_chainId (for keepalive)

Batching eth_call Requests (v2.0.14+)

As of v2.0.14, Multicall is the preferred approach for batching eth_call requests.

Why Multicall?

With v2.0.14, eth_call is 2-10x faster. The EVM execution time is now a small fraction of total CPU time — most overhead is per-RPC framework cost. Multicall amortizes this overhead across multiple calls.

// ✅ Preferred: Multicall (v2.0.14+)
import { multicall } from 'viem/actions';

const results = await multicall(client, {
  contracts: [
    { address: token1, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
    { address: token2, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
    { address: token3, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
  ]
});

Historical Context

Earlier MegaETH guidance recommended JSON-RPC batching over Multicall because:

  • Multicall made it difficult to cache eth_call results effectively
  • Certain dApps benefited significantly from this caching

With v2.0.14's performance improvements, the caching mechanism is deprecated and Multicall is now preferred.

Still Avoid

  • Mixing slow + fast methods — Don't batch eth_getLogs with eth_call; logs are always slower
  • Blocking UX on historical queries — Keep eth_getLogs in background

Rate Limiting

Public endpoints have rate limits based on:

  • CPU time consumption
  • Network bandwidth (32 MB/s average, 15x burst for VIP)

Methods Vulnerable to Abuse

These require VIP endpoints for heavy usage:

  • eth_getLogs (large block ranges)
  • eth_call (complex contracts)
  • debug_* / trace_* (disabled on public)

Best Practices

  1. Warm up connections — Call eth_chainId on app init to pre-establish HTTP connection (avoids DNS/TCP/TLS overhead on first real request)
  2. Use Multicall for eth_call batching — Amortizes per-RPC overhead (v2.0.14+)
  3. Don't batch slow with fast — eth_getLogs blocks entire batch response
  4. Use cursors — eth_getLogsWithCursor instead of huge eth_getLogs
  5. Background historical queries — Never block UX waiting for logs

eth_getLogs Limits

  • Multi-block queries: max 20,000 logs per call
  • Single-block queries: no limit
  • Workaround: Get headers first to count logs, then build queries accordingly

Historical Data

Public endpoint supports eth_call on blocks from past ~15 days. For older data:

  • Use Alchemy/QuickNode
  • Run your own archive node
  • Use indexers (Envio HyperSync recommended)

Latency Optimization

MegaETH's real-time capabilities shine when you optimize for low latency. Here's what matters:

Benchmarks (West Coast US → Public RPC)

Method HTTP WebSocket
eth_chainId 40ms 7ms
eth_getBalance 140ms ~50ms
eth_sendRawTransactionSync 200-450ms 150-300ms

WebSocket is 5-6x faster for simple calls due to persistent connection.

1. Use WebSocket Over HTTP

// ❌ Slow: HTTP per request (TCP + TLS handshake each time)
const result = await fetch(RPC_URL, { method: 'POST', ... });

// ✅ Fast: Persistent WebSocket connection
const ws = new WebSocket('wss://mainnet.megaeth.com/ws');
ws.send(JSON.stringify({ method: 'eth_sendRawTransactionSync', ... }));

2. Pre-Sign Transactions

Don't sign in the hot path. Prepare transactions ahead of time:

// Pre-sign with sequential nonces
const nonce = await publicClient.getTransactionCount({ address });

const signedTxs = await Promise.all([
  wallet.signTransaction({ ...baseTx, nonce: nonce }),
  wallet.signTransaction({ ...baseTx, nonce: nonce + 1 }),
  wallet.signTransaction({ ...baseTx, nonce: nonce + 2 }),
]);

// Later: fire instantly when needed
const receipt = await rpc('eth_sendRawTransactionSync', [signedTxs[0]]);

3. Nonce Pipelining

Don't wait for confirmations between transactions:

// ❌ Slow: Wait for each confirmation
for (const tx of transactions) {
  const receipt = await sendAndWait(tx);
}

// ✅ Fast: Pipeline with sequential nonces
let nonce = await getNonce(address);
const receipts = await Promise.all(
  transactions.map((tx, i) => 
    rpc('eth_sendRawTransactionSync', [
      signTx({ ...tx, nonce: nonce + i })
    ])
  )
);

4. HTTP Keep-Alive

If using HTTP, ensure connection reuse:

import https from 'https';

const agent = new https.Agent({ 
  keepAlive: true,
  maxSockets: 10 
});

// Reuse for all requests
fetch(RPC_URL, { agent, ... });

5. Geographic Proximity

Setup Latency
Cross-continent 150-300ms RTT
Same region (cloud) 20-50ms RTT
Local node <5ms RTT

For ultra-low latency:

  • Use Alchemy/QuickNode geo-distributed endpoints
  • Run your own node in the same datacenter as your app

6. Batch RPC Calls

// ❌ Slow: 3 sequential calls = 3x latency
const a = await rpc('eth_call', [params1]);
const b = await rpc('eth_call', [params2]);
const c = await rpc('eth_call', [params3]);

// ✅ Fast: Single batch = 1x latency
const [a, b, c] = await fetch(RPC_URL, {
  body: JSON.stringify([
    { method: 'eth_call', params: [params1], id: 1 },
    { method: 'eth_call', params: [params2], id: 2 },
    { method: 'eth_call', params: [params3], id: 3 },
  ])
});

Theoretical Minimum Latency

With optimal setup (local node + WebSocket + pre-signed):

  • Sign: ~1ms (pre-computed)
  • Network to local node: ~1ms
  • MegaETH processing: ~10ms
  • Total: ~12ms

Debugging Commands

# Estimate gas
cast estimate \
  --from 0xYourAddress \
  --value 0.001ether \
  0xRecipient \
  --rpc-url https://mainnet.megaeth.com/rpc

# Get balance at block
cast call --block 12345 0xContract "balanceOf(address)(uint256)" 0xAddress \
  --rpc-url https://mainnet.megaeth.com/rpc

# Trace transaction (requires VIP or local node)
cast run <txhash> --rpc-url <vip-endpoint>