RPC API Reference Complete reference for all RPC methods available on Nexis Appchain, including standard Ethereum JSON-RPC, Optimism-specific methods, and custom Nexis AI agent methods. 
Quick Start # HTTP RPC endpoint https://testnet-rpc.nex-t1.ai # WebSocket endpoint wss://testnet-ws.nex-t1.ai # Example request curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_blockNumber",     "params": [],     "id": 1   }' 
HTTP RPC https://testnet-rpc.nex-t1.aiRate Limit: 100 req/s 
WebSocket wss://testnet-ws.nex-t1.aiReal-time subscriptions 
Testnet Chain ID 84532 (0x14A34)Same as Base Sepolia 
Block Time 2 secondsFast finality 
Standard Ethereum JSON-RPC Methods Block Methods eth_blockNumber Get the latest block number. 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_blockNumber",     "params": [],     "id": 1   }' // ethers.js const  blockNumber  =  await  provider . getBlockNumber (); console . log ( 'Latest block:' ,  blockNumber ); # web3.py block_number  =  w3.eth.block_number print ( f "Latest block:  { block_number } " ) Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" :  "0x1b4"  // 436 in decimal } eth_getBlockByNumber Get block information by block number. 
Parameters: 
QUANTITY|TAG - Block number or tag (“earliest”, “latest”, “pending”, “safe”, “finalized”)Boolean - If true, returns full transaction objects; if false, only transaction hashes 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getBlockByNumber",     "params": ["latest", true],     "id": 1   }' // ethers.js const  block  =  await  provider . getBlock ( 'latest' ); console . log ( 'Block:' , {   number:  block . number ,   hash:  block . hash ,   timestamp:  block . timestamp ,   transactions:  block . transactions . length ,   gasUsed:  block . gasUsed . toString (),   gasLimit:  block . gasLimit . toString (), }); // viem import  {  createPublicClient ,  http  }  from  'viem' ; import  {  nexisTestnet  }  from  './chains' ; const  client  =  createPublicClient ({   chain:  nexisTestnet ,   transport:  http (), }); const  block  =  await  client . getBlock ({   blockTag:  'latest' ,   includeTransactions:  true , }); Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" : {     "number" :  "0x1b4" ,     "hash" :  "0xabc123..." ,     "parentHash" :  "0xdef456..." ,     "timestamp" :  "0x6538b7e0" ,     "transactions" : [ "0x789..." ,  "0x012..." ],     "gasUsed" :  "0x47e7c4" ,     "gasLimit" :  "0x1c9c380" ,     "baseFeePerGas" :  "0x3b9aca00" ,     "difficulty" :  "0x0" ,     "extraData" :  "0x" ,     "logsBloom" :  "0x..." ,     "miner" :  "0x4200000000000000000000000000000000000011" ,     "mixHash" :  "0x..." ,     "nonce" :  "0x0000000000000000" ,     "receiptsRoot" :  "0x..." ,     "sha3Uncles" :  "0x..." ,     "size" :  "0x3e8" ,     "stateRoot" :  "0x..." ,     "totalDifficulty" :  "0x0" ,     "transactionsRoot" :  "0x..." ,     "uncles" : []   } } eth_getBlockByHash Get block information by block hash. 
Parameters: 
DATA - 32-byte block hashBoolean - If true, returns full transaction objects 
const  block  =  await  provider . getBlock ( '0xabc123...' ); eth_getBlockTransactionCountByNumber Get transaction count in a block. 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getBlockTransactionCountByNumber",     "params": ["latest"],     "id": 1   }' const  txCount  =  await  provider . send ( 'eth_getBlockTransactionCountByNumber' , [ 'latest' ]); console . log ( 'Transactions in latest block:' ,  parseInt ( txCount ,  16 )); Transaction Methods eth_getTransactionByHash Get transaction details by hash. 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getTransactionByHash",     "params": ["0x123abc..."],     "id": 1   }' const  tx  =  await  provider . getTransaction ( '0x123abc...' ); console . log ( 'Transaction:' , {   from:  tx . from ,   to:  tx . to ,   value:  ethers . formatEther ( tx . value ),   gasPrice:  ethers . formatUnits ( tx . gasPrice ,  'gwei' ),   nonce:  tx . nonce ,   data:  tx . data , }); Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" : {     "blockHash" :  "0xabc..." ,     "blockNumber" :  "0x1b4" ,     "from" :  "0x1234..." ,     "to" :  "0x5678..." ,     "gas" :  "0x5208" ,     "gasPrice" :  "0x3b9aca00" ,     "hash" :  "0x123abc..." ,     "input" :  "0x" ,     "nonce" :  "0x0" ,     "r" :  "0x..." ,     "s" :  "0x..." ,     "v" :  "0x25" ,     "transactionIndex" :  "0x0" ,     "type" :  "0x2" ,     "value" :  "0xde0b6b3a7640000" ,     "maxFeePerGas" :  "0x59682f00" ,     "maxPriorityFeePerGas" :  "0x3b9aca00"   } } eth_getTransactionReceipt Get transaction receipt (confirmation status, logs, gas used). 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getTransactionReceipt",     "params": ["0x123abc..."],     "id": 1   }' const  receipt  =  await  provider . getTransactionReceipt ( '0x123abc...' ); console . log ( 'Receipt:' , {   status:  receipt . status ,  // 1 = success, 0 = failed   blockNumber:  receipt . blockNumber ,   gasUsed:  receipt . gasUsed . toString (),   effectiveGasPrice:  ethers . formatUnits ( receipt . effectiveGasPrice ,  'gwei' ),   logs:  receipt . logs . length , }); Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" : {     "blockHash" :  "0xabc..." ,     "blockNumber" :  "0x1b4" ,     "contractAddress" :  null ,     "cumulativeGasUsed" :  "0x5208" ,     "effectiveGasPrice" :  "0x3b9aca00" ,     "from" :  "0x1234..." ,     "to" :  "0x5678..." ,     "gasUsed" :  "0x5208" ,     "logs" : [],     "logsBloom" :  "0x..." ,     "status" :  "0x1" ,     "transactionHash" :  "0x123abc..." ,     "transactionIndex" :  "0x0" ,     "type" :  "0x2"   } } eth_sendRawTransaction Send a signed transaction. 
// ethers.js const  wallet  =  new  ethers . Wallet ( privateKey ,  provider ); const  tx  =  await  wallet . sendTransaction ({   to:  '0x5678...' ,   value:  ethers . parseEther ( '0.1' ),   gasLimit:  21000 , }); console . log ( 'TX hash:' ,  tx . hash ); await  tx . wait ();  // Wait for confirmation console . log ( 'Confirmed!' ); # Using cast (Foundry) cast  send  0x5678...  \   --value  0.1ether  \   --private-key  $PRIVATE_KEY  \   --rpc-url  https://testnet-rpc.nex-t1.ai # web3.py from  web3  import  Web3 from  eth_account  import  Account w3  =  Web3(Web3.HTTPProvider( 'https://testnet-rpc.nex-t1.ai' )) account  =  Account.from_key( '0xYourPrivateKey' ) tx  =  {     'from' : account.address,     'to' :  '0x5678...' ,     'value' : w3.to_wei( 0.1 ,  'ether' ),     'gas' :  21000 ,     'gasPrice' : w3.eth.gas_price,     'nonce' : w3.eth.get_transaction_count(account.address),     'chainId' :  84532 } signed_tx  =  account.sign_transaction(tx) tx_hash  =  w3.eth.send_raw_transaction(signed_tx.rawTransaction) print ( f "TX hash:  { tx_hash.hex() } " ) # Wait for receipt receipt  =  w3.eth.wait_for_transaction_receipt(tx_hash) print ( f "Status:  { 'Success'  if  receipt[ 'status' ]  ==  1  else  'Failed' } " ) eth_getTransactionCount Get transaction count (nonce) for an address. 
const  nonce  =  await  provider . getTransactionCount ( '0x1234...' ,  'latest' ); console . log ( 'Nonce:' ,  nonce ); // Get pending nonce (includes pending transactions) const  pendingNonce  =  await  provider . getTransactionCount ( '0x1234...' ,  'pending' ); curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getTransactionCount",     "params": ["0x1234...", "latest"],     "id": 1   }' Account Methods eth_getBalance Get account balance. 
const  balance  =  await  provider . getBalance ( '0x1234...' ); console . log ( 'Balance:' ,  ethers . formatEther ( balance ),  'NZT' ); curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getBalance",     "params": ["0x1234...", "latest"],     "id": 1   }' balance_wei  =  w3.eth.get_balance( '0x1234...' ) balance_eth  =  w3.from_wei(balance_wei,  'ether' ) print ( f "Balance:  { balance_eth }  NZT" ) Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" :  "0x8ac7230489e80000"  // 10 NZT in hex wei } eth_getCode Get contract bytecode at an address. 
const  code  =  await  provider . getCode ( '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' ); console . log ( 'Contract code length:' ,  code . length ); console . log ( 'Is contract:' ,  code  !==  '0x' ); curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getCode",     "params": ["0x742d...", "latest"],     "id": 1   }' eth_getStorageAt Get storage value at a specific position. 
// Get storage slot 0 of a contract const  storage  =  await  provider . getStorage (   '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' ,   0  // storage slot ); console . log ( 'Storage at slot 0:' ,  storage ); State Query Methods eth_call Execute a contract function without creating a transaction (read-only). 
// Call a view function const  contract  =  new  ethers . Contract ( address ,  abi ,  provider ); const  result  =  await  contract . getAgent ( agentId ); console . log ( 'Agent data:' ,  result ); // Or use provider.call directly const  data  =  contract . interface . encodeFunctionData ( 'getAgent' , [ agentId ]); const  result  =  await  provider . call ({   to:  address ,   data:  data , }); # Using cast cast  call  0x742d...  "getAgent(uint256)"  1  \   --rpc-url  https://testnet-rpc.nex-t1.ai # web3.py contract  =  w3.eth.contract( address = contract_address,  abi = abi) result  =  contract.functions.getAgent(agent_id).call() print ( f "Agent:  { result } " ) eth_estimateGas Estimate gas needed for a transaction. 
const  gasEstimate  =  await  provider . estimateGas ({   to:  '0x742d...' ,   data:  contract . interface . encodeFunctionData ( 'createTask' , [ ... args ]),   value:  ethers . parseEther ( '1.0' ), }); console . log ( 'Estimated gas:' ,  gasEstimate . toString ()); // Add buffer (10%) for safety const  gasLimit  =  gasEstimate  *  110 n  /  100 n ; curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_estimateGas",     "params": [{       "from": "0x1234...",       "to": "0x742d...",       "data": "0xabcd..."     }],     "id": 1   }' Gas & Fee Methods eth_gasPrice Get current gas price. 
const  gasPrice  =  await  provider . getFeeData (); console . log ( 'Gas price:' ,  ethers . formatUnits ( gasPrice . gasPrice ,  'gwei' ),  'gwei' ); console . log ( 'Max fee:' ,  ethers . formatUnits ( gasPrice . maxFeePerGas ,  'gwei' ),  'gwei' ); console . log ( 'Priority fee:' ,  ethers . formatUnits ( gasPrice . maxPriorityFeePerGas ,  'gwei' ),  'gwei' ); curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_gasPrice",     "params": [],     "id": 1   }' eth_feeHistory Get historical gas fee data. 
Parameters: 
QUANTITY - Number of blocksQUANTITY|TAG - Newest blockArray - Reward percentiles (e.g., [25, 50, 75]) 
const  feeHistory  =  await  provider . send ( 'eth_feeHistory' , [   '0x5' ,  // Last 5 blocks   'latest' ,   [ 25 ,  50 ,  75 ]  // 25th, 50th, 75th percentile ]); console . log ( 'Fee history:' ,  feeHistory ); Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" : {     "oldestBlock" :  "0x1af" ,     "baseFeePerGas" : [       "0x3b9aca00" ,       "0x3b9aca00" ,       "0x3b9aca00"     ],     "gasUsedRatio" : [ 0.5 ,  0.6 ,  0.4 ],     "reward" : [       [ "0x0" ,  "0x0" ,  "0x0" ],       [ "0x0" ,  "0x0" ,  "0x0" ]     ]   } } Event & Log Methods eth_getLogs Get event logs matching filter criteria. 
Parameters: 
fromBlock: Starting block (number or “earliest”, “latest”)toBlock: Ending blockaddress: Contract address(es) to filtertopics: Event signature and indexed parameters 
// Get all TaskCreated events const  logs  =  await  provider . getLogs ({   address:  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' ,   fromBlock:  1000000 ,   toBlock:  'latest' ,   topics:  [     ethers . id ( 'TaskCreated(uint256,address,string,uint256)' )   ] }); console . log ( 'Found' ,  logs . length ,  'TaskCreated events' ); // Decode logs const  iface  =  new  ethers . Interface ([   'event TaskCreated(uint256 indexed taskId, address indexed creator, string description, uint256 reward)' ]); for  ( const  log  of  logs ) {   const  decoded  =  iface . parseLog ( log );   console . log ( 'Task' ,  decoded . args . taskId . toString (),  'created by' ,  decoded . args . creator ); } curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_getLogs",     "params": [{       "address": "0x742d...",       "fromBlock": "0xf4240",       "toBlock": "latest",       "topics": ["0x..."]     }],     "id": 1   }' Advanced filtering: // Filter by multiple contracts const  logs  =  await  provider . getLogs ({   address:  [     '0x742d...' ,  // Tasks contract     '0x1234...'   // Agents contract   ],   fromBlock:  1000000 ,   toBlock:  'latest' }); // Filter by indexed parameters const  agentAddress  =  '0xabcd...' ; const  logs  =  await  provider . getLogs ({   address:  '0x1234...' ,  // Agents contract   topics:  [     ethers . id ( 'StakeIncreased(uint256,address,address,uint256,uint256)' ),     null ,  // agentId (not filtering)     null ,  // asset (not filtering)     ethers . zeroPadValue ( agentAddress ,  32 )  // staker address   ] }); eth_newFilter Create a log filter. 
const  filter  =  await  provider . send ( 'eth_newFilter' , [{   address:  '0x742d...' ,   topics:  [ ethers . id ( 'TaskCreated(uint256,address,string,uint256)' )] }]); console . log ( 'Filter ID:' ,  filter ); // Get changes const  changes  =  await  provider . send ( 'eth_getFilterChanges' , [ filter ]); eth_newBlockFilter Create a block filter for new blocks. 
const  filterId  =  await  provider . send ( 'eth_newBlockFilter' , []); // Poll for new blocks setInterval ( async  ()  =>  {   const  newBlocks  =  await  provider . send ( 'eth_getFilterChanges' , [ filterId ]);   if  ( newBlocks . length  >  0 ) {     console . log ( 'New blocks:' ,  newBlocks );   } },  2000 );  // Poll every 2 seconds eth_chainId Get chain ID. 
const  network  =  await  provider . getNetwork (); console . log ( 'Chain ID:' ,  network . chainId );  // 84532 curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "eth_chainId",     "params": [],     "id": 1   }' Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" :  "0x14A34"  // 84532 } net_version Get network ID (same as chain ID). 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "net_version",     "params": [],     "id": 1   }' web3_clientVersion Get client version information. 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "web3_clientVersion",     "params": [],     "id": 1   }' Response: {   "jsonrpc" :  "2.0" ,   "id" :  1 ,   "result" :  "op-geth/v1.101315.1-stable/linux-amd64/go1.21.5" } Optimism-Specific Methods Nexis is built on the OP Stack, so Optimism-specific methods are available. 
optimism_syncStatus Get L2 sync status relative to L1. 
const  syncStatus  =  await  provider . send ( 'optimism_syncStatus' , []); console . log ( 'Sync status:' , {   unsafeL2:  syncStatus . unsafe_l2 . number ,   safeL2:  syncStatus . safe_l2 . number ,   finalizedL2:  syncStatus . finalized_l2 . number ,   currentL1:  syncStatus . current_l1 . number , }); Response: {   "unsafe_l2" : {     "hash" :  "0xabc..." ,     "number" :  1234567 ,     "timestamp" :  1234567890 ,     "l1origin" : {       "hash" :  "0xdef..." ,       "number" :  9876543     }   },   "safe_l2" : {     "hash" :  "0x123..." ,     "number" :  1234560 ,     "timestamp" :  1234567880   },   "finalized_l2" : {     "hash" :  "0x456..." ,     "number" :  1234550 ,     "timestamp" :  1234567860   },   "current_l1" : {     "hash" :  "0x789..." ,     "number" :  9876545 ,     "timestamp" :  1234567892   } } Sync states explained: 
Unsafe L2 : Latest block received from sequencer (may be reorged)Safe L2 : Block derived from finalized L1 data (unlikely to reorg)Finalized L2 : Block based on finalized L1 block (cannot reorg) 
optimism_rollupConfig Get rollup configuration. 
curl  -X  POST  https://testnet-rpc.nex-t1.ai  \   -H  "Content-Type: application/json"  \   -d  '{     "jsonrpc": "2.0",     "method": "optimism_rollupConfig",     "params": [],     "id": 1   }' Response: {   "genesis" : {     "l1" : {       "hash" :  "0x..." ,       "number" :  1234567     },     "l2" : {       "hash" :  "0x..." ,       "number" :  0     },     "l2_time" :  1234567890   },   "block_time" :  2 ,   "max_sequencer_drift" :  600 ,   "seq_window_size" :  3600 ,   "channel_timeout" :  300 ,   "l1_chain_id" :  84532 ,   "l2_chain_id" :  84532 ,   "batch_inbox_address" :  "0xff..." ,   "deposit_contract_address" :  "0x..." ,   "l1_system_config_address" :  "0x..." } optimism_outputAtBlock Get output root at a specific block (for withdrawals). 
const  outputRoot  =  await  provider . send ( 'optimism_outputAtBlock' , [ 'latest' ]); console . log ( 'Output root:' ,  outputRoot ); WebSocket Subscriptions Connect via WebSocket for real-time events. 
Subscribe to New Blocks import  {  ethers  }  from  'ethers' ; const  wsProvider  =  new  ethers . WebSocketProvider ( 'wss://testnet-ws.nex-t1.ai' ); // Subscribe to new blocks wsProvider . on ( 'block' , ( blockNumber )  =>  {   console . log ( 'New block:' ,  blockNumber ); }); // Or use subscription API const  subscription  =  await  wsProvider . send ( 'eth_subscribe' , [ 'newHeads' ]); wsProvider . on ( subscription , ( block )  =>  {   console . log ( 'New block:' ,  block . number ,  block . hash ); }); Subscribe to Pending Transactions const  subscription  =  await  wsProvider . send ( 'eth_subscribe' , [ 'newPendingTransactions' ]); wsProvider . on ( subscription , ( txHash )  =>  {   console . log ( 'Pending TX:' ,  txHash );   // Get full transaction details   wsProvider . getTransaction ( txHash ). then ( tx  =>  {     console . log ( 'TX details:' ,  tx );   }); }); Subscribe to Event Logs // Subscribe to specific contract events const  subscription  =  await  wsProvider . send ( 'eth_subscribe' , [   'logs' ,   {     address:  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' ,     topics:  [ ethers . id ( 'TaskCreated(uint256,address,string,uint256)' )]   } ]); wsProvider . on ( subscription , ( log )  =>  {   const  iface  =  new  ethers . Interface ([     'event TaskCreated(uint256 indexed taskId, address indexed creator, string description, uint256 reward)'   ]);   const  decoded  =  iface . parseLog ( log );   console . log ( 'Task created:' ,  decoded . args . taskId . toString ()); }); Python WebSocket Example import  asyncio import  websockets import  json async  def  subscribe_blocks ():     uri  =  "wss://testnet-ws.nex-t1.ai"     async  with  websockets.connect(uri)  as  ws:         # Subscribe to new blocks         await  ws.send(json.dumps({             "jsonrpc" :  "2.0" ,             "id" :  1 ,             "method" :  "eth_subscribe" ,             "params" : [ "newHeads" ]         }))         subscription_response  =  await  ws.recv()         print ( f "Subscribed:  { subscription_response } " )         # Listen for blocks         while  True :             message  =  await  ws.recv()             data  =  json.loads(message)             block  =  data[ 'params' ][ 'result' ]             print ( f "New block:  { int (block[ 'number' ],  16 ) } " ) asyncio.run(subscribe_blocks()) Batch Requests Send multiple RPC requests in a single HTTP call. 
// Using ethers.js const  [ blockNumber ,  gasPrice ,  balance ]  =  await  Promise . all ([   provider . getBlockNumber (),   provider . getFeeData (),   provider . getBalance ( '0x1234...' ) ]); // Or using raw batch request const  batchRequest  =  [   {     jsonrpc:  '2.0' ,     id:  1 ,     method:  'eth_blockNumber' ,     params:  []   },   {     jsonrpc:  '2.0' ,     id:  2 ,     method:  'eth_gasPrice' ,     params:  []   },   {     jsonrpc:  '2.0' ,     id:  3 ,     method:  'eth_getBalance' ,     params:  [ '0x1234...' ,  'latest' ]   } ]; const  response  =  await  fetch ( 'https://testnet-rpc.nex-t1.ai' , {   method:  'POST' ,   headers:  {  'Content-Type' :  'application/json'  },   body:  JSON . stringify ( batchRequest ) }); const  results  =  await  response . json (); Rate Limiting Tier Limit Burst Notes Free 100 req/s 150 req/s Public endpoint Developer 500 req/s 750 req/s Register on Discord Enterprise Custom Custom Contact team 
Handling Rate Limits class  RateLimitedProvider  extends  ethers . JsonRpcProvider  {   constructor ( url ,  maxRequestsPerSecond  =  10 ) {     super ( url );     this . maxRPS  =  maxRequestsPerSecond ;     this . requestQueue  =  [];     this . processing  =  false ;     this . requestCount  =  0 ;     // Reset counter every second     setInterval (()  =>  {       this . requestCount  =  0 ;       this . processQueue ();     },  1000 );   }   async  send ( method ,  params ) {     return  new  Promise (( resolve ,  reject )  =>  {       this . requestQueue . push ({  method ,  params ,  resolve ,  reject  });       this . processQueue ();     });   }   async  processQueue () {     if  ( this . processing  ||  this . requestQueue . length  ===  0 )  return ;     if  ( this . requestCount  >=  this . maxRPS )  return ;     this . processing  =  true ;     while  ( this . requestQueue . length  >  0  &&  this . requestCount  <  this . maxRPS ) {       const  request  =  this . requestQueue . shift ();       this . requestCount ++ ;       try  {         const  result  =  await  super . send ( request . method ,  request . params );         request . resolve ( result );       }  catch  ( error ) {         if  ( error . code  ===  429 ) {           // Rate limited - re-queue           this . requestQueue . unshift ( request );           break ;         }         request . reject ( error );       }     }     this . processing  =  false ;   } } // Usage const  provider  =  new  RateLimitedProvider (   'https://testnet-rpc.nex-t1.ai' ,   10  // 10 requests per second ); Error Handling Common Error Codes Code Message Meaning Solution -32700Parse error Invalid JSON Check JSON formatting -32600Invalid request Malformed RPC Verify method and params -32601Method not found Unknown method Check method name -32602Invalid params Wrong parameters Verify param types/count -32603Internal error Server error Retry or contact support -32000Server error Generic error Check error message 3Execution reverted TX failed Check contract logic 429Rate limited Too many requests Implement backoff 
Error Handling Examples async  function  safeRpcCall ( provider ,  method ,  params ,  maxRetries  =  3 ) {   for  ( let  i  =  0 ;  i  <  maxRetries ;  i ++ ) {     try  {       return  await  provider . send ( method ,  params );     }  catch  ( error ) {       console . error ( `Attempt  ${ i  +  1 }  failed:` ,  error . message );       if  ( error . code  ===  429 ) {         // Rate limited - exponential backoff         const  delay  =  Math . pow ( 2 ,  i )  *  1000 ;         console . log ( `Waiting  ${ delay } ms before retry...` );         await  new  Promise ( r  =>  setTimeout ( r ,  delay ));       }  else  if  ( error . code  ===  - 32603 ) {         // Internal error - retry         await  new  Promise ( r  =>  setTimeout ( r ,  1000 ));       }  else  {         // Other error - don't retry         throw  error ;       }     }   }   throw  new  Error ( 'Max retries exceeded' ); } // Usage try  {   const  balance  =  await  safeRpcCall (     provider ,     'eth_getBalance' ,     [ '0x1234...' ,  'latest' ]   );   console . log ( 'Balance:' ,  balance ); }  catch  ( error ) {   console . error ( 'Failed to get balance:' ,  error ); } 1. Use Batch Requests // ❌ Slow: Sequential requests const  block1  =  await  provider . getBlock ( 100 ); const  block2  =  await  provider . getBlock ( 101 ); const  block3  =  await  provider . getBlock ( 102 ); // ✅ Fast: Parallel batch const  [ block1 ,  block2 ,  block3 ]  =  await  Promise . all ([   provider . getBlock ( 100 ),   provider . getBlock ( 101 ),   provider . getBlock ( 102 ), ]); 2. Cache Immutable Data class  CachingProvider  extends  ethers . JsonRpcProvider  {   constructor ( url ) {     super ( url );     this . cache  =  new  Map ();   }   async  getBlock ( blockTag ) {     // Only cache by block number (immutable)     if  ( typeof  blockTag  ===  'number' ) {       const  cacheKey  =  `block_ ${ blockTag } ` ;       if  ( this . cache . has ( cacheKey )) {         return  this . cache . get ( cacheKey );       }       const  block  =  await  super . getBlock ( blockTag );       this . cache . set ( cacheKey ,  block );       return  block ;     }     // Don't cache 'latest', 'pending', etc.     return  super . getBlock ( blockTag );   } } 3. Use WebSockets for Real-time Data // ❌ Polling (wasteful) setInterval ( async  ()  =>  {   const  blockNumber  =  await  provider . getBlockNumber ();   console . log ( 'Block:' ,  blockNumber ); },  2000 ); // ✅ WebSocket subscription (efficient) wsProvider . on ( 'block' , ( blockNumber )  =>  {   console . log ( 'Block:' ,  blockNumber ); }); Complete Integration Example // complete-rpc-integration.ts import  {  ethers  }  from  'ethers' ; class  NexisRPCClient  {   private  httpProvider :  ethers . JsonRpcProvider ;   private  wsProvider :  ethers . WebSocketProvider ;   constructor () {     this . httpProvider  =  new  ethers . JsonRpcProvider (       'https://testnet-rpc.nex-t1.ai'     );     this . wsProvider  =  new  ethers . WebSocketProvider (       'wss://testnet-ws.nex-t1.ai'     );   }   // Block methods   async  getLatestBlock () {     return  await  this . httpProvider . getBlock ( 'latest' );   }   async  getBlockByNumber ( blockNumber :  number ) {     return  await  this . httpProvider . getBlock ( blockNumber );   }   // Transaction methods   async  getTransaction ( txHash :  string ) {     return  await  this . httpProvider . getTransaction ( txHash );   }   async  sendTransaction ( tx :  ethers . TransactionRequest ) {     const  signer  =  await  this . httpProvider . getSigner ();     return  await  signer . sendTransaction ( tx );   }   // Account methods   async  getBalance ( address :  string ) {     return  await  this . httpProvider . getBalance ( address );   }   async  getNonce ( address :  string ) {     return  await  this . httpProvider . getTransactionCount ( address );   }   // Contract interaction   async  callContract (     address :  string ,     abi :  any [],     method :  string ,     args :  any []   ) {     const  contract  =  new  ethers . Contract ( address ,  abi ,  this . httpProvider );     return  await  contract [ method ]( ... args );   }   // Event listening   subscribeToBlocks ( callback :  ( blockNumber :  number )  =>  void ) {     this . wsProvider . on ( 'block' ,  callback );   }   subscribeToLogs (     address :  string ,     topics :  string [],     callback :  ( log :  ethers . Log )  =>  void   ) {     const  filter  =  {       address ,       topics ,     };     this . wsProvider . on ( filter ,  callback );   }   // Batch requests   async  batchCall ( calls :  Array <{     method :  string ;     params :  any [];   }>) {     return  await  Promise . all (       calls . map ( call  =>  this . httpProvider . send ( call . method ,  call . params ))     );   }   // Cleanup   destroy () {     this . wsProvider . destroy ();   } } // Usage const  client  =  new  NexisRPCClient (); // Get latest block const  block  =  await  client . getLatestBlock (); console . log ( 'Latest block:' ,  block . number ); // Subscribe to new blocks client . subscribeToBlocks (( blockNumber )  =>  {   console . log ( 'New block:' ,  blockNumber ); }); // Get balance const  balance  =  await  client . getBalance ( '0x1234...' ); console . log ( 'Balance:' ,  ethers . formatEther ( balance )); // Batch call const  results  =  await  client . batchCall ([   {  method:  'eth_blockNumber' ,  params:  [] },   {  method:  'eth_gasPrice' ,  params:  [] },   {  method:  'eth_getBalance' ,  params:  [ '0x1234...' ,  'latest' ] }, ]); Resources Pro Tip:  Use WebSocket subscriptions for real-time updates and HTTP for one-off queries. This combination provides the best performance!
For production applications, consider running your own RPC node  for better reliability and no rate limits.