Skip to content

Commit

Permalink
Merge pull request #25 from axelarnetwork/feat/transaction-recovery
Browse files Browse the repository at this point in the history
feat: 'working' implementation of addgas complete
  • Loading branch information
alanrsoares authored Sep 7, 2023
2 parents bc61c14 + ed8b7a6 commit 79e803c
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 35 deletions.
2 changes: 1 addition & 1 deletion packages/api/src/gmp/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type BaseGMPParams = {

export type SearchGMPParams = BaseGMPParams & {
contractMethod?: "callContrct" | "callContrctWithToken";
txHash?: `0x${string}`;
txHash?: string | `0x${string}`;
txLogIndex?: number;
status?: GMPTxStatus;
from?: number;
Expand Down
15 changes: 14 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
export const ENVIRONMENTS = {
testnet: "testnet",
mainnet: "mainnet",
devnet: "devnet",
} as const;

export type Environment = keyof typeof ENVIRONMENTS;

export const COSMOS_GAS_RECEIVER_OPTIONS = {
testnet: "axelar1zl3rxpp70lmte2xr6c4lgske2fyuj3hupcsvcd",
mainnet: "axelar1aythygn6z5thymj6tmzfwekzh05ewg3l7d6y89",
} as const;

export type CosmosGasReceiver = keyof typeof COSMOS_GAS_RECEIVER_OPTIONS;

export const AXELARSCAN_API_URLS = {
testnet: "https://testnet.api.gmp.axelarscan.io",
mainnet: "https://api.gmp.axelarscan.io",
} as const;

export type AxelarscanUrl = keyof typeof AXELARSCAN_API_URLS;
9 changes: 7 additions & 2 deletions packages/transaction-recovery/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@
"author": "",
"license": "LicenseRef-LICENSE",
"devDependencies": {
"@axelarjs/config": "workspace:*",
"@axelarjs/cosmos": "workspace:*",
"@axelarjs/api": "workspace:*",
"@axelarjs/config": "workspace:*",
"dotenv": "^16.3.1",
"rimraf": "^5.0.1",
"typescript": "^5.2.2",
"vitest": "^0.34.3"
},
"dependencies": {
"@axelarjs/core": "workspace:*",
"@axelarjs/cosmos": "workspace:*",
"@cosmjs/proto-signing": "^0.30.1",
"@cosmjs/stargate": "^0.31.1"
}
}
63 changes: 51 additions & 12 deletions packages/transaction-recovery/src/addGas.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
import { createAxelarSigningClient } from "@axelarjs/cosmos/signing-client";
import { ENVIRONMENTS } from "@axelarjs/core";

import addGas from "./addGas";
import { vi } from "vitest";

const TX_HASH = `A6516262B303AF6D5D1599F46B52D2ED47DC1C1FFA3E56822A4313916C9AC8C4`;
import addGas, { SendOptions } from "./addGas";

const MOCK_ADD_GAS_RESPONSE = {
code: 0,
height: 2561692,
txIndex: 6,
events: [[]],
rawLog: "",
transactionHash:
"448337FAAAA9EAD528BB9D6B1DD32BDD5171988A87B9C5D1F8578D9927714918",
msgResponses: [],
gasUsed: 130739,
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", () => {
test("do stuff", async () => {
const signingClient = await createAxelarSigningClient({
environment: "testnet",
axelarRpcUrl: "https://axelartest-rpc.quickapi.com",
cosmosBasedWalletDetails: {
mnemonic: process.env["COSMOS_WALLET_MNEMONIC"] || "",
test("broadcast an IBC transfer", async () => {
const txHash =
"6118C285B0C7A139C5636184BECBF8C201FF36B61F44060B82EFE4C535084D9C";

const token = {
denom:
"ibc/9463E39D230614B313B487836D13A392BD1731928713D4C8427A083627048DB3",
amount: "1",
};

const sendOptions: SendOptions = {
txFee: {
gas: "250000",
amount: [{ denom: "uosmo", amount: "30000" }],
},
options: {},
});
channelIdToAxelar: "channel-3",
rpcUrl: "https://rpc.osmotest5.osmosis.zone",
environment: ENVIRONMENTS.testnet,
cosmosAddressPrefix: "osmo",
cosmosWalletMnemonic: process.env["COSMOS_WALLET_MNEMONIC"] as string,
};

const res = await addGas(txHash, token, sendOptions);

await addGas(signingClient, TX_HASH);
expect(res).toEqual(MOCK_ADD_GAS_RESPONSE);
});
});
80 changes: 64 additions & 16 deletions packages/transaction-recovery/src/addGas.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,73 @@
import { createGMPNodeClient } from "@axelarjs/api/gmp/node";
import type { AxelarSigningClient } from "@axelarjs/cosmos/signing-client";
import { COSMOS_GAS_RECEIVER_OPTIONS, Environment } from "@axelarjs/core";

const gmpClient = createGMPNodeClient({
prefixUrl: "https://testnet.api.gmp.axelarscan.io",
});
import type { Coin, StdFee } from "@cosmjs/stargate";

async function addGas(signingClient: AxelarSigningClient, txHash: string) {
const tx = await signingClient.getTx(txHash);
console.log({ tx });
import { getCosmosSigner, getCosmosWallet } from "./cosmosSigner";
import { gmpClient } from "./services";

const fees = await gmpClient.getFees({
destinationChain: "ethereum-2",
sourceChain: "polygon",
});
export type SendOptions = {
channelIdToAxelar: string;
rpcUrl: string;
txFee: StdFee;
timeoutTimestamp?: number;
environment: Environment;
cosmosAddressPrefix: string;
cosmosWalletMnemonic: string;
};

console.log({ fees });
async function addGas(
txHash: string,
token: Coin | "autocalculate",
sendOptions: SendOptions
) {
if (token === "autocalculate") {
throw new Error("autocalculate not yet supported, but we will soon!");
}

// send ibc transfer with memo field using message ID from tx above
// todo
const tx = await gmpClient(sendOptions.environment)
.searchGMP({
txHash,
})
.catch(() => undefined);

return {};
if (!tx || tx?.length < 1) {
throw new Error(`${txHash} could not be found`);
}

const offlineSigner = await getCosmosWallet(
sendOptions.cosmosWalletMnemonic,
sendOptions.cosmosAddressPrefix
);

const sender = await offlineSigner
.getAccounts()
.then(([acc]) => acc?.address);

if (!sender) {
throw new Error("Sender could not be found");
}

const signer = await getCosmosSigner(sendOptions.rpcUrl, offlineSigner);

return signer.signAndBroadcast(
sender,
[
{
typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
value: {
sourcePort: "transfer",
sourceChannel: sendOptions.channelIdToAxelar,
token,
sender,
receiver: COSMOS_GAS_RECEIVER_OPTIONS[sendOptions.environment],
timeoutTimestamp:
sendOptions.timeoutTimestamp ?? (Date.now() + 90) * 1e9,
memo: tx[0]?.call.id,
},
},
],
sendOptions.txFee
);
}

export default addGas;
2 changes: 2 additions & 0 deletions packages/transaction-recovery/src/cosmosSigner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./offlineSigner";
export * from "./signer";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";

export async function getCosmosWallet(mnemonic: string, prefix: string) {
return DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix });
}
9 changes: 9 additions & 0 deletions packages/transaction-recovery/src/cosmosSigner/signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { OfflineDirectSigner } from "@cosmjs/proto-signing";
import { SigningStargateClient } from "@cosmjs/stargate";

export const getCosmosSigner = async (
rpcUrl: string,
offlineDirectSigner: OfflineDirectSigner
) => {
return SigningStargateClient.connectWithSigner(rpcUrl, offlineDirectSigner);
};
7 changes: 7 additions & 0 deletions packages/transaction-recovery/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createGMPNodeClient } from "@axelarjs/api/gmp/node";
import { AXELARSCAN_API_URLS, Environment } from "@axelarjs/core";

export const gmpClient = (env: Environment) =>
createGMPNodeClient({
prefixUrl: AXELARSCAN_API_URLS[env],
});
Loading

2 comments on commit 79e803c

@vercel
Copy link

@vercel vercel bot commented on 79e803c Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

axelar-ui – ./packages/ui

axelar-ui-git-main-axelar-network.vercel.app
axelar-ui-axelar-network.vercel.app
ui.axelar.dev
axelar-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 79e803c Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

axelar-registry – ./apps/registry

axelar-registry-axelar-network.vercel.app
axelar-registry-git-main-axelar-network.vercel.app

Please sign in to comment.