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
}'
Endpoint Information
HTTP RPC
https://testnet-rpc.nex-t1.aiRate Limit: 100 req/sWebSocket
wss://testnet-ws.nex-t1.aiReal-time subscriptionsTestnet Chain ID
84532 (0x14A34)Same as Base SepoliaBlock Time
2 secondsFast finalityStandard 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}")
{
"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,
});
{
"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,
});
{
"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,
});
{
"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")
{
"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 * 110n / 100n;
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);
{
"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
}'
// 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
Chain Information Methods
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
}'
{
"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
}'
{
"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,
});
{
"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
}
}
- 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
}'
{
"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
Rate Limit Information
| 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 |
|---|---|---|---|
-32700 | Parse error | Invalid JSON | Check JSON formatting |
-32600 | Invalid request | Malformed RPC | Verify method and params |
-32601 | Method not found | Unknown method | Check method name |
-32602 | Invalid params | Wrong parameters | Verify param types/count |
-32603 | Internal error | Server error | Retry or contact support |
-32000 | Server error | Generic error | Check error message |
3 | Execution reverted | TX failed | Check contract logic |
429 | Rate 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);
}
Performance Optimization
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
RPC Infrastructure
Learn about RPC architecture
Run Your Own Node
Setup your own RPC node
Smart Contracts
Integrate with Nexis contracts
Building Guide
Complete development guide
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.