From 290a6032bef133f8f60e247ac81b89dadf4e417e Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 15:48:53 +0700 Subject: [PATCH 01/14] chore: update l1 fee calculation in estimateGasFee --- packages/api/src/axelar-query/client.spec.ts | 52 +++---- packages/api/src/axelar-query/client.ts | 2 + packages/api/src/axelar-query/constant.ts | 3 + .../api/src/axelar-query/fee/getL1Fee.spec.ts | 33 ++++- packages/api/src/axelar-query/fee/getL1Fee.ts | 130 ++++-------------- packages/api/src/axelar-query/fee/index.ts | 1 - packages/api/src/axelar-query/fee/types.ts | 36 +---- packages/api/src/axelar-query/fee/utils.ts | 12 -- packages/api/src/axelar-query/isomorphic.ts | 112 +++++++++------ .../api/src/axelar-query/utils/bigint.spec.ts | 26 +++- packages/api/src/axelar-query/utils/bigint.ts | 17 +++ packages/api/src/gmp/types.ts | 6 +- pnpm-lock.yaml | 14 +- 13 files changed, 211 insertions(+), 233 deletions(-) create mode 100644 packages/api/src/axelar-query/constant.ts delete mode 100644 packages/api/src/axelar-query/fee/utils.ts diff --git a/packages/api/src/axelar-query/client.spec.ts b/packages/api/src/axelar-query/client.spec.ts index 05af22914..0cc95c2e8 100644 --- a/packages/api/src/axelar-query/client.spec.ts +++ b/packages/api/src/axelar-query/client.spec.ts @@ -1,6 +1,6 @@ import { ENVIRONMENTS } from "@axelarjs/core"; -import { formatEther, pad } from "viem"; +import { formatEther } from "viem"; import type { AxelarQueryAPIClient, @@ -12,7 +12,7 @@ import { createAxelarQueryClient } from "./client"; describe("axelar-query (node client)", () => { describe("estimateGasFee", () => { const requestParam: EstimateGasFeeParams = { - sourceChain: "ethereum-2", + sourceChain: "ethereum", destinationChain: "avalanche", gasLimit: 700_000n, gasMultiplier: 1.1, @@ -22,14 +22,16 @@ describe("axelar-query (node client)", () => { amountInUnits: "1000000", }; - let api: AxelarQueryAPIClient; + let mainnetApi: AxelarQueryAPIClient; + // let testnetApi: AxelarQueryAPIClient; beforeEach(() => { - api = createAxelarQueryClient(ENVIRONMENTS.testnet, {}); + mainnetApi = createAxelarQueryClient(ENVIRONMENTS.mainnet, {}); + // testnetApi = createAxelarQueryClient(ENVIRONMENTS.testnet, {}); }); test("It should return estimated gas amount in terms of native tokens", async () => { - const fees = await api.estimateGasFee({ + const fees = await mainnetApi.estimateGasFee({ ...requestParam, showDetailedFees: false, }); @@ -40,57 +42,37 @@ describe("axelar-query (node client)", () => { ); }); - test.skip("It should include the L1 gas fee", async () => { + test("It should include the L1 gas fee", async () => { const l2RequestParams: EstimateGasFeeParams = { - sourceChain: "avalanche", + sourceChain: "ethereum", destinationChain: "optimism", gasLimit: 700_000n, gasMultiplier: 1.1, - executeData: pad("0x1234", { size: 5000 }), amount: 1, amountInUnits: "1000000", }; - const fees = (await api.estimateGasFee({ + const fees = (await mainnetApi.estimateGasFee({ ...l2RequestParams, showDetailedFees: true, })) as EstimateGasFeeResponse; - const l1ExecutionFeeWithMultiplier = parseInt( + const l1ExecutionFeeWithMultiplier = BigInt( fees.l1ExecutionFeeWithMultiplier ); - const executionFeeWithMultiplier = parseInt( + const l1ExecutionFee = BigInt(fees.l1ExecutionFee); + const executionFee = BigInt(fees.executionFee); + const executionFeeWithMultiplier = BigInt( fees.executionFeeWithMultiplier ); expect(fees).toBeTruthy(); - expect(l1ExecutionFeeWithMultiplier).toBeGreaterThan( - executionFeeWithMultiplier - ); - }); - - test("it should throw an error if the destination chain is L2 but not specified the executeData", async () => { - const l2RequestParams: EstimateGasFeeParams = { - sourceChain: "ethereum-2", - destinationChain: "optimism", - gasLimit: 700_000n, - gasMultiplier: 1.1, - amount: 1, - amountInUnits: "1000000", - }; - - await expect( - api.estimateGasFee({ - ...l2RequestParams, - showDetailedFees: true, - }) - ).rejects.toThrowError( - "executeData is required to calculate the L1 execution fee for optimism" - ); + expect(l1ExecutionFeeWithMultiplier).toBeGreaterThan(l1ExecutionFee); + expect(executionFeeWithMultiplier).toBeGreaterThan(executionFee); }); test("It should return a detailed object response with the components of the fee", async () => { - const res: EstimateGasFeeResponse = (await api.estimateGasFee({ + const res: EstimateGasFeeResponse = (await mainnetApi.estimateGasFee({ ...requestParam, showDetailedFees: true, })) as EstimateGasFeeResponse; diff --git a/packages/api/src/axelar-query/client.ts b/packages/api/src/axelar-query/client.ts index 9753c04bc..62acb34cc 100644 --- a/packages/api/src/axelar-query/client.ts +++ b/packages/api/src/axelar-query/client.ts @@ -4,6 +4,7 @@ import { type HttpClientOptions, } from "@axelarjs/utils/http-client"; +import { createAxelarscanClient } from "../axelarscan"; import { createGMPClient } from "../gmp/client"; import { AxelarQueryAPIClient } from "./isomorphic"; @@ -17,6 +18,7 @@ export const createAxelarQueryClient = ( }, { gmpClient: createGMPClient(env), + axelarscanClient: createAxelarscanClient(env), }, env ); diff --git a/packages/api/src/axelar-query/constant.ts b/packages/api/src/axelar-query/constant.ts new file mode 100644 index 000000000..4cb218e20 --- /dev/null +++ b/packages/api/src/axelar-query/constant.ts @@ -0,0 +1,3 @@ +// A sample approval execution data on destination chain. Copied it from https://github.com/axelarnetwork/gmp-api/blob/462ebb1176d2f3293ef19fc9122cb8435bfb57b8/config/base_fees.yml#L41C16-L41C22554 +export const DEFAULT_L1_EXECUTE_DATA = + "0x09c5eabe00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002bc0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000016869f63d12923a6b6a1e7d0845bc36761c958f95fc1253061a90b202b4de1e2500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b617070726f7665436f6e747261637443616c6c576974684d696e7400000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000ce16f69375520ab01377ce7b88f5ba8c48f8d666d929706526b352b9b3dfac6e02ee8423446d723c431a26a90399a4bfad35ebeb00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000012874840944511f98378055372e111bfafd7d08f7d89bc050dafe29c866d8f91e640e949000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007506f6c79676f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30786365313646363933373535323061623031333737636537423838663542413843343846384436363600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000761786c555344430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000009c0000000000000000000000000000000000000000000000000000000000001ef210000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000004900000000000000000000000000bad53bcfa41dfd97b7bbc1aa63ed1e2b60ca6b0000000000000000000000000632ebed87ca01f3209d43dfda57c936970247960000000000000000000000000874289da1dea55c05c37362e8f6c4e2d363ab7600000000000000000000000008f08f6263e5a0af04449f6d656e7bd3d61f5d0b000000000000000000000000105a4f54dfdb4c14df0a8980656521dbedad34ba00000000000000000000000010eb643e5d2b5f43815c9fbf147c50ca017bf739000000000000000000000000115535334d51526c3dd1fd0b9c102f9ce5c41533000000000000000000000000155d7eb55353a3c341cfdabb44e5f6b800eeb388000000000000000000000000199f1099769ba5ff2a09f2e8af3fe17ebf4f75590000000000000000000000001fab6d2a6c47568e8791837b3cd7b08a6175518e0000000000000000000000002139db217c3da96f151c55aca010f75d2c498ebe000000000000000000000000249fb4a02da54ce3ccc2eeebf7cff9adb41cf65c00000000000000000000000025d01a8c55037ea0151756ed8b83c3dffc296ad200000000000000000000000045fd1d9fe52728dc6218456affd0f7e0f9d32582000000000000000000000000490a7a6beb9a6258573cc2cce3e9a86df63171bd0000000000000000000000004eb37f3950b4ff4075d91db895cf6807e8db2ed90000000000000000000000005116fd98e95a98955a2932e9c9ba292e8184f68e00000000000000000000000057670691f78fe49ab9d5a2e4decd7010f8813764000000000000000000000000577bc5713e570b31e7d33a76d0e402404b3cf5ec00000000000000000000000057d6aab745ebec3cdc51d4dac92b1e2f9d6b978c0000000000000000000000006f8def421036933383e774d4c16f23b5ff758bfe00000000000000000000000070d6d6ce17c5a7139179baff95563d726e6208f7000000000000000000000000736d209b5af966917d8b0d499be1cec43b20bb9d00000000000000000000000075ca2f93ad9d621e2fa684148c69909e28a0bfa40000000000000000000000007b6848712d7dd631688dae4c1315f29d008e7814000000000000000000000000884dd182f2f567791131408b127f21ae8a6c901d0000000000000000000000008b80247550a3cac82f767bb91c7995b4291441bb0000000000000000000000008e90188bc4a9d9578722fb63ab702e2c4653a40d0000000000000000000000008f1a0936a0e4bd648e1dd77802a16b6f182e12bd00000000000000000000000090b460ad14efe194d23c9682dafc43d1bba0466f00000000000000000000000094c34cd9ef967c3a0aae0a2a3038f96c97259b83000000000000000000000000980e78073926665a1fdab7eaf139871c43d0ddc40000000000000000000000009aaaf117d36f36d4ddd062fc8d52fe538b31490e000000000000000000000000a517cb0ba3c949d012b13596fefc2803b3b91f0a000000000000000000000000a68465e2ee9f02ef4c5d0e09b2e157a34f631e0b000000000000000000000000a72d82741f3c246efd8b137d2c927188c822b57a000000000000000000000000a87d29cf4ce22694f9df052ccac41acb362698a4000000000000000000000000acc4a07ce7f15a690712967275625721cc677d24000000000000000000000000ae1938f872c66db538739ca0b4ff68a542a7ecda000000000000000000000000ae4bb7e81762f3c256b5b8bec612a6ddcc6d5cef000000000000000000000000afecc724083d8b2ce1a17dc0a5ddac08ce4dac01000000000000000000000000bc3d8181c1edeae088e25b79bd51409e0dff7bb8000000000000000000000000be1766e184f0c4d9832facc8193718638214c61d000000000000000000000000be979a5d5ad1adcfd9f23390dc7a09c16198b8da000000000000000000000000c0145bc5f5cd19888b739660c842c6a7819b4c2b000000000000000000000000c0245e5c54ef2c227063c5502a216a8b0313d1b0000000000000000000000000c2a4c6759e30a891619f2e2e5af247dac9b7365f000000000000000000000000c2ace3790099a0c674ca37121df97e589a1695f1000000000000000000000000c3ffa6d084b4670b91135939e14453f42cdb1f3e000000000000000000000000c4540a44cbc891eefdaf4b9a86f4dd51f4f5600f000000000000000000000000c5ef9cddfcacdd1ffd20aa5717c18424516299a6000000000000000000000000c88ea9cb0d2573a4043f200a16e4534f8393ed3e000000000000000000000000c95851c3f0c6373507f19d47f38b52ca676ef197000000000000000000000000d1acc237de7518447abf3fce08e52b510008a2f5000000000000000000000000d3f175d6e6a669a7d9acf153b5e124a86d38355c000000000000000000000000d7c82bb1774d2322c2318e1c39ee17e8dd07e96c000000000000000000000000d8b290ce78582ed643c0b388dcf670728066ad4b000000000000000000000000dc6ca923d9583378f99038a790ca0fa9c6e26f8d000000000000000000000000df8094d4f507861f303396ab1205d42522bf04c6000000000000000000000000e0913fc169ba723fa358282181389bd3af3ec697000000000000000000000000e3caaa4c45a36a4bd3774cc5781938522fb1feb6000000000000000000000000e8692f729f779c5f64c4010c554e9e98d4817f32000000000000000000000000e9c432933b562471aef1d46eb05d5a3e5d3ee57c000000000000000000000000ea475fceed7ae7a89a6aba573251d935bc17928f000000000000000000000000ea98fc28c13828d6b37b17eaf85ffb655f205398000000000000000000000000ef572e9b96e4302d21450be4fc01b042568f3c7c000000000000000000000000f27700773b00f3b24d31a2e1aa8557292f349b00000000000000000000000000f773a12d7db42d4c216e6f5bae3c7b3e6cc2fb99000000000000000000000000f7e53952f76493f8951671e1d735ff0532688d70000000000000000000000000f94135a221859cee2ea4175659b6eaff335de65b000000000000000000000000fc1e02f1446f4ae5b99d9c05ee1ec4901779339f000000000000000000000000fc6a8d595f05a7025cb1c97fa45bbd7d755497dc000000000000000000000000ff8f73d5b9f3f75fde11e3c6eb23c01c89681b1500000000000000000000000000000000000000000000000000000000000000490000000000000000000000000000000000000000000000000000000000000eee000000000000000000000000000000000000000000000000000000000000076b00000000000000000000000000000000000000000000000000000000000007fe0000000000000000000000000000000000000000000000000000000000000bc90000000000000000000000000000000000000000000000000000000000000e6e00000000000000000000000000000000000000000000000000000000000005300000000000000000000000000000000000000000000000000000000000000d8a000000000000000000000000000000000000000000000000000000000000053d0000000000000000000000000000000000000000000000000000000000000d1200000000000000000000000000000000000000000000000000000000000008c50000000000000000000000000000000000000000000000000000000000000a25000000000000000000000000000000000000000000000000000000000000061f000000000000000000000000000000000000000000000000000000000000104500000000000000000000000000000000000000000000000000000000000006ec0000000000000000000000000000000000000000000000000000000000000e62000000000000000000000000000000000000000000000000000000000000075400000000000000000000000000000000000000000000000000000000000005ae0000000000000000000000000000000000000000000000000000000000000b910000000000000000000000000000000000000000000000000000000000000e2c00000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000007560000000000000000000000000000000000000000000000000000000000000a830000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000000b470000000000000000000000000000000000000000000000000000000000000f380000000000000000000000000000000000000000000000000000000000000ddf00000000000000000000000000000000000000000000000000000000000006cb0000000000000000000000000000000000000000000000000000000000000a870000000000000000000000000000000000000000000000000000000000000ae90000000000000000000000000000000000000000000000000000000000000b3a00000000000000000000000000000000000000000000000000000000000008f90000000000000000000000000000000000000000000000000000000000000c5a00000000000000000000000000000000000000000000000000000000000017290000000000000000000000000000000000000000000000000000000000000b400000000000000000000000000000000000000000000000000000000000000fec0000000000000000000000000000000000000000000000000000000000000eb1000000000000000000000000000000000000000000000000000000000000008d0000000000000000000000000000000000000000000000000000000000000eaa00000000000000000000000000000000000000000000000000000000000009340000000000000000000000000000000000000000000000000000000000000a3c00000000000000000000000000000000000000000000000000000000000007d20000000000000000000000000000000000000000000000000000000000000d6d0000000000000000000000000000000000000000000000000000000000000d2a000000000000000000000000000000000000000000000000000000000000009e000000000000000000000000000000000000000000000000000000000000074f0000000000000000000000000000000000000000000000000000000000000eec000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000c8b0000000000000000000000000000000000000000000000000000000000000d800000000000000000000000000000000000000000000000000000000000000e6c0000000000000000000000000000000000000000000000000000000000000cf30000000000000000000000000000000000000000000000000000000000001082000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007750000000000000000000000000000000000000000000000000000000000000fc60000000000000000000000000000000000000000000000000000000000000cc800000000000000000000000000000000000000000000000000000000000007e80000000000000000000000000000000000000000000000000000000000000ccb00000000000000000000000000000000000000000000000000000000000008490000000000000000000000000000000000000000000000000000000000000cca0000000000000000000000000000000000000000000000000000000000000b490000000000000000000000000000000000000000000000000000000000000dcd00000000000000000000000000000000000000000000000000000000000006180000000000000000000000000000000000000000000000000000000000000d6500000000000000000000000000000000000000000000000000000000000012f50000000000000000000000000000000000000000000000000000000000000a830000000000000000000000000000000000000000000000000000000000000b58000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000cbf000000000000000000000000000000000000000000000000000000000000149b000000000000000000000000000000000000000000000000000000000000071a00000000000000000000000000000000000000000000000000000000000010d500000000000000000000000000000000000000000000000000000000000007590000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008a0000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000ba00000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000d200000000000000000000000000000000000000000000000000000000000000da00000000000000000000000000000000000000000000000000000000000000e200000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000f200000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010a0000000000000000000000000000000000000000000000000000000000000112000000000000000000000000000000000000000000000000000000000000011a0000000000000000000000000000000000000000000000000000000000000122000000000000000000000000000000000000000000000000000000000000012a0000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000013a000000000000000000000000000000000000000000000000000000000000014200000000000000000000000000000000000000000000000000000000000000041d90ab8f6f676297769e5ee3741081e139e756b8063857f915f3c18aa55492b0377c850301f44b44ae6a51b24315eb83a3d0967ac92adca3c457337aa4bfcb2e01b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d40296c343f1031bcc9998a86b6c5cb66297d657ec03c810186102d8c6b2f3a23ba952ff9359c4f221f159ce8df08c5131e27ced0ad065dfe9f7164e567348461c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f97f77d4478080d7f8a05c575017e135e77480321369ffaa886c8cf5151fa2a17622f2584ae9ced15f96c2cebf3df5626640d6e96c9324aecb8af619ad3b7b541c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041388107e16868f12a21d50e2636b53a69475cd30e2c33b7640c66ca0018096c2d4ef5db8134e2dc52481d655dd8e581acc2d0fb8f7be83c6df42d6c5cd1b58ba31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114c457f899d174dbe91b6cfe8b95dba26c2a4c936ed55b70de29f94902fa7d2936cb2bf999409a5bded8f56aa765e9aa7818f4872fd99c37a34a238bc3873f671c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041117fb0e77bb1796ec1c118c7cff16ca6ae86fe57e184be7e260c07ca9cb65f0711d8d6b06d8da2c6f214ef06e75fac49e83bd445c1f30d1add3681640fb0b8031b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ffb29e3b044a9a8fa7c3fee4c7f68bf5bc9ee8defa8db9f97d94de40fbdbde2357eccb3abe2af80382450e7b68774d3743cd166d2a4e0fd637d582e93e19a35a1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041326be6706a7c1b5751ee46ced1889832203279021a14962cd279749e7547b77f591552dd62f251b921cb8223b24b00c003faa5aa832c64d3b9e79245661227c51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041b2b6002f94c413aa8578af51f852516a270d248920d76ec5a6c4f837551796815c6878e787c9d350af951ff82348e6452adc5e6dc1933e592a16c154bd5acc681b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414e45aba2560943bdfd56edf9df33a45bcf00ab702785b0569dbb41a1b267d2db21baf6a1fbd88dd8486a3ba5d9e12236af44fe943115661664262250c5c017c51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f8b76e83d766fd95c1614c8631043b66689e54cb54e3a51dfcdce28396d3fccb0909fdc3434db2fc2f243991f85fce499af313854642ca581767c976802c3a831b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004127820cd6b978540aa3344a419c7bf2e2a4f22ed632f1bf90da81d3c278677c961c9b27cb3860655d7b102c36cb1523c020094e55309076d0038351eb25f1f33e1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041c77d02fe8848c9655ba162dee11caa4db78bc7258ca3c38d625fe32de92590ae0c8cc49be7c65290e49659c6668967842895a2115ece167822c1062b496983031b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f67348761e1fb729024ecc6bb1ee1cedd94baa1be508b09617f0c4a1cd9a784a2964fbdeb7e4f49759c7f38e17dab1c3b1dc28255b309d3cb875494d393feb7b1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041af9215d79b43982e763e1513bf202265415fca5e7bc964e88873239c5e5bf99467ee716fb6b26edf1d1ef0d8ec7de6f7b48d03b0169cdbe874430d2d3db9c5ae1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414e23c63ef6953a0353bc7ff6146f8f9ba8a61808fbb483dc5b6fd2abb324eea7024e152ee45e3f9f8b89ab68846170525b1815662faeeecee0efa9cc5c8cdf631c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041236b4b802c2ec5eb387f93d648f05ef37357d7bcbd0a81fb5f0f7ec34fae7db25ef00b5cbd88fa8c899be149df0f1e3f455916125ab3fefbe3692b0ee1ebee521b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004191b5a0cee4d6c1ac37b0f3b67a01338eeb584733ab9eaff25d9356a8d23b57b70bf77f919eb57013a28a0186c581e5d508e97f6ab7d6ef62106246f61f00e5c81b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410342c70ad29d199923730ba99c533ef282414d4e0d4bc0ddb791335aff09e8ad110d8259ed7b2331f948e249aa5dfc3a9699d90bce280d8ce6829fb296e42e001b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004120738466897dac80150f30578868a2ad6b21cb06a0a0e9dde28d91b64adbf55060184accaae153116004e737153abe8850b48006d9942378eafcc7c9d623bc411c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415a6a6fa17851789c70b29dd58b84b0b0bf3a7b0c421387af8b0895cfc064b1307a3516f497578115a19fbb9619dd3cbb1299700cd0fbed757ab3463bc7a2e4111c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415c6910606af5911ba68d5581b5c6c0de3bdefa24cafd7abc898366b0f512aa662509ad62396bf0a7b22980db89a2fbb31da2c1e8811d7936a3a24301cf2aa9951b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004131760d8ada5433d2111f38ead2507d0ae48d62f417540d58b779105aac8b52162311c081604773763ea11cad5995f4b7659da989524d4396dba6ff9a65d1cc131b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a65f9d59a84b798a9a4cbb6b321573bb7614d59e07ae562fd32dcc1005d823ae7c9d6e22b524e3bdd681fd7a028b8136ed3d02113ba90ec8734dc5036a5b4f931c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410c974a6bbc3e767e39832140a661c45791fdff841a2e12b1324011a6e7104c3574be95898b98e3d29f943078f701f0916a243142bb7fb7215933544c97cb6f121b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041eef19484116fd4d50e78b3b9ffc0bbed42fa28da05ff2c989dc2d495a7f11a7a2c8eb7244ad13f2ab1182d8d68912260a35ed0e40ee41f3b4a45489efca358141c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f562d048abdf167f080c3bfed53687ce4537b6f17cc7267eb26aadf1410381455a31f6bc516bde6b2399150615561c3d0349fd1443b710f650de6dbc71d92b151b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041829f74017e53d23a93d0d894a96dad4aed7379d7f726d69b515c182bc157152f2638e7fa46a1ecf588d4450c5e303a05ea7ed960e8fb4f28aeeb7a62e1acfbc31c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417a08ffef9b49f3addd3a54ec293da9a0dc696536be2c56ea764d27cd1423981f0354501d54e8f5f7f8783ad7910dae4c281345c73c584f8171ad9ecd1e6eb4dc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411931fa1f971cde70b4d26b6abe6994d8cd60167cd3fd456f8fc8ac31809f761e3b4197dcd91a5de7233e20b799ac243d764aaea430d5597e49973bbb76784cf31c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412afa4a6a5e29aabc4cf744fe7bc26370ec8a7554ae33af7514782509d7bed8903262769e6e031f0326e1ad869a8c32656fc6cbf71f82d4f0657ab864f89379641b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ae2a9430bc790a7e95e4b69cfc8d3af1dd52688fb9aac974e81435728340e2a07ef5ba06b3b980b045525ea8150c673bf7fe9f007cc6fad7e061ca48bfea0ebd1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004180881a76bffea4ea0d28fa9ea9193455e2ce962a72ab4e724450938190f1420d1781e47360816dd991f8b55dc477b7db358a8f92a3389a1f2d3cc06be3addbb51c00000000000000000000000000000000000000000000000000000000000000"; diff --git a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts index 5075b2179..b83d4bb62 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts @@ -1,13 +1,21 @@ -import { createGMPClient, GMPClient } from "../.."; +import { + createAxelarscanClient, + createGMPClient, + GMPClient, + type EVMChainConfig, +} from "../.."; import { getL1FeeForL2 } from "./getL1Fee"; import { EstimateL1FeeParams } from "./types"; -describe("getL1Fee", () => { +describe.only("getL1Fee", () => { const env = "mainnet"; let client: GMPClient; + let configs: { evm: EVMChainConfig[] }; - beforeAll(() => { + beforeAll(async () => { client = createGMPClient(env); + const axelarscanClient = createAxelarscanClient(env); + configs = await axelarscanClient.getChainConfigs(); }); it("query arbitrum l1 fee should work", async () => { @@ -23,14 +31,20 @@ describe("getL1Fee", () => { l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, }; - const fee = await getL1FeeForL2("mainnet", "arbitrum", params); + const rpcUrl = configs.evm.find((chain) => chain.id === "arbitrum") + ?.endpoints.rpc?.[0]; + + const fee = await getL1FeeForL2(rpcUrl!, params); expect(fee).toBeDefined(); }); it("query optimism l1 fee should work", async () => { + const destChain = "optimism"; + const config = configs.evm.find((c) => c.id === destChain); + const rpcUrl = config?.endpoints.rpc[0]; const fees = await client.getFees({ sourceChain: "avalanche", - destinationChain: "optimism", + destinationChain: destChain, }); // reference: https://optimistic.etherscan.io/tx/0x5203e3629019b8bae494ec5e6b83ddfaf660ae6d5c88ba79093f5f5429143c00 @@ -39,9 +53,10 @@ describe("getL1Fee", () => { executeData: "0x1a98b2e04ee0e180bcfb26420ebb9e7a86f1fdf8c627d79ade87880bf74b7dd73c1b749b00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000258380180000000000000000000000000000000000000000000000000000000000000000646616e746f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a3078636531364636393337353532306162303133373763653742383866354241384334384638443636360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000c9f7113042615ce4796f8cbbfa6f42170d908e0500000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c9f7113042615ce4796f8cbbfa6f42170d908e0500000000000000000000000000000000000000000000000000000002583801800000000000000000000000000000000000000000000000000000000254660d5a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000761786c5553444300000000000000000000000000000000000000000000000000", l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, + l2Type: "op", }; - const fee = await getL1FeeForL2("mainnet", "optimism", params); + const fee = await getL1FeeForL2(rpcUrl!, params); expect(fee).toBeGreaterThan(0n); }); @@ -56,9 +71,13 @@ describe("getL1Fee", () => { executeData: "0x1a98b2e04ee0e180bcfb26420ebb9e7a86f1fdf8c627d79ade87880bf74b7dd73", l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, + l2Type: "mantle", + l1GasOracleAddress: fees.destination_native_token.l1_gas_oracle_address!, }; + const rpcUrl = configs.evm.find((chain) => chain.id === "mantle")?.endpoints + ?.rpc[0]; - const fee = await getL1FeeForL2("mainnet", "mantle", params); + const fee = await getL1FeeForL2(rpcUrl!, params); expect(fee).toBeDefined(); expect(fee).toBeGreaterThan(0n); }); diff --git a/packages/api/src/axelar-query/fee/getL1Fee.ts b/packages/api/src/axelar-query/fee/getL1Fee.ts index 2c99c4382..bdf4a66ec 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.ts @@ -1,21 +1,14 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ -import { Environment } from "@axelarjs/core"; import { createPublicClient, http, parseAbi, - type Chain, type HttpTransport, type PublicClient, } from "viem"; -import { - MAINNET_L2_CHAINS, - TESTNET_L2_CHAINS, - type EstimateL1FeeParams, - type L2Chain, -} from "./types"; +import { type EstimateL1FeeParams } from "./types"; /** * Get the estimated L1 fee for a given L2 chain. @@ -24,116 +17,53 @@ import { * @param params The parameters to use for the estimation. * @returns */ -export function getL1FeeForL2( - env: Environment, - chain: L2Chain, +export async function getL1FeeForL2( + rpcUrl: string, params: EstimateL1FeeParams ): Promise { - const chains = env === "mainnet" ? MAINNET_L2_CHAINS : TESTNET_L2_CHAINS; - const publicClient = createPublicClient({ - chain: chains[chain], - transport: http(), + transport: http(rpcUrl), }); - switch (chain) { - // Most of the ethereum clients are already included L1 fee in the gas estimation for Arbitrum. - case "arbitrum": - return Promise.resolve(0n); - case "optimism": - case "scroll": - case "base": + switch (params.l2Type) { + case "op": return getOptimismL1Fee(publicClient, params); case "mantle": return getMantleL1Fee(publicClient, params); + // Most of the ethereum clients are already included L1 fee in the gas estimation for Arbitrum. + case "arb": + default: + return 0n; } } -async function getOptimismL1Fee( - publicClient: PublicClient, +async function getOptimismL1Fee( + publicClient: PublicClient, estimateL1FeeParams: EstimateL1FeeParams ) { - const { l1GasPrice, executeData } = estimateL1FeeParams; + const { executeData } = estimateL1FeeParams; const contractAddress = "0x420000000000000000000000000000000000000F"; - const abi = parseAbi([ - "function getL1GasUsed(bytes) returns (uint256)", - "function scalar() returns (uint256)", - "function overhead() returns (uint256)", - ]); + const abi = parseAbi(["function getL1Fee(bytes) returns (uint256)"]); - const multicallResponse = await publicClient.multicall({ - contracts: [ - { - address: contractAddress, - abi, - functionName: "getL1GasUsed" as never, - args: [executeData], - }, - { - address: contractAddress, - abi, - functionName: "scalar" as never, - args: [], - }, - { - address: contractAddress, - abi, - functionName: "overhead" as never, - args: [], - }, - ], + const fee = await publicClient.readContract({ + address: contractAddress, + abi, + functionName: "getL1Fee", + args: [executeData], }); - const [gasUsed, _dynamicOverhead, _fixedOverhead] = multicallResponse.flatMap( - (r) => r.result ?? 0n - ) as [bigint, bigint, bigint]; - - const dynamicOverhead = _dynamicOverhead || 684000n; - const fixedOverhead = _fixedOverhead || 2100n; - - const totalGasUsed = - ((gasUsed + fixedOverhead) * dynamicOverhead) / 1_000_000n; - const gasPrice = BigInt(l1GasPrice.value); - - return totalGasUsed * gasPrice; + return fee; } -// TODO: Not used for now because the gas estimation is already included the L1 fee by default. -// async function getArbitrumL1Fee( -// publicClient: PublicClient, -// destinationContractAddress: string, -// executeData: string -// ) { -// // Arbitrum NodeInterface contract address -// const contractAddress = "0x00000000000000000000000000000000000000C8"; - -// // https://github.com/OffchainLabs/nitro-contracts/blob/0a149d2af9aee566c4abf493479ec15e5fc32d98/src/node-interface/NodeInterface.sol#L112 -// const abi = parseAbi([ -// "function gasEstimateL1Component(address to, bool contractCreation, bytes calldata data) external payable returns (uint64,uint256,uint256)", -// ]); - -// const fee = (await publicClient.readContract({ -// address: contractAddress, -// abi, -// functionName: "gasEstimateL1Component" as never, -// args: [destinationContractAddress, false, executeData], -// })) as [bigint, bigint, bigint]; - -// return fee[0]; -// } - -async function getMantleL1Fee( - publicClient: PublicClient, +async function getMantleL1Fee( + publicClient: PublicClient, estimateL1FeeParams: EstimateL1FeeParams ) { const contractAddress = "0x420000000000000000000000000000000000000F"; const { l1GasPrice } = estimateL1FeeParams; - const abi = parseAbi([ - "function overhead() returns (uint256)", - "function scalar() returns (uint256)", - ]); + const abi = parseAbi(["function overhead() returns (uint256)"]); const multicallResponse = await publicClient.multicall({ contracts: [ @@ -143,20 +73,14 @@ async function getMantleL1Fee( functionName: "overhead" as never, args: [], }, - { - address: contractAddress, - abi, - functionName: "scalar" as never, - args: [], - }, ], }); - const [fixedOverhead, dynamicOverhead] = multicallResponse.flatMap( - (r) => r.result ?? 0n - ) as [bigint, bigint]; + const [fixedOverhead] = multicallResponse.flatMap((r) => r.result ?? 0n) as [ + bigint + ]; - const totalGasUsed = (fixedOverhead * dynamicOverhead) / 1_000_000n; + const totalGasUsed = fixedOverhead; const gasPrice = BigInt(l1GasPrice.value); return totalGasUsed * gasPrice; diff --git a/packages/api/src/axelar-query/fee/index.ts b/packages/api/src/axelar-query/fee/index.ts index afe63e244..f920367f9 100644 --- a/packages/api/src/axelar-query/fee/index.ts +++ b/packages/api/src/axelar-query/fee/index.ts @@ -1,3 +1,2 @@ export * from "./getL1Fee"; -export * from "./utils"; export * from "./types"; diff --git a/packages/api/src/axelar-query/fee/types.ts b/packages/api/src/axelar-query/fee/types.ts index abff52c36..d3ce31386 100644 --- a/packages/api/src/axelar-query/fee/types.ts +++ b/packages/api/src/axelar-query/fee/types.ts @@ -1,39 +1,9 @@ -import type { Chain } from "viem"; -import { - arbitrum, - arbitrumSepolia, - base, - baseSepolia, - mantle, - mantleTestnet, - optimism, - optimismSepolia, - scroll, - scrollSepolia, -} from "viem/chains"; - -import { TokenUnit } from "../../gmp"; - -export type L2Chain = "optimism" | "arbitrum" | "mantle" | "base" | "scroll"; - -export const MAINNET_L2_CHAINS = { - arbitrum, - base, - optimism, - scroll, - mantle, -} as Record; - -export const TESTNET_L2_CHAINS = { - arbitrum: arbitrumSepolia, - base: baseSepolia, - optimism: optimismSepolia, - scroll: scrollSepolia, - mantle: mantleTestnet, -} as Record; +import { TokenUnit, type L2Type } from "../../gmp"; export type EstimateL1FeeParams = { destinationContractAddress?: `0x${string}` | undefined; executeData: `0x${string}`; l1GasPrice: TokenUnit; + l1GasOracleAddress?: `0x${string}` | undefined; + l2Type?: L2Type; }; diff --git a/packages/api/src/axelar-query/fee/utils.ts b/packages/api/src/axelar-query/fee/utils.ts deleted file mode 100644 index ff4cd97ad..000000000 --- a/packages/api/src/axelar-query/fee/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { L2Chain } from "./types"; - -export function isL2Chain(value: string): value is L2Chain { - const validChains: L2Chain[] = [ - "optimism", - "arbitrum", - "mantle", - "base", - "scroll", - ]; - return validChains.includes(value as L2Chain); -} diff --git a/packages/api/src/axelar-query/isomorphic.ts b/packages/api/src/axelar-query/isomorphic.ts index f0637efac..49f8e1ab3 100644 --- a/packages/api/src/axelar-query/isomorphic.ts +++ b/packages/api/src/axelar-query/isomorphic.ts @@ -2,22 +2,27 @@ import { Environment } from "@axelarjs/core"; import { parseUnits } from "viem"; +import type { AxelarscanClient } from "../axelarscan"; +import type { GetBaseFeesResult } from "../gmp"; import type { GMPClient } from "../gmp/isomorphic"; import { RestService, type ClientMeta, type RestServiceOptions, } from "../lib/rest-service"; -import { getL1FeeForL2, isL2Chain } from "./fee"; +import { DEFAULT_L1_EXECUTE_DATA } from "./constant"; +import { getL1FeeForL2 } from "./fee"; import type { EstimateGasFeeParams, EstimateGasFeeResponse } from "./types"; -import { gasToWei } from "./utils/bigint"; +import { gasToWei, multiplyFloatByBigInt } from "./utils/bigint"; type AxelarscanClientDependencies = { gmpClient: GMPClient; + axelarscanClient: AxelarscanClient; }; export class AxelarQueryAPIClient extends RestService { protected gmpClient: GMPClient; + protected axelarScanClient: AxelarscanClient; protected env: Environment; public constructor( @@ -28,6 +33,7 @@ export class AxelarQueryAPIClient extends RestService { ) { super(options, meta); this.gmpClient = dependencies.gmpClient; + this.axelarScanClient = dependencies.axelarscanClient; this.env = env; } @@ -42,6 +48,66 @@ export class AxelarQueryAPIClient extends RestService { }); } + private async getRpcUrl(chain: string) { + const configs = await this.axelarScanClient.getChainConfigs(); + return configs.evm.find((c) => c.id === chain)?.endpoints?.rpc?.[0]; + } + + private async _getL1FeeForL2( + executeData: `0x${string}` | undefined, + destinationChain: string, + actualGasMultiplier: number, + feeResponse: GetBaseFeesResult + ) { + const { destination_native_token, source_token, ethereum_token } = + feeResponse; + + if (!destination_native_token.l1_gas_price_in_units) { + return { + l1ExecutionFee: 0n, + l1ExecutionFeeWithMultiplier: 0n, + }; + } + + const actualExecuteData = executeData || DEFAULT_L1_EXECUTE_DATA; + const rpcUrl = await this.getRpcUrl(destinationChain); + + if (!rpcUrl) { + throw new Error("Failed to retrieve RPC URL for the destination chain."); + } + + // Calculate the L1 execution fee. This value is in ETH. + const ethL1ExecutionFee = await getL1FeeForL2(rpcUrl, { + executeData: actualExecuteData, + l1GasPrice: destination_native_token.l1_gas_price_in_units, + l2Type: feeResponse.l2_type, + l1GasOracleAddress: + feeResponse.destination_native_token.l1_gas_oracle_address, + }); + + // Convert the L1 execution fee to the source token + const srcTokenPrice = Number(source_token.token_price.usd); + const ethTokenPrice = Number(ethereum_token.token_price.usd); + const ethToSrcTokenPriceRatio = ethTokenPrice / srcTokenPrice; + + // Calculate the L1 execution fee in the source token + const l1ExecutionFee = multiplyFloatByBigInt( + ethToSrcTokenPriceRatio, + ethL1ExecutionFee + ); + + // Calculate the L1 execution fee with the gas multiplier + const l1ExecutionFeeWithMultiplier = multiplyFloatByBigInt( + actualGasMultiplier, + l1ExecutionFee + ); + + return { + l1ExecutionFee, + l1ExecutionFeeWithMultiplier, + }; + } + /** * Calculate estimated gas amount to pay for the gas receiver contract. * @param sourceChain Chain ID (as recognized by Axelar) of the source chain @@ -95,7 +161,6 @@ export class AxelarQueryAPIClient extends RestService { source_token, destination_native_token, execute_gas_multiplier, - ethereum_token, express_supported, } = response; @@ -137,45 +202,14 @@ export class AxelarQueryAPIClient extends RestService { const baseFee = parseUnits(base_fee.toString(), source_token.decimals); - let l1ExecutionFee = 0n; - let l1ExecutionFeeWithMultiplier = 0; - - // If the destination chain is L2, calculate the L1 execution fee - if (isL2Chain(destinationChain)) { - if (!executeData) { - throw new Error( - `executeData is required to calculate the L1 execution fee for ${destinationChain}` - ); - } - - if (!destination_native_token.l1_gas_price_in_units) { - throw new Error( - `Could not find L1 gas price for ${destinationChain}. Please try again later.` - ); - } - - // Calculate the L1 execution fee. This value is in ETH. - l1ExecutionFee = await getL1FeeForL2(this.env, destinationChain, { - destinationContractAddress, + const { l1ExecutionFee, l1ExecutionFeeWithMultiplier } = + await this._getL1FeeForL2( executeData, - l1GasPrice: destination_native_token.l1_gas_price_in_units, - }); - - // Convert the L1 execution fee to the source token - const srcTokenPrice = Number(source_token.token_price.usd); - const ethTokenPrice = Number(ethereum_token.token_price.usd); - const ethToSrcTokenPriceRatio = ethTokenPrice / srcTokenPrice; - - l1ExecutionFee = BigInt( - Math.ceil(Number(l1ExecutionFee) * ethToSrcTokenPriceRatio) + destinationChain, + actualGasMultiplier, + response ); - // Calculate the L1 execution fee with the gas multiplier - l1ExecutionFeeWithMultiplier = Math.floor( - Number(l1ExecutionFee) * Number(actualGasMultiplier) - ); - } - // If showDetailedFees is false, return the total fee amount if (!showDetailedFees) { return ( diff --git a/packages/api/src/axelar-query/utils/bigint.spec.ts b/packages/api/src/axelar-query/utils/bigint.spec.ts index cac27c2da..263d96271 100644 --- a/packages/api/src/axelar-query/utils/bigint.spec.ts +++ b/packages/api/src/axelar-query/utils/bigint.spec.ts @@ -1,8 +1,32 @@ -import { gasToWei } from "./bigint"; +import { gasToWei, multiplyFloatByBigInt } from "./bigint"; describe("bigint", () => { test("should work even gas_price has more fractional digits than specified decimals", () => { const wei = gasToWei(1000000n, "0.00000001", 6); expect(wei).toBe(10000n); }); + + it("should handle multiplication with whole numbers without loss of precision", () => { + const floatNum = 2.0; + const bigIntNum = 12345678901234567890n; + + const result = multiplyFloatByBigInt(floatNum, bigIntNum); + expect(result).toEqual(24691357802469135780n); + }); + + it("should handle multiplication with decimals without loss of precision", () => { + const floatNum = 3.14159; + const bigIntNum = 12345678901234567890n; + + const result = multiplyFloatByBigInt(floatNum, bigIntNum); + expect(result).toEqual(38785061379329506137n); + }); + + it("should handle very large floating-point numbers", () => { + const floatNum = 1.2345678901234567; // Large float + const bigIntNum = 1000n; + + const result = multiplyFloatByBigInt(floatNum, bigIntNum); + expect(result).toEqual(1234n); + }); }); diff --git a/packages/api/src/axelar-query/utils/bigint.ts b/packages/api/src/axelar-query/utils/bigint.ts index 560eecdf3..38b445399 100644 --- a/packages/api/src/axelar-query/utils/bigint.ts +++ b/packages/api/src/axelar-query/utils/bigint.ts @@ -36,3 +36,20 @@ export function gasToWei( ); } } + +export function multiplyFloatByBigInt(floatNum: number, bigIntNum: bigint) { + // Determine the number of decimal places in the float + const decimalPlaces = floatNum.toString().split(".")[1]?.length || 0; + + // Scaling factor + const scalingFactor = 10 ** decimalPlaces; + + // Convert float to scaled BigInt (as before) + const scaledBigInt = BigInt(floatNum * scalingFactor); + + // Perform the multiplication (both are now BigInts) + const result = scaledBigInt * bigIntNum; + + // Divide by scaling factor to get the final result + return result / BigInt(scalingFactor); +} diff --git a/packages/api/src/gmp/types.ts b/packages/api/src/gmp/types.ts index 79d73bb25..a52fd8de5 100644 --- a/packages/api/src/gmp/types.ts +++ b/packages/api/src/gmp/types.ts @@ -401,6 +401,8 @@ export type TokenUnit = { decimals: number; }; +export type L2Type = "op" | "mantle" | "arb" | undefined; + export type Token = { contract_address: string; symbol: string; @@ -414,7 +416,7 @@ export type Token = { gas_price_gwei: string; }; -type GetBaseFeesResult = { +export type GetBaseFeesResult = { base_fee: number; base_fee_usd: number; source_base_fee: number; @@ -433,9 +435,11 @@ type GetBaseFeesResult = { source_express_fee: ExpressFee; destination_express_fee: ExpressFee; source_token: Token; + l2_type: L2Type; destination_native_token: Token & { name: string; symbol: string; + l1_gas_oracle_address?: `0x${string}` | undefined; }; ethereum_token: { name: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f258ede7..5fe053ade 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10327,7 +10327,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.1.6(@types/node@20.11.27) + vite: 5.1.6(@types/node@20.11.20) transitivePeerDependencies: - supports-color dev: true @@ -11075,6 +11075,9 @@ packages: /@web3modal/scaffold@4.1.0(@types/react@18.2.21)(react@18.2.0)(valtio@1.13.2): resolution: {integrity: sha512-BZdE+T65jmm1hLwXjayZZVGim4LU8acUuKUbzvnHHQrop/oaM4cQbAhRdLll6xpWK4hDfvb+Ep9PBu/1IiLDHg==} + peerDependenciesMeta: + '@web3modal/siwe': + optional: true dependencies: '@web3modal/common': 4.1.0 '@web3modal/core': 4.1.0(@types/react@18.2.21)(react@18.2.0) @@ -11135,6 +11138,15 @@ packages: '@wagmi/connectors': '>=4.0.0' '@wagmi/core': '>=2.0.0' viem: '>=2.0.0' + peerDependenciesMeta: + '@web3modal/siwe': + optional: true + react: + optional: true + react-dom: + optional: true + vue: + optional: true dependencies: '@wagmi/connectors': 4.1.14(@types/react@18.2.21)(@vercel/kv@1.0.1)(@wagmi/core@2.6.5)(react-dom@18.2.0)(react-native@0.73.6)(react@18.2.0)(typescript@5.3.3)(viem@2.8.1)(zod@3.22.4) '@wagmi/core': 2.6.5(@types/react@18.2.21)(react@18.2.0)(typescript@5.3.3)(viem@2.8.1)(zod@3.22.4) From 67fd56c5c357e1496cd36621df927de6f7a6ed36 Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 15:58:38 +0700 Subject: [PATCH 02/14] chore: remove `destinationContractAddress` from EstimateL1FeeParams --- packages/api/src/axelar-query/fee/getL1Fee.spec.ts | 5 ++--- packages/api/src/axelar-query/fee/types.ts | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts index b83d4bb62..261fcb49b 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts @@ -25,9 +25,9 @@ describe.only("getL1Fee", () => { }); const params: EstimateL1FeeParams = { - destinationContractAddress: "0xce16F69375520ab01377ce7B88f5BA8C48F8D666", executeData: "0x1a98b2e0e68ba0eb84262d4bcf91955ec2680b37bcedd59a1f48e18d183dac9961bf9d1400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000d40000000000000000000000000000000000000000000000000000000000deac2c6000000000000000000000000000000000000000000000000000000000000000762696e616e636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307863653136463639333735353230616230313337376365374238386635424138433438463844363636000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bc000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004607cad6135d7a119185ebe062d3b369b1b536ef000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a8000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000000000000000000000000000000000000000000640000000000000000000000004fd39c9e151e50580779bd04b1f7ecc310079fd3000000000000000000000000000000000000000000000000000000000deac2c6000000000000000000000000000000000000000000000000000000000dc647500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f40521500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc80000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000640000000000000000000000004fd39c9e151e50580779bd04b1f7ecc310079fd3000000000000000000000000000000000000000000000000000000000de83dbf000000000000000000000000000000000000000000000000015d8c7908dbe7130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc80000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000242e1a7d4d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000004607cad6135d7a119185ebe062d3b369b1b536ef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000761786c5553444300000000000000000000000000000000000000000000000000", + l1GasOracleAddress: fees.destination_native_token.l1_gas_oracle_address!, l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, }; @@ -49,10 +49,10 @@ describe.only("getL1Fee", () => { // reference: https://optimistic.etherscan.io/tx/0x5203e3629019b8bae494ec5e6b83ddfaf660ae6d5c88ba79093f5f5429143c00 const params: EstimateL1FeeParams = { - destinationContractAddress: "0xce16F69375520ab01377ce7B88f5BA8C48F8D666", executeData: "0x1a98b2e04ee0e180bcfb26420ebb9e7a86f1fdf8c627d79ade87880bf74b7dd73c1b749b00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000258380180000000000000000000000000000000000000000000000000000000000000000646616e746f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a3078636531364636393337353532306162303133373763653742383866354241384334384638443636360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000c9f7113042615ce4796f8cbbfa6f42170d908e0500000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c9f7113042615ce4796f8cbbfa6f42170d908e0500000000000000000000000000000000000000000000000000000002583801800000000000000000000000000000000000000000000000000000000254660d5a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000761786c5553444300000000000000000000000000000000000000000000000000", l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, + l1GasOracleAddress: fees.destination_native_token.l1_gas_oracle_address!, l2Type: "op", }; @@ -67,7 +67,6 @@ describe.only("getL1Fee", () => { }); const params: EstimateL1FeeParams = { - destinationContractAddress: "0xce16F69375520ab01377ce7B88f5BA8C48F8D666", executeData: "0x1a98b2e04ee0e180bcfb26420ebb9e7a86f1fdf8c627d79ade87880bf74b7dd73", l1GasPrice: fees.destination_native_token.l1_gas_price_in_units!, diff --git a/packages/api/src/axelar-query/fee/types.ts b/packages/api/src/axelar-query/fee/types.ts index d3ce31386..a99a963c6 100644 --- a/packages/api/src/axelar-query/fee/types.ts +++ b/packages/api/src/axelar-query/fee/types.ts @@ -1,7 +1,6 @@ import { TokenUnit, type L2Type } from "../../gmp"; export type EstimateL1FeeParams = { - destinationContractAddress?: `0x${string}` | undefined; executeData: `0x${string}`; l1GasPrice: TokenUnit; l1GasOracleAddress?: `0x${string}` | undefined; From 6bbfb128e07a9bf9e93e50d793daeb0923929d19 Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 16:05:57 +0700 Subject: [PATCH 03/14] chore: remove unused params --- packages/api/src/axelar-query/isomorphic.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/api/src/axelar-query/isomorphic.ts b/packages/api/src/axelar-query/isomorphic.ts index 49f8e1ab3..4eb2076b3 100644 --- a/packages/api/src/axelar-query/isomorphic.ts +++ b/packages/api/src/axelar-query/isomorphic.ts @@ -112,16 +112,15 @@ export class AxelarQueryAPIClient extends RestService { * Calculate estimated gas amount to pay for the gas receiver contract. * @param sourceChain Chain ID (as recognized by Axelar) of the source chain * @param destinationChain Chain ID (as recognized by Axelar) of the destination chain + * @param gasLimit An estimated gas amount required to execute `executeWithToken` function. * @param sourceTokenSymbol (Optional) the token symbol on the source chain * @param sourceContractAddress (Optional) the address of the contract invoking the GMP call from the source chain * @param sourceTokenAddress (Optional) the contract address of the token symbol on the source chain - * @param executeData (Optional) the transaction data to be executed on the destination chain. Required if the destination chain is L2. - * @param destinationContractAddress (Optional) the address of the contract invoking the GMP call from the source chain - * @param amount (Optional) the amount of assets transferred in terms of symbol, not unit denom, e.g. use 1 for 1 axlUSDC, not 1000000 - * @param amountInUnits (Optional) the amount of assets transferred in terms of unit denom, not symbol, e.g. use 1000000 for 1 axlUSDC, not 1 + * @param executeData (Optional) The data to be executed on the destination chain. It's recommended to specify it if the destination chain is an L2 chain to calculate more accurate gas fee. + * @param destinationContractAddress (Optional) the destination contract address for checking express supported + * @param amountInUnits (Optional) An amount (in the smallest denomination) that using in callContractWithToken for checking express supported * @param minGasPrice (Optional) A minimum value, in wei, for the gas price on the destination chain that is used to override the estimated gas price if it falls below this specified value. - * @param gasLimit (Optional) An estimated gas amount required to execute `executeWithToken` function. The default value is 1MM which should be sufficient for most transactions. - * @param gasMultiplier (Optional) A multiplier used to create a buffer above the calculated gas fee, to account for potential slippage throughout tx execution, e.g. 1.1 = 10% buffer + * @param gasMultiplier (Optional) A multiplier used to create a buffer above the calculated gas fee, to account for potential slippage throughout tx execution, e.g. 1.1 = 10% buffer. Default to "auto" which will use the gas multiplier from the GMP response. * @param showDetailedFees (Optional) will return the full breakdown of fee components if specified true * @returns */ @@ -133,7 +132,6 @@ export class AxelarQueryAPIClient extends RestService { sourceContractAddress, sourceTokenAddress, destinationContractAddress, - amount, amountInUnits, executeData, minGasPrice = "0", @@ -151,7 +149,6 @@ export class AxelarQueryAPIClient extends RestService { sourceContractAddress, sourceTokenAddress, destinationContractAddress, - amount, amountInUnits, }); From 99c2f0a31afe7af866cee2c96450a8ed87859311 Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 16:08:40 +0700 Subject: [PATCH 04/14] chore: update changeset --- .changeset/fluffy-elephants-shake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fluffy-elephants-shake.md diff --git a/.changeset/fluffy-elephants-shake.md b/.changeset/fluffy-elephants-shake.md new file mode 100644 index 000000000..8731facd6 --- /dev/null +++ b/.changeset/fluffy-elephants-shake.md @@ -0,0 +1,5 @@ +--- +"@axelarjs/api": patch +--- + +Improve l1 fee calculation for estimateGasFee From e7d686dc1770f253f25ec457c5268c4b0c2e998f Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 16:11:12 +0700 Subject: [PATCH 05/14] chore: remove test.only --- packages/api/src/axelar-query/fee/getL1Fee.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts index 261fcb49b..1445838b3 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts @@ -7,7 +7,7 @@ import { import { getL1FeeForL2 } from "./getL1Fee"; import { EstimateL1FeeParams } from "./types"; -describe.only("getL1Fee", () => { +describe("getL1Fee", () => { const env = "mainnet"; let client: GMPClient; let configs: { evm: EVMChainConfig[] }; From 9c09e70bb2e1c735743fee328ef203be1bd7617d Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 16:19:54 +0700 Subject: [PATCH 06/14] chore: fix gas limit low error --- packages/api/src/axelar-query/isomorphic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/axelar-query/isomorphic.ts b/packages/api/src/axelar-query/isomorphic.ts index 4eb2076b3..e9a9aeda4 100644 --- a/packages/api/src/axelar-query/isomorphic.ts +++ b/packages/api/src/axelar-query/isomorphic.ts @@ -138,7 +138,7 @@ export class AxelarQueryAPIClient extends RestService { gasMultiplier = "auto", showDetailedFees = false, }: EstimateGasFeeParams): Promise { - if (gasLimit < 21000) { + if (gasLimit < 1) { throw new Error("Gas limit is too low."); } From 3a2b4893a5dcc38f7555d0f00a5d7078eb95114a Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 19:39:09 +0700 Subject: [PATCH 07/14] chore: fix use l1GasOracleAddress --- packages/api/src/axelar-query/fee/getL1Fee.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.ts b/packages/api/src/axelar-query/fee/getL1Fee.ts index bdf4a66ec..c3131fd79 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.ts @@ -41,9 +41,10 @@ async function getOptimismL1Fee( publicClient: PublicClient, estimateL1FeeParams: EstimateL1FeeParams ) { - const { executeData } = estimateL1FeeParams; + const { executeData, l1GasOracleAddress } = estimateL1FeeParams; - const contractAddress = "0x420000000000000000000000000000000000000F"; + const contractAddress = + l1GasOracleAddress || "0x420000000000000000000000000000000000000F"; const abi = parseAbi(["function getL1Fee(bytes) returns (uint256)"]); const fee = await publicClient.readContract({ @@ -60,8 +61,9 @@ async function getMantleL1Fee( publicClient: PublicClient, estimateL1FeeParams: EstimateL1FeeParams ) { - const contractAddress = "0x420000000000000000000000000000000000000F"; - const { l1GasPrice } = estimateL1FeeParams; + const { l1GasPrice, l1GasOracleAddress } = estimateL1FeeParams; + const contractAddress = + l1GasOracleAddress || "0x420000000000000000000000000000000000000F"; const abi = parseAbi(["function overhead() returns (uint256)"]); From 2bd8314a772f40a485de864e31c8cca705eac4da Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 19:41:04 +0700 Subject: [PATCH 08/14] chore: remove multicall --- packages/api/src/axelar-query/fee/getL1Fee.ts | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.ts b/packages/api/src/axelar-query/fee/getL1Fee.ts index c3131fd79..282d87487 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.ts @@ -67,23 +67,14 @@ async function getMantleL1Fee( const abi = parseAbi(["function overhead() returns (uint256)"]); - const multicallResponse = await publicClient.multicall({ - contracts: [ - { - address: contractAddress, - abi, - functionName: "overhead" as never, - args: [], - }, - ], + const fixedOverhead = await publicClient.readContract({ + address: contractAddress, + abi, + functionName: "overhead", + args: [], }); - const [fixedOverhead] = multicallResponse.flatMap((r) => r.result ?? 0n) as [ - bigint - ]; - - const totalGasUsed = fixedOverhead; const gasPrice = BigInt(l1GasPrice.value); - return totalGasUsed * gasPrice; + return fixedOverhead * gasPrice; } From 553d9bcdc8bc0cb7be8bedb092b19ac14cfaf437 Mon Sep 17 00:00:00 2001 From: npty Date: Fri, 15 Mar 2024 20:50:42 +0700 Subject: [PATCH 09/14] chore: fix potential math error --- packages/api/src/axelar-query/isomorphic.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/api/src/axelar-query/isomorphic.ts b/packages/api/src/axelar-query/isomorphic.ts index e9a9aeda4..e8a09ce25 100644 --- a/packages/api/src/axelar-query/isomorphic.ts +++ b/packages/api/src/axelar-query/isomorphic.ts @@ -192,9 +192,7 @@ export class AxelarQueryAPIClient extends RestService { const excludedL1ExecutionFeeWithMultiplier = actualGasMultiplier > 1 - ? Math.floor( - Number(excludedL1ExecutionFee) * Number(actualGasMultiplier) - ) + ? multiplyFloatByBigInt(actualGasMultiplier, excludedL1ExecutionFee) : excludedL1ExecutionFee; const baseFee = parseUnits(base_fee.toString(), source_token.decimals); From a4137bfd0789d1619ac4067ad1b27232261a681a Mon Sep 17 00:00:00 2001 From: npty Date: Tue, 19 Mar 2024 13:58:30 +0700 Subject: [PATCH 10/14] chore: remove mantle fee --- packages/api/src/axelar-query/fee/getL1Fee.ts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.ts b/packages/api/src/axelar-query/fee/getL1Fee.ts index 282d87487..026bd0c17 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.ts @@ -29,8 +29,6 @@ export async function getL1FeeForL2( case "op": return getOptimismL1Fee(publicClient, params); case "mantle": - return getMantleL1Fee(publicClient, params); - // Most of the ethereum clients are already included L1 fee in the gas estimation for Arbitrum. case "arb": default: return 0n; @@ -56,25 +54,3 @@ async function getOptimismL1Fee( return fee; } - -async function getMantleL1Fee( - publicClient: PublicClient, - estimateL1FeeParams: EstimateL1FeeParams -) { - const { l1GasPrice, l1GasOracleAddress } = estimateL1FeeParams; - const contractAddress = - l1GasOracleAddress || "0x420000000000000000000000000000000000000F"; - - const abi = parseAbi(["function overhead() returns (uint256)"]); - - const fixedOverhead = await publicClient.readContract({ - address: contractAddress, - abi, - functionName: "overhead", - args: [], - }); - - const gasPrice = BigInt(l1GasPrice.value); - - return fixedOverhead * gasPrice; -} From 28241858fd365fbef2ab60f16525742fec720803 Mon Sep 17 00:00:00 2001 From: npty Date: Tue, 19 Mar 2024 13:59:22 +0700 Subject: [PATCH 11/14] chore: update tests --- packages/api/src/axelar-query/fee/getL1Fee.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts index 1445838b3..ffb69007a 100644 --- a/packages/api/src/axelar-query/fee/getL1Fee.spec.ts +++ b/packages/api/src/axelar-query/fee/getL1Fee.spec.ts @@ -77,7 +77,6 @@ describe("getL1Fee", () => { ?.rpc[0]; const fee = await getL1FeeForL2(rpcUrl!, params); - expect(fee).toBeDefined(); - expect(fee).toBeGreaterThan(0n); + expect(fee).toBe(0n); }); }); From 68c8ebe580d84112b7b3937ba76b32e2fc65b6be Mon Sep 17 00:00:00 2001 From: npty Date: Tue, 19 Mar 2024 14:06:20 +0700 Subject: [PATCH 12/14] chore: cleanup --- pnpm-lock.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bcee0d71..c309650ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7625,6 +7625,7 @@ packages: /@swagger-api/apidom-ns-json-schema-draft-4@0.97.0: resolution: {integrity: sha512-eBMIPxX4huNDGle6TOfSe1kKS1/HvL6w66GWWLFxZW2doCQHMADgjo7j/kVowrXiJtEoMgjBVp3W30WkcwBVug==} + requiresBuild: true dependencies: '@babel/runtime-corejs3': 7.24.0 '@swagger-api/apidom-ast': 0.97.0 @@ -7879,6 +7880,7 @@ packages: /@swagger-api/apidom-parser-adapter-workflows-json-1@0.97.0: resolution: {integrity: sha512-UvnISzq5JDG43sTIJ2oE8u8qALHmBKbYMGncYgUdlHx7z5RgPAWxIRDWH40YFzUSuKSRNp4TI7eG/9MUd3RnGA==} + requiresBuild: true dependencies: '@babel/runtime-corejs3': 7.24.0 '@swagger-api/apidom-core': 0.97.0 @@ -7906,6 +7908,7 @@ packages: /@swagger-api/apidom-parser-adapter-yaml-1-2@0.97.0: resolution: {integrity: sha512-3f1ADjQyKyLnuRhPuoHMgWMW28o0ylohWCQwX4q69CMH0kqGxP7HnqIU/i0I2cxZdjGv72OCdiKwaR/OgHcmEw==} + requiresBuild: true dependencies: '@babel/runtime-corejs3': 7.24.0 '@swagger-api/apidom-ast': 0.97.0 @@ -8811,7 +8814,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.1.6(@types/node@20.11.20) + vite: 5.1.6(@types/node@20.11.28) transitivePeerDependencies: - supports-color dev: true @@ -9564,8 +9567,10 @@ packages: - react dev: false - /@web3modal/scaffold@4.1.0(@types/react@18.2.21)(react@18.2.0)(valtio@1.13.2): - resolution: {integrity: sha512-BZdE+T65jmm1hLwXjayZZVGim4LU8acUuKUbzvnHHQrop/oaM4cQbAhRdLll6xpWK4hDfvb+Ep9PBu/1IiLDHg==} + /@web3modal/scaffold@4.1.1(@types/react@18.2.21)(@web3modal/wallet@4.1.1)(react@18.2.0): + resolution: {integrity: sha512-GBryCiyl+taz5DPq0expxzfMVcrpKjWvEBSAqT1tPUSthnzOWnVF77XlUAYgFZqzPsEu9lQ1dHCdqZx7WWMCXA==} + peerDependencies: + '@web3modal/wallet': 4.1.1 peerDependenciesMeta: '@web3modal/siwe': optional: true From dae42b97b21c8e11d0b52cbd7ae2e320b572caf6 Mon Sep 17 00:00:00 2001 From: npty Date: Wed, 20 Mar 2024 20:16:30 +0700 Subject: [PATCH 13/14] chore: make gasMultiplier optional --- packages/api/src/axelar-query/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/axelar-query/types.ts b/packages/api/src/axelar-query/types.ts index 394c11fd0..180e45ff2 100644 --- a/packages/api/src/axelar-query/types.ts +++ b/packages/api/src/axelar-query/types.ts @@ -2,7 +2,7 @@ import type { GetFeesParams } from ".."; export type EstimateGasFeeParams = GetFeesParams & { gasLimit: bigint; - gasMultiplier: number | "auto"; + gasMultiplier?: number | "auto"; minGasPrice?: string; showDetailedFees?: boolean; }; From b521d08b8b857362e84fa194c4a1883b73703965 Mon Sep 17 00:00:00 2001 From: npty Date: Wed, 20 Mar 2024 20:22:08 +0700 Subject: [PATCH 14/14] chore: add @axelarjs/utils as dependency --- packages/api/package.json | 1 + pnpm-lock.yaml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/api/package.json b/packages/api/package.json index 3cd44371c..f1cf51359 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -99,6 +99,7 @@ }, "dependencies": { "@axelarjs/core": "workspace:*", + "@axelarjs/utils": "workspace:*", "isomorphic-unfetch": "^4.0.2", "rambda": "^9.1.1", "viem": "^2.8.11" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c309650ba..34fe2eaa9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -354,6 +354,9 @@ importers: '@axelarjs/core': specifier: workspace:* version: link:../core + '@axelarjs/utils': + specifier: workspace:* + version: link:../utils isomorphic-unfetch: specifier: ^4.0.2 version: 4.0.2 @@ -370,9 +373,6 @@ importers: '@axelarjs/config': specifier: workspace:* version: link:../config - '@axelarjs/utils': - specifier: workspace:* - version: link:../utils '@types/node': specifier: ^20.11.28 version: 20.11.28