github.com/ethereum-optimism/optimism@v1.7.2/packages/fee-estimation/src/estimateFees.spec.ts (about)

     1  /**
     2   * The first 2 test cases are good documentation of how to use this library
     3   */
     4  import { vi, test, expect, beforeEach } from 'vitest'
     5  import { formatEther } from 'viem/utils'
     6  import {
     7    baseFee,
     8    decimals,
     9    estimateFees,
    10    gasPrice,
    11    getL1Fee,
    12    getL1GasUsed,
    13    getL2Client,
    14    l1BaseFee,
    15    overhead,
    16    scalar,
    17    version,
    18  } from './estimateFees'
    19  import {
    20    optimistABI,
    21    optimistAddress,
    22    l2StandardBridgeABI,
    23    l2StandardBridgeAddress,
    24  } from '@eth-optimism/contracts-ts'
    25  import { parseEther, parseGwei } from 'viem'
    26  
    27  vi.mock('viem', async () => {
    28    const _viem = (await vi.importActual('viem')) as any
    29    return {
    30      ..._viem,
    31      // no way to get historical gas price
    32      createPublicClient: (...args: [any]) => {
    33        const client = _viem.createPublicClient(...args)
    34        client.getGasPrice = async () => parseGwei('0.00000042')
    35        return client
    36      },
    37    }
    38  })
    39  
    40  // using this optimist https://optimistic.etherscan.io/tx/0xaa291efba7ea40b0742e5ff84a1e7831a2eb6c2fc35001fa03ba80fd3b609dc9
    41  const blockNumber = BigInt(107028270)
    42  const optimistOwnerAddress =
    43    '0x77194aa25a06f932c10c0f25090f3046af2c85a6' as const
    44  const functionDataBurn = {
    45    functionName: 'burn',
    46    // this is an erc721 abi
    47    abi: optimistABI,
    48    args: [BigInt(optimistOwnerAddress)],
    49    account: optimistOwnerAddress,
    50    to: optimistAddress[10],
    51    chainId: 10,
    52  } as const
    53  const functionDataBurnWithPriorityFees = {
    54    ...functionDataBurn,
    55    maxFeePerGas: parseGwei('2'),
    56    maxPriorityFeePerGas: parseGwei('2'),
    57  } as const
    58  // This tx
    59  // https://optimistic.etherscan.io/tx/0xe6f3719be7327a991b9cb562ebf8d979cbca72bbdb2775f55a18274f4d0c9bbf
    60  const functionDataWithdraw = {
    61    abi: l2StandardBridgeABI,
    62    functionName: 'withdraw',
    63    value: BigInt(parseEther('0.00000001')),
    64    account: '0x6387a88a199120aD52Dd9742C7430847d3cB2CD4',
    65    // currently a bug is making chain id 10 not exist
    66    to: l2StandardBridgeAddress[420],
    67    chainId: 10,
    68    args: [
    69      // l2 token address
    70      '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    71      // amount
    72      BigInt(parseEther('0.00000001')),
    73      // l1 gas
    74      0,
    75      // extra data
    76      '0x0',
    77    ],
    78    maxFeePerGas: parseGwei('.2'),
    79    maxPriorityFeePerGas: parseGwei('.1'),
    80  } as const
    81  
    82  const clientParams = {
    83    chainId: functionDataBurn.chainId,
    84    rpcUrl: process.env.VITE_L2_RPC_URL ?? 'https://mainnet.optimism.io',
    85  } as const
    86  
    87  const viemClient = getL2Client(clientParams)
    88  
    89  const paramsWithRpcUrl = {
    90    client: clientParams,
    91    blockNumber,
    92  } as const
    93  const paramsWithViemClient = {
    94    client: viemClient,
    95    viemClient,
    96    blockNumber,
    97  } as const
    98  const blockNumberWithdraw = BigInt(107046472)
    99  const paramsWithRpcUrlWithdraw = {
   100    client: clientParams,
   101    blockNumber: blockNumberWithdraw,
   102  } as const
   103  
   104  beforeEach(() => {
   105    vi.resetAllMocks()
   106  })
   107  
   108  test('estimateFees should return correct fees', async () => {
   109    // burn
   110    const res = await estimateFees({ ...paramsWithRpcUrl, ...functionDataBurn })
   111    expect(res).toMatchInlineSnapshot('20573203833264n')
   112    expect(formatEther(res)).toMatchInlineSnapshot('"0.000020573203833264"')
   113    expect(
   114      await estimateFees({ ...paramsWithRpcUrl, ...functionDataBurn })
   115    ).toMatchInlineSnapshot('20573203833264n')
   116    expect(
   117      await estimateFees({ ...paramsWithViemClient, ...functionDataBurn })
   118    ).toMatchInlineSnapshot('20573203833264n')
   119    expect(
   120      await estimateFees({
   121        ...paramsWithRpcUrl,
   122        ...functionDataBurnWithPriorityFees,
   123      })
   124    ).toMatchInlineSnapshot('21536992690265n')
   125    // what is the l2 and l1 part of the fees for reference?
   126    const l1Fee = await getL1Fee({ ...paramsWithRpcUrl, ...functionDataBurn })
   127    const l2Fee = res - l1Fee
   128    expect(l1Fee).toMatchInlineSnapshot('20573185216764n')
   129    expect(formatEther(l1Fee)).toMatchInlineSnapshot('"0.000020573185216764"')
   130    expect(l2Fee).toMatchInlineSnapshot('18616500n')
   131    expect(formatEther(l2Fee)).toMatchInlineSnapshot('"0.0000000000186165"')
   132  
   133    // withdraw
   134    const res2 = await estimateFees({
   135      ...paramsWithRpcUrlWithdraw,
   136      ...functionDataWithdraw,
   137    })
   138    expect(res2).toMatchInlineSnapshot('62857090247510n')
   139    expect(
   140      await estimateFees({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   141    ).toMatchInlineSnapshot('62857090247510n')
   142    expect(
   143      await estimateFees({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   144    ).toMatchInlineSnapshot('62857090247510n')
   145    expect(
   146      await estimateFees({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   147    ).toMatchInlineSnapshot('62857090247510n')
   148    expect(formatEther(res2)).toMatchInlineSnapshot('"0.00006285709024751"')
   149    // what is the l2 and l1 part of the fees for reference?
   150    const l1Fee2 = await getL1Fee({
   151      ...paramsWithRpcUrlWithdraw,
   152      ...functionDataWithdraw,
   153    })
   154    const l2Fee2 = res2 - l1Fee
   155    expect(l1Fee2).toMatchInlineSnapshot('62857038894110n')
   156    expect(formatEther(l1Fee2)).toMatchInlineSnapshot('"0.00006285703889411"')
   157    expect(l2Fee2).toMatchInlineSnapshot('42283905030746n')
   158    expect(formatEther(l2Fee2)).toMatchInlineSnapshot('"0.000042283905030746"')
   159  })
   160  
   161  test('baseFee should return the correct result', async () => {
   162    expect(await baseFee(paramsWithRpcUrl)).toMatchInlineSnapshot('64n')
   163    expect(await baseFee(paramsWithViemClient)).toMatchInlineSnapshot('64n')
   164  })
   165  
   166  test('decimals should return the correct result', async () => {
   167    expect(await decimals(paramsWithRpcUrl)).toMatchInlineSnapshot('6n')
   168    expect(await decimals(paramsWithViemClient)).toMatchInlineSnapshot('6n')
   169  })
   170  
   171  test('gasPrice should return the correct result', async () => {
   172    expect(await gasPrice(paramsWithRpcUrl)).toMatchInlineSnapshot('64n')
   173    expect(await gasPrice(paramsWithViemClient)).toMatchInlineSnapshot('64n')
   174  })
   175  
   176  test('getL1Fee should return the correct result', async () => {
   177    // burn
   178    expect(
   179      await getL1Fee({ ...paramsWithRpcUrl, ...functionDataBurn })
   180    ).toMatchInlineSnapshot('20573185216764n')
   181    expect(
   182      await getL1Fee({ ...paramsWithViemClient, ...functionDataBurn })
   183    ).toMatchInlineSnapshot('20573185216764n')
   184    expect(
   185      await getL1Fee({
   186        ...paramsWithViemClient,
   187        ...functionDataBurnWithPriorityFees,
   188      })
   189    ).toMatchInlineSnapshot('21536974073765n')
   190    expect(
   191      formatEther(
   192        await getL1Fee({ ...paramsWithViemClient, ...functionDataBurn })
   193      )
   194    ).toMatchInlineSnapshot('"0.000020573185216764"')
   195    // withdraw
   196    expect(
   197      await getL1Fee({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   198    ).toMatchInlineSnapshot('62857038894110n')
   199    expect(
   200      formatEther(
   201        await getL1Fee({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   202      )
   203    ).toMatchInlineSnapshot('"0.00006285703889411"')
   204  })
   205  
   206  test('getL1GasUsed should return the correct result', async () => {
   207    // burn
   208    expect(
   209      await getL1GasUsed({ ...paramsWithRpcUrl, ...functionDataBurn })
   210    ).toMatchInlineSnapshot('2220n')
   211    expect(
   212      await getL1GasUsed({ ...paramsWithViemClient, ...functionDataBurn })
   213    ).toMatchInlineSnapshot('2220n')
   214    expect(
   215      await getL1GasUsed({
   216        ...paramsWithViemClient,
   217        ...functionDataBurnWithPriorityFees,
   218      })
   219    ).toMatchInlineSnapshot('2324n')
   220    // withdraw
   221    expect(
   222      await getL1GasUsed({ ...paramsWithRpcUrlWithdraw, ...functionDataWithdraw })
   223    ).toMatchInlineSnapshot('2868n')
   224  })
   225  
   226  test('l1BaseFee should return the correct result', async () => {
   227    expect(await l1BaseFee(paramsWithRpcUrl)).toMatchInlineSnapshot(
   228      '13548538813n'
   229    )
   230    expect(await l1BaseFee(paramsWithViemClient)).toMatchInlineSnapshot(
   231      '13548538813n'
   232    )
   233  })
   234  
   235  test('overhead should return the correct result', async () => {
   236    expect(await overhead(paramsWithRpcUrl)).toMatchInlineSnapshot('188n')
   237    expect(await overhead(paramsWithViemClient)).toMatchInlineSnapshot('188n')
   238  })
   239  
   240  test('scalar should return the correct result', async () => {
   241    expect(await scalar(paramsWithRpcUrl)).toMatchInlineSnapshot('684000n')
   242    expect(await scalar(paramsWithViemClient)).toMatchInlineSnapshot('684000n')
   243  })
   244  
   245  test('version should return the correct result', async () => {
   246    expect(await version(paramsWithRpcUrl)).toMatchInlineSnapshot('"1.0.0"')
   247    expect(await version(paramsWithViemClient)).toMatchInlineSnapshot('"1.0.0"')
   248  })