Gas optimization

Learn how to optimize gas costs when using the Moromoro SDK.

Understanding Gas Costs

Gas costs for swaps consist of:

  • Base transaction cost (~21,000 gas)

  • Router contract execution (~50,000–150,000 gas)

  • DEX interaction costs (varies by DEX type)

  • Token transfers (~50,000 gas per transfer)

  • Split trade overhead (if using multiple paths)

Gas-Aware Quote Selection

The SDK automatically considers gas costs when calculating the best rate.

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

async function gasAwareSwap() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://rpc.hyperliquid.xyz/evm'
  )
  const moroClient = new MoroBestRate(provider, 'hyperevm')

  const HYPE = '0x5555555555555555555555555555555555555555'
  const USDT = '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'
  const amountIn = ethers.utils.parseUnits('10', 18)

  // Provide accurate gas price for better rate calculation
  const gasPrice = await provider.getGasPrice()
  console.log('Current gas price:', ethers.utils.formatUnits(gasPrice, 'gwei'), 'gwei')

  // SDK considers gas costs in the amountOut calculation
  const quote = await moroClient.getQuote(
    HYPE,
    USDT,
    amountIn,
    gasPrice,
    { enableSplit: true }
  )

  console.log('Gas fees:', quote.gasFees)
  console.log('Net amount out (after gas):', quote.amountOut)
}

gasAwareSwap()

Optimizing for L2 Chains

L2 chains like Optimism and Arbitrum have different gas models.

async function optimizeL2Gas() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://mainnet.optimism.io'
  )
  const moroClient = new MoroBestRate(provider, 'optimism')

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

  // L2 chains need both L1 and L2 gas prices
  const l1GasPrice = ethers.utils.parseUnits('20', 'gwei')
  const l2GasPrice = await provider.getGasPrice()

  console.log('L2 gas price:', ethers.utils.formatUnits(l2GasPrice, 'gwei'), 'gwei')

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

  console.log('L2 is cheaper due to lower gas costs!')
}

optimizeL2Gas()

Batch Approvals

Approve once for unlimited use to save gas on future swaps.

async function unlimitedApproval() {
  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 USDT = '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'

  // Approve unlimited (MaxUint256) - only need to do this once
  console.log('Approving unlimited USDT...')
  const approveTx = await moroClient.approve(
    signer,
    USDT,
    ethers.constants.MaxUint256 // Unlimited approval
  )

  if (approveTx) {
    await approveTx.wait()
    console.log('✓ Unlimited approval granted')
    console.log('Future swaps will not require approval')
  }
}

unlimitedApproval()

Minimizing Split Paths

Control the number of paths to balance rate improvement vs gas cost.

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

  // Limit candidate paths to reduce gas costs
  const moroClient = new MoroBestRate(provider, 'hyperevm', {
    maxCandidatePathsCount: 10 // Lower = less gas, but potentially worse rate
  })

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

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

  if (quote.type === 'split') {
    console.log('Number of paths:', quote.paths.length)
    console.log('This will use less gas than many paths')
  }
}

optimizeSplitPaths()

Dynamic Gas Pricing

Adjust gas price based on network conditions.

async function dynamicGasPricing() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://rpc.hyperliquid.xyz/evm'
  )
  const moroClient = new MoroBestRate(provider, 'hyperevm')

  // Get current gas price
  const currentGasPrice = await provider.getGasPrice()

  // Add 10% buffer for faster confirmation
  const gasPrice = currentGasPrice.mul(110).div(100)

  console.log('Base gas price:', ethers.utils.formatUnits(currentGasPrice, 'gwei'), 'gwei')
  console.log('Using gas price:', ethers.utils.formatUnits(gasPrice, 'gwei'), 'gwei')

  const HYPE = '0x5555555555555555555555555555555555555555'
  const USDT = '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'
  const amountIn = ethers.utils.parseUnits('10', 18)

  const quote = await moroClient.getQuote(HYPE, USDT, amountIn, gasPrice)

  // Quote calculation includes the higher gas price
  console.log('Amount out (accounting for gas):', quote.amountOut)
}

dynamicGasPricing()

Estimating Gas Costs

Estimate total gas cost before executing.

async function estimateGasCost() {
  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 = await provider.getGasPrice()

  const quote = await moroClient.getQuote(HYPE, USDT, amountIn, gasPrice)

  // Estimate gas
  const minOut = ethers.BigNumber.from(quote.amountOut).mul(99).div(100)

  try {
    const estimatedGas = await moroClient.swap(
      signer,
      HYPE,
      USDT,
      amountIn,
      minOut,
      quote
    ).then(tx => tx.estimateGas())

    const totalGasCost = estimatedGas.mul(gasPrice)

    console.log('Estimated gas:', estimatedGas.toString())
    console.log('Total gas cost:', ethers.utils.formatEther(totalGasCost), 'HYPE')

  } catch (error) {
    console.log('Could not estimate:', error.message)
  }
}

estimateGasCost()

Comparing Gas Costs

Compare gas costs between single and split trades.

async function compareGasCosts() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://rpc.hyperliquid.xyz/evm'
  )
  const moroClient = new MoroBestRate(provider, 'hyperevm')

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

  // Single path
  const singleQuote = await moroClient.getQuote(
    HYPE,
    USDT,
    amountIn,
    gasPrice,
    { enableSplit: false }
  )

  // Split path
  const splitQuote = await moroClient.getQuote(
    HYPE,
    USDT,
    amountIn,
    gasPrice,
    { enableSplit: true }
  )

  console.log('Single Path:')
  console.log('- Amount out:', ethers.utils.formatUnits(singleQuote.amountOut, 6))
  console.log('- Gas fees:', singleQuote.gasFees)

  console.log('\nSplit Path:')
  console.log('- Amount out:', ethers.utils.formatUnits(splitQuote.amountOut, 6))
  console.log('- Gas fees:', splitQuote.gasFees)

  // Determine if split is worth it
  const singleNet = parseFloat(ethers.utils.formatUnits(singleQuote.amountOut, 6))
  const splitNet = parseFloat(ethers.utils.formatUnits(splitQuote.amountOut, 6))

  console.log('\nNet benefit of split:', (splitNet - singleNet).toFixed(6), 'USDT')
}

compareGasCosts()

Zero Gas Options Helper

Use the built-in helper for testing without gas considerations.

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

async function testWithoutGas() {
  const provider = new ethers.providers.JsonRpcProvider(
    'https://rpc.hyperliquid.xyz/evm'
  )
  const moroClient = new MoroBestRate(provider, 'hyperevm')

  const HYPE = '0x5555555555555555555555555555555555555555'
  const USDT = '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'
  const amountIn = ethers.utils.parseUnits('10', 18)

  // Use zero gas for pure rate comparison
  const gasPrice = zeroGasOptions()

  const quote = await moroClient.getQuote(HYPE, USDT, amountIn, gasPrice)

  console.log('Pure output (no gas deduction):', quote.amountOut)
  console.log('This is useful for comparing DEX rates without gas overhead')
}

testWithoutGas()

Gas Optimization Checklist

  • ✅ Use unlimited approvals for frequently traded tokens

  • ✅ Provide accurate gas prices to SDK for better routing

  • ✅ Consider L2 chains for high-frequency trading

  • ✅ Limit split paths for small trades

  • ✅ Batch multiple swaps when possible

  • ✅ Monitor gas prices and swap during low-cost periods

  • ✅ Use native tokens when possible (no approval needed)

Advanced: Custom Gas Limit

Set custom gas limits for specific scenarios.

async function customGasLimit() {
  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')

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

  // Set custom gas limit
  const tx = await moroClient.swap(
    signer,
    HYPE,
    USDT,
    amountIn,
    minOut,
    quote,
    0,
    0,
    ethers.constants.AddressZero,
    {
      gasLimit: 300000,      // Custom limit
      gasPrice: gasPrice     // Custom price
    }
  )

  const receipt = await tx.wait()
  console.log('Actual gas used:', receipt.gasUsed.toString())
  console.log('Gas limit:', '300000')
  console.log('Efficiency:', (receipt.gasUsed.toNumber() / 300000 * 100).toFixed(2) + '%')
}

customGasLimit()

See Also