Tempo RPC: A Developer's Guide (Chain ID 4217)
Tempo is a chain built for payments. It runs the EVM, accepts ordinary Ethereum transactions, and answers the usual eth_ methods, but it has no native token. Gas is paid in dollar stablecoins, blocks arrive about twice a second and are final when they arrive, and there is a new transaction type, 0x76, that batches calls and lets someone else pay the fee.
Most of that is good news for a payments backend. It also breaks a few assumptions that EVM code makes without thinking: that eth_getBalance means something, that timestamp is unique per block, and that every transaction has one to address. Everything below was measured against the live chain on October 17, 2026, through the SwiftNodes endpoint and Tempo's public RPC.
The endpoint
https://rpc.swiftnodes.io/rpc/tempo?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/tempo?key=YOUR_API_KEY
import { createPublicClient, http, defineChain } from "viem";
const tempo = defineChain({
id: 4217,
name: "Tempo",
// Tempo has no native token. viem requires this field, so it is a placeholder:
// never read balances or fees from it.
nativeCurrency: { name: "USD", symbol: "USD", decimals: 18 },
rpcUrls: { default: { http: ["https://rpc.swiftnodes.io/rpc/tempo?key=YOUR_API_KEY"] } },
});
const client = createPublicClient({ chain: tempo, transport: http() });
What we measured
| Property | Value |
|---|---|
| Chain ID | 4217 (0x1079) |
| Client | tempo/v1.16.1-acfc30e/x86_64-unknown-linux-gnu |
| Block 1 | January 16, 2026 |
| Block interval | 551 ms on average (517 to 596 ms over 100 blocks) |
| Finality | immediate: safe = finalized = latest |
| Block gas limit | 500,000,000 |
| Activity | 92 transactions in 400 blocks; 318 blocks empty |
| Base fee | 600,000,000, flat across eth_feeHistory |
eth_maxPriorityFeePerGas |
0 |
| Fee currency | USD stablecoins (6 decimals) |
eth_getBalance |
the same huge constant for every address |
eth_getLogs |
20,000 results per request |
| Tracing | callTracer works; the default tracer does not |
| WebSocket | newHeads works: 18 heads in 10 seconds |
There is no native token
This is the first thing that will surprise your code. We called eth_getBalance on a busy sender, on address 0x…0001, and on the same sender a thousand, a million, twenty million and forty-four million blocks back. Every call returned the same value:
0x9612084f0316e0ebd5182f398e5195a51b5ca47667d4c9b26c9b26c9b26c9b2
That is about 4.2 × 10^75, a sentinel, not a balance. eth_getProof for the same account reports "balance": "0x0". So a wallet screen, a "has enough gas?" check or a portfolio tracker that reads eth_getBalance shows nonsense, and a check that compares it with a fee always passes.
Money on Tempo lives in TIP-20 tokens, which answer the ERC-20 interface. The ones we saw had addresses starting with 0x20c0:
| Token | Address | Decimals | Supply |
|---|---|---|---|
| pathUSD | 0x20c0000000000000000000000000000000000000 |
6 | 51.2 million |
| USDC.e | 0x20c000000000000000000000b9537d11c60e8b50 |
6 | 25.1 million |
| OUSD | 0x20c0000000000000000000006a37da5c996874be |
6 | 529 million |
Read balances the ERC-20 way:
import { erc20Abi, formatUnits } from "viem";
const raw = await client.readContract({
address: "0x20c000000000000000000000b9537d11c60e8b50", // USDC.e
abi: erc20Abi,
functionName: "balanceOf",
args: [account],
});
console.log(formatUnits(raw, 6)); // dollars
symbol, decimals, totalSupply and Transfer events all behave like ERC-20, so indexers built for tokens carry over unchanged.
Fees are paid in dollars
Every block we sampled had a base fee of exactly 600,000,000 and a priority fee of zero. Those numbers are not gwei of anything. The receipt names the token that paid (feeToken) and who paid (feePayer), and the fee itself shows up as a Transfer of that token to 0xfeec000000000000000000000000000000000000. Comparing that transfer with gasUsed × effectiveGasPrice gives the conversion:
| Transaction | Gas used | gasUsed × price | Fee transfer | In dollars |
|---|---|---|---|---|
Type 0x2 contract call |
26,579 | 1.59 × 10^13 | 16 units USDC.e | $0.000016 |
Type 0x76 batched payment |
54,670 | 3.28 × 10^13 | 33 units USDC.e | $0.000033 |
So the price works out as 10^-18 dollars per unit, and a 6-decimal stablecoin is charged gasUsed × gasPrice ÷ 10^12 units, rounded up. A plain USDC.e transfer estimated at 38,284 gas, which is about $0.000023.
Two consequences:
- Plain Ethereum transactions work but still pay in stablecoins. The
0x2transaction above has nofeeTokenfield of its own, yet its receipt shows USDC.e paid the fee. The sender needs a stablecoin balance, not "ETH". - Fee code should read the receipt, not assume a native token. To show what a user paid, take
feeTokenfrom the receipt and decode theTransferto the0xfeec…address, or computegasUsed × effectiveGasPrice ÷ 10^12.
The 0x76 transaction type
Of the 92 transactions in our 400-block sample, 73 were type 0x76, Tempo's own format, and only 9 were standard EIP-1559 (0x2). A 0x76 transaction carries fields no other EVM chain has:
| Field | What it holds |
|---|---|
calls |
an array of {to, value, input}: several calls in one transaction |
feeToken |
the stablecoin to pay with (it was null in our sample, and the receipt still named USDC.e) |
feePayerSignature |
a second signature from whoever sponsors the fee |
nonceKey, nonce |
a nonce plus a key, so one account can run parallel nonce lanes |
validBefore, validAfter |
a time window, after which the transaction can no longer be included |
signature |
an object with a signature type (secp256k1 here), a version and a keyId |
keyAuthorization, aaAuthorizationList |
delegated keys and account authorizations |
The receipt adds feeToken and feePayer, and its to is the first call's target. Three practical points:
- A transaction decoder that only knows types 0 to 4 will reject or mis-parse
0x76. If you store raw transactions, keep unknown types as JSON rather than dropping them. - One transaction can move money to several places. Index the
Transferlogs, not the transaction'stoandvalue. - Parallel nonce lanes change the nonce management story: a payout service can send on several
nonceKeylanes without one stuck transaction blocking the rest.
Half-second blocks and millisecond timestamps
Over 100 consecutive blocks the interval was 551 ms on average, never under 517 ms or over 596 ms. That breaks the assumption that timestamp is unique: the standard field is in seconds, so two consecutive blocks often share a timestamp, and we saw intervals of 0 and 1 seconds. Tempo adds timestampMillis (and timestampMillisPart) to every block. Use it for ordering and latency metrics.
Blocks also carry a consensusContext with epoch, view, parentView and proposer, which is the consensus round that produced the block.
For live data, a WebSocket subscription is the comfortable choice at this speed. Through our endpoint, eth_subscribe("newHeads") delivered 18 headers in 10 seconds. Polling over HTTP every second works too, but you will get two blocks per poll. Reconnect handling matters more at 2 blocks per second; see reconnecting a WebSocket without losing events.
Instant finality
eth_getBlockByNumber("safe") -> 44526575
eth_getBlockByNumber("finalized") -> 44526575
eth_getBlockByNumber("latest") -> 44526575
All three tags return the same block. Tempo is one of the chains with zero finality lag in our survey of the finalized block tag across 62 chains. For a payments product this is the headline feature: once the receipt exists, the payment is final, so you can mark an invoice paid without a confirmation count. Code that waits for finalized works as written and simply never waits.
Logs: 20,000 results per request
eth_getLogs is capped by result count, not block range:
| Range | Result |
|---|---|
| 1,000 blocks | 1,016 logs |
| 10,000 blocks | 10,784 logs |
| 100,000 blocks | query exceeds max results 20000, retry with the range 44426969-44441423 |
The error names a range that would fit, here about 14,000 blocks. That is a convenient retry signal, but it is computed for unfiltered traffic at that moment. Filter by address and topics and you can usually cover far more blocks per call. At 550 ms per block, 14,000 blocks is only about two hours of chain, so plan backfills in many requests. More on the different kinds of caps in eth_getLogs range caps.
Receipts and tracing
eth_getBlockReceipts works and includes the feeToken and feePayer fields. eth_estimateGas works as usual.
Tracing needs care. With {"tracer": "callTracer"}, debug_traceTransaction returns a proper call tree, and for a 0x76 transaction the top-level call goes to the zero address with one child per entry in calls. The default struct-log tracer did not: for the Tempo transactions and the block we tried, it returned "failed": true with empty structLogs, even for transactions whose receipt status is 1. trace_transaction returned a placeholder action with zero addresses. So use callTracer, and never take failed from the default tracer as the outcome; take status from the receipt.
| Method | Result |
|---|---|
eth_getLogs |
works, 20,000-result cap |
eth_getBlockReceipts |
works, with feeToken and feePayer |
eth_getBalance |
returns a constant; use balanceOf |
safe / finalized |
equal to latest |
debug_traceTransaction with callTracer |
works |
Default tracer, trace_transaction |
placeholder output for 0x76 |
eth_subscribe("newHeads") |
works over WebSocket |
Summary
- Payments chain, chain ID 4217, no native token. Fees are paid in 6-decimal USD stablecoins.
eth_getBalancereturns the same huge constant for every address. ReadbalanceOfon pathUSD, USDC.e or other TIP-20 tokens.- A fee is
gasUsed × gasPrice ÷ 10^12stablecoin units: a contract call costs a few thousandths of a cent. - Most traffic is type
0x76: batched calls, sponsored fees, parallel nonces. IndexTransferlogs, nottoandvalue. - 550 ms blocks: use
timestampMillis. Finality is immediate. eth_getLogsis capped at 20,000 results; trace withcallTracer.
Tempo endpoints and method support are on our Tempo RPC page, with 127 other chains on the same key. For another stablecoin-first chain, compare Plasma. SwiftNodes has a free tier to try it.
John Sullivan covers RPC infrastructure, node operations, and multi-chain development at SwiftNodes — what it actually takes to keep endpoints fast, fresh, and reliable across EVM and non-EVM networks.
Related posts
- Morph RPC: A Developer's Guide (Chain ID 2818)
Morph is a payments-focused Ethereum L2 with its own transaction type for paying gas in tokens. Measured: ~2 s blocks, a 0.001 gwei base fee, a transfer costing ~$0.002 (97% L1 data), MorphTx (0x7f) paying gas in USDC, extra receipt fields, safe equal to finalized at ~18 minutes, and full tracing.
- Etherlink RPC: A Developer's Guide (Chain ID 42793)
Etherlink is the EVM rollup on Tezos. Measured: sub-second to 1.5 s blocks, a fixed 1 gwei base fee, plain transfers that use 621,000 gas because the data fee is charged as gas, a 500-block eth_getLogs cap, and no safe tag.
- Bitlayer RPC: A Developer's Guide (Chain ID 200901)
Bitlayer is an EVM chain that pays gas in BTC. Measured: 3-second blocks from 21 rotating validators, a hard 0.025 gwei minimum tip, a transfer that costs 52.5 satoshis, no safe or finalized tags, and a public RPC that keeps only recent state.