Skip to content

Complete Flow Code Example v2

Below is a complete logic transaction flow into the LayerZero Gas.zip contract that handles estimateFees() prior to calling sendDeposits().

viem
import { encodePacked, parseEther, http, createWalletClient, publicActions } from 'viem'
import { optimism } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { estimateFeesAbi, lzDepositAbi } from './abis'
 
const account = privateKeyToAccount('0x...')
 
const client = createWalletClient({
  account,
  chain: optimism,
  transport: http(),
}).extend(publicActions)
 
type ChainParams = {
  [key: string]: {
    v2LZid: number
    chainId: string
    valueInEther: string
  }
}
 
const contractParams: ChainParams = {
  gnosis: {
    v2LZid: 30145,
    chainId: '100',
    valueInEther: '0.000002',
  },
  fuse: {
    v2LZid: 30138,
    chainId: '122',
    valueInEther: '0.000002',
  },
}
 
// Estimate
const createReceiveOptions = (gasLimit: bigint) => {
  return encodePacked(
    ['bytes', 'uint8', 'uint16', 'uint8', 'bytes'],
    [encodePacked(['uint16'], [3]), 1, 16 + 1, 1, encodePacked(['uint128'], [gasLimit])],
  )
}
 
const createNativeOptions = (gasLimit: bigint, amount: bigint, to: string) => {
  return encodePacked(
    ['bytes', 'uint8', 'uint16', 'uint8', 'bytes'],
    [
      createReceiveOptions(gasLimit),
      1,
      32 + 16 + 1,
      2,
      encodePacked(['uint128', 'bytes32'], [amount, `0x${to.slice(2).padStart(64, '0')}` as `0x${string}`]),
    ],
  )
}
 
async function estimateFees(): Promise<bigint> {
  const nullAddress = '0x0000000000000000000000000000000000000000'
  const feeChains: {
    v2LZid: number
    chainId: string
  }[] = []
  const options: `0x${string}`[] = []
  const messages: `0x${string}`[] = []
 
  for (const chain in contractParams) {
    const selection = contractParams[chain]
    feeChains.push({
      v2LZid: selection.v2LZid,
      chainId: selection.chainId,
    })
    options.push(createNativeOptions(BigInt(20_000), parseEther(selection.valueInEther), nullAddress))
    messages.push('0x')
  }
 
  let fees: bigint[] = []
  try {
    const v2LZids = feeChains.map((feeChain) => feeChain.v2LZid)
 
    fees = (await client.readContract({
      address: '0x26DA582889f59EaaE9dA1f063bE0140CD93E6a4f',
      abi: estimateFeesAbi,
      functionName: 'estimateFees',
      args: [v2LZids, messages, options],
    })) as bigint[]
  } catch (error) {
    console.error('Read Contract Error', error)
  }
 
  const lzFees = fees.reduce((p, c) => p + c, BigInt(0))
  return lzFees
}
 
// Deposit
const createOptimizedAdapterParams = (dstChainId: bigint, nativeAmount: bigint) => {
  return (dstChainId << BigInt(224)) | nativeAmount
}
 
;(async () => {
  const lzFee = await estimateFees()
  const adapterParamsDeposit: bigint[] = []
  for (const chain in contractParams) {
    const selection = contractParams[chain]
    adapterParamsDeposit.push(
      createOptimizedAdapterParams(BigInt(selection.v2LZid), parseEther(selection.valueInEther)),
    )
  }
 
  const { request } = await client.simulateContract({
    address: '0x26DA582889f59EaaE9dA1f063bE0140CD93E6a4f',
    abi: lzDepositAbi,
    functionName: 'sendDeposits',
    value: lzFee,
    args: [adapterParamsDeposit, account.address],
  })
 
  await client.writeContract(request)
})().catch((error) => console.error(error))