diff --git a/packages/transaction-recovery/scripts/clean.sh b/packages/transaction-recovery/scripts/clean.sh index eb9a582ef..3d6a8bbed 100755 --- a/packages/transaction-recovery/scripts/clean.sh +++ b/packages/transaction-recovery/scripts/clean.sh @@ -1,3 +1,3 @@ #!/bin/bash -npx rimraf build cosmosSigner services *.js *.d.ts \ No newline at end of file +npx rimraf build add-gas *.js *.d.ts \ No newline at end of file diff --git a/packages/transaction-recovery/src/addGas/addGas.spec.ts b/packages/transaction-recovery/src/add-gas/addGas.spec.ts similarity index 63% rename from packages/transaction-recovery/src/addGas/addGas.spec.ts rename to packages/transaction-recovery/src/add-gas/addGas.spec.ts index ab33b413b..9b322f92c 100644 --- a/packages/transaction-recovery/src/addGas/addGas.spec.ts +++ b/packages/transaction-recovery/src/add-gas/addGas.spec.ts @@ -1,10 +1,13 @@ +import { createAxelarQueryNodeClient } from "@axelarjs/api/axelar-query/node"; +import { createAxelarConfigNodeClient } from "@axelarjs/api/config/node"; +import { createGMPNodeClient } from "@axelarjs/api/gmp/node"; import { ENVIRONMENTS } from "@axelarjs/core"; import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import { vi } from "vitest"; import { type AutocalculateGasOptions, type SendOptions } from "../types"; -import { addGas } from "./addGas"; +import { addGas, AddGasDependencies } from "./addGas"; const MOCK_ADD_GAS_RESPONSE = { code: 0, @@ -19,19 +22,22 @@ const MOCK_ADD_GAS_RESPONSE = { gasWanted: 250000, }; -vi.mock("../cosmosSigner/signer", () => { - const mockAddGasSignAndBroadcast = () => MOCK_ADD_GAS_RESPONSE; - - const getCosmosSigner = vi.fn(() => ({ - signAndBroadcast: vi.fn().mockImplementation(mockAddGasSignAndBroadcast), - })); - - return { - getCosmosSigner, +describe("addGas", () => { + const mockSignAndBroadcast = () => MOCK_ADD_GAS_RESPONSE; + + const mockGetSigningStargateClient = vi.fn(() => + Promise.resolve({ + signAndBroadcast: vi.fn().mockImplementation(mockSignAndBroadcast), + }) + ); + + const DEFAULT_ADD_GAS_DEPENDENCIES: AddGasDependencies = { + axelarQueryClient: createAxelarQueryNodeClient(ENVIRONMENTS.testnet), + configClient: createAxelarConfigNodeClient(ENVIRONMENTS.testnet), + gmpClient: createGMPNodeClient(ENVIRONMENTS.testnet), + getSigningStargateClient: mockGetSigningStargateClient as any, }; -}); -describe("addGas", () => { test("broadcast an IBC transfer", async () => { const txHash = "6118C285B0C7A139C5636184BECBF8C201FF36B61F44060B82EFE4C535084D9C"; @@ -56,12 +62,15 @@ describe("addGas", () => { offlineSigner, }; - const res = await addGas({ - txHash, - token, - sendOptions, - chain: "osmosis-6", - }); + const res = await addGas( + { + txHash, + token, + sendOptions, + chain: "osmosis-6", + }, + DEFAULT_ADD_GAS_DEPENDENCIES + ); expect(res).toEqual({ broadcastResult: MOCK_ADD_GAS_RESPONSE, @@ -93,13 +102,16 @@ describe("addGas", () => { offlineSigner, }; - const res = await addGas({ - txHash, - token: "autocalculate", - sendOptions, - autocalculateGasOptions, - chain: "osmosis-6", - }); + const res = await addGas( + { + txHash, + token: "autocalculate", + sendOptions, + autocalculateGasOptions, + chain: "osmosis-6", + }, + DEFAULT_ADD_GAS_DEPENDENCIES + ); expect(res).toEqual({ broadcastResult: MOCK_ADD_GAS_RESPONSE, diff --git a/packages/transaction-recovery/src/addGas/addGas.ts b/packages/transaction-recovery/src/add-gas/addGas.ts similarity index 66% rename from packages/transaction-recovery/src/addGas/addGas.ts rename to packages/transaction-recovery/src/add-gas/addGas.ts index 2e3865ce9..3c6df577c 100644 --- a/packages/transaction-recovery/src/addGas/addGas.ts +++ b/packages/transaction-recovery/src/add-gas/addGas.ts @@ -1,27 +1,40 @@ -import { S3CosmosChainConfig } from "@axelarjs/api/s3/types"; -import { COSMOS_GAS_RECEIVER_OPTIONS, Environment } from "@axelarjs/core"; +import { AxelarQueryAPIClient, ConfigClient, GMPClient } from "@axelarjs/api"; +import { AxelarCosmosChainConfig } from "@axelarjs/api/config/types"; +import { COSMOS_GAS_RECEIVER_OPTIONS } from "@axelarjs/core"; -import { assertIsDeliverTxSuccess, Coin } from "@cosmjs/stargate"; +import { OfflineSigner } from "@cosmjs/proto-signing"; +import { + assertIsDeliverTxSuccess, + Coin, + SigningStargateClient, +} from "@cosmjs/stargate"; -import { getCosmosSigner } from "../cosmosSigner"; -import { getGmpClient, getS3Client } from "../services"; import { AddGasParams, AddGasResponse, GetFullFeeOptions } from "../types"; +export type AddGasDependencies = { + axelarQueryClient: AxelarQueryAPIClient; + configClient: ConfigClient; + gmpClient: GMPClient; + getSigningStargateClient: ( + rpcUrl: string, + offlineSigner: OfflineSigner + ) => Promise; +}; + /** * Adds gas to a transaction that might be stuck due to insufficient gas * * @param params {AddGasParams} - Parameters to add gas to a transaction * @returns {Promise} - Response from adding gas to a transaction */ -export async function addGas({ - autocalculateGasOptions, - sendOptions, - ...params -}: AddGasParams): Promise { - const chainConfig = await fetchChainConfig( - sendOptions.environment, - params.chain - ); +export async function addGas( + { autocalculateGasOptions, sendOptions, ...params }: AddGasParams, + dependencies: AddGasDependencies +): Promise { + const chainConfig = await dependencies.configClient + .getChainConfigs(sendOptions.environment) + .then((res) => res.chains[params.chain] as AxelarCosmosChainConfig) + .catch(() => undefined); if (!chainConfig) { throw new Error(`chain ID ${params.chain} not found`); @@ -29,7 +42,9 @@ export async function addGas({ const { rpc, channelIdToAxelar } = chainConfig.cosmosConfigs; - const tx = await fetchGMPTransaction(sendOptions.environment, params.txHash); + const [tx] = await dependencies.gmpClient + .searchGMP({ txHash: params.txHash }) + .catch(() => []); if (!tx) { return { @@ -56,9 +71,9 @@ export async function addGas({ ? params.token : await getFullFee({ tx, - environment: sendOptions.environment, autocalculateGasOptions, chainConfig, + axelarQueryClient: dependencies.axelarQueryClient, }); const sender = await sendOptions.offlineSigner @@ -81,9 +96,12 @@ export async function addGas({ }; } - const signer = await getCosmosSigner(rpcUrl, sendOptions.offlineSigner); + const signingStargateClient = await dependencies.getSigningStargateClient( + rpcUrl, + sendOptions.offlineSigner + ); - const broadcastResult = await signer.signAndBroadcast( + const broadcastResult = await signingStargateClient.signAndBroadcast( sender, [ { @@ -111,38 +129,13 @@ export async function addGas({ broadcastResult, }; } - -async function fetchChainConfig(environment: Environment, chain: string) { - const s3Client = await getS3Client(environment); - return s3Client - .getChainConfigs(environment) - .then((res) => res.chains[chain] as S3CosmosChainConfig) - .catch(() => undefined); -} - -async function fetchGMPTransaction(environment: Environment, txHash: string) { - const gmpClient = await getGmpClient(environment); - const [tx] = await gmpClient.searchGMP({ txHash }).catch(() => []); - - return tx; -} - async function getFullFee({ - environment, autocalculateGasOptions, tx, chainConfig, + axelarQueryClient, }: GetFullFeeOptions): Promise { - const apiClient = - typeof window === "undefined" - ? ( - await import("@axelarjs/api/axelar-query/node") - ).createAxelarQueryNodeClient(environment, {}) - : ( - await import("@axelarjs/api/axelar-query/browser") - ).createAxelarQueryBrowserClient(environment, {}); - - const amount = await apiClient.estimateGasFee({ + const amount = await axelarQueryClient.estimateGasFee({ sourceChain: tx.call.chain, destinationChain: tx.call.returnValues.destinationChain, gasLimit: autocalculateGasOptions?.gasLimit ?? BigInt(1_000_000), @@ -150,8 +143,6 @@ async function getFullFee({ sourceTokenSymbol: tx.gas_paid.returnValues.denom, }); - console.log({ amount }); - const denom = getIBCDenomOnSrcChain( tx.gas_paid.returnValues.denom, chainConfig @@ -172,7 +163,7 @@ function matchesOriginalTokenPayment( function getIBCDenomOnSrcChain( denomOnAxelar: string, - chain: S3CosmosChainConfig + chain: AxelarCosmosChainConfig ) { const { ibcDenom } = chain.assets?.find(({ id }) => id === denomOnAxelar) ?? {}; diff --git a/packages/transaction-recovery/src/add-gas/browser.ts b/packages/transaction-recovery/src/add-gas/browser.ts new file mode 100644 index 000000000..08eac9b6c --- /dev/null +++ b/packages/transaction-recovery/src/add-gas/browser.ts @@ -0,0 +1,21 @@ +import { + createAxelarQueryBrowserClient, + createConfigBrowserClient, + createGMPBrowserClient, +} from "@axelarjs/api"; + +import { SigningStargateClient } from "@cosmjs/stargate"; + +import { AddGasParams } from "~/types"; +import { addGas } from "./addGas"; + +export default function addGasBrowser(params: AddGasParams) { + const { environment } = params.sendOptions; + + return addGas(params, { + axelarQueryClient: createAxelarQueryBrowserClient(environment, {}), + configClient: createConfigBrowserClient(environment), + gmpClient: createGMPBrowserClient(environment), + getSigningStargateClient: SigningStargateClient.connectWithSigner, + }); +} diff --git a/packages/transaction-recovery/src/addGas/index.ts b/packages/transaction-recovery/src/add-gas/index.ts similarity index 100% rename from packages/transaction-recovery/src/addGas/index.ts rename to packages/transaction-recovery/src/add-gas/index.ts diff --git a/packages/transaction-recovery/src/add-gas/node.ts b/packages/transaction-recovery/src/add-gas/node.ts new file mode 100644 index 000000000..9a4c1c375 --- /dev/null +++ b/packages/transaction-recovery/src/add-gas/node.ts @@ -0,0 +1,21 @@ +import { + createAxelarQueryNodeClient, + createConfigNodeClient, + createGMPNodeClient, +} from "@axelarjs/api"; + +import { SigningStargateClient } from "@cosmjs/stargate"; + +import { AddGasParams } from "~/types"; +import { addGas } from "./addGas"; + +export default function addGasNode(params: AddGasParams) { + const { environment } = params.sendOptions; + + return addGas(params, { + axelarQueryClient: createAxelarQueryNodeClient(environment, {}), + configClient: createConfigNodeClient(environment), + gmpClient: createGMPNodeClient(environment), + getSigningStargateClient: SigningStargateClient.connectWithSigner, + }); +} diff --git a/packages/transaction-recovery/src/cosmosSigner/index.ts b/packages/transaction-recovery/src/cosmosSigner/index.ts deleted file mode 100644 index 5282af685..000000000 --- a/packages/transaction-recovery/src/cosmosSigner/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./signer"; diff --git a/packages/transaction-recovery/src/cosmosSigner/signer.ts b/packages/transaction-recovery/src/cosmosSigner/signer.ts deleted file mode 100644 index 6b965b0c6..000000000 --- a/packages/transaction-recovery/src/cosmosSigner/signer.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { OfflineSigner } from "@cosmjs/proto-signing"; -import { SigningStargateClient } from "@cosmjs/stargate"; - -export const getCosmosSigner = async ( - rpcUrl: string, - offlineDirectSigner: OfflineSigner -) => { - return SigningStargateClient.connectWithSigner(rpcUrl, offlineDirectSigner); -}; diff --git a/packages/transaction-recovery/src/index.ts b/packages/transaction-recovery/src/index.ts index e501453ed..3c68f9845 100644 --- a/packages/transaction-recovery/src/index.ts +++ b/packages/transaction-recovery/src/index.ts @@ -1 +1 @@ -export * from "./addGas"; +export * from "./add-gas"; diff --git a/packages/transaction-recovery/src/services/index.ts b/packages/transaction-recovery/src/services/index.ts deleted file mode 100644 index 454bbddf8..000000000 --- a/packages/transaction-recovery/src/services/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AXELARSCAN_API_URLS, Environment, S3_API_URLS } from "@axelarjs/core"; - -export const getGmpClient = async (env: Environment) => - typeof window === "undefined" - ? (await import("@axelarjs/api/gmp/node")).createGMPNodeClient({ - prefixUrl: AXELARSCAN_API_URLS[env], - }) - : (await import("@axelarjs/api/gmp/browser")).createGMPBrowserClient({ - prefixUrl: AXELARSCAN_API_URLS[env], - }); - -export const getS3Client = async (env: Environment) => - typeof window === "undefined" - ? (await import("@axelarjs/api/s3/node")).createS3NodeClient({ - prefixUrl: S3_API_URLS[env], - }) - : (await import("@axelarjs/api/s3/browser")).createS3BrowserClient({ - prefixUrl: S3_API_URLS[env], - }); diff --git a/packages/transaction-recovery/src/types.ts b/packages/transaction-recovery/src/types.ts index 0ac849d1e..e7cd54925 100644 --- a/packages/transaction-recovery/src/types.ts +++ b/packages/transaction-recovery/src/types.ts @@ -1,8 +1,12 @@ -import { S3CosmosChainConfig, SearchGMPResponseData } from "@axelarjs/api"; -import { Environment } from "@axelarjs/core"; +import type { + AxelarCosmosChainConfig, + AxelarQueryAPIClient, + SearchGMPResponseData, +} from "@axelarjs/api"; +import type { Environment } from "@axelarjs/core"; -import { OfflineSigner } from "@cosmjs/proto-signing"; -import { Coin, DeliverTxResponse, StdFee } from "@cosmjs/stargate"; +import type { OfflineSigner } from "@cosmjs/proto-signing"; +import type { Coin, DeliverTxResponse, StdFee } from "@cosmjs/stargate"; export type SendOptions = { txFee: StdFee; @@ -31,8 +35,8 @@ export type AddGasResponse = { }; export type GetFullFeeOptions = { - environment: Environment; autocalculateGasOptions?: AutocalculateGasOptions | undefined; tx: SearchGMPResponseData; - chainConfig: S3CosmosChainConfig; + chainConfig: AxelarCosmosChainConfig; + axelarQueryClient: AxelarQueryAPIClient; };