Skip to main content

Making RPC Calls Using Avalanche SDK

In this guide, you will learn how to make JSON-RPC calls to Avalanche’s chains using the Avalanche SDK Client, a TypeScript SDK that provides comprehensive tools to interact with all Avalanche chains (P-Chain, X-Chain, C-Chain) and various APIs, including wallet functionality for transaction signing and management.

Prerequisites

Before you begin, make sure you have the following:
  • Node.js (v14+) installed on your machine
  • Basic familiarity with TypeScript/JavaScript and the command line
  • Access to an Avalanche node endpoint (public or private)

Step 1: Install Dependencies

Create a new project and install the required packages:
# Create a new Node.js project
mkdir avalanche-sdk-example
cd avalanche-sdk-example
npm init -y

# Install Avalanche SDK
npm install @avalanche-sdk/client

# Install TypeScript dependencies (optional, for TypeScript examples)
npm install -D typescript @types/node tsx

# Initialize TypeScript (if using TypeScript)
npx tsc --init

Step 2: Create the Avalanche Client

Create a new file called avalancheClient.ts to set up the Avalanche SDK client:
import { createAvalancheClient } from '@avalanche-sdk/client'
import { avalanche, avalancheFuji } from '@avalanche-sdk/client/chains'

// Create client for mainnet
export const mainnetClient = createAvalancheClient({
  chain: avalanche,
  transport: {
    type: 'http',
    // URL is optional - defaults to chain's default RPC endpoint
  }
})

// Create client for testnet (Fuji)
export const testnetClient = createAvalancheClient({
  chain: avalancheFuji,
  transport: {
    type: 'http',
  }
})

// Access different chain clients
const pChainClient = mainnetClient.pChain
const xChainClient = mainnetClient.xChain
const cChainClient = mainnetClient.cChain

// Access API clients
const adminClient = mainnetClient.admin
const infoClient = mainnetClient.info
const healthClient = mainnetClient.health

Step 3: P-Chain Operations

Create a file called pChainOperations.ts to demonstrate P-Chain operations:
import { createAvalancheClient } from '@avalanche-sdk/client'
import { avalanche } from '@avalanche-sdk/client/chains'

const client = createAvalancheClient({
  chain: avalanche,
  transport: { type: 'http' }
})

async function pChainExamples() {
  try {
    // Get the current height of the P-Chain
    console.log('Fetching P-Chain height...')
    const height = await client.pChain.getHeight()
    console.log('Current P-Chain Height:', height)

    // Get current validators
    console.log('\nFetching current validators...')
    const validators = await client.pChain.getCurrentValidators({})
    console.log(`Total validators: ${validators.validators.length}`)
    
    // Display first 3 validators
    validators.validators.slice(0, 3).forEach((validator, index) => {
      console.log(`\nValidator ${index + 1}:`)
      console.log(`  Node ID: ${validator.nodeID}`)
      console.log(`  Stake Amount: ${validator.stakeAmount}`)
      console.log(`  Start Time: ${validator.startTime}`)
      console.log(`  End Time: ${validator.endTime}`)
    })

    // Get minimum stake requirements
    console.log('\nMinimum stake requirements:')
    const minStake = await client.pChain.getMinStake({})
    console.log('Min Stake:', minStake)

    // Get balance for a P-Chain address
    const address = 'P-avax1tzdcgj4ehsvhhxpl3zylss2ukyyqvqc8nmkrx6'
    const balance = await client.pChain.getBalance({
      addresses: [address]
    })
    console.log(`\nBalance for ${address}:`, balance)

    // Get current supply
    const supply = await client.pChain.getCurrentSupply()
    console.log('\nCurrent AVAX Supply:', supply)

  } catch (error) {
    console.error('Error in P-Chain operations:', error)
  }
}

// Run the example
pChainExamples()

Step 4: X-Chain Operations

Create a file called xChainOperations.ts for X-Chain operations:
import { createAvalancheClient } from '@avalanche-sdk/client'
import { avalanche } from '@avalanche-sdk/client/chains'

const client = createAvalancheClient({
  chain: avalanche,
  transport: { type: 'http' }
})

async function xChainExamples() {
  try {
    // Get X-Chain height
    const height = await client.xChain.getHeight()
    console.log('X-Chain Height:', height)

    // Get all balances for an address
    const address = 'X-avax1tzdcgj4ehsvhhxpl3zylss2ukyyqvqc8nmkrx6'
    const balances = await client.xChain.getAllBalances({
      address: address
    })
    console.log(`\nAll balances for ${address}:`, balances)

    // Get specific asset balance
    const assetID = 'AVAX' // You can use actual asset ID
    const balance = await client.xChain.getBalance({
      address: address,
      assetID: assetID
    })
    console.log(`\n${assetID} balance:`, balance)

    // Get UTXOs
    const utxos = await client.xChain.getUTXOs({
      addresses: [address],
      limit: 5
    })
    console.log('\nUTXOs:', utxos)

  } catch (error) {
    console.error('Error in X-Chain operations:', error)
  }
}

// Run the example
xChainExamples()

Step 5: Wallet Operations

Create a file called walletOperations.ts to demonstrate wallet functionality:
import { 
  createAvalancheWalletClient, 
  privateKeyToAvalancheAccount 
} from '@avalanche-sdk/client'
import { avalanche } from '@avalanche-sdk/client/chains'

// IMPORTANT: Never hardcode private keys in production!
// Use environment variables or secure key management
const PRIVATE_KEY = process.env.PRIVATE_KEY || '0x...'

async function walletExamples() {
  try {
    // Create an account from private key
    const account = privateKeyToAvalancheAccount(PRIVATE_KEY)

    // Get addresses
    const evmAddress = account.getEVMAddress()
    const pChainAddress = account.getXPAddress("P", "avax")
    const xChainAddress = account.getXPAddress("X", "avax")

    console.log('EVM Address:', evmAddress)
    console.log('P-Chain Address:', pChainAddress)
    console.log('X-Chain Address:', xChainAddress)

    // Create a wallet client
    const walletClient = createAvalancheWalletClient({
      account,
      chain: avalanche,
      transport: {
        type: "http",
      },
    })

    // Get account public key
    const pubKey = await walletClient.getAccountPubKey()
    console.log('\nPublic Key:', pubKey)

    // Example: Prepare a P-Chain base transaction
    const pChainWallet = walletClient.pChain
    const baseTx = await pChainWallet.prepareBaseTxn({
      outputs: [{
        addresses: [pChainAddress],
        amount: 1000000000, // 1 AVAX in nAVAX
      }],
    })
    console.log('\nPrepared base transaction:', baseTx)

    // Example: Sign a message
    const signedMessage = await walletClient.signXPMessage({
      message: "Hello Avalanche",
    })
    console.log('\nSigned message:', signedMessage)

  } catch (error) {
    console.error('Error in wallet operations:', error)
  }
}

// Run the example
walletExamples()

Step 6: Cross-Chain Transfers

Create a file called crossChainTransfers.ts for cross-chain transfer examples:
import { 
  createAvalancheWalletClient, 
  privateKeyToAvalancheAccount 
} from '@avalanche-sdk/client'
import { avalanche } from '@avalanche-sdk/client/chains'

const PRIVATE_KEY = process.env.PRIVATE_KEY || '0x...'

async function crossChainTransferExample() {
  try {
    const account = privateKeyToAvalancheAccount(PRIVATE_KEY)
    const walletClient = createAvalancheWalletClient({
      account,
      chain: avalanche,
      transport: { type: "http" },
    })

    // Example: Export from X-Chain to P-Chain
    const xChainWallet = walletClient.xChain
    const exportTx = await xChainWallet.prepareExportTxn({
      exportedOutputs: [{
        addresses: [account.getXPAddress("P", "avax")],
        amount: 0.1, // 0.1 AVAX
      }],
      destinationChain: "P",
    })

    console.log('Prepared export transaction:', exportTx)

    // Send the transaction
    const result = await walletClient.sendXPTransaction(exportTx)
    console.log('Transaction sent:', result)

    // Wait for confirmation
    await walletClient.waitForTxn({
      txID: result.txID,
      chainAlias: "X"
    })
    console.log('Transaction confirmed!')

  } catch (error) {
    console.error('Error in cross-chain transfer:', error)
  }
}

// Run the example
crossChainTransferExample()

Step 7: Advanced Transport Configuration

The SDK supports multiple transport types for different use cases:
import { createAvalancheClient } from '@avalanche-sdk/client'
import { avalanche } from '@avalanche-sdk/client/chains'

// HTTP Transport with custom configuration
const httpClient = createAvalancheClient({
  chain: avalanche,
  transport: {
    type: "http",
    url: "https://api.avax.network/ext/bc/C/rpc", // Custom RPC URL
    config: {
      fetchOptions: {
        headers: {
          "Custom-Header": "value"
        },
      },
      retryCount: 3,
      retryDelay: 1000,
      timeout: 5000
    }
  },
  apiKey: "your-api-key", // Optional
  rlToken: "your-rate-limit-token" // Optional
})

// WebSocket Transport for real-time updates
const wsClient = createAvalancheClient({
  chain: avalanche,
  transport: {
    type: "ws",
    url: "wss://api.avax.network/ext/bc/C/ws",
    config: {
      retryCount: 3,
      retryDelay: 1000
    }
  }
})

// Fallback Transport for high availability
const fallbackClient = createAvalancheClient({
  chain: avalanche,
  transport: {
    type: "fallback",
    transports: [
      { type: "http", url: "https://api.avax.network/ext/bc/C/rpc" },
      { type: "http", url: "https://rpc.ankr.com/avalanche" },
      { type: "http", url: "https://avalanche.public-rpc.com" }
    ],
    config: {
      retryCount: 5,
      retryDelay: 2000
    }
  }
})

Using Environment Variables

For production use, store sensitive data in environment variables:
import { createAvalancheClient } from '@avalanche-sdk/client'
import { avalanche, avalancheFuji } from '@avalanche-sdk/client/chains'

const network = process.env.AVALANCHE_NETWORK || 'mainnet'
const chain = network === 'mainnet' ? avalanche : avalancheFuji

export const client = createAvalancheClient({
  chain,
  transport: {
    type: 'http',
    url: process.env.AVALANCHE_RPC_URL,
  },
  apiKey: process.env.AVALANCHE_API_KEY,
})

Conclusion

The Avalanche SDK provides a comprehensive set of tools for interacting with the Avalanche network:
  • Multi-Chain Support: Complete API coverage for P-Chain, X-Chain, and C-Chain
  • Wallet Functionality: Transaction signing, account management, and cross-chain transfers
  • Type Safety: Full TypeScript support with auto-completion
  • Transport Flexibility: HTTP, WebSocket, and fallback options for different use cases
  • Built on Viem: Full compatibility with viem functionality
For more examples and detailed documentation:
I