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: Gateway methods and Solana deposit #179

Merged
merged 18 commits into from
Sep 11, 2024
Prev Previous commit
Next Next commit
refactor zetachainWithdrawAndCall
  • Loading branch information
fadeev committed Sep 6, 2024
commit b10bd018b7d9869c7bfd5456d502bc9cffc890ca
1 change: 1 addition & 0 deletions packages/client/src/abi/GatewayEVM.sol/GatewayEVM.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/client/src/abi/GatewayZEVM.sol/GatewayZEVM.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/client/src/abi/ZRC20.sol/ZRC20.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/client/src/abi/ZRC20.sol/ZRC20Errors.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/client/src/client.ts
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import {
solanaDeposit,
trackCCTX,
withdraw,
zetachainWithdrawAndCall,
} from ".";

export interface ZetaChainClientParamsBase {
@@ -128,4 +129,5 @@ export class ZetaChainClient {
getZRC20FromERC20 = getZRC20FromERC20;
getZRC20GasToken = getZRC20GasToken;
solanaDeposit = solanaDeposit;
zetachainWithdrawAndCall = zetachainWithdrawAndCall;
}
1 change: 1 addition & 0 deletions packages/client/src/index.ts
Original file line number Diff line number Diff line change
@@ -14,3 +14,4 @@ export * from "./sendZeta";
export * from "./solanaDeposit";
export * from "./trackCCTX";
export * from "./withdraw";
export * from "./zetachainWithdrawAndCall";
101 changes: 101 additions & 0 deletions packages/client/src/zetachainWithdrawAndCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { ethers } from "ethers";

import GatewayABI from "./abi/GatewayZEVM.sol/GatewayZEVM.json";
import ZRC20ABI from "./abi/ZRC20.sol/ZRC20.json";
import { ZetaChainClient } from "./client";

export const zetachainWithdrawAndCall = async function (
this: ZetaChainClient,
args: {
amount: string;
zrc20: string;
receiver: string;
function: string;
types: string;
values: any[];
gasLimit: number;
gasPrice: ethers.BigNumber;
gatewayZetaChain: string;
callOnRevert: boolean;
onRevertGasLimit: number;
revertAddress: string;
revertMessage: string;
}
) {
const signer = this.signer;
const { utils } = ethers;

const gateway = new ethers.Contract(
args.gatewayZetaChain,
GatewayABI.abi,
signer
);
Comment on lines +28 to +32
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error handling for contract instantiation.

Instantiating a new contract with ethers.Contract should include error handling to manage cases where the contract address or ABI might be incorrect, or the network connection fails. Consider wrapping this in a try-catch block.

+ try {
  const gateway = new ethers.Contract(
    args.gatewayZetaChain,
    GatewayABI.abi,
    signer
  );
+ } catch (error) {
+   console.error('Failed to instantiate Gateway contract:', error);
+   throw error;
+ }

Committable suggestion was skipped due to low confidence.


const revertOptions = {
abortAddress: "0x0000000000000000000000000000000000000000",
callOnRevert: args.callOnRevert,
onRevertGasLimit: args.onRevertGasLimit,
revertAddress: args.revertAddress,
// not used
revertMessage: utils.hexlify(utils.toUtf8Bytes(args.revertMessage)),
};

const txOptions = {
gasLimit: args.gasLimit,
gasPrice: args.gasPrice,
};

const functionSignature = utils.id(args.function).slice(0, 10);
const encodedParameters = utils.defaultAbiCoder.encode(
JSON.parse(args.types),
args.values
);

const message = utils.hexlify(
utils.concat([functionSignature, encodedParameters])
);
Comment on lines +47 to +55
Copy link
Contributor

Choose a reason for hiding this comment

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

Optimize encoding of function calls.

The encoding of function calls using utils.id and slicing the result can be error-prone and hard to understand. Consider using ethers.js utilities more effectively to encode the function signature directly, or provide detailed comments explaining this operation.

const zrc20 = new ethers.Contract(args.zrc20, ZRC20ABI.abi, signer);
const decimals = await zrc20.decimals();
const value = utils.parseUnits(args.amount, decimals);
const [gasZRC20, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(
args.gasLimit
);
if (args.zrc20 === gasZRC20) {
const approveGasAndWithdraw = await zrc20.approve(
args.gatewayZetaChain,
value.add(gasFee),
txOptions
);
await approveGasAndWithdraw.wait();
} else {
const gasZRC20Contract = new ethers.Contract(
gasZRC20,
ZRC20ABI.abi,
signer
);
const approveGas = await gasZRC20Contract.approve(
args.gatewayZetaChain,
gasFee,
txOptions
);
await approveGas.wait();
const approveWithdraw = await zrc20.approve(
args.gatewayZetaChain,
value,
txOptions
);
await approveWithdraw.wait();
}
const method =
"withdrawAndCall(bytes,uint256,address,bytes,uint256,(address,bool,address,bytes,uint256))";
const tx = await gateway[method](
utils.hexlify(args.receiver),
value,
args.zrc20,
message,
args.gasLimit,
revertOptions,
txOptions
);
return tx;
Comment on lines +57 to +99
Copy link
Contributor

Choose a reason for hiding this comment

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

Review and optimize token handling and transaction execution logic.

The logic for handling token approvals and executing the transaction is complex and involves multiple conditional branches. This could be simplified or at least better documented to improve maintainability. Additionally, ensure that all asynchronous operations are properly awaited and errors are handled appropriately.

+ try {
  const decimals = await zrc20.decimals();
  const value = utils.parseUnits(args.amount, decimals);
  const [gasZRC20, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(args.gasLimit);
  if (args.zrc20 === gasZRC20) {
    const approveGasAndWithdraw = await zrc20.approve(
      args.gatewayZetaChain,
      value.add(gasFee),
      txOptions
    );
    await approveGasAndWithdraw.wait();
  } else {
    // Handle other cases similarly...
  }
  const tx = await gateway['withdrawAndCall'](utils.hexlify(args.receiver), value, args.zrc20, message, args.gasLimit, revertOptions, txOptions);
  return tx;
+ } catch (error) {
+   console.error('Transaction execution failed:', error);
+   throw error;
+ }

Committable suggestion was skipped due to low confidence.

};
97 changes: 19 additions & 78 deletions packages/tasks/src/zetachainWithdrawAndCall.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,31 @@
import { task, types } from "hardhat/config";
import type { HardhatRuntimeEnvironment } from "hardhat/types";

import GatewayABI from "./abi/GatewayZEVM.sol/GatewayZEVM.json";
import ZRC20ABI from "./abi/ZRC20.sol/ZRC20.json";
import { ZetaChainClient } from "../../client/src/";

export const zetachainWithdrawAndCall = async (
args: any,
hre: HardhatRuntimeEnvironment
) => {
const [signer] = await hre.ethers.getSigners();
const { utils } = hre.ethers;

const gateway = new hre.ethers.Contract(
args.gatewayZetaChain,
GatewayABI.abi,
signer
);

const revertOptions = {
abortAddress: "0x0000000000000000000000000000000000000000",
callOnRevert: args.callOnRevert,
onRevertGasLimit: args.onRevertGasLimit,
revertAddress: args.revertAddress,
// not used
revertMessage: utils.hexlify(utils.toUtf8Bytes(args.revertMessage)),
};

const txOptions = {
gasLimit: args.gasLimit,
gasPrice: args.gasPrice,
};

const functionSignature = utils.id(args.function).slice(0, 10);
const encodedParameters = utils.defaultAbiCoder.encode(
JSON.parse(args.types),
args.values
);

const message = utils.hexlify(
utils.concat([functionSignature, encodedParameters])
);

const { ethers } = hre as any;
const [signer] = await ethers.getSigners();
const client = new ZetaChainClient({ network: "testnet", signer });
try {
const zrc20 = new hre.ethers.Contract(args.zrc20, ZRC20ABI.abi, signer);
const decimals = await zrc20.decimals();
const value = utils.parseUnits(args.amount, decimals);
const [gasZRC20, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(
args.gasLimit
);
if (args.zrc20 === gasZRC20) {
const approveGasAndWithdraw = await zrc20.approve(
args.gatewayZetaChain,
value.add(gasFee),
txOptions
);
await approveGasAndWithdraw.wait();
} else {
const gasZRC20Contract = new hre.ethers.Contract(
gasZRC20,
ZRC20ABI.abi,
signer
);
const approveGas = await gasZRC20Contract.approve(
args.gatewayZetaChain,
gasFee,
txOptions
);
await approveGas.wait();
const approveWithdraw = await zrc20.approve(
args.gatewayZetaChain,
value,
txOptions
);
await approveWithdraw.wait();
}
const method =
"withdrawAndCall(bytes,uint256,address,bytes,uint256,(address,bool,address,bytes,uint256))";
const tx = await gateway[method](
utils.hexlify(args.receiver),
value,
args.zrc20,
message,
args.gasLimit,
revertOptions,
txOptions
);
const tx = await client.zetachainWithdrawAndCall({
amount: args.amount,
zrc20: args.zrc20,
receiver: args.receiver,
function: args.function,
types: args.types,
values: args.values,
gasLimit: args.gasLimit,
gasPrice: args.gasPrice,
gatewayZetaChain: args.gatewayZetaChain,
callOnRevert: args.callOnRevert,
onRevertGasLimit: args.onRevertGasLimit,
revertAddress: args.revertAddress,
revertMessage: args.revertMessage,
});

const receipt = await tx.wait();
console.log("Transaction hash:", receipt.transactionHash);