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

v0.16 #325

Merged
merged 7 commits into from
May 8, 2024
Merged

v0.16 #325

Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ 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.16.0] - 2024-MAY-1

- Upgraded axelar-cgp-solidity to `6.3.0` to enable support for Node.js version >= 20
- Fixed an issue with the generation of `commandId`
- Changed the type of `executeData` from `0x${string}` to `string` to ensure compatibility with most libraries and clients
- Corrected the documentation for the `estimateGasFee` function regarding gas limit calculation
- Resolved an issue with the calculation of L1 gas fees when the source and destination tokens have different decimal places

## [0.15.0] - 2024-MARCH-20

- Improved the accuracy of `estimateGasFee` function by incorporating L1 rollup fee for destination L2 chain.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@axelar-network/axelarjs-sdk",
"version": "0.15.0",
"version": "0.16.0",
"description": "The JavaScript SDK for Axelar Network",
"repository": {
"type": "git",
Expand Down Expand Up @@ -41,7 +41,7 @@
"author": "Axelar Network",
"license": "MIT",
"dependencies": {
"@axelar-network/axelar-cgp-solidity": "^4.5.0",
"@axelar-network/axelar-cgp-solidity": "^6.3.0",
"@axelar-network/axelarjs-types": "^0.33.0",
"@cosmjs/json-rpc": "^0.30.1",
"@cosmjs/stargate": "0.31.0-alpha.1",
Expand Down
17 changes: 15 additions & 2 deletions pnpm-lock.yaml

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

12 changes: 10 additions & 2 deletions src/libs/AxelarQueryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ export class AxelarQueryAPI {
);
}

// Calculate the L1 execution fee. This value is in ETH.
// Calculate the L1 execution fee. This value is in ETH wei.
l1ExecutionFee = await this.estimateL1GasFee(destChainId, {
executeData: executeData || DEFAULT_L1_EXECUTE_DATA,
l1GasPrice: destToken.l1_gas_price_in_units,
Expand All @@ -310,10 +310,18 @@ export class AxelarQueryAPI {
const ethTokenPrice = Number(ethereumToken.token_price.usd);
const ethToSrcTokenPriceRatio = ethTokenPrice / srcTokenPrice;

const actualL1ExecutionFee = l1ExecutionFee
let actualL1ExecutionFee = l1ExecutionFee
.mul(Math.ceil(ethToSrcTokenPriceRatio * 1000))
.div(1000);

if (sourceToken.decimals !== destToken.decimals) {
actualL1ExecutionFee = BigNumberUtils.convertTokenAmount(
actualL1ExecutionFee,
destToken.decimals,
sourceToken.decimals
);
}

l1ExecutionFee = BigNumber.from(actualL1ExecutionFee.toString());

// Calculate the L1 execution fee with the gas multiplier
Expand Down
8 changes: 8 additions & 0 deletions src/libs/BigNumberUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@ export class BigNumberUtils {
public static divideToGetWei(bn: BigNumber | string, number: string, units: number): BigNumber {
return BigNumber.from(bn).div(parseUnits(number, units));
}

public static convertTokenAmount(
ethAmount: BigNumber,
sourceDecimals: number,
targetDecimals: number
) {
return ethAmount.mul(parseUnits("1", targetDecimals)).div(parseUnits("1", sourceDecimals));
}
}
11 changes: 7 additions & 4 deletions src/libs/TransactionRecoveryApi/AxelarGMPRecoveryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi {
});
}

public getCidFromSrcTxHash(destChainId: string, txHash: string, eventIndex: number) {
return getCommandId(destChainId, txHash, eventIndex, this.environment, rpcInfo);
public getCidFromSrcTxHash(destChainId: string, messageId: string, eventIndex: number) {
const chainId = rpcInfo[this.environment].networkInfo[destChainId.toLowerCase()]?.chainId;
return getCommandId(messageId, eventIndex, chainId);
}

public async doesTxMeetConfirmHt(chain: string, txHash: string, provider?: JsonRpcProvider) {
Expand Down Expand Up @@ -244,8 +245,10 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi {
};
}

const commandId = this.getCidFromSrcTxHash(destChainId, srcTxHash, eventIndex);
const eventResponse = await this.axelarQueryApi.getEVMEvent(srcChainId, srcTxHash, eventIndex);
const isCallContract = eventResponse?.event?.contractCall ? true : false;
const messageId = isCallContract ? `${srcTxHash}-${eventIndex}` : srcTxHash;
const commandId = this.getCidFromSrcTxHash(destChainId, messageId, eventIndex);

if (!eventResponse || this.isEVMEventFailed(eventResponse)) {
const errorMessage = this.isEVMEventFailed(eventResponse)
Expand Down Expand Up @@ -1149,7 +1152,7 @@ export class AxelarGMPRecoveryAPI extends AxelarRecoveryApi {

const executeParams = response.data as ExecuteParams;
const gasLimitBuffer = evmWalletDetails?.gasLimitBuffer || 0;
const { destinationChain, destinationContractAddress, srcTxInfo } = executeParams;
const { destinationChain, destinationContractAddress } = executeParams;

const signer = this.getSigner(
destinationChain,
Expand Down
38 changes: 16 additions & 22 deletions src/libs/TransactionRecoveryApi/helpers/getCommandId.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { arrayify, keccak256 } from "ethers/lib/utils";
import { Environment } from "src/libs/types";
import { RPCInfoType } from "../constants/chain";
import { arrayify, concat, hexlify, hexZeroPad, keccak256 } from "ethers/lib/utils";

export const getCommandId = (
chainName: string,
txHash: string,
sourceEventIndex: number,
environment: Environment,
rpcInfo: RPCInfoType
) => {
const chainID: number = rpcInfo[environment].networkInfo[chainName.toLowerCase()]?.chainId;
if (!chainID) return "";
const seiArr = arrayify(sourceEventIndex).reverse();
const txHashWithEventIndex = new Uint8Array([
...arrayify(txHash),
...new Uint8Array(8).map((a, i) => seiArr[i] || a),
]);
const chainIdByteArray = arrayify(chainID);
const dataToHash = new Uint8Array(txHashWithEventIndex.length + chainIdByteArray.length);
dataToHash.set(txHashWithEventIndex, 0);
dataToHash.set(chainIdByteArray, txHashWithEventIndex.length);
return keccak256(dataToHash).slice(2); // remove 0x prefix
const stringToCharcodeArray = (text: string) => Array.from(text, (char) => char.charCodeAt(0));

// This function is specifically designed for use with EVM-based chains. Its behavior may not be as expected if used with Cosmos-based chains or other types of chains.
export const getCommandId = (messageId: string, sourceEventIndex: number, chainId: number) => {
if (messageId.includes("-")) {
return keccak256(concat([stringToCharcodeArray(messageId), hexlify(chainId)]));
} else {
return keccak256(
concat([
messageId,
arrayify(hexZeroPad(hexlify(sourceEventIndex), 8)).reverse(),
hexlify(chainId),
])
);
}
};
41 changes: 38 additions & 3 deletions src/libs/test/AxelarQueryAPI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ const MOCK_EXECUTE_DATA =
"0x1a98b2e0e68ba0eb84262d4bcf91955ec2680b37bcedd59a1f48e18d183dac9961bf9d1400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000d40000000000000000000000000000000000000000000000000000000000deac2c6000000000000000000000000000000000000000000000000000000000000000762696e616e636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307863653136463639333735353230616230313337376365374238386635424138433438463844363636000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bc000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004607cad6135d7a119185ebe062d3b369b1b536ef000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a8000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f4052150000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000000000000000000000000000000000000000000640000000000000000000000004fd39c9e151e50580779bd04b1f7ecc310079fd3000000000000000000000000000000000000000000000000000000000deac2c6000000000000000000000000000000000000000000000000000000000dc647500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f40521500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc80000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000640000000000000000000000004fd39c9e151e50580779bd04b1f7ecc310079fd3000000000000000000000000000000000000000000000000000000000de83dbf000000000000000000000000000000000000000000000000015d8c7908dbe7130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc80000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000242e1a7d4d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000004607cad6135d7a119185ebe062d3b369b1b536ef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000761786c5553444300000000000000000000000000000000000000000000000000";

describe("AxelarQueryAPI", () => {
const api = new AxelarQueryAPI({ environment: Environment.TESTNET });
const api = new AxelarQueryAPI({
environment: Environment.TESTNET,
axelarRpcUrl: "https://axelar-testnet-rpc.qubelabs.io:443",
});

beforeEach(() => {
vitest.clearAllMocks();
Expand Down Expand Up @@ -222,6 +225,32 @@ describe("AxelarQueryAPI", () => {
}
});

test("It should include L1 fee for L2 destination chain for cosmos source chains", async () => {
// Mainnet
const mainnetL2Chains = ["optimism"];
const mainnetApi = new AxelarQueryAPI({ environment: Environment.MAINNET });
const mainnetQueries = [];
for (const mainnetL2Chain of mainnetL2Chains) {
const query = await mainnetApi.estimateGasFee(
"osmosis",
mainnetL2Chain as EvmChain,
500000,
"auto",
undefined,
undefined,
undefined
);
mainnetQueries.push(query);
}

const mainnetResponses = await Promise.all(mainnetQueries);

mainnetResponses.forEach((response) => {
expect(response).toBeDefined();
expect(String(response).length).toBeLessThanOrEqual(6);
});
});

test("It should return estimated gas amount that makes sense for native token", async () => {
const gasAmount = await api.estimateGasFee(
CHAINS.TESTNET.AVALANCHE as EvmChain,
Expand Down Expand Up @@ -378,7 +407,10 @@ describe("AxelarQueryAPI", () => {
let api: AxelarQueryAPI;

beforeEach(async () => {
api = new AxelarQueryAPI({ environment: Environment.TESTNET });
api = new AxelarQueryAPI({
environment: Environment.TESTNET,
axelarRpcUrl: "https://axelar-testnet-lcd.qubelabs.io",
});
});

test("it should retrieve the gas receiver address remotely", async () => {
Expand All @@ -392,7 +424,10 @@ describe("AxelarQueryAPI", () => {
let api: AxelarQueryAPI;

beforeEach(async () => {
api = new AxelarQueryAPI({ environment: Environment.TESTNET });
api = new AxelarQueryAPI({
environment: Environment.TESTNET,
axelarRpcUrl: "https://axelar-testnet-rpc.qubelabs.io:443",
});
vitest.clearAllMocks();

/**
Expand Down
26 changes: 26 additions & 0 deletions src/libs/test/TransactionRecoveryAPI/AxelarGMPRecoveryAPI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,32 @@ describe("AxelarGMPRecoveryAPI", () => {
});
});

describe("getCidFromSrcTxHash", () => {
const mainnetApi = new AxelarGMPRecoveryAPI({ environment: Environment.MAINNET });

// https://axelarscan.io/gmp/0x3828bf893801f337e08d15b89efc9c3c2d9196fe7f83f3b7640425b24d122cb2:12
it("should return the correct commandId from evm -> evm for ContractCallWithToken event", () => {
expect(
mainnetApi.getCidFromSrcTxHash(
"celo",
"0x3828bf893801f337e08d15b89efc9c3c2d9196fe7f83f3b7640425b24d122cb2",
8
)
).toEqual("0xa45da101fcfed541b8251cb8a288b5b7dd84086377eb9cf3f8d4a99f11e062e0");
});

// https://axelarscan.io/gmp/0x92f676751feccab46a048a16aaf81b26620a3683933b56a722ce742de8ea7429:349
it("should return the correct commandId from evm -> evm for ContractCall event", () => {
expect(
mainnetApi.getCidFromSrcTxHash(
"blast",
"0x92f676751feccab46a048a16aaf81b26620a3683933b56a722ce742de8ea7429-5",
5
)
).toEqual("0xe6868c6e94240fa6a37cc71d265106a00ad8fa0652319f145e3235f703046574");
});
});

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

Expand Down
2 changes: 0 additions & 2 deletions src/libs/test/TransactionRecoveryAPI/EncodingTests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ describe("AxelarDepositRecoveryAPI", () => {
const txHash = "0x2c9083bebd1f82b86b7b0d3298885f90767b584742df9ec3a9c9f15872a1fff9";
const eventIndex = await api.getEventIndex("ethereum-2" as EvmChain, txHash);
const res = await api.getCidFromSrcTxHash(EvmChain.MOONBEAM, txHash, eventIndex as number);
console.log("eventIndex", eventIndex);
console.log("res", res);
expect(res).toEqual("58c46960e6483f61bf206d1bd1819917d2b009f58d7050e05b4be1d13247b4ed");
}, 60000);
});
Expand Down
Loading