Custom provider

Learn how to configure custom providers and RPC endpoints for optimal performance.

Basic Provider Setup

const { ethers } = require('ethers')
const { MoroBestRate } = require('@moromoro/moro-sdk')

// JsonRpcProvider
const provider = new ethers.providers.JsonRpcProvider(
  'https://rpc.hyperliquid.xyz/evm'
)

const moroClient = new MoroBestRate(provider, 'hyperevm')

Using Custom RPC Endpoints

// High-performance RPC
const customProvider = new ethers.providers.JsonRpcProvider(
  'https://your-custom-rpc.com',
  {
    chainId: 998, // HyperEVM chain ID (example)
    name: 'hyperevm'
  }
)

const moroClient = new MoroBestRate(customProvider, 'hyperevm')

Provider with API Key

const apiKey = process.env.RPC_API_KEY

const provider = new ethers.providers.JsonRpcProvider(
  `https://your-rpc-provider.com/${apiKey}`
)

const moroClient = new MoroBestRate(provider, 'hyperevm')

WebSocket Provider

For real-time updates and better performance:

const { ethers } = require('ethers')
const { MoroBestRate } = require('@moromoro/moro-sdk')

const wsProvider = new ethers.providers.WebSocketProvider(
  'wss://your-websocket-endpoint.com'
)

const moroClient = new MoroBestRate(wsProvider, 'hyperevm')

// Remember to close connection when done
process.on('exit', () => {
  wsProvider.destroy()
})

Fallback Provider

Use multiple RPC endpoints for reliability:

const { ethers } = require('ethers')
const { MoroBestRate } = require('@moromoro/moro-sdk')

const provider = new ethers.providers.FallbackProvider([
  {
    provider: new ethers.providers.JsonRpcProvider('https://rpc1.hyperliquid.xyz/evm'),
    priority: 1,
    stallTimeout: 2000
  },
  {
    provider: new ethers.providers.JsonRpcProvider('https://rpc2.hyperliquid.xyz/evm'),
    priority: 2,
    stallTimeout: 2000
  }
])

const moroClient = new MoroBestRate(provider, 'hyperevm')

Provider Caching

Reuse provider instances for better performance:

const { ethers } = require('ethers')
const { MoroBestRate } = require('@moromoro/moro-sdk')

class ProviderManager {
  constructor() {
    this.providers = new Map()
  }

  getProvider(network, rpcUrl) {
    const key = `${network}-${rpcUrl}`

    if (!this.providers.has(key)) {
      const provider = new ethers.providers.JsonRpcProvider(rpcUrl)
      this.providers.set(key, provider)
    }

    return this.providers.get(key)
  }

  getClient(network, rpcUrl, options = {}) {
    const provider = this.getProvider(network, rpcUrl)
    return new MoroBestRate(provider, network, options)
  }
}

// Usage
const manager = new ProviderManager()

const client1 = manager.getClient('hyperevm', 'https://rpc.hyperliquid.xyz/evm')
const client2 = manager.getClient('hyperevm', 'https://rpc.hyperliquid.xyz/evm') // Reuses provider

Custom Network Configuration

const { ethers } = require('ethers')
const { initProvider } = require('@moromoro/moro-sdk')

// Using SDK's provider initializer
const provider = initProvider('https://rpc.hyperliquid.xyz/evm')

// Or custom configuration
const customProvider = new ethers.providers.JsonRpcProvider(
  'https://your-rpc.com',
  {
    chainId: 998,
    name: 'hyperevm'
  }
)

Provider with Retry Logic

const { ethers } = require('ethers')

class RetryProvider extends ethers.providers.JsonRpcProvider {
  constructor(url, network, maxRetries = 3) {
    super(url, network)
    this.maxRetries = maxRetries
  }

  async send(method, params) {
    let lastError

    for (let i = 0; i < this.maxRetries; i++) {
      try {
        return await super.send(method, params)
      } catch (error) {
        lastError = error
        console.log(`Retry ${i + 1}/${this.maxRetries} for ${method}`)
        await new Promise(r => setTimeout(r, 1000 * (i + 1)))
      }
    }

    throw lastError
  }
}

const provider = new RetryProvider('https://rpc.hyperliquid.xyz/evm', 'hyperevm', 3)
const moroClient = new MoroBestRate(provider, 'hyperevm')

Provider Performance Monitoring

class MonitoredProvider extends ethers.providers.JsonRpcProvider {
  constructor(url, network) {
    super(url, network)
    this.stats = {
      calls: 0,
      errors: 0,
      totalTime: 0
    }
  }

  async send(method, params) {
    this.stats.calls++
    const start = Date.now()

    try {
      const result = await super.send(method, params)
      this.stats.totalTime += Date.now() - start
      return result
    } catch (error) {
      this.stats.errors++
      throw error
    }
  }

  getStats() {
    return {
      ...this.stats,
      avgTime: this.stats.calls > 0 ? this.stats.totalTime / this.stats.calls : 0,
      errorRate: this.stats.calls > 0 ? this.stats.errors / this.stats.calls : 0
    }
  }
}

const provider = new MonitoredProvider('https://rpc.hyperliquid.xyz/evm', 'hyperevm')
const moroClient = new MoroBestRate(provider, 'hyperevm')

// After some operations
console.log('Provider stats:', provider.getStats())

Environment-Based Configuration

const { ethers } = require('ethers')
const { MoroBestRate } = require('@moromoro/moro-sdk')

function getProvider(network) {
  const rpcUrls = {
    hyperevm: {
      production: process.env.HYPEREVM_RPC_PROD,
      development: 'https://rpc.hyperliquid.xyz/evm',
      test: process.env.HYPEREVM_RPC_TEST
    },
    bsc: {
      production: process.env.BSC_RPC_PROD,
      development: 'https://bsc-dataseed.binance.org',
      test: process.env.BSC_RPC_TEST
    }
  }

  const env = process.env.NODE_ENV || 'development'
  const rpcUrl = rpcUrls[network][env]

  if (!rpcUrl) {
    throw new Error(`No RPC URL configured for ${network} in ${env}`)
  }

  return new ethers.providers.JsonRpcProvider(rpcUrl)
}

// Usage
const provider = getProvider('hyperevm')
const moroClient = new MoroBestRate(provider, 'hyperevm')

Provider Connection Testing

async function testProvider(provider) {
  try {
    // Test 1: Get block number
    const blockNumber = await provider.getBlockNumber()
    console.log('✓ Block number:', blockNumber)

    // Test 2: Get network
    const network = await provider.getNetwork()
    console.log('✓ Network:', network.name, 'Chain ID:', network.chainId)

    // Test 3: Get gas price
    const gasPrice = await provider.getGasPrice()
    console.log('✓ Gas price:', ethers.utils.formatUnits(gasPrice, 'gwei'), 'gwei')

    // Test 4: Response time
    const start = Date.now()
    await provider.getBlockNumber()
    const responseTime = Date.now() - start
    console.log('✓ Response time:', responseTime, 'ms')

    return {
      working: true,
      blockNumber,
      network,
      gasPrice: gasPrice.toString(),
      responseTime
    }
  } catch (error) {
    console.error('✗ Provider test failed:', error.message)
    return {
      working: false,
      error: error.message
    }
  }
}

// Test your provider
const provider = new ethers.providers.JsonRpcProvider('https://rpc.hyperliquid.xyz/evm')
testProvider(provider).then(result => {
  console.log('Test result:', result)
})

Multi-Provider Pool

class ProviderPool {
  constructor(urls, network) {
    this.providers = urls.map(url =>
      new ethers.providers.JsonRpcProvider(url, network)
    )
    this.currentIndex = 0
  }

  getProvider() {
    const provider = this.providers[this.currentIndex]
    this.currentIndex = (this.currentIndex + 1) % this.providers.length
    return provider
  }

  async getWorkingProvider() {
    for (const provider of this.providers) {
      try {
        await provider.getBlockNumber()
        return provider
      } catch (error) {
        console.log('Provider failed, trying next...')
      }
    }
    throw new Error('No working providers available')
  }
}

// Usage
const pool = new ProviderPool(
  [
    'https://rpc1.hyperliquid.xyz/evm',
    'https://rpc2.hyperliquid.xyz/evm'
  ],
  'hyperevm'
)

const provider = await pool.getWorkingProvider()
const moroClient = new MoroBestRate(provider, 'hyperevm')

See Also