Multi chain

The Moromoro SDK supports multiple blockchain networks. This guide shows how to use the SDK across different chains.

Supported Networks

Network
Chain ID
Native Token
Example RPC

HyperEVM

-

HYPE

https://rpc.hyperliquid.xyz/evm

BSC

56

BNB

https://bsc-dataseed.binance.org

Ethereum

1

ETH

Your RPC URL

Polygon

137

MATIC

https://polygon-rpc.com

Arbitrum

42161

ETH

https://arb1.arbitrum.io/rpc

Avalanche

43114

AVAX

https://api.avax.network/ext/bc/C/rpc

Optimism

10

ETH

https://mainnet.optimism.io

HyperEVM Example

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

async function swapOnHyperEVM() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://rpc.hyperliquid.xyz/evm'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'hyperevm')

  const HYPE = '0x5555555555555555555555555555555555555555'
  const USDT = '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'
  const amountIn = ethers.utils.parseUnits('10', 18)
  const gasPrice = ethers.BigNumber.from('5000000000') // 5 gwei

  const quote = await moroClient.getQuote(HYPE, USDT, amountIn, gasPrice)
  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)

  const tx = await moroClient.swap(signer, HYPE, USDT, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on HyperEVM')
}

swapOnHyperEVM()

BSC Example

async function swapOnBSC() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://bsc-dataseed.binance.org'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'bsc')

  // BNB = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee (native)
  // BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56
  const BNB = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
  const BUSD = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'
  const amountIn = ethers.utils.parseUnits('1', 18) // 1 BNB
  const gasPrice = ethers.utils.parseUnits('5', 'gwei')

  const quote = await moroClient.getQuote(
    BNB,
    BUSD,
    amountIn,
    gasPrice,
    { enableSplit: true }
  )

  console.log('Will receive:', ethers.utils.formatUnits(quote.amountOut, 18), 'BUSD')

  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)
  const tx = await moroClient.swap(signer, BNB, BUSD, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on BSC')
}

swapOnBSC()

Polygon Example

async function swapOnPolygon() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://polygon-rpc.com'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'polygon')

  // MATIC (wrapped) = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
  // USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
  const WMATIC = '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270'
  const USDC = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'
  const amountIn = ethers.utils.parseUnits('1000', 18) // 1000 WMATIC
  const gasPrice = ethers.utils.parseUnits('50', 'gwei')

  // Approve WMATIC first
  await moroClient.approve(signer, WMATIC, amountIn)

  const quote = await moroClient.getQuote(WMATIC, USDC, amountIn, gasPrice)
  console.log('Output:', ethers.utils.formatUnits(quote.amountOut, 6), 'USDC')

  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)
  const tx = await moroClient.swap(signer, WMATIC, USDC, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on Polygon')
}

swapOnPolygon()

Arbitrum Example (L2)

For L2 chains like Arbitrum and Optimism, you need to provide L2 gas price.

async function swapOnArbitrum() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://arb1.arbitrum.io/rpc'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'arbitrum')

  // ETH = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
  // USDC = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8
  const ETH = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
  const USDC = '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8'
  const amountIn = ethers.utils.parseUnits('1', 18) // 1 ETH

  // For L2 chains, provide both L1 and L2 gas prices
  const l1GasPrice = ethers.utils.parseUnits('20', 'gwei')  // Ethereum L1
  const l2GasPrice = ethers.utils.parseUnits('0.1', 'gwei') // Arbitrum L2

  const quote = await moroClient.getQuote(
    ETH,
    USDC,
    amountIn,
    l1GasPrice,
    {
      enableSplit: true,
      gasPriceL2: l2GasPrice  // Required for L2 chains
    }
  )

  console.log('Output:', ethers.utils.formatUnits(quote.amountOut, 6), 'USDC')

  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)
  const tx = await moroClient.swap(signer, ETH, USDC, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on Arbitrum')
}

swapOnArbitrum()

Optimism Example (L2)

async function swapOnOptimism() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://mainnet.optimism.io'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'optimism')

  // ETH = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
  // OP = 0x4200000000000000000000000000000000000042
  const ETH = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
  const OP = '0x4200000000000000000000000000000000000042'
  const amountIn = ethers.utils.parseUnits('1', 18)

  const l1GasPrice = ethers.utils.parseUnits('20', 'gwei')
  const l2GasPrice = ethers.utils.parseUnits('0.001', 'gwei')

  const quote = await moroClient.getQuote(
    ETH,
    OP,
    amountIn,
    l1GasPrice,
    {
      enableSplit: true,
      gasPriceL2: l2GasPrice
    }
  )

  console.log('Output:', ethers.utils.formatUnits(quote.amountOut, 18), 'OP')

  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)
  const tx = await moroClient.swap(signer, ETH, OP, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on Optimism')
}

swapOnOptimism()

Avalanche Example

async function swapOnAvalanche() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://api.avax.network/ext/bc/C/rpc'
  )
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  const moroClient = new MoroBestRate(provider, 'avalanche')

  // WAVAX = 0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7
  // USDC = 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E
  const WAVAX = '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7'
  const USDC = '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E'
  const amountIn = ethers.utils.parseUnits('10', 18) // 10 AVAX
  const gasPrice = ethers.utils.parseUnits('30', 'gwei')

  await moroClient.approve(signer, WAVAX, amountIn)

  const quote = await moroClient.getQuote(WAVAX, USDC, amountIn, gasPrice)
  console.log('Output:', ethers.utils.formatUnits(quote.amountOut, 6), 'USDC')

  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)
  const tx = await moroClient.swap(signer, WAVAX, USDC, amountIn, minOut, quote)
  await tx.wait()

  console.log('✓ Swapped on Avalanche')
}

swapOnAvalanche()

Multi-Chain Manager

Utility class to manage swaps across multiple chains.

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

class MultiChainSwapManager {
  constructor(privateKey) {
    this.privateKey = privateKey
    this.clients = {}
    this.providers = {}
  }

  addChain(network, rpcUrl) {
    this.providers[network] = new ethers.providers.JsonRpcProvider(rpcUrl)
    this.clients[network] = new MoroBestRate(
      this.providers[network],
      network
    )
  }

  getSigner(network) {
    return new ethers.Wallet(this.privateKey, this.providers[network])
  }

  async swap(network, srcToken, destToken, amountIn, slippage = 1) {
    if (!this.clients[network]) {
      throw new Error(`Network ${network} not configured`)
    }

    const client = this.clients[network]
    const signer = this.getSigner(network)

    // Get appropriate gas price
    const gasPrice = await this.providers[network].getGasPrice()

    // Get quote
    const isL2 = network === 'arbitrum' || network === 'optimism'
    const quoteOpts = { enableSplit: true }

    if (isL2) {
      quoteOpts.gasPriceL2 = gasPrice.div(10) // Estimate L2 gas
    }

    const quote = await client.getQuote(
      srcToken,
      destToken,
      amountIn,
      gasPrice,
      quoteOpts
    )

    // Approve if needed
    if (srcToken !== '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' &&
        srcToken !== '0x5555555555555555555555555555555555555555') {
      const approveTx = await client.approve(signer, srcToken, amountIn)
      if (approveTx) await approveTx.wait()
    }

    // Calculate min output
    const minOut = ethers.BigNumber.from(quote.amountOut)
      .mul(100 - slippage)
      .div(100)

    // Execute swap
    const tx = await client.swap(
      signer,
      srcToken,
      destToken,
      amountIn,
      minOut,
      quote
    )

    return tx.wait()
  }
}

// Usage
async function useMultiChainManager() {
  const manager = new MultiChainSwapManager(process.env.PRIVATE_KEY)

  // Configure chains
  manager.addChain('hyperevm', 'https://rpc.hyperliquid.xyz/evm')
  manager.addChain('bsc', 'https://bsc-dataseed.binance.org')
  manager.addChain('polygon', 'https://polygon-rpc.com')

  // Swap on HyperEVM
  await manager.swap(
    'hyperevm',
    '0x5555555555555555555555555555555555555555', // HYPE
    '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb', // USDT
    ethers.utils.parseUnits('10', 18)
  )

  console.log('✓ Swapped on HyperEVM')

  // Swap on BSC
  await manager.swap(
    'bsc',
    '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // BNB
    '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', // BUSD
    ethers.utils.parseUnits('1', 18)
  )

  console.log('✓ Swapped on BSC')
}

useMultiChainManager()

Getting Network Gas Prices

async function getGasPrices() {
  const networks = {
    hyperevm: 'https://rpc.hyperliquid.xyz/evm',
    bsc: 'https://bsc-dataseed.binance.org',
    polygon: 'https://polygon-rpc.com',
    arbitrum: 'https://arb1.arbitrum.io/rpc',
    optimism: 'https://mainnet.optimism.io'
  }

  for (const [network, rpc] of Object.entries(networks)) {
    const provider = new ethers.providers.JsonRpcProvider(rpc)
    const gasPrice = await provider.getGasPrice()

    console.log(`${network}:`, ethers.utils.formatUnits(gasPrice, 'gwei'), 'gwei')
  }
}

getGasPrices()

Network-Specific Configurations

const NETWORK_CONFIGS = {
  hyperevm: {
    rpc: 'https://rpc.hyperliquid.xyz/evm',
    nativeToken: '0x5555555555555555555555555555555555555555',
    defaultGasPrice: '5000000000', // 5 gwei
    isL2: false
  },
  bsc: {
    rpc: 'https://bsc-dataseed.binance.org',
    nativeToken: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
    defaultGasPrice: '5000000000',
    isL2: false
  },
  arbitrum: {
    rpc: 'https://arb1.arbitrum.io/rpc',
    nativeToken: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
    defaultGasPrice: '100000000', // 0.1 gwei
    isL2: true,
    l1GasPrice: '20000000000' // 20 gwei
  },
  optimism: {
    rpc: 'https://mainnet.optimism.io',
    nativeToken: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
    defaultGasPrice: '1000000', // 0.001 gwei
    isL2: true,
    l1GasPrice: '20000000000'
  }
}

function getNetworkConfig(network) {
  return NETWORK_CONFIGS[network]
}

Best Practices

1

Always check network before transactions

Verify you're connected to the intended network (RPC URL / chain) before signing or sending transactions.

2

Use appropriate gas prices for each network

Set gas prices according to network conditions. For L2s, provide both L1 and L2 gas pricing when required.

3

For L2 chains, always provide gasPriceL2 option

L2 chains like Arbitrum and Optimism require an L2 gas price for accurate quoting and execution.

4

Test with small amounts first on new networks

Validate flow and permissions with minimal amounts before committing larger sums.

5

Keep separate private keys per network for security

Using different keys per environment or network reduces risk if a key is compromised.

See Also