diff --git a/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts b/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts index a07d5ec..3cdd80b 100644 --- a/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts +++ b/packages/plugin/src/MultichainHardhatRuntimeEnvironmentField.ts @@ -9,11 +9,21 @@ import { transferStatusInterval, mapNetworkArgs, } from "./utils"; -import { AdapterABI } from "./adapterABI"; +import { + AdapterABI, + AdapterBytecode, + CreateXABI, + CreateXBytecode, + MockBridgeABI, + MockBridgeBytecode, + MockFeeHandlerABI, + MockFeeHandlerBytecode, +} from "./adapterABI"; import { DeployOptions, NetworkArguments, DeployMultichainResponse, + DeployedLocalEnvironmentContracts, } from "./types"; export class MultichainHardhatRuntimeEnvironmentField { @@ -26,7 +36,7 @@ export class MultichainHardhatRuntimeEnvironmentField { this.web3 = new Web3(provider); } - public ADAPTER_ADDRESS = vars.get( + private ADAPTER_ADDRESS = vars.get( "ADAPTER_ADDRESS", "0x85d62ad850b322152bf4ad9147bfbf097da42217" ); @@ -49,6 +59,84 @@ export class MultichainHardhatRuntimeEnvironmentField { this.isInitiated; } + /** + * Initializes the local development environment by deploying mock contracts necessary for testing interactions with the Sygma Bridge through Adapter contracts. This setup is vital for developers aiming to simulate the deployment process and contract interactions within a local and controlled environment, closely replicating interactions with the Sygma Bridge in production. + * + * @param deployer - Optional. The Ethereum address of the deployer account. If not provided, the method defaults to using the first available account. This account is tasked with deploying the mock contracts and is essential for setting up the local testing environment. + * @returns A `Promise` that resolves to an object containing the addresses of the deployed mock contracts. These addresses are crucial for conducting further development or testing, enabling comprehensive interaction with the contracts. + * + * @example + * const { adapterAddress } = await initLocalEnvironment(); + * + * const options = { + * salt: "0xcafe00000000000000000000000000000000000000000000000000000000cafe", + * adapterAddress, + * }; + * await this.hre.multichain.deployMultichain("HelloContract", networkArgs, options); + */ + public async initLocalEnvironment( + deployer?: string + ): Promise { + // Assign default values if is not provided + if (!deployer) deployer = (await this.web3.eth.getAccounts())[0]; + + const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; + + /** Deploy Mock Sygma Bridge */ + const DOMAIN_ID = BigInt(10); + + const feeHandler = new this.web3.eth.Contract(MockFeeHandlerABI); + const feeHandlerResponse = await feeHandler + .deploy({ data: MockFeeHandlerBytecode }) + .send({ from: deployer }); + const feeHandlerAddress = + feeHandlerResponse.options.address || ZERO_ADDRESS; + + const bridge = new this.web3.eth.Contract(MockBridgeABI); + const bridgeResponse = await bridge + .deploy({ + data: MockBridgeBytecode, + arguments: [deployer, feeHandlerAddress, DOMAIN_ID], + }) + .send({ from: deployer }); + const bridgeAddress = bridgeResponse.options.address || ZERO_ADDRESS; + + /** Deploy Adapter */ + const RESOURCE_ID = + "0x000000000000000000000000000000000000000000000000000000000000cafe"; + + const createX = new this.web3.eth.Contract(CreateXABI); + const createXResponse = await createX + .deploy({ + data: CreateXBytecode, + }) + .send({ from: deployer }); + const createXAddress = createXResponse.options.address || ZERO_ADDRESS; + console.log(`CreateX locally deployed: ${createXAddress}`); + + const adapter = new this.web3.eth.Contract(AdapterABI); + const adapterResponse = await adapter + .deploy({ + data: AdapterBytecode, + arguments: [createXAddress, bridgeAddress, RESOURCE_ID], + }) + .send({ from: deployer }); + const adapterAddress = adapterResponse.options.address || ZERO_ADDRESS; + + console.log( + `Adapter locally deployed: ${adapterAddress}` + + "\n" + + "Local environment initiated" + ); + + return { + adapterAddress, + createXAddress, + bridgeAddress, + feeHandlerAddress, + }; + } + /** * Deploys a contract to multiple blockchain networks. * diff --git a/packages/plugin/src/adapterABI.ts b/packages/plugin/src/adapterABI.ts index bc7ca71..1cc54cf 100644 --- a/packages/plugin/src/adapterABI.ts +++ b/packages/plugin/src/adapterABI.ts @@ -1,3 +1,16 @@ import CrosschainDeployAdapter from "@chainsafe/hardhat-plugin-multichain-deploy-contracts/artifacts/contracts/CrosschainDeployAdapter.sol/CrosschainDeployAdapter"; +import CreateX from "@chainsafe/hardhat-plugin-multichain-deploy-contracts/artifacts/contracts/deps/CreateX.sol/CreateX"; +import MockFeeHandler from "@chainsafe/hardhat-plugin-multichain-deploy-contracts/artifacts/contracts/mocks/MockFeeHandler.sol/MockFeeHandler"; +import MockBridge from "@chainsafe/hardhat-plugin-multichain-deploy-contracts/artifacts/contracts/mocks/MockBridge.sol/MockBridge"; export const AdapterABI = CrosschainDeployAdapter.abi; +export const AdapterBytecode = CrosschainDeployAdapter.bytecode; + +export const CreateXABI = CreateX.abi; +export const CreateXBytecode = CreateX.bytecode; + +export const MockFeeHandlerABI = MockFeeHandler.abi; +export const MockFeeHandlerBytecode = MockFeeHandler.bytecode; + +export const MockBridgeABI = MockBridge.abi; +export const MockBridgeBytecode = MockBridge.bytecode; diff --git a/packages/plugin/src/types.ts b/packages/plugin/src/types.ts index 99d75f8..a1da71d 100644 --- a/packages/plugin/src/types.ts +++ b/packages/plugin/src/types.ts @@ -40,3 +40,10 @@ export interface DeployMultichainResponse { domainIDs: bigint[]; transactionHash: HexString; } + +export interface DeployedLocalEnvironmentContracts { + createXAddress: string; + adapterAddress: string; + feeHandlerAddress: string; + bridgeAddress: string; +} diff --git a/packages/plugin/test/fixture-projects/hardhat-localhost/hardhat.config.ts b/packages/plugin/test/fixture-projects/hardhat-localhost/hardhat.config.ts new file mode 100644 index 0000000..98cb05e --- /dev/null +++ b/packages/plugin/test/fixture-projects/hardhat-localhost/hardhat.config.ts @@ -0,0 +1,15 @@ +// We load the plugin here. +import { HardhatUserConfig } from "hardhat/types"; +import { Environment } from "@buildwithsygma/sygma-sdk-core"; + +import "../../../src/index"; + +const config: HardhatUserConfig = { + solidity: "0.7.3", + defaultNetwork: "hardhat", + multichain: { + environment: Environment.TESTNET, + }, +}; + +export default config; diff --git a/packages/plugin/test/helpers.ts b/packages/plugin/test/helpers.ts index 34d44c0..79bf836 100644 --- a/packages/plugin/test/helpers.ts +++ b/packages/plugin/test/helpers.ts @@ -1,6 +1,7 @@ import path from "path"; import { resetHardhatContext } from "hardhat/plugins-testing"; import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { TASK_NODE } from "hardhat/builtin-tasks/task-names"; declare module "mocha" { interface Context { @@ -19,3 +20,9 @@ export function useEnvironment(fixtureProjectName: string) { resetHardhatContext(); }); } + +export function useHardhatNode() { + beforeEach("Loading hardhat node", function () { + this.hre.run(TASK_NODE); + }); +} diff --git a/packages/plugin/test/project.test.ts b/packages/plugin/test/project.test.ts index ff1cfa7..60d38c3 100644 --- a/packages/plugin/test/project.test.ts +++ b/packages/plugin/test/project.test.ts @@ -5,7 +5,7 @@ import chaiAsPromised from "chai-as-promised"; import { Environment } from "@buildwithsygma/sygma-sdk-core"; import { MultichainHardhatRuntimeEnvironmentField } from "../src/MultichainHardhatRuntimeEnvironmentField"; -import { useEnvironment } from "./helpers"; +import { useEnvironment, useHardhatNode } from "./helpers"; use(chaiAsPromised); @@ -35,4 +35,20 @@ describe("Integration tests examples", function () { describe("Hardhat Runtime Environment extension", function () { useEnvironment("hardhat-project"); }); + + describe("Hardhat Runtime Environment extension - initLocalEnvironment", function () { + useEnvironment("hardhat-localhost"); + useHardhatNode(); + + it("Should deploy all required contracts on testnet", async function () { + const addresses = await this.hre.multichain.initLocalEnvironment(); + + assert.deepEqual(addresses, { + adapterAddress: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", + createXAddress: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + bridgeAddress: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + feeHandlerAddress: "0x5FbDB2315678afecb367f032d93F642f64180aa3", + }); + }); + }); });