evm-rpc · git:20260610.3c03764 · 2026-06-10 · sha256 80089fec18d6193c
evm-rpc git:20260610.3c03764A
Immutable. This exact content never changes and is served at /api/v1/blob/80089fec18d6193c.
---
name: evm-rpc
description: Query EVM JSON-RPC methods for transaction debugging and endpoint
triage, including eth_getTransactionReceipt and debug_traceTransaction. Use
when the user asks to inspect tx status, retrieve receipts, run tracers,
compare EVM vs Cosmos outcomes, or choose between EVM RPC and Comet RPC
endpoints.
---
# EVM RPC: Receipt and Trace Playbook
Use this skill for EVM transaction debugging with JSON-RPC.
## Quick Start
Set a hash and endpoint, then run receipt first and trace second.
```bash
evm_tx="0xYOUR_evm_tx"
EVM_RPC="https://evm-rpc.archive.testnet-2.nibiru.fi"
curl -s -X POST \
-H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$evm_tx\"],\"id\":1}" \
"$EVM_RPC" | jq
curl -s -X POST \
-H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"debug_traceTransaction\",\"params\":[\"$evm_tx\",{\"tracer\":\"callTracer\"}],\"id\":1}" \
"$EVM_RPC" | jq
```
## Endpoint Map - Nibiru Examples
Chain-agnostic rule: methods determine endpoint family.
| Purpose | Example endpoint | Methods |
|---|---|---|
| EVM JSON-RPC (mainnet) | `https://evm-rpc.nibiru.fi` | `eth_*`, `debug_*`, `net_*`, `web3_*` |
| EVM JSON-RPC archive (mainnet) | `https://evm-rpc.archive.nibiru.fi` | historical reads, tracing |
| EVM JSON-RPC archive (testnet) | `https://evm-rpc.archive.testnet-2.nibiru.fi` | testnet tracing and historical reads |
| Comet RPC archive (mainnet) | `https://rpc.archive.nibiru.fi` | `/block_results`, `/consensus_params` |
| Comet RPC archive (testnet) | `https://rpc.archive.testnet-2.nibiru.fi` | `/block_results`, `/consensus_params` |
Rules:
- Run `eth_*` and `debug_*` only on EVM RPC endpoints.
- Run `/block_results` and `/consensus_params` only on Comet RPC endpoints.
- Prefer archive endpoints for old heights/hashes and tracing workflows.
## Basic Queries (Health / Identity)
### web3_clientVersion
Queries the traceability info like the client name, version, Git commit, Go version,
runtime architecture, and build tags.
```bash
curl -X POST https://evm-rpc.nibiru.fi \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "web3_clientVersion",
"params": [],
"id": 1
}'
```
The response looks like this: "Nibiru 2.6.0: Compiled at Git commit 3cf97e3468f8ce922c8760f839f8f336ca0c37f4 using Go go1.24.5, arch amd64, and build tags (netgo osusergo ledger static rocksdb pebbledb muslc)"
### eth_chainId
Queries the EIP-155 replay-protection chain id for the current ethereum blockchain (Nibiru).
```bash
curl -X POST https://evm-rpc.nibiru.fi \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_chainId",
"params": [],
"id": 1
}'
```
## Transaction Triage Workflow
Use this sequence to avoid false conclusions:
1. `eth_getTransactionByHash`
- Confirms the tx exists and gives gas fields, type, input, and block refs.
2. `eth_getTransactionReceipt`
- Authoritative EVM execution result.
3. `debug_traceTransaction` (usually `callTracer`)
- Explains internal call path and where execution diverged.
4. Optional cross-layer checks on Comet RPC
- `block_results?height=...`, `consensus_params?height=...`.
## Concrete Command Cookbook
### 1 - Get Transaction by Hash
```bash
evm_tx="0xYOUR_evm_tx"
EVM_RPC="https://evm-rpc.archive.testnet-2.nibiru.fi"
curl -s -X POST \
-H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionByHash\",\"params\":[\"$evm_tx\"],\"id\":1}" \
"$EVM_RPC" | jq
```
### 2 - Get Transaction Receipt - Authoritative Status
```bash
evm_tx="0xYOUR_evm_tx"
EVM_RPC="https://evm-rpc.archive.testnet-2.nibiru.fi"
curl -s -X POST \
-H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$evm_tx\"],\"id\":1}" \
"$EVM_RPC" | jq
```
Interpretation:
- `result == null`: **Not mined** or rejected. Either the tx is still in the mempool, it was dropped, or it failed consensus/validation (e.g., bad nonce, invalid signature, insufficient funds for gas). It is not in any block.
- `status == "0x1"`: **Full Success**. The transaction was executed successfully, and all state changes were applied.
- `status == "0x0"`: **Execution Failure (Revert)**. The transaction was successfully mined and included in a block (consuming gas), but the EVM execution was reverted. No state changes occurred except for the gas fee deduction from the sender.
- `blockNumber` present: Mined/included in a block.
- `logs` present: Events emitted (decode by `address`, `topics`, `data`). Note that a reverted tx (`0x0`) will generally have an empty `logs` array, even if it attempted to emit them before reverting.
### 3 - Run Debug Tracer - Call Tree View
```bash
evm_tx="0xYOUR_evm_tx"
EVM_RPC="https://evm-rpc.archive.testnet-2.nibiru.fi"
curl -s -X POST \
-H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"debug_traceTransaction\",\"params\":[\"$evm_tx\",{\"tracer\":\"callTracer\"}],\"id\":1}" \
"$EVM_RPC" | jq
```
Interpretation:
- Inspect top-level `from`, `to`, `gas`, `gasUsed`.
- Walk `calls[]` for internal call chain and outputs.
- Use trace to explain behavior; use receipt status to decide success/failure.
### 4 - Cross-Layer Checks with Comet RPC
```bash
HEIGHT="5959008"
TM_RPC="https://rpc.archive.testnet-2.nibiru.fi"
curl -s "$TM_RPC/block_results?height=$HEIGHT" | jq
curl -s "$TM_RPC/consensus_params?height=$HEIGHT" | jq
```
Use when EVM and Cosmos observations appear inconsistent.
### 5 - Check Deployed Bytecode for an ABI Mismatch
Use this when a transaction reverts very early, the trace only shows a top-level
`execution reverted`, and the calldata targets a function that may not exist in
the deployed runtime bytecode. This catches frontend ABI or artifact drift, such
as calling a newly added function against an older deployed contract.
The method is:
1. Compute the 4-byte selector from the canonical function signature.
2. Fetch runtime bytecode with `eth_getCode`.
3. Search the runtime bytecode for the selector without the `0x` prefix.
4. Compare against known selectors that should exist on the same contract.
```bash
CONTRACT_ADDR="0xCONTRACT_ADDR"
FUNCTION_SIG="claimReferrerRewardsToEvm(uint256[])"
EVM_RPC="https://evm-rpc.archive.nibiru.fi"
BLOCK_TAG="latest" # or a hex block number like "0x273e1fa"
bun - <<'TS'
import { id } from "ethers"
const contractAddr = process.env.CONTRACT_ADDR
const functionSig = process.env.FUNCTION_SIG
const rpc = process.env.EVM_RPC
const blockTag = process.env.BLOCK_TAG ?? "latest"
if (!contractAddr || !functionSig || !rpc) {
throw new Error("set CONTRACT_ADDR, FUNCTION_SIG, and EVM_RPC")
}
const selector = id(functionSig).slice(0, 10)
const resp = await fetch(rpc, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "eth_getCode",
params: [contractAddr, blockTag],
id: 1,
}),
})
const json = await resp.json()
if (json.error) {
throw new Error(JSON.stringify(json.error))
}
const code = String(json.result ?? "0x").toLowerCase()
const selectorNoPrefix = selector.slice(2).toLowerCase()
console.log({
contractAddr,
blockTag,
functionSig,
selector,
byteLength: Math.max(0, (code.length - 2) / 2),
selectorPresent: code.includes(selectorNoPrefix),
})
TS
```
To compare multiple selectors, use the same runtime bytecode and check a list.
This is useful when one new selector is missing but older selectors are present.
```bash
CONTRACT_ADDR="0xCONTRACT_ADDR"
EVM_RPC="https://evm-rpc.archive.nibiru.fi"
BLOCK_TAG="latest"
bun - <<'TS'
import { id } from "ethers"
const contractAddr = process.env.CONTRACT_ADDR
const rpc = process.env.EVM_RPC
const blockTag = process.env.BLOCK_TAG ?? "latest"
const signatures = [
"claimReferrerRewardsToEvm(uint256[])",
"executeSimpleFunctions(bytes)",
"getDenomOfCollateralIndex(uint256)",
]
if (!contractAddr || !rpc) {
throw new Error("set CONTRACT_ADDR and EVM_RPC")
}
const resp = await fetch(rpc, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "eth_getCode",
params: [contractAddr, blockTag],
id: 1,
}),
})
const json = await resp.json()
if (json.error) {
throw new Error(JSON.stringify(json.error))
}
const code = String(json.result ?? "0x").toLowerCase()
for (const sig of signatures) {
const selector = id(sig).slice(0, 10)
console.log({
sig,
selector,
present: code.includes(selector.slice(2).toLowerCase()),
})
}
TS
```
Interpretation:
- `selectorPresent: true`: The runtime bytecode likely has a dispatcher entry
for that function. Continue debugging arguments, require checks, internal
calls, and traces.
- `selectorPresent: false` while older selectors are present: The deployed
contract likely does not implement the ABI function being called. Update the
address, deploy the newer contract, or call an older available function.
- Very low `gasUsed` with `status: "0x0"` and a missing selector often means
the call hit the dispatcher fallback/revert before meaningful contract logic.
- For proxies, minimal proxies, diamonds, or custom fallback dispatchers, the
selector may be absent from the proxy runtime bytecode. Check the implementation
address or facet bytecode instead.
## Receipt and Trace Rules of Thumb
- **Receipt status is the authoritative EVM truth** for success vs. failure.
- **Mined does not mean successful**: A transaction can be in a block and consume gas (`0x0`), but have zero effect on state. Always check the `status` field.
- **Null receipt implies non-existence**: If `eth_getTransactionReceipt` returns `null`, the transaction was never mined. This is usually due to a consensus/mempool error (invalid signature, wrong chain ID, bad nonce, or insufficient funds to cover the max gas cost).
- **Consensus failures don't have receipts**: Errors like "insufficient funds" or "bad nonce" prevent a transaction from even entering a block, so no EVM status is ever generated.
- **A non-empty `logs` array** (at the receipt level) generally only exists for successful transactions (`0x1`).
- **Gas consumption**: Even in failure (`0x0`), the `gasUsed` is still charged to the sender up to the point of reversion.
- **Gas Comparison**: Compare receipt `gasUsed` with the `gas` (limit) from `eth_getTransactionByHash` to see if the transaction ran out of gas.
- **Tracing Failures**: If tracing fails, verify the provider supports the `debug` namespace and retry on an archive endpoint.
## Endpoint Selection Guide
Choose endpoint by method and historical depth:
- Latest, simple reads (`eth_blockNumber`, recent receipt):
- Standard EVM RPC is usually enough.
- Historical receipts, old block state, trace/debug:
- Prefer archive EVM RPC.
- Tendermint/Comet block metadata and app-level event correlation:
- Use Comet RPC endpoints.
## Common Pitfalls
- Calling Comet paths on EVM RPC host (or the reverse).
- Using the wrong network endpoint for a valid tx hash.
- Assuming `result == null` always means pending; it may be wrong chain/provider.
- Treating trace output alone as final status without reading receipt.
- Ignoring timeout/retry behavior for freshly broadcast transactions.
## Reusable Triage Template
```bash
evm_tx="0xYOUR_evm_tx"
EVM_RPC="https://evm-rpc.archive.testnet-2.nibiru.fi"
TM_RPC="https://rpc.archive.testnet-2.nibiru.fi"
# 1) tx details
curl -s -X POST -H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionByHash\",\"params\":[\"$evm_tx\"],\"id\":1}" \
"$EVM_RPC" | jq
# 2) receipt status
curl -s -X POST -H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$evm_tx\"],\"id\":1}" \
"$EVM_RPC" | jq
# 3) call trace
curl -s -X POST -H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"debug_traceTransaction\",\"params\":[\"$evm_tx\",{\"tracer\":\"callTracer\"}],\"id\":1}" \
"$EVM_RPC" | jq
```
## Additional Resources
- Zero-gas debug walkthrough:
`/home/realu/ki/boku/epics/epic-evm/26-02-zero-gas/26-02-10-zero-gas-debug.md`
- Existing endpoint conventions:
`/home/realu/ki/boku/nibi/cook/index.ts`