Skip to content

Commit

Permalink
refactor: move contract utility methods to utils file
Browse files Browse the repository at this point in the history
  • Loading branch information
Jennievon committed Aug 26, 2024
1 parent 7303f5f commit 679c533
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 115 deletions.
121 changes: 118 additions & 3 deletions tools/bridge-frontend/src/lib/utils/contractUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { showToast } from "@/src/components/ui/use-toast";
import { ToastType } from "@/src/types";
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
import { ethers } from "ethers";

Expand All @@ -8,15 +10,115 @@ const handleError = (error: any, customMessage: string) => {
"Ensure your wallet is unlocked and an account is connected"
);
}
throw new Error(error);
return error;
};

const constructMerkleTree = (leafEntries: any[], msgHash: string) => {
showToast(ToastType.INFO, "Constructing Merkle tree");
const tree = StandardMerkleTree.of(leafEntries, ["string", "bytes32"]);
const proof = tree.getProof(["v", msgHash]);

return { tree, proof };
};

const estimateGas = async (
receiver: string,
value: string,
bridgeContract: ethers.Contract
) => {
try {
if (!value || isNaN(Number(value))) {
throw new Error("Invalid value provided for gas estimation.");
}

const parsedValue = ethers.utils.parseEther(value);
showToast(ToastType.INFO, "Estimating gas for the transaction");
return await bridgeContract?.estimateGas.sendNative(receiver, {
value: parsedValue,
});
} catch (error) {
return handleError(error, "Error estimating gas");
}
};

const estimateAndPopulateTx = async (
receiver: string,
value: string,
gasPrice: any,
bridgeContract: ethers.Contract
) => {
try {
showToast(ToastType.INFO, "Estimating gas for the transaction");
const estimatedGas = await estimateGas(receiver, value, bridgeContract);

showToast(ToastType.INFO, "Populating transaction");
const populatTxResp = await bridgeContract?.populateTransaction.sendNative(
receiver,
{
value: ethers.utils.parseEther(value),
gasPrice,
gasLimit: estimatedGas,
}
);
console.log("🚀 ~ useContractService ~ populatTxResp:", populatTxResp);
return populatTxResp;
} catch (error) {
return handleError(error, "Error populating transaction");
}
};

const extractAndProcessValueTransfer = async (
txReceipt: any,
messageBusContract: ethers.Contract,
provider: ethers.providers.JsonRpcProvider
) => {
try {
showToast(
ToastType.INFO,
"Extracting and processing value transfer event data"
);

const valueTransferEvent = txReceipt.logs.find(
(log: any) =>
log.topics[0] ===
ethers.utils.id("ValueTransfer(address,address,uint256,uint64)")
);
console.log("🚀 ~ useContract ~ valueTransferEvent:", valueTransferEvent);

if (!valueTransferEvent) {
throw new Error("ValueTransfer event not found in the logs");
}

showToast(ToastType.INFO, "ValueTransfer event found; parsing event data");

const valueTransferEventData =
messageBusContract?.interface.parseLog(valueTransferEvent);

if (!valueTransferEventData) {
throw new Error("ValueTransfer event data not found");
}

showToast(
ToastType.INFO,
"ValueTransfer event data found; fetching block data"
);

const block = await provider.send("eth_getBlockByHash", [
ethers.utils.hexValue(txReceipt.blockHash),
true,
]);

if (!block) {
throw new Error("Block not found");
}

showToast(ToastType.INFO, "Block data found; processing value transfer");

return { valueTransferEventData, block };
} catch (error) {
return handleError(error, "Error processing value transfer");
}
};
const estimateGasWithTimeout = async (
managementContract: ethers.Contract,
msg: any,
Expand All @@ -27,6 +129,7 @@ const estimateGasWithTimeout = async (
) => {
let gasLimit: ethers.BigNumber | null = null;
const startTime = Date.now();
showToast(ToastType.INFO, "Estimating gas for the transaction");
while (!gasLimit) {
try {
gasLimit = await managementContract.estimateGas.ExtractNativeValue(
Expand All @@ -35,16 +138,28 @@ const estimateGasWithTimeout = async (
root,
{}
);
console.log("🚀 ~ gasLimit:", gasLimit);
} catch (error: any) {
console.log(`Estimate gas threw error: ${error.reason}`);
console.error(`Estimate gas threw error: ${error.reason}`);
}
if (Date.now() - startTime >= timeout) {
console.log("Timed out waiting for gas estimate, using default");
showToast(
ToastType.INFO,
"Timed out waiting for gas estimate; using default"
);
return ethers.BigNumber.from(2000000);
}
await new Promise((resolve) => setTimeout(resolve, interval));
}
return gasLimit;
};

export { handleError, constructMerkleTree, estimateGasWithTimeout };
export {
handleError,
constructMerkleTree,
estimateGasWithTimeout,
extractAndProcessValueTransfer,
estimateAndPopulateTx,
estimateGas,
};
130 changes: 18 additions & 112 deletions tools/bridge-frontend/src/services/useContractService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useEffect, useMemo } from "react";
import { ethers } from "ethers";
import useWalletStore from "../stores/wallet-store";
import useContractStore from "../stores/contract-store";
import { toast } from "../components/ui/use-toast";
import { ToastType } from "../types";
import { useGeneralService } from "./useGeneralService";
import { privateKey } from "../lib/constants";
Expand All @@ -11,10 +10,13 @@ import ManagementContractAbi from "../../artifacts/ManagementContract.sol/Manage
import IMessageBusAbi from "../../artifacts/IMessageBus.sol/IMessageBus.json";
import {
constructMerkleTree,
estimateAndPopulateTx,
estimateGasWithTimeout,
extractAndProcessValueTransfer,
handleError,
} from "../lib/utils/contractUtils";
import { isAddress } from "ethers/lib/utils";
import { showToast } from "../components/ui/use-toast";

export const useContractService = () => {
const { signer, isL1ToL2, provider, address } = useWalletStore();
Expand Down Expand Up @@ -88,7 +90,8 @@ export const useContractService = () => {
!signer ||
!wallet ||
!managementContract ||
!messageBusContract
!messageBusContract ||
!provider
) {
return handleError(null, "Contract or signer not found");
}
Expand All @@ -105,13 +108,11 @@ export const useContractService = () => {
gasPrice,
bridgeContract
);
console.log("🚀 ~ sendNative ~ tx:", tx);
const txResponse = await signer.sendTransaction(tx);
console.log("Transaction response:", txResponse);

toast({
description: "Transaction sent; waiting for confirmation",
variant: ToastType.INFO,
});
showToast(ToastType.INFO, "Transaction sent; waiting for confirmation");

const txReceipt = await txResponse.wait();
console.log("Transaction receipt:", txReceipt);
Expand All @@ -121,7 +122,11 @@ export const useContractService = () => {
}

const { valueTransferEventData, block } =
await extractAndProcessValueTransfer(txReceipt, messageBusContract);
await extractAndProcessValueTransfer(
txReceipt,
messageBusContract,
provider
);

const { tree, proof } = constructMerkleTree(
JSON.parse(atob(block.result.crossChainTree)),
Expand Down Expand Up @@ -160,18 +165,15 @@ export const useContractService = () => {
const responseL1 = await wallet.sendTransaction(txL1);
console.log("L1 txn response:", responseL1);

toast({
description: "Value transfer sent to L2; waiting for confirmation",
variant: ToastType.INFO,
});
showToast(
ToastType.INFO,
"Transaction sent to L1; waiting for confirmation"
);

const receiptL1 = await responseL1.wait();
console.log("L1 txn receipt:", receiptL1);

toast({
description: "Value transfer completed",
variant: ToastType.SUCCESS,
});
showToast(ToastType.SUCCESS, "Transaction processed successfully");

return receiptL1;
} catch (error) {
Expand Down Expand Up @@ -205,7 +207,7 @@ export const useContractService = () => {
const balance = await signer.provider?.getBalance(walletAddress);
return ethers.utils.formatEther(balance);
} catch (error) {
return handleError(error, "Error checking Ether balance");
handleError(error, "Error checking Ether balance");
}
};

Expand Down Expand Up @@ -260,107 +262,11 @@ export const useContractService = () => {
}
};

const estimateGas = async (
receiver: string,
value: string,
bridgeContract: ethers.Contract
) => {
try {
if (!value || isNaN(Number(value))) {
throw new Error("Invalid value provided for gas estimation.");
}

const parsedValue = ethers.utils.parseEther(value);
return await bridgeContract?.estimateGas.sendNative(receiver, {
value: parsedValue,
});
} catch (error) {
return handleError(error, "Error estimating gas");
}
};

const estimateAndPopulateTx = async (
receiver: string,
value: string,
gasPrice: any,
bridgeContract: ethers.Contract
) => {
try {
const estimatedGas = await estimateGas(receiver, value, bridgeContract);
return await bridgeContract?.populateTransaction.sendNative(receiver, {
value: ethers.utils.parseEther(value),
gasPrice,
gasLimit: estimatedGas,
});
} catch (error) {
return handleError(error, "Error populating transaction");
}
};

const extractAndProcessValueTransfer = async (
txReceipt: any,
messageBusContract: ethers.Contract
) => {
try {
toast({
description: "Extracting logs from the transaction",
variant: ToastType.INFO,
});

const valueTransferEvent = txReceipt.logs.find(
(log: any) =>
log.topics[0] ===
ethers.utils.id("ValueTransfer(address,address,uint256,uint64)")
);
console.log("🚀 ~ useContract ~ valueTransferEvent:", valueTransferEvent);

if (!valueTransferEvent) {
throw new Error("ValueTransfer event not found in the logs");
}

toast({
description: "ValueTransfer event found in the logs; processing data",
variant: ToastType.INFO,
});

const valueTransferEventData =
messageBusContract?.interface.parseLog(valueTransferEvent);

if (!valueTransferEventData) {
throw new Error("ValueTransfer event data not found");
}

toast({
description: "ValueTransfer event data found; fetching block",
variant: ToastType.INFO,
});

const block = await provider.send("eth_getBlockByHash", [
ethers.utils.hexValue(txReceipt.blockHash),
true,
]);

if (!block) {
throw new Error("Block not found");
}

toast({
description: "Block found; processing value transfer",
variant: ToastType.INFO,
});

return { valueTransferEventData, block };
} catch (error) {
return handleError(error, "Error processing value transfer");
}
};

return {
sendNative,
getNativeBalance,
getTokenBalance,
sendERC20,
getBridgeTransactions,
estimateGas,
};
};

0 comments on commit 679c533

Please sign in to comment.