diff --git a/src/constants/index.ts b/src/constants/index.ts index 1a1bac33..9e02a781 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -39,7 +39,7 @@ const devnetConfigs: EnvironmentConfigs = { }; const testnetConfigs: EnvironmentConfigs = { resourceUrl: "https://nest-server-testnet.axelar.dev", - axelarRpcUrl: "https://rpc-axelar-testnet.imperator.co:443", // "https://testnet.rpc.axelar.dev/chain/axelar", + axelarRpcUrl: "https://testnet.rpc.axelar.dev/chain/axelar", axelarLcdUrl: "https://lcd-axelar-testnet.imperator.co", depositServiceUrl: "https://deposit-service.testnet.axelar.dev", axelarGMPApiUrl: "https://testnet.api.gmp.axelarscan.io", diff --git a/src/libs/AxelarQueryAPI.ts b/src/libs/AxelarQueryAPI.ts index 59dd1beb..aa2667ae 100644 --- a/src/libs/AxelarQueryAPI.ts +++ b/src/libs/AxelarQueryAPI.ts @@ -327,7 +327,7 @@ export class AxelarQueryAPI { * Calculate estimated gas amount to pay for the gas receiver contract. * @param sourceChainId Can be of the EvmChain enum or string. If string, should try to generalize to use the CHAINS constants (e.g. CHAINS.MAINNET.ETHEREUM) * @param destinationChainId Can be of the EvmChain enum or string. If string, should try to generalize to use the CHAINS constants (e.g. CHAINS.MAINNET.ETHEREUM) - * @param gasLimit An estimated gas amount required to execute `executeWithToken` function. + * @param gasLimit An estimated gas amount required to execute the transaction at the destination chain. For destinations on OP Stack chains (Optimism, Base, Scroll, Fraxtal, Blast, etc.), set only the L2 gas limit. The endpoint will automatically handle L1 gas estimation and bundling. * @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. supports up to 3 decimal places * The default value is "auto", which uses the gas multiplier from the fee response * @param sourceChainTokenSymbol (Optional) the gas token symbol on the source chain. diff --git a/src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts b/src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts index b3a71309..1ff57367 100644 --- a/src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts +++ b/src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts @@ -173,8 +173,9 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi { }); } - public getCidFromSrcTxHash(destChainId: string, txHash: string, eventIndex: number) { - return getCommandId(destChainId, txHash, eventIndex, this.environment, rpcInfo); + public getCidFromSrcTxHash(destChainId: string, messageId: string, eventIndex: number) { + const chainId = rpcInfo[this.environment].networkInfo[destChainId.toLowerCase()]?.chainId; + return getCommandId(messageId, eventIndex, chainId); } public async doesTxMeetConfirmHt(chain: string, txHash: string, provider?: JsonRpcProvider) { @@ -244,8 +245,10 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi { }; } - const commandId = this.getCidFromSrcTxHash(destChainId, srcTxHash, eventIndex); const eventResponse = await this.axelarQueryApi.getEVMEvent(srcChainId, srcTxHash, eventIndex); + const isCallContract = eventResponse?.event?.contractCall ? true : false; + const messageId = isCallContract ? `${srcTxHash}-${eventIndex}` : srcTxHash; + const commandId = this.getCidFromSrcTxHash(destChainId, messageId, eventIndex); if (!eventResponse || this.isEVMEventFailed(eventResponse)) { const errorMessage = this.isEVMEventFailed(eventResponse) @@ -1149,7 +1152,7 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi { const executeParams = response.data as ExecuteParams; const gasLimitBuffer = evmWalletDetails?.gasLimitBuffer || 0; - const { destinationChain, destinationContractAddress, srcTxInfo } = executeParams; + const { destinationChain, destinationContractAddress } = executeParams; const signer = this.getSigner( destinationChain, diff --git a/src/libs/TransactionRecoveryApi/helpers/getCommandId.ts b/src/libs/TransactionRecoveryApi/helpers/getCommandId.ts index 06a8bb37..f2bd1413 100644 --- a/src/libs/TransactionRecoveryApi/helpers/getCommandId.ts +++ b/src/libs/TransactionRecoveryApi/helpers/getCommandId.ts @@ -1,24 +1,18 @@ -import { arrayify, keccak256 } from "ethers/lib/utils"; -import { Environment } from "src/libs/types"; -import { RPCInfoType } from "../constants/chain"; +import { arrayify, concat, hexlify, hexZeroPad, keccak256 } from "ethers/lib/utils"; -export const getCommandId = ( - chainName: string, - txHash: string, - sourceEventIndex: number, - environment: Environment, - rpcInfo: RPCInfoType -) => { - const chainID: number = rpcInfo[environment].networkInfo[chainName.toLowerCase()]?.chainId; - if (!chainID) return ""; - const seiArr = arrayify(sourceEventIndex).reverse(); - const txHashWithEventIndex = new Uint8Array([ - ...arrayify(txHash), - ...new Uint8Array(8).map((a, i) => seiArr[i] || a), - ]); - const chainIdByteArray = arrayify(chainID); - const dataToHash = new Uint8Array(txHashWithEventIndex.length + chainIdByteArray.length); - dataToHash.set(txHashWithEventIndex, 0); - dataToHash.set(chainIdByteArray, txHashWithEventIndex.length); - return keccak256(dataToHash).slice(2); // remove 0x prefix +const stringToCharcodeArray = (text: string) => Array.from(text, (char) => char.charCodeAt(0)); + +// This function is specifically designed for use with EVM-based chains. Its behavior may not be as expected if used with Cosmos-based chains or other types of chains. +export const getCommandId = (messageId: string, sourceEventIndex: number, chainId: number) => { + if (messageId.includes("-")) { + return keccak256(concat([stringToCharcodeArray(messageId), hexlify(chainId)])); + } else { + return keccak256( + concat([ + messageId, + arrayify(hexZeroPad(hexlify(sourceEventIndex), 8)).reverse(), + hexlify(chainId), + ]) + ); + } }; diff --git a/src/libs/test/TransactionRecoveryAPI/AxelarGMPRecoveryAPI.spec.ts b/src/libs/test/TransactionRecoveryAPI/AxelarGMPRecoveryAPI.spec.ts index 63e752ca..860ccbc8 100644 --- a/src/libs/test/TransactionRecoveryAPI/AxelarGMPRecoveryAPI.spec.ts +++ b/src/libs/test/TransactionRecoveryAPI/AxelarGMPRecoveryAPI.spec.ts @@ -687,6 +687,32 @@ describe("AxelarGMPRecoveryAPI", () => { }); }); + describe("getCidFromSrcTxHash", () => { + const mainnetApi = new AxelarGMPRecoveryAPI({ environment: Environment.MAINNET }); + + // https://axelarscan.io/gmp/0x3828bf893801f337e08d15b89efc9c3c2d9196fe7f83f3b7640425b24d122cb2:12 + it("should return the correct commandId from evm -> evm for ContractCallWithToken event", () => { + expect( + mainnetApi.getCidFromSrcTxHash( + "celo", + "0x3828bf893801f337e08d15b89efc9c3c2d9196fe7f83f3b7640425b24d122cb2", + 8 + ) + ).toEqual("0xa45da101fcfed541b8251cb8a288b5b7dd84086377eb9cf3f8d4a99f11e062e0"); + }); + + // https://axelarscan.io/gmp/0x92f676751feccab46a048a16aaf81b26620a3683933b56a722ce742de8ea7429:349 + it("should return the correct commandId from evm -> evm for ContractCall event", () => { + expect( + mainnetApi.getCidFromSrcTxHash( + "blast", + "0x92f676751feccab46a048a16aaf81b26620a3683933b56a722ce742de8ea7429-5", + 5 + ) + ).toEqual("0xe6868c6e94240fa6a37cc71d265106a00ad8fa0652319f145e3235f703046574"); + }); + }); + describe.skip("calculateNativeGasFee", () => { const api = new AxelarGMPRecoveryAPI({ environment: Environment.TESTNET }); diff --git a/src/libs/test/TransactionRecoveryAPI/EncodingTests.spec.ts b/src/libs/test/TransactionRecoveryAPI/EncodingTests.spec.ts index 0f4fc179..b6494f28 100644 --- a/src/libs/test/TransactionRecoveryAPI/EncodingTests.spec.ts +++ b/src/libs/test/TransactionRecoveryAPI/EncodingTests.spec.ts @@ -31,8 +31,6 @@ describe("AxelarDepositRecoveryAPI", () => { const txHash = "0x2c9083bebd1f82b86b7b0d3298885f90767b584742df9ec3a9c9f15872a1fff9"; const eventIndex = await api.getEventIndex("ethereum-2" as EvmChain, txHash); const res = await api.getCidFromSrcTxHash(EvmChain.MOONBEAM, txHash, eventIndex as number); - console.log("eventIndex", eventIndex); - console.log("res", res); expect(res).toEqual("58c46960e6483f61bf206d1bd1819917d2b009f58d7050e05b4be1d13247b4ed"); }, 60000); });