Skip to content

Commit

Permalink
feat: add bridge call task (PundiAI#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
todd-woko authored Feb 21, 2024
1 parent 5af4655 commit 5d665f1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 15 deletions.
63 changes: 62 additions & 1 deletion solidity/tasks/bridge_tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GetOracleSet,
SUB_CHECK_PRIVATE_KEY,
SUB_CONFIRM_TRANSACTION,
SUB_CREATE_ASSET_DATA,
SUB_CREATE_TRANSACTION,
TransactionToJson,
vote_power
Expand Down Expand Up @@ -196,4 +197,64 @@ const addBridgeToken = task("add-bridge-token", "add bridge token into bridge co
}
});

AddTxParam([sendToFx, initBridge, addBridgeToken])
const bridgeERC20Call = task("bridge-erc20-call", "bridge erc20 and call contract function")
.addParam("bridgeContract", "bridge contract address", undefined, string, false)
.addParam("dstChainId", "destination chain id", undefined, string, false)
.addParam("callGasLimit", "call gas limit", "0", string, true)
.addParam("receiver", "call receiver", undefined, string, false)
.addParam("to", "call to", undefined, string, false)
.addParam("message", "call message", undefined, string, false)
.addParam("callValue", "call value", "0", string, true)
.addParam("bridgeTokens", "bridge token address list", undefined, string, false)
.addParam("bridgeAmounts", "bridge token amount list", undefined, string, false)
.setAction(async (taskArgs, hre) => {
const {
bridgeContract,
dstChainId,
callGasLimit,
receiver,
to,
message,
callValue,
bridgeTokens,
bridgeAmounts
} = taskArgs;
const {wallet} = await hre.run(SUB_CHECK_PRIVATE_KEY, taskArgs);
const from = await wallet.getAddress();

const asset = await hre.run(SUB_CREATE_ASSET_DATA, {
bridgeTokens: bridgeTokens,
bridgeAmounts: bridgeAmounts,
assetType: "ERC20"
});

const bridge_logic_factory = await hre.ethers.getContractFactory("FxBridgeLogic")
const data = bridge_logic_factory.interface.encodeFunctionData('bridgeCall', [
dstChainId, callGasLimit, receiver, to, message, callValue, asset
])

const tx = await hre.run(SUB_CREATE_TRANSACTION, {
from: from, to: bridgeContract, data: data, value: taskArgs.value,
gasPrice: taskArgs.gasPrice,
maxFeePerGas: taskArgs.maxFeePerGas,
maxPriorityFeePerGas: taskArgs.maxPriorityFeePerGas,
nonce: taskArgs.nonce,
gasLimit: taskArgs.gasLimit,
});

const {answer} = await hre.run(SUB_CONFIRM_TRANSACTION, {
message: `\n${TransactionToJson(tx)}\n`,
disableConfirm: taskArgs.disableConfirm,
});
if (!answer) return;

try {
const bridgeCallTx = await wallet.sendTransaction(tx);
await bridgeCallTx.wait();
console.log(`bridge call success, ${bridgeCallTx.hash}`)
} catch (e) {
console.log(`bridge call failed, ${e}`)
}
});

AddTxParam([sendToFx, initBridge, addBridgeToken, bridgeERC20Call])
28 changes: 27 additions & 1 deletion solidity/tasks/subtasks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {subtask} from "hardhat/config";
import {LedgerSigner} from "@ethers-ext/signer-ledger";
import {Block, HDNodeWallet, TransactionLike} from "ethers";
import {AbiCoder, Block, HDNodeWallet, solidityPacked, TransactionLike} from "ethers";
import axios from "axios";
import {ConfigurableTaskDefinition} from "hardhat/types";
import {boolean, string} from "hardhat/internal/core/params/argumentTypes";
Expand All @@ -17,6 +17,7 @@ export const SUB_CONFIRM_TRANSACTION: string = "sub:confirm-transaction";
export const SUB_MNEMONIC_WALLET: string = "sub:mnemonic-wallet";
export const SUB_SEND_ETH: string = "sub:send-eth";
export const SUB_GET_CONTRACT_ADDR: string = "sub:get-contract-addr";
export const SUB_CREATE_ASSET_DATA: string = "sub:create-asset-data";

// public flag
export const DISABLE_CONFIRM_FLAG: string = "disableConfirm";
Expand Down Expand Up @@ -207,6 +208,21 @@ subtask(SUB_CONFIRM_TRANSACTION, "confirm transaction").setAction(
return {answer: _answer};
});

subtask(SUB_CREATE_ASSET_DATA, "create asset data").setAction(
async (taskArgs, hre) => {
const {bridgeTokens, bridgeAmounts, assetType} = taskArgs;
const bridgeToken = bridgeTokens.split(",");
const bridgeAmount = bridgeAmounts.split(",");
if (bridgeToken.length !== bridgeAmount.length) {
throw new Error("Please provide the same number of bridge tokens and bridge amounts");
}
let amounts: BigInt[] = [];
bridgeAmount.forEach((value: string) => {
amounts.push(hre.ethers.parseUnits(value, "wei"));
});
return await encodeERC20(assetType, bridgeToken, amounts);
});

// function Transaction to json string
export function TransactionToJson(transaction: TransactionLike): string {
return JSON.stringify({
Expand Down Expand Up @@ -246,6 +262,16 @@ export async function GetGravityId(restRpc: string, chainName: string): Promise<
return response.data.params.gravity_id;
}

export async function encodeERC20(assetType: string, tokens: string[], amounts: BigInt[]): Promise<string> {
const abiCode = new AbiCoder;
let tokenData = "";
for (let i = 0; i < tokens.length; i++) {
tokenData += solidityPacked(["address"], [tokens[i]]).substring(2);
}
const tokenAmountData = abiCode.encode(["bytes", "uint256[]"], ["0x" + tokenData, amounts]);
return abiCode.encode(["string", "bytes"], [assetType, tokenAmountData]);
}

export function AddTxParam(tasks: ConfigurableTaskDefinition[]) {
tasks.forEach((task) => {
task.addParam(NONCE_FLAG, "nonce", undefined, string, true)
Expand Down
16 changes: 3 additions & 13 deletions solidity/test/bridge_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@ import {ethers} from "hardhat";
import {HardhatEthersSigner} from "@nomicfoundation/hardhat-ethers/signers";
import {expect} from "chai";
import {ERC20TokenTest, FxBridgeLogic} from "../typechain-types"
import {AbiCoder, encodeBytes32String, solidityPacked} from "ethers"


async function encodeERC20(assetType: string, tokens: string[], amounts: BigInt[]): Promise<string> {
const abiCode = new AbiCoder;
let tokenData = "";
for (let i = 0; i < tokens.length; i++) {
tokenData += solidityPacked(["address"], [tokens[i]]).substring(2);
}
const tokenAmountData = abiCode.encode(["bytes", "uint256[]"], ["0x" + tokenData, amounts]);
return abiCode.encode(["string", "bytes"], [assetType, tokenAmountData]);
}
import {encodeBytes32String} from "ethers"
import {encodeERC20} from "../tasks/subtasks";

// total power 10000
export function examplePowers(): number[] {
Expand Down Expand Up @@ -56,7 +46,7 @@ describe("bridge call tests", function () {
const fxBridgeLogicProxy = await transparentUpgradeableProxyFactory.deploy(fxBridgeLogicAddress, admin.address, "0x")
const fxBridgeLogicProxyAddress = await fxBridgeLogicProxy.getAddress()

fxBridge = <FxBridgeLogic>await fxBridgeLogicFactory.attach(fxBridgeLogicProxyAddress)
fxBridge = <FxBridgeLogic>fxBridgeLogicFactory.attach(fxBridgeLogicProxyAddress)

const powers: number[] = examplePowers();
const validators = signers.slice(0, powers.length)
Expand Down

0 comments on commit 5d665f1

Please sign in to comment.