HoodSynapse
block ← Console
Connect Envelope Chain state Blocks Accounts Transactions Events Orbit internals Known gaps Limits

Robinhood Chain reference.

Every method below was executed against mainnet while this page was written — the responses are captured output, not illustrations. Read the left column for what a call does, the right column for what it returns.

networkRobinhood Chain
chain id4663
clientnitro/v3.11.3
gasETH
transportHTTP · CORS open
A

Connect

wallet · sdk
Network parameters

Robinhood Chain is an Arbitrum Orbit L2 settling to Ethereum. It is EVM-equivalent, so existing tooling — ethers, viem, web3.py, Foundry — works unchanged.

MAINNET
chainId4663 · 0x1237
rpcrpc.mainnet.chain.robinhood.com
explorerrobinhoodchain.blockscout.com
TESTNET
chainId46630 · 0xB626
rpcrpc.testnet.chain.robinhood.com
faucetfaucet.testnet.chain.robinhood.com
ADD TO WALLETjavascript
await window.ethereum.request({
  method: 'wallet_addEthereumChain',
  params: [{
    chainId: '0x1237',
    chainName: 'Robinhood Chain',
    nativeCurrency: {
      name: 'Ether', symbol: 'ETH', decimals: 18
    },
    rpcUrls: ['https://rpc.mainnet.chain.robinhood.com'],
    blockExplorerUrls: ['https://robinhoodchain.blockscout.com']
  }]
});
Request envelope

Every call is an HTTP POST with the same JSON body. Only method and params change between calls.

No API key, no account, no headers beyond content type.

Everything returns hex. Heights, balances, gas and timestamps are hex strings. Decode with parseInt(h,16), or BigInt(h) when the value can exceed 2⁵³.
REQUESTcurl
curl -X POST https://rpc.mainnet.chain.robinhood.com \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber",
       "params":[],"id":1}'
RESPONSEjson
{ "jsonrpc": "2.0", "id": 1, "result": "0xdec54d" }
B

Chain state

identity · gas
eth_chainIdVERIFIED

Network identifier. Use it to refuse work when a wallet is pointed at the wrong chain.

PARAMS
none
RESPONSEjson
{ "result": "0x1237" }   // 4663
eth_gasPriceVERIFIED

Current gas price in wei. On this chain it sits around 0.05 gwei — roughly three orders of magnitude below Ethereum L1.

RESPONSEjson
{ "result": "0x30e9f90" }   // 0.0514 gwei
eth_maxPriorityFeePerGasVERIFIED

Returns 0x0.

Tipping buys nothing here. Ordering is decided by the sequencer, not by a fee auction. Set priority fee to zero and let the base fee carry the transaction.
RESPONSEjson
{ "result": "0x0" }
web3_clientVersionVERIFIED

Node build string. Confirms the chain runs Arbitrum Nitro, which is what makes the Orbit fields further down appear.

RESPONSEjson
{ "result": "nitro/v3.11.3-rc.4-4bed0c5/linux-arm64/go1.25.12" }
C

Blocks

~4s cadence
eth_getBlockByNumberVERIFIED

Fetch a block by height, or by the tag latest.

PARAMS
blockhex height or 'latest'
fulltrue expands transactions into objects

Passing false returns hashes only and is much lighter — use it for polling.

RESPONSE (trimmed)json
{
  "number":        "0xdec54d",
  "timestamp":     "0x6a5dec90",
  "gasUsed":       "0x71d02",
  "baseFeePerGas": "0x3165ff0",
  "transactions":  [ /* 6 hashes */ ],
  // orbit-only, see section E
  "l1BlockNumber": "0x1863755",
  "sendRoot":      "0xf6c227e8…",
  "sendCount":     "0x227"
}
Polling for new blocks

The public endpoint is HTTP only — no WebSocket subscriptions. New blocks are discovered by polling.

Poll at block time. Blocks land every ~4s. Polling every second triples your request count and hands you the same block three times.
POLLERjavascript
let seen = 0;

setInterval(async () => {
  const b = await call('eth_getBlockByNumber', ['latest', false]);
  const h = parseInt(b.number, 16);
  if (h === seen) return;
  seen = h;
  console.log(h, b.transactions.length, 'tx');
}, 4000);
D

Accounts

balances · code
eth_getBalanceVERIFIED

Balance in wei at a given block.

PARAMS
address20-byte hex
block'latest' or hex height
Use BigInt. Wei values overflow JavaScript's safe integer range. Convert with BigInt(hex) and only cast to Number after dividing by 1e18.
CALLjavascript
const wei = await call('eth_getBalance', [addr, 'latest']);
const eth = Number(BigInt(wei)) / 1e18;
// 0.000237
eth_getCode

Returns deployed bytecode. An empty result (0x) means the address is a plain wallet, not a contract — the cheapest way to tell them apart.

RESPONSEjson
{ "result": "0x" }        // EOA, not a contract
E

Transactions

submitted vs executed
eth_getTransactionByHash VERIFIED
eth_getTransactionReceipt VERIFIED

A transaction has two halves and you need both: what was submitted (the transaction) and what happened (the receipt).

Mined is not successful. A reverted transaction still occupies a block and still burns gas. Check receipt.status === '0x1' before treating anything as done.
CAPTURED FROM MAINNETpython
h  = '0xb951c0274bd58288b01dbf3a94965a7efdfed4c2…'
tx = call('eth_getTransactionByHash', [h])
rc = call('eth_getTransactionReceipt', [h])

# from   0x6d9da725…  →  to  0x24d7cd0d…
# status 0x1  (success)
# gas    189,966
# logs   5
System transactions

Most blocks open with an internal ArbOS transaction: sender equals recipient, value is zero, gasUsed is 0x0.

It is chain bookkeeping, not user activity.

Filter it out. Counting raw transactions.length inflates every metric you publish by one per block.
SYSTEM TX SHAPEjson
{
  "from":    "0x…000a4b05",
  "to":      "0x…000a4b05",   // identical
  "value":   "0x0",
  "gasUsed": "0x0"
}
F

Events

logs · filters
eth_getLogs

Historical events, filtered by address and topic.

Always bound the range. With ~4s blocks, 2,000 blocks ≈ two hours of history — page through longer windows in chunks rather than widening one query until it times out.

FILTERjavascript
const latest = parseInt(await call('eth_blockNumber'), 16);

const logs = await call('eth_getLogs', [{
  fromBlock: '0x' + (latest - 2000).toString(16),
  toBlock:   'latest',
  address:   contract,
  topics:    [transferTopic]
}]);
G

Orbit internals

not on ethereum
l1BlockNumber

The Ethereum L1 block this L2 block is anchored to. An L2 block is only as final as the L1 block behind it — read this when you need real finality, not just inclusion.

FIELDjson
"l1BlockNumber": "0x1863755"   // 25,573,205
sendRoot · sendCount

Messages travelling L2 → L1 (withdrawals, cross-chain calls) accumulate into a merkle tree. sendRoot is its current root; sendCount is the running total of queued messages.

Watch sendCount to detect outbound activity without parsing every transaction.

FIELDSjson
"sendRoot":  "0xf6c227e8bd780bce1fd394c5bcd9513f…",
"sendCount": "0x227"                // 551
The miner field is the sequencer

There is no mining and no validator here. The miner address is a readable marker — decode its tail as ASCII and it spells what it is.

DECODEjavascript
const m = '0xa4b000000000000000000073657175656e636572';
Buffer.from(m.slice(-18), 'hex').toString();
// → "sequencer"
H

Known gaps

handle these
eth_syncingUNAVAILABLE

Not exposed on the public endpoint. Clients that assume it exists will read undefined and carry on silently.

Check for error first. A JSON-RPC failure returns HTTP 200 with an error object — inspect it before touching result.
RESPONSEjson
{
  "error": {
    "message": "the method eth_syncing does not exist/is not available"
  }
}
I

Limits

going to production
The public endpoint

Free, keyless, CORS-open — ideal for reading, prototyping and browser apps. It is rate limited and not intended for production.

Move to a dedicated provider once you need archive history, throughput, or an uptime guarantee: Alchemy, QuickNode, Blockdaemon, dRPC, Validation Cloud.

Never sign in the browser. Everything documented here is read-only. Private keys belong in a wallet the user controls or a backend you control — never in page code.
ENDPOINT PROPERTIESsummary
auth          none — no key required
cors          access-control-allow-origin: *
transport     HTTP POST only — no websocket
rate limit    yes, unspecified — back off on failure
archive       not guaranteed