Ethereum Interface (eth )
Ethereum Interface (eth_) provides an Ethereum-compatible JSON-RPC layer that allows existing wallets, tools, and libraries to interact with Pod using familiar methods and conventions. It is designed to be drop-in compatible with standard Ethereum client workflows, allowing developers to use common tooling such as ethers.js, alloy.rs, and cast without modification.
The interface covers the transaction submission and receipt lifecycle, including balance and nonce discovery, read-only contract calls, log queries, and real-time subscriptions.
📝 This is a JSON-RPC 2.0 API. The request path is not important; the method to execute is defined by the method field in the request body. You can send all requests to /, and any path after / is optional and used only for documentation clarity.
Returns the account's native cash on the orderbook, in wei, floored at zero: the balance bridge deposits are credited to and orders, transfers and withdrawals spend.
The amount withdrawable now is the orderbook contract's withdrawableBalance(token, account) (via eth_call), or withdrawable_cash from ob_getPositions.
The block_number parameter is accepted for Ethereum compatibility but is ignored.
2.0eth_getBalance1Balance in wei (hex-encoded uint256)
Unsigned 256-bit integer (hex-encoded with 0x prefix)
0x6f05b59d3b200000Pattern: ^0x[a-fA-F0-9]+$POST /eth_getBalance HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 115
{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"id": 1,
"params": [
"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28",
"latest"
]
}Balance in wei (hex-encoded uint256)
{
"jsonrpc": "2.0",
"result": "0x6f05b59d3b200000",
"id": 1
}Returns the chain ID used for signing transactions (EIP-155).
2.0eth_chainId1[]Chain ID (hex-encoded)
0x50dPOST /eth_chainId HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 59
{
"jsonrpc": "2.0",
"method": "eth_chainId",
"id": 1,
"params": []
}Chain ID (hex-encoded)
{
"jsonrpc": "text",
"result": "0x50d",
"id": 1
}Returns the transaction that matches the given hash, or null if not found.
2.0eth_getTransactionByHash1Parameters:
transaction_hash(bytes32): The transaction hash to look up
["0xf74e07ff80dc54c7e894396954326fe13f07d176746a6a29d0ea34922b856402"]Transaction object, or null if not found.
POST /eth_getTransactionByHash HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 140
{
"jsonrpc": "2.0",
"method": "eth_getTransactionByHash",
"id": 1,
"params": [
"0xf74e07ff80dc54c7e894396954326fe13f07d176746a6a29d0ea34922b856402"
]
}Transaction object, or null if not found.
{
"jsonrpc": "text",
"result": {
"type": "text",
"chainId": "text",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000001",
"nonce": "text",
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000001",
"blockNumber": "text",
"transactionIndex": "text",
"from": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28",
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28",
"value": "0x6f05b59d3b200000",
"gas": "text",
"gasPrice": "text",
"maxFeePerGas": "text",
"maxPriorityFeePerGas": "text",
"accessList": [
{}
],
"input": "text",
"v": "text",
"yParity": "text",
"r": "text",
"s": "text"
},
"id": 1
}Returns the transaction count (nonce) for the specified address. Required for transaction signing to prevent replay attacks.
Pod-specific: pending returns the next nonce to sign with, counting attested but not yet finalized transactions. Every other tag (latest, safe, finalized, earliest, or a block number) returns the finalized nonce. A tag that does not parse is rejected with invalid params.
2.0eth_getTransactionCount1Parameters:
address(address): The address to get nonce forblock_tag(string):pendingfor the next nonce including in-flight transactions; any other tag or block number for the committed nonce
["0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28","pending"]Nonce (hex-encoded uint256)
Unsigned 256-bit integer (hex-encoded with 0x prefix)
0x6f05b59d3b200000Pattern: ^0x[a-fA-F0-9]+$POST /eth_getTransactionCount HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 125
{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"id": 1,
"params": [
"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28",
"pending"
]
}Nonce (hex-encoded uint256)
{
"jsonrpc": "text",
"result": "0x6f05b59d3b200000",
"id": 1
}Submits a signed EIP-1559 transaction to the network. Returns the transaction hash on success.
The transaction must be RLP-encoded and signed. Use this method to submit orderbook operations (order submissions, cancellations, updates, transfers) to the orderbook contract, and bridge withdrawals to the bridge contract.
For synchronous attestation feedback (successes/errors from validators), use pod_sendRawTransaction.
2.0eth_sendRawTransaction1Transaction hash
32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc.
0x0000000000000000000000000000000000000000000000000000000000000001Pattern: ^0x[a-fA-F0-9]{64}$POST /eth_sendRawTransaction HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 81
{
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"id": 1,
"params": [
"0x02f8..."
]
}Transaction hash
{
"jsonrpc": "text",
"result": "0x0000000000000000000000000000000000000000000000000000000000000001",
"id": 1
}Executes a new message call immediately without creating a transaction on the blockchain.
Use this method for read-only operations on the orderbook contract, such as:
balanceOf(address token, address account)- Get an account's balance for a token
Orderbook Contract Address: 0x50d0000000000000000000000000000000000002
2.0eth_call1Parameters:
transaction(object): Call object withto,data, and optionallyfrom
The call takes only this object and runs against current state.
[{"to":"0x50d0000000000000000000000000000000000002","data":"0x..."}]Return data (hex-encoded)
0x000...POST /eth_call HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 122
{
"jsonrpc": "2.0",
"method": "eth_call",
"id": 1,
"params": [
{
"to": "0x50d0000000000000000000000000000000000002",
"data": "0x..."
}
]
}Return data (hex-encoded)
{
"jsonrpc": "text",
"result": "0x000...",
"id": 1
}Retrieves the transaction receipt including execution status and event logs.
Pod-specific: The receipt includes pod_metadata containing validator attestations for transaction finality verification.
Returns null if the transaction is not found or not yet processed.
2.0eth_getTransactionReceipt1Parameters:
transaction_hash(bytes32): The transaction hash to look up
["0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"]Transaction receipt with Pod-specific attestation data, or null if not found.
POST /eth_getTransactionReceipt HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 141
{
"jsonrpc": "2.0",
"method": "eth_getTransactionReceipt",
"id": 1,
"params": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}Transaction receipt with Pod-specific attestation data, or null if not found.
{
"jsonrpc": "2.0",
"result": {
"type": "0x2",
"status": "0x1",
"cumulativeGasUsed": "0xf4240",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionHash": "0x63dfbb7b3294d3d9aedb9bd1a306ec40156d0da1c374b2348f60c57186704fcd",
"transactionIndex": "0x0",
"blockHash": "0x9f2e1c0a4b7d6835f1a0c9d8e7b6a5948372615f0e9d8c7b6a594837261504f3",
"blockNumber": "0x1a4",
"gasUsed": "0xf4240",
"effectiveGasPrice": "0x1",
"from": "0xe51e549231219c35040efcf784f58776d5065d26",
"to": "0x000000000000000000000000000000000000c10b",
"contractAddress": null,
"pod_metadata": {
"attestations": [
{
"validator_address": "0x3ab7e9c61dece769dc872322ad1e83a5012aa480",
"sequence_number": 14661,
"batch_index": 0,
"timestamp": 1770737135051543,
"signature": "30450221008bd92c1b51d5f38b2938dab90aa6c401e5695092930885a12a1e42ae445bbbde0220068e6160d83d763079ff0861b21a71af625670dc40361075da7d1b13c92a50c4"
}
],
"committee_epoch": 0
}
},
"id": 1
}Estimates the gas required for a transaction.
Pod-specific behavior: the estimate is a table lookup. If the transaction specifies a gas value, that value is returned. Otherwise the gas comes from the fixed per-contract cost table, keyed by to and the call's selector: 21000 for a plain transfer, an unknown contract, or an unknown selector; 21000 per inner intent for submitBatch; 0 for exempt calls (the solver's submitSolutions and the relayer's processDeposits, matched against the unauthenticated from, bridge withdraw, CLOB delegated calls, and the lock contract).
2.0eth_estimateGas1Parameters:
transaction(object): Transaction object withto,data,value,from, etc.
[{"to":"0x50d0000000000000000000000000000000000002","value":"0x0"}]Estimated gas (hex-encoded)
Unsigned 256-bit integer (hex-encoded with 0x prefix)
0x6f05b59d3b200000Pattern: ^0x[a-fA-F0-9]+$POST /eth_estimateGas HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 128
{
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"id": 1,
"params": [
{
"to": "0x50d0000000000000000000000000000000000002",
"value": "0x0"
}
]
}Estimated gas (hex-encoded)
{
"jsonrpc": "text",
"result": "0x6f05b59d3b200000",
"id": 1
}Returns an array of log objects matching the given filter criteria.
fromBlock/toBlock are block heights (inclusive); latest, pending, safe, finalized and an omitted bound mean the tip, and earliest the oldest retained block. A range is clamped to the retained chain; one wholly below it or above the tip (e.g. fromBlock = tip + 1) returns []. blockHash selects a single block.
Rejected with invalid params: an inverted range, a range spanning more than 7,200 blocks, and a query matching more than 10,000 logs.
2.0eth_getLogs1Parameters:
filter(object): Filter object withaddress,topics, and eitherfromBlock/toBlockorblockHash
[{"address":"0x50d0000000000000000000000000000000000002","topics":[],"fromBlock":"0x1a0","toBlock":"latest"}]Array of log objects
POST /eth_getLogs HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 166
{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"id": 1,
"params": [
{
"address": "0x50d0000000000000000000000000000000000002",
"topics": [],
"fromBlock": "0x1a0",
"toBlock": "latest"
}
]
}Array of log objects
{
"jsonrpc": "text",
"result": [
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28",
"topics": [
"0x0000000000000000000000000000000000000000000000000000000000000001"
],
"data": "text",
"blockHash": "text",
"blockNumber": "text",
"transactionHash": "0x0000000000000000000000000000000000000000000000000000000000000001",
"transactionIndex": "text",
"logIndex": "text",
"removed": true
}
],
"id": 1
}Creates a subscription to receive real-time updates over WebSocket. Updates are pushed after each auction settlement for the subscribed orderbook(s) / account.
Subscription types:
pod_orderbook— each notification is a singleOrderbookSnapshotfor the orderbook (the same shapeob_getOrderbookreturns).pod_orders— each notification is an array ofOrderUpdatedescribing what changed to orders this settlement: new/invalid orders, expirations, cancellations, modifications, and fills.pod_orders_v2— the same information aspod_ordersin a smaller, extensible frame: oneOrdersFrameV2per orderbook per batch, which names the batch and the orderbook once, publishes each order created in that batch once, and expresses everything else as events referencing it. Prefer this for new integrations;pod_ordersis unchanged and stays supported.pod_candles— a per-tick candle hint (CandleTick) per cleared orderbook: clearing price and volume at the batch deadline, for folding into the forming bar. Not a closed OHLCV bar (seeob_getCandles).pod_activity— anActivityFrame: one account's activity in one tick, its order events on every orderbook (thepod_orders_v2events) and the money it moved (backstop sweeps, bridge deposits and withdrawals, transfers). Requiresaccount(aliasbidder).pod_markets— aMarketDynamicEntryper orderbook carrying live market statistics (last clearing price, 24h volume/high/low, perp mark/oracle/funding/open-interest) and its lifecycle (status,live_at_us,disable_at_us,settlement_price). Sent each tick for the orderbooks that cleared or had a lifecycle event.pod_positions— aPositionsUpdate({ account, data }, wheredatamatchesob_getPositions) for the subscribed account, pushed for a tick that touches it: order flow on any orderbook (new, fill, cancel, expiry, modification, trigger arm/cancel/update), a backstop sweep or ADL close, a bridge deposit or withdrawal, or a transfer either way. Requiresaccount(aliasbidder).pod_triggers— aTriggersUpdate(theob_getTriggersfields plusaccount, at most 200 triggers) for the subscribed account, pushed for a tick that touches it, on the same rule aspod_positions. Requiresaccount.newHeads— aBlockHeaderper block as it is flushed, in height order, each height once. Takes no options. A subscriber that falls behind the block feed is closed with-32020and noresume_since; resubscribe and fill the gap witheth_getBlockByNumber.pod_withdrawals— an array ofWithdrawalUpdate: what became of every bridge withdrawal that settled this tick — claimable on the bridged chain, or refused with the reason. Tick-level rather than per-orderbook, since a withdrawal belongs to no book, soorderbook_idsdoes not apply;accountnarrows it to one withdrawer. A tick with no matching outcomes sends nothing at all rather than an empty array.pod_transfers— an array ofTransferUpdate: what became of every account-to-account transfer that settled this tick. The sibling ofpod_withdrawals, kept separate because a transfer'stois an account on this ledger while a withdrawal's is an address on the claim chain — one channel would deliver two meanings of the same field name. Tick-level, soorderbook_idsdoes not apply;accountmatches either side, so a recipient hears the credit as readily as a sender hears the debit. A tick with no matching outcomes sends nothing at all rather than an empty array.
pod_orderbook, pod_orders, pod_orders_v2, pod_activity, pod_candles, pod_withdrawals, and pod_transfers are delta channels (they stream what changed each tick). pod_markets, pod_positions, and pod_triggers are state channels (each pushes a current snapshot). newHeads is served from the block feed. See since below for how each behaves on catch-up.
Subscriptions follow the standard Ethereum eth_subscribe pattern:
Subscribe with
eth_subscribe→ receive a subscription ID.Receive updates as
eth_subscriptionnotifications (see the notification shape below).Cancel with
eth_unsubscribe, passing the subscription ID.
Notification format. Updates arrive as JSON-RPC notifications, not responses:
The result payload shape depends on the subscription type (see the list above).
Reading a pod_orders_v2 frame. orders holds the orders created in this batch, each once; events says what happened. An event names its order either by o (an index into this frame's orders) or by id (an order resting from an earlier batch, whose owner is a) — exactly one of the two. Owners are interned into accts and referenced by index, except when the subscription names exactly one account, where accts and every a are omitted because every row belongs to you. A subscription naming several accounts carries them, so decode on whether accts is present rather than on whether you sent a filter. Absent optional fields carry a documented default (see OrderEntityV2), so a plain user-signed limit order is small.
Two things clients most often get wrong. batch is the batch an action landed in, which for an order is at or before the deadline it was signed for — an intent may be included in an earlier batch than it targets. And a fill carries both kinds of amount: b/q are what that fill filled, while tb/tq/tf are the order's running totals. Apply b/q; use the totals to check your own figure. Reading a total as a per-batch amount double-counts. There is no per-fill fee, so difference tf for that.
Identity. id is the resting order id, derived as keccak256(abi_encode(signer, nonce, sequence)) — the signing key, that transaction's nonce, and the order's position inside a submitBatch envelope (0 when the transaction carries one intent). You can compute it before broadcasting and match your own orders on the first frame that mentions them. Derive from the delegate's address for a delegated order: the id keys on the signer, while a/accts report the owner. Note n is the transaction's nonce, so orders from one envelope share n and tx and differ only in id.
Every terminal event carries the order's final totals, whichever shape ends it: a fill bearing st for an order that filled out, or cancel/expire for one removed from the book — both with tb/tq/tf. So a terminal handler is uniform and needs no accumulation of the order's earlier fills, which matters for a partially filled order canceled for its remainder: the amounts it did fill travel with the cancel. An order that both fills and terminates in the same batch reports the totals on both events, with the same values.
Engine-generated closes. A backstop sweep leg and an ADL close each appear as a synthetic order: a new for an entity of kind backstop_transfer, adl or adl_counterparty, followed by a terminal fill. An ADL close is delivered to both parties.
Reading a pod_activity frame. It uses the pod_orders_v2 vocabulary for one account across every orderbook, plus three money kinds (backstop, bridge_transfer, transfer). ActivityFrame gives its fields and event order.
Forward compatibility. Clients MUST ignore event kinds (k) and fields they do not recognise: new event kinds will be added without a new channel version. Existing keys are never renamed or repurposed.
Server-initiated close. The server may end a subscription on its own — most often because it dropped ticks for a subscriber that fell behind, which it does rather than serve a delta stream with a gap in it. That arrives on the same eth_subscription method with error in place of result, carrying a code, whether the stream is resumable, and the resume_since watermark to resubscribe from:
Nothing further is sent for that subscription; the connection and any other subscriptions on it are unaffected. Because a delta stream never has holes, this close is the only signal that data was lost — while a subscription is open, no updates means an idle market. See JSON-RPC Errors for every code and the recommended client response.
On pod_orders_v2 the close additionally carries resume_since_book whenever the batch it stopped in was only partly delivered — the last book you were sent. Pass both back, as since and since_book, and you receive exactly the frames you never got: no replay, no gap. This is the case the two-part cursor exists for, because a close midway through a batch is precisely when you cannot tell where you got to — frames already accepted by the connection may not have reached your code yet. resume_since_book is absent when the batch landed whole, and then resume_since alone is the position.
Filtering. pod_orderbook, pod_orders, pod_orders_v2, pod_candles, and pod_markets accept orderbook_ids (alias clob_ids) to restrict the stream to specific orderbooks (empty/omitted = all). pod_orders and pod_orders_v2 additionally accept bidder to deliver only that account's updates, and pod_orders_v2 accepts bidders — a set of up to 64 distinct accounts — to follow several on one subscription instead of opening one each. bidder and bidders are mutually exclusive, and naming more than one account makes the frame carry accts/a (see above). pod_positions and pod_triggers are account-scoped and require account (alias bidder); they ignore orderbook_ids. pod_withdrawals takes account optionally — omitted streams every account's outcomes — and matches it against withdrawer, the debited account; it ignores orderbook_ids too. pod_transfers takes account optionally on the same terms, but matches it against either from or to. pod_activity requires account, rejects bidders, and ignores orderbook_ids. depth applies to pod_orderbook snapshots only and is at least 1.
Catch-up (since). Optionally pass since (a solution time in microseconds) to catch up with no gap or duplicate. Delta channels (pod_orderbook, pod_orders, pod_activity, pod_candles, pod_withdrawals, pod_transfers) replay buffered ticks with deadline strictly greater than since (pod_orders_v2 differs, see below). If since predates the retained buffer — or the buffer is empty, as right after a node start — the subscription is rejected with -32602 "since too old; backfill via REST then resubscribe" (for pod_withdrawals that is GET /v1/bridge/withdrawals[/{account}]?since=, which takes the same cursor and serves the same shape; pod_transfers has no REST backfill: resubscribe live). State channels (pod_markets, pod_positions, pod_triggers) emit one current snapshot immediately when since is passed (any value), then stream live. Omitted = live-only: a state channel sends nothing until a tick touches it. Which option applies to which subscription type is summarised in SubscriptionParams.
Catch-up on pod_orders_v2 (since + since_book). One batch settles many orderbooks and is delivered as one frame each, so a batch is not atomic on the wire — a client can hold part of one. Resume on the pair: since is the batch of the last frame you accepted and since_book its book. Replay starts at the batch equal to since (inclusive), skips every book at or below since_book within that batch, and delivers later batches whole, so a client that accepted 7 of 10 books receives the remaining 3 without a gap or a duplicate. Track one pair, not a per-book map. Omitting since_book means "the whole of since arrived", which is correct if you subscribe to a single orderbook, because a batch is then one frame.
2.0eth_subscribe1Messages received on the subscription. The immediate reply to eth_subscribe is the
subscription ID; every subsequent message is an eth_subscription notification whose
params.result carries the streamed payload — its shape determined by the subscription
type (see the method description and EthSubscriptionMessage).
POST /eth_subscribe HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 171
{
"jsonrpc": "2.0",
"method": "eth_subscribe",
"id": 1,
"params": [
"pod_orderbook",
{
"clob_ids": [
"0x0000000000000000000000000000000000000000000000000000000000000001"
],
"depth": 50
}
]
}Messages received on the subscription. The immediate reply to eth_subscribe is the
subscription ID; every subsequent message is an eth_subscription notification whose
params.result carries the streamed payload — its shape determined by the subscription
type (see the method description and EthSubscriptionMessage).
{
"jsonrpc": "2.0",
"result": "0x9ce59a13059e417087c02d3236a0b1cc",
"id": 1
}Cancels an active subscription created with eth_subscribe. Pass the subscription ID returned by the original eth_subscribe call. Returns true if a matching subscription was found and removed.
2.0eth_unsubscribe1Parameters:
subscription_id(string): The ID returned byeth_subscribe
["0x9ce59a13059e417087c02d3236a0b1cc"]Whether the subscription was found and cancelled
POST /eth_unsubscribe HTTP/1.1
Host: rpc.podtestnet.dev/
Content-Type: application/json
Accept: */*
Content-Length: 99
{
"jsonrpc": "2.0",
"method": "eth_unsubscribe",
"id": 1,
"params": [
"0x9ce59a13059e417087c02d3236a0b1cc"
]
}Whether the subscription was found and cancelled
{
"jsonrpc": "text",
"result": true,
"id": 1
}Last updated

