Skip to Content

Devnet

Devnet is Supra’s public development network. It runs development builds, and the node version is in the info.description of its /docs/api.json. An upgrade may change an interface in a way that breaks existing contracts, transactions or clients, and the network is reset from a new genesis when needed.

Testnet and Mainnet keep their state across upgrades, and each upgrade stays compatible with what is already deployed on them, so they are upgraded less often than Devnet.

Devnet carries SupraEVM; see Getting Started with SupraEVM. How SupraEVM’s JSON-RPC surface differs from Ethereum’s is in Differences from Ethereum; gas caps and the price floor are in Gas and Fees.

This page states Devnet’s parameters and the envelope it runs in, which is narrower than a production network’s: its state is reset, its history is pruned, and its public endpoint is served by a pool of nodes behind a load balancer.

Network parameters

ParameterValue
Move chain ID50
RPC hosthttps://rpc-devnet.supra.com
Interactive API pagehttps://rpc-devnet.supra.com/docs
FaucetGET https://rpc-devnet.supra.com/rpc/v4/wallet/faucet/<move_address>
Explorerhttps://devnet.suprascan.io

The EVM chain ID and the EVM’s JSON-RPC and WebSocket endpoints are in Network parameters in Getting Started with SupraEVM.

The network is transient

A Devnet reset starts the chain from a new genesis. Everything held in chain state is destroyed:

  • deployed contracts, at every address, including contracts deployed by anyone else that yours calls;
  • account balances, on both SupraEVM and SupraMVM, and any SUPRA crossed between them;
  • the full transaction and block history, so no hash, height or receipt from before a reset can be read afterwards;
  • accounts themselves, so nonces restart from zero and an address that held code holds none.

Nothing survives a reset except the keys you hold. Treat any deployment on Devnet as reproducible from source: keep the deployment script, the constructor arguments and the addresses your tests depend on in version control, so redeploying after a reset is a single command rather than a reconstruction.

Contract addresses are not stable across a reset either. A CREATE address is derived from the deployer’s address and nonce, so redeploying from a fresh account nonce can reproduce an address, but only if the same deployer sends the same number of prior transactions. Use CREATE2 or read the address from the deployment receipt rather than hard-coding it.

The chain ID is the same after a reset. An EVM transaction carries no expiry, so a transaction signed before a reset becomes valid again once its sender’s nonce reaches the transaction’s nonce, and anyone holding a copy can submit it. If that matters to your tests, deploy from a new key after each reset. Move transactions are not affected: each carries an expiration time, which has passed by the time Devnet is back up.

Each reset is announced in a banner at the top of the SupraScan  landing page at least 24 hours in advance.

History retention

Devnet’s nodes prune: they retain a window of recent history and drop older blocks. The floor moves forward as the chain advances.

Read the current floor rather than assuming it. The earliest block tag resolves to the oldest height a node still retains, not to genesis, so eth_getBlockByNumber("earliest") is how a client discovers the floor of the node it is talking to:

curl -s -X POST https://rpc-devnet.supra.com/rpc/v1/eth -H 'Content-Type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["earliest",false]}'

A request below the floor is refused rather than answered with an empty result, so that a client can tell “this range was pruned” from “this range held nothing”:

  • On the EVM JSON-RPC surface, a block-reading method such as eth_getBlockByNumber or eth_getBlockTransactionCountByNumber given a height below the floor is rejected with error code -32002 (“Resource unavailable”), carrying the floor in data.oldestBlock. Resume from that height rather than treating the range as empty. On /rpc/v1/eth, a state-reading method such as eth_getBalance or eth_call refuses any numbered height with -39001, before the floor is consulted.
  • A block or transaction addressed by hash is answered with result: null once the node has pruned it, because a hash carries no height.
  • On the REST surface, a height below the floor is answered with HTTP 410 Gone, with the floor in the x-supra-oldest-block response header.

The answer each method gives, including the cases that answer -32002 for a hash, is on the node’s hosted API page, https://rpc-devnet.supra.com/docs .

An indexer built against Devnet must tolerate its own start height falling out of the window: a backfill that pauses for longer than the retention window cannot be resumed from where it stopped, and has to restart from the current floor. History older than the window is not available from Devnet, so capture what you need as you index.

Load balancer

rpc-devnet.supra.com is served by a pool of nodes behind a load balancer. The load balancer uses sticky sessions keyed on the client’s source IP address: requests from one source IP address go to one node. A client whose source IP address changes, or whose node leaves the pool, is moved to another node.

The following are held by each node separately. A client sees one node’s answers while its source IP address is stable, and can see different answers after it is moved:

  • Transactions accepted and not yet executed. A node holds the transactions it has accepted in its own memory until they execute. eth_getTransactionCount(address, "pending") adds only the sender’s transactions held by the node answering, and eth_getTransactionByHash for a transaction that has not executed yet is answered with result: null by every other node. Once the transaction executes, every node that has executed its block answers for it.
  • The chain head. Each node serves the blocks it has executed, so latest and eth_blockNumber on two nodes can differ by the blocks one has executed and the other has not.
  • The retention floor. Each node prunes on its own schedule, so earliest and the oldestBlock of a refusal can differ between nodes.
  • WebSocket connections. A WebSocket connection stays on the node it was opened on until it closes. The connection caps in WebSocket limits are counted per node.

After a client is moved, eth_getTransactionCount(address, "pending") on the new node does not count the transactions still pending on the old one. A client sending several transactions from one account can track its outstanding nonces itself, or wait for each receipt, rather than read the next nonce from pending.

Request rate limits

The public endpoint limits each client IP address’s request rate. A request over the limit is answered with 429 Too Many Requests. The limit is not published and may change; see Requesting higher limits.

A node may also limit the rate of some operations itself. Where it does, the limit is stated in the descriptions of those operations on the Devnet API page, https://rpc-devnet.supra.com/docs .

Cross-origin requests

A browser dapp can call Devnet’s endpoints only if the node’s CORS policy admits the page’s origin. The node builds that policy from its configured list of allowed origins: when the list is empty it sends a wildcard, admitting any origin; when the list is non-empty only the listed origins are admitted, and a page served from any other origin is blocked by the browser.

A cross-origin page may read the x-supra-chain-id, x-supra-cursor, x-supra-history-indexed-from, x-supra-oldest-block and x-supra-block-height response headers; every other response header is hidden from it by the browser. The paging cursor and the retention floor described above are among those exposed, so a browser client can page and can detect pruning.

The allowed methods are GET and POST, the allowed request header is Content-Type, and a preflight result may be cached for one hour.

Devnet admits requests from any origin.

Request size and result bounds

Request bodies are bounded, per endpoint group, by the node’s compiled-in limits:

Endpoint groupMaximum JSON request body
EVM JSON-RPC (/rpc/v1/eth, including batches)10,000,000 bytes
Transaction submission (REST)5,000,000 bytes
Proofs (REST, /rpc/v4/proofs)1,000,000 bytes

A body above the limit is rejected before it is parsed. A JSON-RPC batch is bounded as one body, and holds at most 10 requests: a larger batch is rejected as a whole with error code -32600, and none of its requests is served. Split a larger batch into several.

Results are bounded too. eth_getLogs bounds both the range it will scan and the number of logs it will return:

  • A query whose fromBlock..toBlock spans more blocks than the range bound is rejected with error code -32005 and the message Query exceeded max block range of <n>.
  • A query that would return more logs than the result bound is rejected with error code -32005 and the message Query returned more than <n> results.

The values configured on Devnet’s node are listed in the description of the SupraEVM JSON-RPC 2.0 API operation on the Devnet API page, https://rpc-devnet.supra.com/docs .

Neither answer is a truncated result: the request is refused, so narrow the block range or the address and topic filters and repeat it. A log-following client should page in fixed block spans below the range bound rather than asking for an open-ended range.

debug_traceCall is bounded the same way, by a gas ceiling, a ceiling on the number of call frames one trace may record, and a ceiling on the bytes of accounts a prestateTracer trace may return. It answers -32005 when a trace reaches a frame beyond the bound or exceeds the byte ceiling. Only /rpc/v1/eth and the WebSocket serve the method.

WebSocket limits

The EVM WebSocket endpoint is wss://rpc-devnet.supra.com/rpc/v1/eth. Only text frames are supported. Four limits apply, each counted per node:

  • A global connection cap on the node, across all clients.
  • A per-bearer-token connection cap. A client presenting, in an Authorization: Bearer <token> header, a token the node is configured with gets its own bucket of connections.
  • A shared bucket for every client presenting no bearer token or a token the node is not configured with. All such clients draw from one bucket of the same size, so an anonymous client competes for connections with every other anonymous client on that node.
  • A per-connection subscription cap, on the number of active subscriptions one connection may hold.

The connection caps are shared with the node’s Supra-native WebSocket endpoint, /rpc/v4/ws. The values configured on Devnet’s node are listed in the description of the EVM JSON-RPC WebSocket subscriptions (v1) operation on the Devnet API page, https://rpc-devnet.supra.com/docs .

A connection over either connection cap fails the WebSocket handshake with HTTP 429 Too Many Requests, the response header X-WebSocket-Reject-Reason: limit and Retry-After: 1. The connection is never opened, so a client has to distinguish this from a connection that opens and later closes. An eth_subscribe over the subscription cap is answered on the open connection with error code -32000 and a message beginning Subscription rejected:; the connection and its existing subscriptions stay open.

Reuse one connection for several subscriptions. A client that opens a connection per subscription consumes the connection cap at the rate the subscription cap was sized to absorb, and an anonymous client doing so can exhaust the shared bucket for every other anonymous client. One connection holding many subscriptions is bounded only by the per-connection subscription cap.

Requesting higher limits

If a limit on this page blocks your work, email support@supra.com with this subject line, exactly as written:

[Supra API] Limits request

In the body, give:

  • the network;
  • which limit blocks you, with the error you received;
  • what you are building or testing.

Reporting a problem

Report problems with Devnet to support@supra.com. Include:

  • the endpoint you called, and whether it was the JSON-RPC, REST or WebSocket surface;
  • the exact request, including the full JSON-RPC body, and the exact response, including the error code and any data field;
  • the time of the request, with a timezone, and the block height at the time if you have it;
  • the transaction hash, for anything that was submitted;
  • the source IP address the request was sent from, which identifies the node that served it;
  • what you expected instead.

An answer that names a limit on this page — -32002 with data.oldestBlock, -32005, -32600 for a batch, 410 Gone, 429 — is the endpoint behaving as configured rather than a defect. To have a limit raised, see Requesting higher limits.

Last updated on