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

chore: Refactor deployment flow #46

Merged
merged 4 commits into from
Feb 7, 2024
Merged
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
6 changes: 6 additions & 0 deletions docs/plugin/DeployOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface DeployOptions {
salt?: MatchPrimitiveType<"bytes32", unknown>;
isUniquePerChain?: boolean;
customNonPayableTxOptions?: NonPayableCallOptions;
adapterAddress?: Address;
}
```

Expand All @@ -25,6 +26,10 @@ interface DeployOptions {
- **Details**: Customizes transaction settings for contract calls. This option allows setting sender details and other transaction parameters.
- **Reference**: For detailed information about `NonPayableCallOptions`, please refer to the [web3.js documentation](https://docs.web3js.org/api/web3-types/interface/NonPayableCallOptions/).

### adapterAddress
- **Description**: Specifies address of a custom adapter for deployments. This is useful for local testing or when needing to interact with a specific deployment strategy, such as a mocked adapter.
- **Purpose**: Allows the user to override the default deployment adapter with their own, providing greater flexibility and control over the deployment process.

## Example

In this example, `DeployOptions` is configured to deploy a contract with a specified salt for address generation, ensuring unique addresses on each chain, and customizing the sender address for the deployment transaction.
Expand All @@ -36,6 +41,7 @@ const options: DeployOptions = {
customNonPayableTxOptions: {
from: "0x1605B51d318bFfBFd246D565Ee55522b66ddc34a",
},
adapterAddress: "0x1234567890ABCDEF1234567890ABCDEF12345678"
};
```

Expand Down
95 changes: 48 additions & 47 deletions packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Config, Domain } from "@buildwithsygma/sygma-sdk-core";
import Web3, {
ContractAbi,
Transaction,
utils,
PayableCallOptions,
} from "web3";
import Web3, { ContractAbi, utils, PayableCallOptions } from "web3";
import { vars } from "hardhat/config";
import {
getConfigEnvironmentVariable,
Expand All @@ -15,12 +10,16 @@ import {
mapNetworkArgs,
} from "./utils";
import { AdapterABI } from "./adapterABI";
import { DeployOptions, DeploymentInfo, NetworkArguments } from "./types";
import {
DeployOptions,
NetworkArguments,
DeployMultichainResponse,
} from "./types";

export class MultichainHardhatRuntimeEnvironmentField {
private isInitiated: boolean = false;
private domains: Domain[] = [];
private readonly web3: Web3 | null;
private readonly web3: Web3;

public constructor(private readonly hre: HardhatRuntimeEnvironment) {
const provider = this.hre.network.provider;
Expand Down Expand Up @@ -56,10 +55,9 @@ export class MultichainHardhatRuntimeEnvironmentField {
* @param contractName - The name of the contract to be deployed.
* @param networkArgs - An object mapping network identifiers to their deployment arguments. Each network can have unique settings for the deployment. See {@link https://github.com/ChainSafe/hardhat-plugin-multichain-deploy/docs/plugin/NetworkArguments NetworkArguments}.
* @param options - Optional settings for the deployment process. These can include various configurations specific to the deployment. See {@link https://github.com/ChainSafe/hardhat-plugin-multichain-deploy/docs/plugin/DeployOptions DeployOptions}.
* @returns A Promise resolving to a Transaction object or void.
* @returns A Promise resolving to a Transaction object.
*
* @example
* ```
* const networkArgs = {
* sepolia: {
* args: [ 18, "token" ],
Expand All @@ -71,16 +69,12 @@ export class MultichainHardhatRuntimeEnvironmentField {
* };
*
* this.hre.multichain.deployMultichain("HelloContract", networkArgs, options);
* ```
*/
public async deployMultichain<Abi extends ContractAbi = any>(
contractName: string,
networkArgs: NetworkArguments<Abi>,
options?: DeployOptions
): Promise<{
deploymentInfo: DeploymentInfo[];
receipt: Transaction;
} | void> {
): Promise<DeployMultichainResponse> {
const artifact = this.hre.artifacts.readArtifactSync(contractName);

return this.deployMultichainBytecode(
Expand All @@ -98,10 +92,9 @@ export class MultichainHardhatRuntimeEnvironmentField {
* @param contractAbi - The ABI of the contract. It defines the methods and structures used to interact with the binary contract.
* @param networkArgs - An object mapping network identifiers to their deployment arguments. Each network can have unique settings for the deployment. See {@link https://github.com/ChainSafe/hardhat-plugin-multichain-deploy/docs/plugin/NetworkArguments NetworkArguments}.
* @param options - Optional settings for the deployment process. These can include various configurations specific to the deployment. See {@link https://github.com/ChainSafe/hardhat-plugin-multichain-deploy/docs/plugin/DeployOptions DeployOptions}.
* @returns A Promise resolving to a Transaction object or void.
* @returns A Promise resolving to a Transaction object.
*
* @example
* ```
* const contractBytecode = "0x60a060405234801561001057600080fd5b5060405161052b38038061052b83...";
* const contractAbi = [{ ... }, { ... }];
*
Expand All @@ -115,37 +108,32 @@ export class MultichainHardhatRuntimeEnvironmentField {
* salt: "0xcafe00000000000000000000000000000000000000000000000000000000cafe",
* };
*
* this.hre.multichain.deployMultichain(contractBytecode, contractAbi, networkArgs, options);
* ```
* this.hre.multichain.deployMultichainBytecode(contractBytecode, contractAbi, networkArgs, options);
*/
public async deployMultichainBytecode<Abi extends ContractAbi = any>(
contractBytecode: string,
contractAbi: Abi,
networkArgs: NetworkArguments<Abi>,
options?: DeployOptions
): Promise<{
deploymentInfo: DeploymentInfo[];
receipt: Transaction;
} | void> {
): Promise<DeployMultichainResponse> {
if (!this.isInitiated) await this.initConfig();
if (!this.web3) return;

//optional params
const salt = options?.salt ?? utils.randomBytes(32);
const isUniquePerChain = options?.isUniquePerChain ?? false;

//adapter contract
const adapterContract = new this.web3.eth.Contract<typeof AdapterABI>(
AdapterABI,
this.ADAPTER_ADDRESS
);
const adapterAddress = options?.adapterAddress ?? this.ADAPTER_ADDRESS;

const { constructorArgs, initDatas, deployDomainIDs } = mapNetworkArgs(
contractAbi,
networkArgs,
this.domains
);

const adapterContract = new this.web3.eth.Contract<typeof AdapterABI>(
AdapterABI,
adapterAddress
);

const fees = await adapterContract.methods
.calculateDeployFee(
contractBytecode,
Expand Down Expand Up @@ -182,9 +170,7 @@ export class MultichainHardhatRuntimeEnvironmentField {
const networkNames = Object.keys(networkArgs);
const { transactionHash } = receipt;
console.log(
`Multichain deployment initiated, transaction hash: ${transactionHash}

` +
`Multichain deployment initiated, transaction hash: ${transactionHash}` +
"\n" +
"Destinaton networks:" +
networkNames.join("\r\n")
Expand All @@ -199,7 +185,7 @@ export class MultichainHardhatRuntimeEnvironmentField {
return deployDomain.chainId;
});

const deploymentInfo: DeploymentInfo[] = await Promise.all(
await Promise.all(
destinationDomainChainIDs.map(async (domainChainID, index) => {
const network = networkNames[index];

Expand All @@ -214,27 +200,42 @@ export class MultichainHardhatRuntimeEnvironmentField {
console.log(
`Contract deploying on ${network.toUpperCase()}: ${contractAddress}`
);
})
);

return {
transactionHash,
domainIDs: deployDomainIDs,
};
}

/**
* Fetches and logs the deployment information for a smart contract deployed across multiple blockchain networks.
* This function retrieves the status of a contract's deployment on each specified network domain using the transaction hash
* obtained from the `deployMultichain` or `deployMultichainBytecode` function.
*
* @param transactionHash The hash of the transaction returned by `deployMultichain` or `deployMultichainBytecode`.
* @param domainIDs An array of bigint values representing the domain IDs on which the contract was deployed. These IDs correspond
* to the blockchain networks registered on Sygma and should match the ones used during the deployment process.
*
* @example
* const { transactionHash, domainIDs } = await this.hre.multichain.deployMultichain("HelloContract", networkArgs);
* await getDeploymentInfo(transactionHash, domainIDs);
*/
public async getDeploymentInfo(
transactionHash: string,
domainIDs: bigint[]
): Promise<void> {
await Promise.all(
domainIDs.map(async (domainId): Promise<void> => {
const explorerUrl = await transferStatusInterval(
this.hre.config.multichain.environment,
transactionHash,
domainChainID
domainId
);

console.log(`Bridge transfer executed. More details: ${explorerUrl}`);

return {
network,
contractAddress,
explorerUrl,
transactionHash,
};
})
);

return {
receipt,
deploymentInfo,
};
}
}
11 changes: 6 additions & 5 deletions packages/plugin/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
Address,
ContractAbi,
ContractConstructorArgs,
ContractMethods,
HexString,
MatchPrimitiveType,
NonPayableCallOptions,
} from "web3";
Expand Down Expand Up @@ -31,11 +33,10 @@ export interface DeployOptions {
salt?: MatchPrimitiveType<"bytes32", unknown>;
isUniquePerChain?: boolean;
customNonPayableTxOptions?: NonPayableCallOptions;
adapterAddress?: Address;
}

export interface DeploymentInfo {
network: string;
contractAddress: string;
explorerUrl: string;
transactionHash: string;
export interface DeployMultichainResponse {
domainIDs: bigint[];
transactionHash: HexString;
}
2 changes: 1 addition & 1 deletion packages/plugin/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export function mapNetworkArgs<Abi extends ContractAbi = any>(
export async function transferStatusInterval(
environment: Environment,
txHash: string,
domainID: number
domainID: bigint
): Promise<string> {
let explorerUrl: string = "";

Expand Down
Loading