diff --git a/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts b/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts index d281f41..75ed528 100644 --- a/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts +++ b/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts @@ -11,10 +11,11 @@ import { getConfigEnvironmentVariable, getNetworkChainId, sumedFees, + transferStatusInterval, mapNetworkArgs, } from "./utils"; import { AdapterABI } from "./adapterABI"; -import { DeployOptions, NetworkArguments } from "./types"; +import { DeployOptions, DeploymentInfo, NetworkArguments } from "./types"; export class MultichainHardhatRuntimeEnvironmentField { private isInitiated: boolean = false; @@ -62,7 +63,10 @@ export class MultichainHardhatRuntimeEnvironmentField { contractName: string, networkArgs: NetworkArguments, options?: DeployOptions - ): Promise { + ): Promise<{ + deploymentInfo: DeploymentInfo[]; + receipt: Transaction; + } | void> { const artifact = this.hre.artifacts.readArtifactSync(contractName); return this.deployMultichainBytecode( @@ -78,7 +82,10 @@ export class MultichainHardhatRuntimeEnvironmentField { contractAbi: Abi, networkArgs: NetworkArguments, options?: DeployOptions - ): Promise { + ): Promise<{ + deploymentInfo: DeploymentInfo[]; + receipt: Transaction; + } | void> { if (!this.isInitiated) await this.initConfig(); if (!this.web3) return; @@ -118,8 +125,8 @@ export class MultichainHardhatRuntimeEnvironmentField { value: sumedFees(fees), }; } - - return adapterContract.methods + console.log("Sending transaction..."); + const receipt = await adapterContract.methods .deploy( contractBytecode, this.gasLimit, @@ -131,5 +138,62 @@ export class MultichainHardhatRuntimeEnvironmentField { fees ) .send(payableTxOptions); + const networkNames = Object.keys(networkArgs); + const { transactionHash } = receipt; + console.log( + `Multichain deployment initiated, transaction hash: ${transactionHash} + + ` + + "\n" + + "Destinaton networks:" + + networkNames.join("\r\n") + ); + + const [deployer] = await this.web3.eth.getAccounts(); + + const destinationDomainChainIDs = deployDomainIDs.map((deployDomainID) => { + const deployDomain: Domain = this.domains.find( + (domain) => BigInt(domain.id) === deployDomainID + )!; + return deployDomain.chainId; + }); + + const deploymentInfo: DeploymentInfo[] = await Promise.all( + destinationDomainChainIDs.map(async (domainChainID, index) => { + const network = networkNames[index]; + + const contractAddress = await adapterContract.methods + .computeContractAddressForChain( + deployer, + salt, + isUniquePerChain, + domainChainID + ) + .call(); + console.log( + `Contract deploying on ${network.toUpperCase()}: ${contractAddress}` + ); + + const explorerUrl = await transferStatusInterval( + this.hre.config.multichain.environment, + transactionHash, + domainChainID + ); + + console.log(`Bridge transfer executed. More details: ${explorerUrl}`); + + return { + network, + contractAddress, + explorerUrl, + transactionHash, + }; + }) + ); + + return { + receipt, + deploymentInfo, + }; } } diff --git a/packages/plugin/src/types.ts b/packages/plugin/src/types.ts index 339871f..7dd6037 100644 --- a/packages/plugin/src/types.ts +++ b/packages/plugin/src/types.ts @@ -30,3 +30,10 @@ export interface DeployOptions { isUniquePerChain?: boolean; customNonPayableTxOptions?: NonPayableCallOptions; } + +export interface DeploymentInfo { + network: string; + contractAddress: string; + explorerUrl: string; + transactionHash: string; +} diff --git a/packages/plugin/src/utils.ts b/packages/plugin/src/utils.ts index f61e01c..590e531 100644 --- a/packages/plugin/src/utils.ts +++ b/packages/plugin/src/utils.ts @@ -1,6 +1,10 @@ import assert from "assert"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Domain, Environment } from "@buildwithsygma/sygma-sdk-core"; +import { + Domain, + Environment, + getTransferStatusData, +} from "@buildwithsygma/sygma-sdk-core"; import { AbiFallbackFragment, Bytes, @@ -146,3 +150,36 @@ export function mapNetworkArgs( initDatas, }; } + +export async function transferStatusInterval( + environment: Environment, + txHash: string, + domainID: number +): Promise { + let explorerUrl: string = ""; + + await new Promise((resolve) => { + let controller: AbortController; + setInterval(() => { + controller = new AbortController(); + void getTransferStatusData(environment, txHash, domainID.toString()).then( + (transferStatus) => { + explorerUrl = transferStatus.explorerUrl; + + if (transferStatus.status === "executed") { + controller.abort(); + resolve(explorerUrl); + } + if (transferStatus.status === "failed") { + throw new HardhatPluginError( + "@chainsafe/hardhat-plugin-multichain-deploy", + `Bridge transfer failed` + ); + } + } + ); + }, 1000); + }); + + return explorerUrl; +}