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

Implement query transfer status api #154

Merged
merged 11 commits into from
Sep 9, 2022
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.10.4] - 22-SEPTEMBER-6

- add `AxelarTransferAPI` to allow query transfer status for cross-chain transfer via deposit address or sendToken method.
- rename `axelarCachingServiceUrl` to `axelarGMPApiUrl`

## [0.10.3] - 2022-SEPTEMBER-5

- update the `AxelarGMPRecoveryAPI` to allow for rpc/lcd endpoint overrides in constructor for the API
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,47 @@ export interface EnvironmentConfigs {
resourceUrl: string;
axelarRpcUrl: string;
axelarLcdUrl: string;
axelarCachingServiceUrl: string;
axelarGMPApiUrl: string;
recoveryApiUrl: string;
axelarCrosschainApiUrl: string;
axelarscanUrl: string;
}

const localConfigs: EnvironmentConfigs = {
resourceUrl: `http://localhost:4000`,
axelarRpcUrl: "https://axelar-testnet-rpc.axelar-dev.workers.dev",
axelarLcdUrl: "https://axelar-testnet-lcd.axelar-dev.workers.dev",
axelarCachingServiceUrl: "https://testnet.api.gmp.axelarscan.io",
axelarGMPApiUrl: "https://testnet.api.gmp.axelarscan.io",
recoveryApiUrl: "https://axelar-signing-relayer-testnet.axelar.dev",
axelarCrosschainApiUrl: "https://testnet.api.axelarscan.io/cross-chain",
axelarscanUrl: "https://testnet.axelarscan.io",
};
const devnetConfigs: EnvironmentConfigs = {
resourceUrl: `https://nest-server-devnet.axelar.dev`,
axelarRpcUrl: "",
axelarLcdUrl: "",
axelarCachingServiceUrl: "https://devnet.api.gmp.axelarscan.io",
axelarGMPApiUrl: "https://devnet.api.gmp.axelarscan.io",
recoveryApiUrl: "",
axelarCrosschainApiUrl: "",
axelarscanUrl: "",
};
const testnetConfigs: EnvironmentConfigs = {
resourceUrl: `https://nest-server-testnet.axelar.dev`,
axelarRpcUrl: "https://axelar-testnet-rpc.axelar-dev.workers.dev",
axelarLcdUrl: "https://axelar-testnet-lcd.axelar-dev.workers.dev",
axelarCachingServiceUrl: "https://testnet.api.gmp.axelarscan.io",
axelarGMPApiUrl: "https://testnet.api.gmp.axelarscan.io",
recoveryApiUrl: "https://axelar-signing-relayer-testnet.axelar.dev",
axelarCrosschainApiUrl: "https://testnet.api.axelarscan.io/cross-chain",
axelarscanUrl: "https://testnet.axelarscan.io",
};
const mainnetConfigs: EnvironmentConfigs = {
resourceUrl: `https://nest-server-mainnet.axelar.dev`,
axelarRpcUrl: "https://axelar-rpc.quickapi.com",
axelarLcdUrl: "https://axelar-lcd.quickapi.com",
axelarCachingServiceUrl: "https://api.gmp.axelarscan.io",
axelarGMPApiUrl: "https://api.gmp.axelarscan.io",
recoveryApiUrl: "https://axelar-signing-relayer-mainnet.axelar.dev",
axelarCrosschainApiUrl: "https://api.axelarscan.io/cross-chain",
axelarscanUrl: "https://axelarscan.io",
};

configsMap["local"] = localConfigs;
Expand Down
12 changes: 6 additions & 6 deletions src/libs/AxelarQueryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ export class AxelarQueryAPI {
readonly environment: Environment;
readonly lcdApi: RestService;
readonly rpcApi: RestService;
readonly axelarCachingServiceApi: RestService;
readonly axelarGMPServiceApi: RestService;
readonly axelarRpcUrl: string;
readonly axelarLcdUrl: string;
readonly axelarCachingServiceUrl: string;
readonly axelarGMPServiceUrl: string;
private allAssets: AssetConfig[];
private axelarQueryClient: AxelarQueryClientType;

Expand All @@ -36,12 +36,12 @@ export class AxelarQueryAPI {

this.axelarRpcUrl = axelarRpcUrl || links.axelarRpcUrl;
this.axelarLcdUrl = axelarLcdUrl || links.axelarLcdUrl;
this.axelarCachingServiceUrl = links.axelarCachingServiceUrl;
this.axelarGMPServiceUrl = links.axelarGMPApiUrl;
this.environment = environment;

this.lcdApi = new RestService(this.axelarLcdUrl);
this.rpcApi = new RestService(this.axelarRpcUrl);
this.axelarCachingServiceApi = new RestService(this.axelarCachingServiceUrl);
this.axelarGMPServiceApi = new RestService(this.axelarGMPServiceUrl);

this._initializeAssets();
}
Expand Down Expand Up @@ -114,7 +114,7 @@ export class AxelarQueryAPI {
sourceChainName: EvmChain,
destinationChainName: EvmChain
): Promise<BaseFeeResponse> {
return this.axelarCachingServiceApi
return this.axelarGMPServiceApi
.post("", {
method: "getFees",
destinationChain: destinationChainName,
Expand Down Expand Up @@ -150,7 +150,7 @@ export class AxelarQueryAPI {
sourceTokenSymbol: sourceChainTokenSymbol,
});

return this.axelarCachingServiceApi.get(`?${params}`).then((resp) => resp.result);
return this.axelarGMPServiceApi.get(`?${params}`).then((resp) => resp.result);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi {
transactionHash?: string,
error?: any
) {
return await this.execPost(super.getAxelarCachingServiceUrl, "", {
return await this.execPost(super.getAxelarGMPApiUrl, "", {
method: "saveGMP",
sourceTransactionHash,
transactionHash,
Expand Down
10 changes: 5 additions & 5 deletions src/libs/TransactionRecoveryApi/AxelarRecoveryApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export interface ExecuteParamsResponse {
export class AxelarRecoveryApi {
readonly environment: Environment;
readonly recoveryApiUrl: string;
readonly axelarCachingServiceUrl: string;
readonly axelarGMPApiUrl: string;
readonly axelarRpcUrl: string;
readonly axelarLcdUrl: string;
readonly config: AxelarRecoveryAPIConfig;
Expand All @@ -64,7 +64,7 @@ export class AxelarRecoveryApi {
public constructor(config: AxelarRecoveryAPIConfig) {
const { environment } = config;
const links: EnvironmentConfigs = getConfigs(environment);
this.axelarCachingServiceUrl = links.axelarCachingServiceUrl;
this.axelarGMPApiUrl = links.axelarGMPApiUrl;
this.recoveryApiUrl = links.recoveryApiUrl;
this.axelarRpcUrl = config.axelarRpcUrl || links.axelarRpcUrl;
this.axelarLcdUrl = config.axelarLcdUrl || links.axelarLcdUrl;
Expand All @@ -73,7 +73,7 @@ export class AxelarRecoveryApi {
}

public async fetchGMPTransaction(txHash: string, txLogIndex?: number) {
return await this.execGet(this.axelarCachingServiceUrl, {
return await this.execGet(this.axelarGMPApiUrl, {
method: "searchGMP",
txHash,
txLogIndex,
Expand Down Expand Up @@ -290,7 +290,7 @@ export class AxelarRecoveryApi {
.then((res) => res.json())
.then((res) => res.data);
}
get getAxelarCachingServiceUrl(): string {
return this.axelarCachingServiceUrl;
get getAxelarGMPApiUrl(): string {
return this.axelarGMPApiUrl;
}
}
66 changes: 66 additions & 0 deletions src/libs/TransactionRecoveryApi/AxelarTransferAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { getConfigs } from "../../constants";
import {
AxelarTransferAPIConfig,
QueryTransferOptions,
QueryTransferResponse,
QueryTransferStatus,
} from "../types";
import { RestService } from "../../services";

export class AxelarTransferApi {
private axelarCrosschainUrl: string;
private axelarnscanUrl: string;
readonly axelarCrosschainApi: RestService;

public constructor(config: AxelarTransferAPIConfig) {
const environment = config.environment;
const links = getConfigs(environment);
this.axelarCrosschainUrl = links.axelarCrosschainApiUrl;
this.axelarnscanUrl = links.axelarscanUrl;
this.axelarCrosschainApi = new RestService(this.axelarCrosschainUrl);
}

public async queryTransferStatus(
txHash: string,
options?: QueryTransferOptions
): Promise<QueryTransferResponse> {
const response = await this.axelarCrosschainApi
.post("/transfers-status", {
txHash,
...options,
})
.catch(() => undefined);

if (!response) {
return {
success: false,
error: "Axelar Transfer API is not available",
};
}
if (response.length === 0) {
return {
success: false,
error: "No transfer found",
};
}

const transfer = response[0];
return {
success: true,
data: {
id: transfer.source.id,
status: transfer.status as QueryTransferStatus,
type: transfer.source.type,
amount: transfer.source.amount,
fee: transfer.source.fee,
denom: transfer.source.denom,
senderChain: transfer.source.sender_chain,
senderAddress: transfer.source.sender_address,
recipientChain: transfer.source.recipient_chain,
recipientAddress: transfer.source.recipient_address,
blockExplorerUrl: `${this.axelarnscanUrl}/transfer/${transfer.source.id}`,
blockHeight: transfer.source.height,
},
};
}
}
1 change: 1 addition & 0 deletions src/libs/TransactionRecoveryApi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./AxelarDepositRecoveryAPI";
export * from "./AxelarGMPRecoveryAPI";
export * from "./constants/error";
export * from "./AxelarRecoveryApi";
export * from "./AxelarTransferAPI";
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ describe("AxelarDepositRecoveryAPI", () => {
]);
const executeParams = await api.queryExecuteParams(txHash);

expect(api.execGet).toHaveBeenCalledWith(api.axelarCachingServiceUrl, {
expect(api.execGet).toHaveBeenCalledWith(api.axelarGMPApiUrl, {
method: "searchGMP",
txHash,
});
Expand Down Expand Up @@ -340,7 +340,7 @@ describe("AxelarDepositRecoveryAPI", () => {
]);
const executeParams = await api.queryExecuteParams(txHash);

expect(api.execGet).toHaveBeenCalledWith(api.axelarCachingServiceUrl, {
expect(api.execGet).toHaveBeenCalledWith(api.axelarGMPApiUrl, {
method: "searchGMP",
txHash,
});
Expand Down
47 changes: 47 additions & 0 deletions src/libs/test/TransactionRecoveryAPI/AxelarTransferAPI.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { getConfigs } from "../../../constants";
import { AxelarTransferApi } from "../../TransactionRecoveryApi";
import { Environment } from "../../types";
import { transferResponseExecutedStub } from "../stubs";

describe("AxelarTransferApi", () => {
const api = new AxelarTransferApi({ environment: Environment.TESTNET });

it("should return error given the transfer api could not be reached", async () => {
jest.spyOn(api.axelarCrosschainApi, "post").mockRejectedValueOnce(undefined);
const response = await api.queryTransferStatus("0x123");
expect(response.success).toBe(false);
expect(response.error).toBe("Axelar Transfer API is not available");
});

it("should return error when no transfer is found", async () => {
jest.spyOn(api.axelarCrosschainApi, "post").mockResolvedValueOnce([]);
const response = await api.queryTransferStatus("0x123");
expect(response.success).toBe(false);
expect(response.error).toBe("No transfer found");
});

it("should query transfer status successfully when given tx hash is valid", async () => {
const mockResponse = transferResponseExecutedStub();
jest.spyOn(api.axelarCrosschainApi, "post").mockResolvedValueOnce(mockResponse);
const response = await api.queryTransferStatus(
"6D1B1CD4B754280461BD7AD43B4838BBD8A467AA346B7584052025F83B5EB90F"
);
expect(response.success).toBe(true);
expect(response.data).toEqual({
id: mockResponse[0].source.id,
status: mockResponse[0].status,
type: mockResponse[0].source.type,
amount: mockResponse[0].source.amount,
fee: mockResponse[0].source.fee,
denom: mockResponse[0].source.denom,
senderChain: mockResponse[0].source.sender_chain,
senderAddress: mockResponse[0].source.sender_address,
recipientChain: mockResponse[0].source.recipient_chain,
recipientAddress: mockResponse[0].source.recipient_address,
blockHeight: mockResponse[0].source.height,
blockExplorerUrl: `${getConfigs(Environment.TESTNET).axelarscanUrl}/transfer/${
mockResponse[0].source.id
}`,
});
});
});
Loading