Skip to content

Commit

Permalink
refactor: adapt add-gas module to support IOC pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
alanrsoares committed Sep 18, 2023
1 parent 1912f6c commit 650c112
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 110 deletions.
2 changes: 1 addition & 1 deletion packages/transaction-recovery/scripts/clean.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash

npx rimraf build cosmosSigner services *.js *.d.ts
npx rimraf build add-gas *.js *.d.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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";
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
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<SigningStargateClient>;
};

/**
* 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<AddGasResponse>} - Response from adding gas to a transaction
*/
export async function addGas({
autocalculateGasOptions,
sendOptions,
...params
}: AddGasParams): Promise<AddGasResponse> {
const chainConfig = await fetchChainConfig(
sendOptions.environment,
params.chain
);
export async function addGas(
{ autocalculateGasOptions, sendOptions, ...params }: AddGasParams,
dependencies: AddGasDependencies
): Promise<AddGasResponse> {
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`);
}

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 {
Expand All @@ -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
Expand All @@ -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,
[
{
Expand Down Expand Up @@ -111,47 +129,20 @@ 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<Coin> {
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),
gasMultiplier: autocalculateGasOptions?.gasMultipler ?? 1,
sourceTokenSymbol: tx.gas_paid.returnValues.denom,
});

console.log({ amount });

const denom = getIBCDenomOnSrcChain(
tx.gas_paid.returnValues.denom,
chainConfig
Expand All @@ -172,7 +163,7 @@ function matchesOriginalTokenPayment(

function getIBCDenomOnSrcChain(
denomOnAxelar: string,
chain: S3CosmosChainConfig
chain: AxelarCosmosChainConfig
) {
const { ibcDenom } =
chain.assets?.find(({ id }) => id === denomOnAxelar) ?? {};
Expand Down
21 changes: 21 additions & 0 deletions packages/transaction-recovery/src/add-gas/browser.ts
Original file line number Diff line number Diff line change
@@ -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,
});
}
21 changes: 21 additions & 0 deletions packages/transaction-recovery/src/add-gas/node.ts
Original file line number Diff line number Diff line change
@@ -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,
});
}
1 change: 0 additions & 1 deletion packages/transaction-recovery/src/cosmosSigner/index.ts

This file was deleted.

9 changes: 0 additions & 9 deletions packages/transaction-recovery/src/cosmosSigner/signer.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/transaction-recovery/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./addGas";
export * from "./add-gas";
19 changes: 0 additions & 19 deletions packages/transaction-recovery/src/services/index.ts

This file was deleted.

16 changes: 10 additions & 6 deletions packages/transaction-recovery/src/types.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -31,8 +35,8 @@ export type AddGasResponse = {
};

export type GetFullFeeOptions = {
environment: Environment;
autocalculateGasOptions?: AutocalculateGasOptions | undefined;
tx: SearchGMPResponseData;
chainConfig: S3CosmosChainConfig;
chainConfig: AxelarCosmosChainConfig;
axelarQueryClient: AxelarQueryAPIClient;
};

0 comments on commit 650c112

Please sign in to comment.