Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:add-tx-recovery #363

Merged
merged 69 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
f1df65a
chore: init manualRelayToDestChain
npty Mar 5, 2024
083c6c8
chore: pending work and disable husky
npty Mar 12, 2024
b34a139
feat: add `AxelarRecoveryApiClient`
npty Mar 24, 2024
8f2399d
chore: add axelar recovery api urls
npty Mar 24, 2024
7dffa09
chore: add createAxelarBroadcastClient
npty Mar 24, 2024
9c6cfd0
feat: implement confirm step
npty Mar 24, 2024
8d9ff07
feat: implement sign tx flow
npty Mar 24, 2024
fb3864d
feat: improve sign tx
npty Mar 24, 2024
8313cc6
feat: implement route message
npty Mar 24, 2024
a1a6e1f
chore: add signEvmTx to axelar-recovery client
npty Mar 26, 2024
607ffb4
chore: implement signGatewayApprove tx
npty Mar 27, 2024
fae30ab
chore: refactor error for each recovery step
npty Mar 27, 2024
4837982
chore: fix build error
npty Mar 27, 2024
87b830a
chore: add retry
npty Apr 1, 2024
20255c1
chore: add built path to gitignore
npty May 20, 2024
6480156
chore: returns early if fail to proceed
npty May 20, 2024
e595fdc
docs(changeset): add tx recovery
npty May 21, 2024
84f1eae
docs(changeset): Add a tx recovery feature
npty May 21, 2024
2c2e88b
feat: implement escapeAfterConfirm
npty May 28, 2024
79c1f43
chore: make options optional
npty May 28, 2024
2c3548a
Merge branch 'main' into feat/add-tx-recovery
npty May 28, 2024
7e8d36b
chore: add tests
npty May 28, 2024
f732349
chore: moving files and folders
npty May 28, 2024
bdc8447
chore: check for tx status first
npty May 29, 2024
b09b586
chore: remove unnecessary check
npty May 29, 2024
bcce241
chore: fix checking finalized block issue
npty May 29, 2024
42c6bf0
chore: fix error msg
npty May 29, 2024
2119fc2
chore: refactor recovery methods
npty May 29, 2024
daeda35
chore: add test for axelar confirm tx
npty May 30, 2024
a76dc76
chore: add tests for axelarConfirmTx
npty May 30, 2024
1ca9d7b
chore: remove unused import
npty May 30, 2024
b89a920
chore: add more assertion axelarConfirmTx
npty May 30, 2024
13433c4
chore: add tests for axelar sign tx
npty May 30, 2024
19fd536
chore: add evm gateway approve test
npty May 30, 2024
6baf137
chore: fix sign commands
npty May 31, 2024
72ef90c
chore: remove execute tx signing from backend
npty May 31, 2024
eb72f70
chore: remove unused import
npty May 31, 2024
4e1dd0c
chore: remove the signEvmTx command from axelar-recovery api
npty May 31, 2024
961cbf6
chore: move getWalletClient to common folder
npty May 31, 2024
89845bf
chore: use wallet client to sendRawTransaction
npty May 31, 2024
7aeff38
chore: implement response mapping
npty Jun 3, 2024
d462c7f
chore: fix build error
npty Jun 3, 2024
e844aa4
chore: implement recovery tests
npty Jun 3, 2024
00ec9ad
chore: update isomorphic test
npty Jun 3, 2024
869df7e
chore: fix tests
npty Jun 3, 2024
86663e2
chore: fix tests
npty Jun 3, 2024
d8103f1
chore: add messageId and txLogIndex to params
npty Jun 3, 2024
1b2c62d
chore: remove txEventIndex
npty Jun 3, 2024
4face80
chore: fix import
npty Jun 3, 2024
687ee47
chore: skip manual test
npty Jun 3, 2024
c5b45fe
chore: fix test expect
npty Jun 3, 2024
b29797d
chore: uncomment husky
npty Jun 3, 2024
291b7c9
chore: remove outdated changeset
npty Jun 3, 2024
d8f9d71
chore: add changeset
npty Jun 4, 2024
abbc3e8
chore: typo
npty Jun 4, 2024
21ef0e4
feat: add lcd urls to core package
npty Jun 4, 2024
d9d44d0
feat: add stargate connect function with fallback to other rpc urls
npty Jun 4, 2024
a17e4d7
chore: fix tests
npty Jun 4, 2024
46f209d
chore: update changeset
npty Jun 4, 2024
74246d4
chore: fix error in deposit address
npty Jun 4, 2024
876722a
chore: fix wrong type
npty Jun 4, 2024
09c3e98
chore: extract helper function 'shouldAbortRecovery'
npty Jun 10, 2024
c21ee80
chore: separate actions and types for axelar txs
npty Jun 10, 2024
89796df
chore: add more reasons to retry batch commands
npty Jun 10, 2024
0a2482f
chore: added more tests and fix error
npty Jun 10, 2024
9b0720f
chore: remove sign tx from evm to ibc
npty Jun 10, 2024
3a1b97b
chore: move batch commands query in sign commands inside try block
npty Jun 10, 2024
faa437f
chore: move batch commands query to the try block
npty Jun 10, 2024
4719824
chore: remove undefined
npty Jun 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/mighty-birds-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@axelarjs/transaction-recovery": minor
"@axelarjs/api": minor
"@axelarjs/cosmos": patch
"@axelarjs/core": patch
"@axelarjs/maestro": patch
---

- Added `manualRelayToDestChain` function in the `@axelarjs/transaction-recovery` module for enhanced transaction recovery capabilities.
- Added `searchBatchedCommands` query for the Axelarscan client in the `@axelarjs/api` module.
- Added Axelar Recovery client to facilitate server-side signing of Axelar transactions in the `@axelarjs/api` module.
- Added `AXELAR_LCD_URLS` to `@axelarjs/core` module.
- Added `connectToFirstAvailable` function to allow passing multiple rpc urls and connect to first available node in the `@axelarjs/cosmos` module.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import {
createUseSimulateContract,
createUseWriteContract,
createUseSimulateContract,
} from "wagmi/codegen";

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
12 changes: 6 additions & 6 deletions apps/maestro/src/lib/contracts/InterchainToken.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import {
createUseReadContract,
createUseWriteContract,
createUseSimulateContract,
createUseWatchContractEvent,
createUseWriteContract,
} from "wagmi/codegen";

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -518,14 +518,14 @@ export const useReadInterchainTokenNameHash =
* Wraps __{@link useReadContract}__ with `abi` set to __{@link interchainTokenAbi}__ and `functionName` set to `"nonces"`
*/
export const useReadInterchainTokenNonces = /*#__PURE__*/ createUseReadContract(
{ abi: interchainTokenAbi, functionName: "nonces" }
{ abi: interchainTokenAbi, functionName: "nonces" },
);

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link interchainTokenAbi}__ and `functionName` set to `"symbol"`
*/
export const useReadInterchainTokenSymbol = /*#__PURE__*/ createUseReadContract(
{ abi: interchainTokenAbi, functionName: "symbol" }
{ abi: interchainTokenAbi, functionName: "symbol" },
);

/**
Expand Down Expand Up @@ -566,7 +566,7 @@ export const useWriteInterchainTokenApprove =
* Wraps __{@link useWriteContract}__ with `abi` set to __{@link interchainTokenAbi}__ and `functionName` set to `"burn"`
*/
export const useWriteInterchainTokenBurn = /*#__PURE__*/ createUseWriteContract(
{ abi: interchainTokenAbi, functionName: "burn" }
{ abi: interchainTokenAbi, functionName: "burn" },
);

/**
Expand All @@ -591,7 +591,7 @@ export const useWriteInterchainTokenIncreaseAllowance =
* Wraps __{@link useWriteContract}__ with `abi` set to __{@link interchainTokenAbi}__ and `functionName` set to `"init"`
*/
export const useWriteInterchainTokenInit = /*#__PURE__*/ createUseWriteContract(
{ abi: interchainTokenAbi, functionName: "init" }
{ abi: interchainTokenAbi, functionName: "init" },
);

/**
Expand All @@ -616,7 +616,7 @@ export const useWriteInterchainTokenInterchainTransferFrom =
* Wraps __{@link useWriteContract}__ with `abi` set to __{@link interchainTokenAbi}__ and `functionName` set to `"mint"`
*/
export const useWriteInterchainTokenMint = /*#__PURE__*/ createUseWriteContract(
{ abi: interchainTokenAbi, functionName: "mint" }
{ abi: interchainTokenAbi, functionName: "mint" },
);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import {
createUseReadContract,
createUseWriteContract,
createUseSimulateContract,
createUseWatchContractEvent,
createUseWriteContract,
} from "wagmi/codegen";

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import {
createUseReadContract,
createUseWriteContract,
createUseSimulateContract,
createUseWatchContractEvent,
createUseWriteContract,
} from "wagmi/codegen";

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 2 additions & 2 deletions apps/maestro/src/lib/contracts/TokenManager.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import {
createUseReadContract,
createUseWriteContract,
createUseSimulateContract,
createUseWatchContractEvent,
createUseWriteContract,
} from "wagmi/codegen";

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -418,7 +418,7 @@ export const useReadTokenManagerFlowInAmount =
* Wraps __{@link useReadContract}__ with `abi` set to __{@link tokenManagerAbi}__ and `functionName` set to `"flowLimit"`
*/
export const useReadTokenManagerFlowLimit = /*#__PURE__*/ createUseReadContract(
{ abi: tokenManagerAbi, functionName: "flowLimit" }
{ abi: tokenManagerAbi, functionName: "flowLimit" },
);

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/api/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
/axelar-config
/deposit-address
/deposit-service
/axelar-recovery
/docs

*.d.ts
*.js
.turbo/
.turbo/
4 changes: 3 additions & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
"license": "LicenseRef-LICENSE",
"devDependencies": {
"@axelarjs/config": "workspace:*",
"@types/node": "^20.11.30",
"@cosmjs/stargate": "^0.31.3",
"@types/node": "^20.11.28",
"dotenv": "^16.4.5",
"fast-check": "^3.17.0",
"gh-pages": "^6.1.1",
Expand All @@ -102,6 +103,7 @@
},
"dependencies": {
"@axelarjs/core": "workspace:*",
"@axelarjs/cosmos": "workspace:*",
"@axelarjs/utils": "workspace:*",
"isomorphic-unfetch": "^4.0.2",
"rambda": "^9.1.1",
Expand Down
26 changes: 26 additions & 0 deletions packages/api/src/axelar-recovery/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { AXELAR_RECOVERY_API_URLS, type Environment } from "@axelarjs/core";
import {
HttpClient,
type HttpClientOptions,
} from "@axelarjs/utils/http-client";

import { createAxelarConfigClient } from "../axelar-config";
import { AxelarRecoveryApiClient } from "./isomorphic";

export const createAxelarRecoveryApiClient = (
env: Environment,
options?: HttpClientOptions
) =>
AxelarRecoveryApiClient.init(
{
instance: HttpClient.extend({
...(options ?? {
prefixUrl: AXELAR_RECOVERY_API_URLS[env],
}),
}),
},
{
axelarConfigClient: createAxelarConfigClient(env),
},
env
);
3 changes: 3 additions & 0 deletions packages/api/src/axelar-recovery/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./types";
export * from "./isomorphic";
export * from "./client";
100 changes: 100 additions & 0 deletions packages/api/src/axelar-recovery/isomorphic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { AXELAR_RPC_URLS, Environment } from "@axelarjs/core";
import { createAxelarBroadcastClient } from "@axelarjs/cosmos";
import type { Body as HttpBody } from "@axelarjs/utils/http-client";

import type { DeliverTxResponse } from "@cosmjs/stargate";

import { AxelarConfigClient } from "../axelar-config";
import {
RestService,
type ClientMeta,
type RestServiceOptions,
} from "../lib/rest-service";
import type { ChainModule } from "./types";

export type AxelarRecoveryQueryDependencies = {
axelarConfigClient: AxelarConfigClient;
};

export class AxelarRecoveryApiClient extends RestService {
protected env: Environment;
protected rpcUrl: string;
protected deps: AxelarRecoveryQueryDependencies;

public constructor(
options: RestServiceOptions,
deps: AxelarRecoveryQueryDependencies,
env: Environment,
meta?: ClientMeta
) {
super(options, meta);
this.deps = deps;
this.rpcUrl = AXELAR_RPC_URLS[env];
this.env = env;
}

static init(
options: RestServiceOptions,
deps: AxelarRecoveryQueryDependencies,
env: Environment
) {
return new AxelarRecoveryApiClient(options, deps, env, {
name: "AxelarRecoveryQueryAPI",
version: "0.0.1",
});
}

private async generateTxBytesAndBroadcast<B extends HttpBody>(
endpoint: string,
body: B
) {
const { data: txBytes } = await this.client
.post(endpoint, body)
.json<{ data: Uint8Array }>();

const broadcaster = await createAxelarBroadcastClient(this.rpcUrl);

return broadcaster.broadcastTx(txBytes);
}

async confirm(
txHash: `0x${string}`,
module: ChainModule,
chain: string
): Promise<DeliverTxResponse> {
return this.generateTxBytesAndBroadcast("/confirm_gateway_tx", {
txHash,
module,
chain,
});
}

async createPendingTransfers(module: ChainModule, chain: string) {
return this.generateTxBytesAndBroadcast("/create_pending_transfers", {
module,
chain,
});
}

async executePendingTransfers(module: ChainModule, chain: string) {
return this.generateTxBytesAndBroadcast("/execute_pending_transfers", {
module,
chain,
});
}

async routeMessage(payload: string, id: string) {
return this.generateTxBytesAndBroadcast("/route_message", {
payload,
id,
});
}

async signCommands(chain: string, module: ChainModule) {
return this.generateTxBytesAndBroadcast("/sign_commands", {
chain,
module,
});
}

}
1 change: 1 addition & 0 deletions packages/api/src/axelar-recovery/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type ChainModule = "axelarnet" | "evm";
17 changes: 17 additions & 0 deletions packages/api/src/axelarscan/isomorphic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
LinkEvent,
LinkRequestRawResponse,
LinkRequestResponse,
SearchBatchesResponse,
} from "./types";

export type AxelarApiParams<T extends Record<string, unknown>> = T & {
Expand Down Expand Up @@ -66,6 +67,22 @@ export class AxelarscanClient extends RestService {
return await this.client.get(path).json<LinkRequestRawResponse>();
}

async searchBatchedCommands(params: {
commandId?: string | undefined;
sourceTransactionHash?: string | undefined;
}) {
const json = {
commandId: params.commandId,
sourceTransactionHash: params.sourceTransactionHash,
};

const result = await this.client
.post("token/searchBatches", { json })
.json<SearchBatchesResponse>();

return result;
}

async getRecentLinkTransactions(params: {
size: number;
}): Promise<LinkRequestResponse[]> {
Expand Down
27 changes: 27 additions & 0 deletions packages/api/src/axelarscan/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,30 @@ export type LinkRequestResponse = {
tokenAddress?: string | undefined;
timestamp?: number;
};

export type BaseChainConfigsResponse = {
evm: EVMChainConfig[];
cosmos: CosmosChainConfig[];
};

export type SearchBatchesData = {
data: string;
command_ids: string[];
batch_id: string;
id: string;
status: string;
execute_data: string;
chain: string;
commands: SearchBatchesCommands[];
};

export type SearchBatchesCommands = {
executed: boolean;
id: string;
transactionHash: string;
type: string;
};

export type SearchBatchesResponse = {
data: SearchBatchesData[];
};
6 changes: 3 additions & 3 deletions packages/api/src/deposit-address/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ describe("deposit address client (node)", () => {
const api = createDepositAddressApiClient(ENVIRONMENTS.testnet);
const dummyAccount = privateKeyToAccount(generatePrivateKey());
const otcRes: OTC = await retryGetOtc(api, dummyAccount.address);
const fromChain = "osmosis-7";
const toChain = "ethereum-2";
const fromChain = "ojo";
const toChain = "ethereum-sepolia";
const asset = "uaxl";

const signature = await dummyAccount.signMessage({
Expand Down Expand Up @@ -88,7 +88,7 @@ describe("deposit address client (node)", () => {
// retry if get http error 429 (too many requests)
const otcRes = await retryGetOtc(api, dummyAccount.address);
const fromChain = "Fantom";
const toChain = "ethereum-2";
const toChain = "ethereum-sepolia";
const asset = "uaxl";

const signature = await dummyAccount.signMessage({
Expand Down
Loading
Loading