Skip to main content
Rainbow provides accurate gas estimation for swaps, including token approvals and complex multi-step transactions.

Gas Architecture

Gas fees calculated using EIP-1559 mechanism:
// From src/__swaps__/types/gas.ts
enum GasSpeed {
  URGENT = 'urgent',
  FAST = 'fast',
  NORMAL = 'normal',
  CUSTOM = 'custom',
}

interface GasFeeParams {
  maxBaseFee: GasFeeParam;           // Max base fee willing to pay
  maxPriorityFeePerGas: GasFeeParam; // Tip for validators
  option: GasSpeed;                   // Speed selection
  estimatedTime: {                    // Estimated confirmation time
    amount: number;
    display: string;
  };
  gasFee: {                           // Total fee estimate
    amount: string;                   // In wei
    display: string;                  // Formatted
  };
  transactionGasParams: TransactionGasParams; // For transaction
}

interface TransactionGasParams {
  maxPriorityFeePerGas: string;      // In wei
  maxFeePerGas: string;              // In wei
}

Gas Estimation Flow

1

Fetch Network Gas Data

Get current network gas prices:
  • Query gas price oracles
  • Get base fee from latest block
  • Fetch priority fee recommendations
  • Build fee options (normal, fast, urgent)
2

Estimate Gas Limit

Calculate gas units needed:
// From src/__swaps__/screens/Swap/hooks/useSwapEstimatedGasLimit.ts
const gasLimit = await (
  quote.swapType === SwapType.crossChain
    ? estimateUnlockAndCrosschainSwap({ chainId, quote })
    : estimateUnlockAndSwap({ chainId, quote })
);
3

Calculate Total Cost

Compute total gas fee:
const gasFee = calculateGasFeeWorklet(gasSettings, gasLimit);
const totalCost = mulWorklet(gasLimit, maxFeePerGas);
4

Convert to Display Currency

Show cost in user’s currency:
const nativeAssetPrice = getNativeAssetPrice(chainId);
const feeInNative = formatUnits(gasFee, 18);
const feeInUSD = mulWorklet(feeInNative, nativeAssetPrice);
5

Display to User

Show gas estimate in UI:
  • Gas cost in native token (ETH, MATIC, etc.)
  • Gas cost in USD
  • Estimated confirmation time
  • Option to customize

Gas Limit Estimation

Estimating gas units required:

Simple Swap

// From src/__swaps__/screens/Swap/hooks/useSwapEstimatedGasLimit.ts
async function estimateUnlockAndSwap({
  chainId,
  quote,
}: {
  chainId: ChainId;
  quote: Quote;
}): Promise<string> {
  // Check if approval needed
  const requiresApproval = await checkTokenAllowance(
    quote.sellTokenAsset.address,
    quote.allowanceTarget,
    quote.sellAmount
  );
  
  let totalGas = BigNumber.from(0);
  
  // Add approval gas if needed
  if (requiresApproval) {
    const approvalGas = await estimateApprovalGas(
      quote.sellTokenAsset.address,
      quote.allowanceTarget,
      quote.sellAmount
    );
    totalGas = totalGas.add(approvalGas);
  }
  
  // Add swap gas
  const swapGas = await estimateSwapGas(quote);
  totalGas = totalGas.add(swapGas);
  
  // Add 10% safety margin
  const withMargin = totalGas.mul(110).div(100);
  
  return withMargin.toString();
}

Cross-Chain Swap

async function estimateUnlockAndCrosschainSwap({
  chainId,
  quote,
}: {
  chainId: ChainId;
  quote: CrosschainQuote;
}): Promise<string> {
  let totalGas = BigNumber.from(0);
  
  // Estimate for each transaction in route
  for (const route of quote.routes) {
    for (const userTx of route.userTxs || []) {
      const txGas = await provider.estimateGas({
        to: userTx.to,
        data: userTx.data,
        value: userTx.value,
        from: currentAddress,
      });
      
      totalGas = totalGas.add(txGas);
    }
  }
  
  // Add safety margin
  return totalGas.mul(110).div(100).toString();
}

Gas Price Calculation

EIP-1559 gas price components:

Base Fee

  • Network Base Fee: Set by protocol, burns
  • Dynamic: Adjusts based on block fullness
  • Cannot be lower: Transaction fails if base fee too low

Priority Fee

  • Validator Tip: Incentive for inclusion
  • User Sets: You control this amount
  • Higher = Faster: More likely to be included quickly

Max Fee Per Gas

// Total maximum you're willing to pay per gas unit
maxFeePerGas = maxBaseFee + maxPriorityFeePerGas;

// Actual cost:
actualCost = gasUsed * (baseFee + priorityFee);

// Refund if base fee lower than max:
refund = gasUsed * (maxBaseFee - actualBaseFee);

Gas Speed Options

Different speed tiers:
Standard Speed
  • Base fee: Current network base fee
  • Priority fee: 1-2 Gwei
  • Confirmation: 1-2 minutes typically
  • Cost: Lowest
Best for: Non-urgent swaps

Gas Calculation

Calculating actual gas cost:
// From providers/SyncSwapStateAndSharedValues.tsx
export function calculateGasFeeWorklet(
  gasSettings: GasSettings,
  gasLimit: string
): string {
  'worklet';
  
  if (!gasSettings || !gasLimit) return '0';
  
  // EIP-1559 transaction
  if ('maxFeePerGas' in gasSettings) {
    // Use maxFeePerGas as upper bound
    return mulWorklet(
      gasLimit,
      gasSettings.maxFeePerGas
    );
  }
  
  // Legacy transaction
  if ('gasPrice' in gasSettings) {
    return mulWorklet(
      gasLimit,
      gasSettings.gasPrice
    );
  }
  
  return '0';
}

Gas Fee Display

Formatting gas costs for users:
// From src/__swaps__/screens/Swap/hooks/useEstimatedGasFee.ts
export function useEstimatedGasFee({
  chainId,
  gasLimit,
  gasSettings,
}: {
  chainId: ChainId;
  gasLimit: string | undefined;
  gasSettings: GasSettings | undefined;
}) {
  const nativeNetworkAsset = useNativeAsset({ chainId });
  const nativeCurrency = userAssetsStoreManager(state => state.currency);
  
  return useMemo(() => {
    if (!gasLimit || !gasSettings || !nativeNetworkAsset?.price) return;
    
    // Calculate total gas fee
    const gasFee = calculateGasFeeWorklet(gasSettings, gasLimit);
    if (isNaN(Number(gasFee))) return;
    
    const networkAssetPrice = nativeNetworkAsset.price.value?.toString();
    if (!networkAssetPrice) {
      // Show in Gwei if no price
      return `${formatNumber(weiToGwei(gasFee))} Gwei`;
    }
    
    // Convert to native token amount
    const feeFormatted = formatUnits(
      safeBigInt(gasFee),
      nativeNetworkAsset.decimals
    ).toString();
    
    // Calculate USD value
    const feeInUserCurrency = multiply(networkAssetPrice, feeFormatted);
    
    // Format in user's currency
    return convertAmountToNativeDisplayWorklet(
      feeInUserCurrency,
      nativeCurrency,
      true
    );
  }, [gasLimit, gasSettings, nativeCurrency, nativeNetworkAsset]);
}

Gas Optimization

Rainbow optimizes gas usage:

Route Optimization

// Choose route with best gas efficiency
const optimizedRoute = routes.reduce((best, current) => {
  const bestScore = divWorklet(
    best.outputAmount,
    best.estimatedGas
  );
  
  const currentScore = divWorklet(
    current.outputAmount,
    current.estimatedGas
  );
  
  return greaterThanWorklet(currentScore, bestScore) ? current : best;
});

Approval Optimization

  • Check existing allowance before requesting approval
  • Exact amount approvals by default (safer)
  • Unlimited approval option for convenience
  • Batch approvals when possible

Gas Tokens

For advanced users:
  • Chi token support (on compatible networks)
  • Gas token burning for rebates
  • Optimized for high gas periods

Gas Safety Margins

Safety buffers prevent failures:
const SAFETY_MARGIN = 1.1; // 10% buffer

const safeGasLimit = estimatedGas.mul(110).div(100);
Why margins needed:
  • Gas estimation can be imperfect
  • Network conditions change
  • Some operations have variable gas
  • Prevents out-of-gas failures
The 10% safety margin is only an upper limit. You only pay for gas actually used. The margin just ensures your transaction won’t fail.

Custom Gas Settings

Advanced users can customize:
interface CustomGasSettings {
  maxBaseFee: string;           // In Gwei
  maxPriorityFeePerGas: string; // In Gwei
  gasLimit?: string;            // Override estimated limit
}

const setCustomGas = (settings: CustomGasSettings) => {
  // Validate settings
  if (Number(settings.maxBaseFee) < currentBaseFee) {
    warn('Base fee too low, transaction may not confirm');
  }
  
  if (Number(settings.maxPriorityFeePerGas) < 1) {
    warn('Priority fee very low, confirmation may be slow');
  }
  
  // Apply custom settings
  swapsStore.setState({ customGas: settings });
};
Setting gas too low can result in:
  • Transaction stuck pending
  • Never confirmed
  • Wasted time
  • Need to speed up or cancel (costs more gas)
Only use custom gas if you understand the risks!

Gas for Different Chains

Gas varies by network:
Mainnet Gas
  • Highest gas costs
  • 15-50+ Gwei typical
  • Can spike to 100+ Gwei
  • Swaps often $10-50+
Tips:
  • Swap during low-activity hours
  • Use L2s for smaller amounts
  • Batch transactions

Handling Gas Spikes

What to do when gas is high:
1

Check If Urgent

Determine if swap is time-sensitive:
  • Market moving fast? May need to pay
  • Routine swap? Can wait
  • Arbitrage? Calculate if profitable
2

Consider Alternatives

Explore options:
  • Wait for lower gas
  • Use L2 or sidechain
  • Bridge to cheaper network
  • Batch with other operations
3

Optimize If Proceeding

If must swap now:
  • Use exact amount approval (one-time cost)
  • Choose optimal gas speed
  • Ensure trade size justifies cost
  • Consider gas in trade calculations

Gas Estimation Errors

Handling estimation failures:
Error: Cannot estimate gasCauses:
  • Insufficient balance
  • Token not approved
  • Swap would fail
  • Network issues
Solutions:
  • Check balances
  • Verify token approval
  • Try smaller amount
  • Check network connection
Warning: Estimated gas unusually highCauses:
  • Complex multi-hop swap
  • High network congestion
  • Inefficient route
Solutions:
  • Wait for lower gas
  • Try different token pair
  • Use different chain
  • Reduce trade size
Error: Transaction failed, out of gasCauses:
  • Estimate was too low
  • Network conditions changed
  • Swap requirements changed
Solutions:
  • Increase gas limit
  • Add larger safety margin
  • Try again with updated estimate

Swaps Overview

Complete swap functionality

Quote Fetching

How swap quotes work

Atomic Swaps

Advanced swap features

Build docs developers (and LLMs) love