diff --git a/README.md b/README.md index 9b1a44194..807faf08c 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,28 @@ docker compose logs -f This allows you to monitor logs coming from e.g. the `hardhat` nodes +#### Exposing test networks on `localhost` + +It is possible to expose the test networks defined in `docker-compose.yaml` on your host machine. To do this, you can run: + +```bash +yarn start +``` + +You will need to use the `MNEMONIC` defined in `docker-compose.templates.yaml` if you require funded accounts: + +```bash +export MNEMONIC='test test test test test test test test test test test junk' +``` + +To stop the network containers, just run: + +```bash +yarn stop +``` + +**Don't forget that the state of the local networks disappears after they are stopped and any deployment files created in one session will be invalid in the next one.** + ### Troubleshooting #### Problems with committing diff --git a/docker-compose.local.yaml b/docker-compose.local.yaml new file mode 100644 index 000000000..6fb0455a1 --- /dev/null +++ b/docker-compose.local.yaml @@ -0,0 +1,24 @@ +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Docker compose for exposed test networks +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +version: "3.9" + +services: + # ~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + # + # Expose nodes on host ports + # + # .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo. + network-vengaboys: + ports: + - "10001:8545" + + network-britney: + ports: + - "10002:8545" diff --git a/docker-compose.templates.yaml b/docker-compose.templates.yaml index e7d528fc9..a8fc3d4e9 100644 --- a/docker-compose.templates.yaml +++ b/docker-compose.templates.yaml @@ -32,7 +32,7 @@ services: # We'll provide a single testing MNEMONIC for the project so that the test EVM nodes # account are in sync with the hardhat accounts environment: - - MNEMONIC='test test test test test test test test test test test test' + - MNEMONIC=test test test test test test test test test test test junk logging: driver: local options: diff --git a/docker-compose.yaml b/docker-compose.yaml index 17f414e8a..71d121997 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -41,6 +41,18 @@ services: condition: service_healthy logging: driver: none + # The default containerized setup will specify the network URLs + # for the internal networks + # + # This works in conjunction with hardhat configs in the test projects. + # + # If these environment variables are not specified, the exposed networks are used + # that need to be started using docker compose up: + # + # docker compose -f docker-compose.yaml -f docker-compose.local.yaml up network-britney network-vengaboys + environment: + - NETWORK_URL_BRITNEY=http://network-britney:8545 + - NETWORK_URL_VENGABOYS=http://network-vengaboys:8545 volumes: - ./node_modules/.cache/turbo:/app/node_modules/.cache/turbo - ./packages:/app/packages diff --git a/package.json b/package.json index 21053d8e5..f64072edd 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "dev": "npx turbo run dev", "lint": "npx turbo run lint", "prepare": "husky install", + "start": "docker compose -f docker-compose.yaml -f docker-compose.local.yaml up network-britney network-vengaboys", + "stop": "docker compose down", "test": "docker compose run --rm $DOCKER_COMPOSE_RUN_TESTS_ARGS tests" }, "lint-staged": { diff --git a/packages/ua-utils-evm-hardhat-test/hardhat.config.ts b/packages/ua-utils-evm-hardhat-test/hardhat.config.ts index c234fe239..689ef45ce 100644 --- a/packages/ua-utils-evm-hardhat-test/hardhat.config.ts +++ b/packages/ua-utils-evm-hardhat-test/hardhat.config.ts @@ -4,6 +4,10 @@ import assert from 'assert' import { EndpointId } from '@layerzerolabs/lz-definitions' import type { HardhatUserConfig } from 'hardhat/types' +// These tasks are only for when you want to play with this setup +// using your own keyboard (using exposed networks) +import './tasks' + const MNEMONIC = process.env.MNEMONIC assert(MNEMONIC, `Missing MNEMONIC environment variable`) @@ -18,14 +22,26 @@ const config: HardhatUserConfig = { networks: { vengaboys: { eid: EndpointId.ETHEREUM_MAINNET, - url: 'http://network-vengaboys:8545', + // Containerized setup defines these environment variables + // to point the networks to the internal ones + // + // If these are not specified, exposed networks are used + // + // See root README.md for usage with exposed network + url: process.env.NETWORK_URL_VENGABOYS ?? 'http://localhost:10001', accounts: { mnemonic: MNEMONIC, }, }, britney: { eid: EndpointId.AVALANCHE_MAINNET, - url: 'http://network-britney:8545', + // Containerized setup defines these environment variables + // to point the networks to the internal ones + // + // If these are not specified, exposed networks are used + // + // See root README.md for usage with exposed network + url: process.env.NETWORK_URL_BRITNEY ?? 'http://localhost:10002', accounts: { mnemonic: MNEMONIC, }, diff --git a/packages/ua-utils-evm-hardhat-test/tasks/index.ts b/packages/ua-utils-evm-hardhat-test/tasks/index.ts new file mode 100644 index 000000000..221fd0fe9 --- /dev/null +++ b/packages/ua-utils-evm-hardhat-test/tasks/index.ts @@ -0,0 +1,25 @@ +import { task } from 'hardhat/config' +import { setupDefaultEndpoint } from '../test/__utils__/endpoint' +import { deployOApp } from '../test/__utils__/oapp' + +/** + * Task that will: + * + * - Deploy EndpointV2-related infrastructure + * - Wire the EndpointV2-related infrastructure with default configuration + * - Deploy the DefaultOApp + * + * If you want to expose the networks locally + * and deploy your own endpoints, this task is tjust for you! + * + * See the root README.md section for info about how to expose networks locally + */ +task('lz:test:oapp:deploy', 'Deploy the test OApp on a default EndpointV2 infrastructure', async () => { + // Deploy the DefaultOApp along with the EndpointV2 + // + // This will wipe the existing deployments so watch out + await deployOApp() + + // This will wire up the endpoints + await setupDefaultEndpoint() +}) diff --git a/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts b/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts index 901b53420..3c04bb377 100644 --- a/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts +++ b/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts @@ -59,29 +59,43 @@ export const getDefaultUlnConfig = (dvnAddress: string): Uln302UlnConfig => { } /** - * Helper function that deploys a fresh endpoint infrastructure: - * - * - EndpointV2 - * - ReceiveUln302 - * - SendUln302 + * Deploys an enpoint fixture. Useful for tests + */ +export const deployEndpointFixture = async () => { + const environmentFactory = createNetworkEnvironmentFactory() + const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET) + const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET) + + await Promise.all([eth.deployments.fixture('EndpointV2'), avax.deployments.fixture('EndpointV2')]) +} + +/** + * Deploys an enpoint fixture. Useful for when deployment files need to be persisted + */ +export const deployEndpoint = async () => { + const environmentFactory = createNetworkEnvironmentFactory() + const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET) + const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET) + + await Promise.all([ + eth.deployments.run('EndpointV2', { writeDeploymentsToFiles: true }), + avax.deployments.run('EndpointV2', { writeDeploymentsToFiles: true }), + ]) +} + +/** + * Helper function that wires the endpoint infrastructure. * - * After deploying, it will wire up the elements with minimal configuration + * The contracts still need to be deployed (use deployEndpoint or deployEndpointFixture) */ export const setupDefaultEndpoint = async (): Promise => { // This is the tooling we are going to need const logger = createLogger() - const environmentFactory = createNetworkEnvironmentFactory() const contractFactory = createConnectedContractFactory() const signerFactory = createSignerFactory() const ulnSdkFactory = createUln302Factory(contractFactory) const endpointSdkFactory = createEndpointFactory(contractFactory, ulnSdkFactory) - // First we deploy the endpoint - const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET) - const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET) - - await Promise.all([eth.deployments.fixture('EndpointV2'), avax.deployments.fixture('EndpointV2')]) - // For the graphs, we'll also need the pointers to the contracts const ethSendUlnPoint = omniContractToPoint(await contractFactory(ethSendUln)) const avaxSendUlnPoint = omniContractToPoint(await contractFactory(avaxSendUln)) diff --git a/packages/ua-utils-evm-hardhat-test/test/__utils__/oapp.ts b/packages/ua-utils-evm-hardhat-test/test/__utils__/oapp.ts index 07eb1842b..e2bc1714f 100644 --- a/packages/ua-utils-evm-hardhat-test/test/__utils__/oapp.ts +++ b/packages/ua-utils-evm-hardhat-test/test/__utils__/oapp.ts @@ -6,5 +6,16 @@ export const deployOApp = async () => { const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET) const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET) + await Promise.all([ + eth.deployments.run('OApp', { writeDeploymentsToFiles: true }), + avax.deployments.run('OApp', { writeDeploymentsToFiles: true }), + ]) +} + +export const deployOAppFixture = async () => { + const environmentFactory = createNetworkEnvironmentFactory() + const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET) + const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET) + await Promise.all([eth.deployments.fixture('OApp'), avax.deployments.fixture('OApp')]) } diff --git a/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts b/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts index 517fc2c12..af654e98b 100644 --- a/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts @@ -2,7 +2,7 @@ import 'hardhat' import { createConnectedContractFactory } from '@layerzerolabs/utils-evm-hardhat' import { omniContractToPoint } from '@layerzerolabs/utils-evm' import { EndpointId } from '@layerzerolabs/lz-definitions' -import { getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' +import { deployEndpointFixture, getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' import { createEndpointFactory, createUln302Factory } from '@layerzerolabs/protocol-utils-evm' describe('endpoint/config', () => { @@ -16,6 +16,7 @@ describe('endpoint/config', () => { const avaxDvn = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'DVN' } beforeEach(async () => { + await deployEndpointFixture() await setupDefaultEndpoint() }) diff --git a/packages/ua-utils-evm-hardhat-test/test/oapp/config.test.ts b/packages/ua-utils-evm-hardhat-test/test/oapp/config.test.ts index 4a0a42624..1d195c4b1 100644 --- a/packages/ua-utils-evm-hardhat-test/test/oapp/config.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/oapp/config.test.ts @@ -9,8 +9,8 @@ import { import type { OmniGraphHardhat } from '@layerzerolabs/utils-evm-hardhat' import { omniContractToPoint } from '@layerzerolabs/utils-evm' import { EndpointId } from '@layerzerolabs/lz-definitions' -import { setupDefaultEndpoint } from '../__utils__/endpoint' -import { deployOApp } from '../__utils__/oapp' +import { deployEndpointFixture, setupDefaultEndpoint } from '../__utils__/endpoint' +import { deployOAppFixture } from '../__utils__/oapp' describe('oapp/config', () => { const ethContract = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'DefaultOApp' } @@ -39,11 +39,12 @@ describe('oapp/config', () => { } beforeAll(async () => { + await deployEndpointFixture() await setupDefaultEndpoint() }) beforeEach(async () => { - await deployOApp() + await deployOAppFixture() }) it('should return all setPeer transactions', async () => { diff --git a/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts b/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts index 1e7083f6d..8ec5c52d9 100644 --- a/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts @@ -1,4 +1,9 @@ -import { getDefaultExecutorConfig, getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' +import { + deployEndpointFixture, + getDefaultExecutorConfig, + getDefaultUlnConfig, + setupDefaultEndpoint, +} from '../__utils__/endpoint' import { createContractFactory, getEidForNetworkName } from '@layerzerolabs/utils-evm-hardhat' import hre from 'hardhat' import { TASK_LZ_GET_DEFAULT_CONFIG } from '@layerzerolabs/ua-utils-evm-hardhat' @@ -6,6 +11,7 @@ import { omniContractToPoint } from '@layerzerolabs/utils-evm' describe('task: getDefaultConfig', () => { beforeEach(async () => { + await deployEndpointFixture() await setupDefaultEndpoint() }) diff --git a/packages/ua-utils-evm-hardhat-test/test/task/getOAppConfig.test.ts b/packages/ua-utils-evm-hardhat-test/test/task/getOAppConfig.test.ts index 780dbc8bc..32e773e70 100644 --- a/packages/ua-utils-evm-hardhat-test/test/task/getOAppConfig.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/task/getOAppConfig.test.ts @@ -1,4 +1,9 @@ -import { getDefaultExecutorConfig, getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' +import { + deployEndpointFixture, + getDefaultExecutorConfig, + getDefaultUlnConfig, + setupDefaultEndpoint, +} from '../__utils__/endpoint' import { createContractFactory, getEidForNetworkName } from '@layerzerolabs/utils-evm-hardhat' import hre from 'hardhat' import { AddressZero } from '@ethersproject/constants' @@ -7,6 +12,7 @@ import { omniContractToPoint } from '@layerzerolabs/utils-evm' describe('task: getOAppConfig', () => { beforeEach(async () => { + await deployEndpointFixture() await setupDefaultEndpoint() }) diff --git a/packages/ua-utils-evm-hardhat-test/test/task/oapp/wire.test.ts b/packages/ua-utils-evm-hardhat-test/test/task/oapp/wire.test.ts index d039f7fb9..35f981471 100644 --- a/packages/ua-utils-evm-hardhat-test/test/task/oapp/wire.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/task/oapp/wire.test.ts @@ -1,8 +1,9 @@ import hre from 'hardhat' import { isFile, promptToContinue } from '@layerzerolabs/io-utils' -import { resolve } from 'path' +import { relative, resolve } from 'path' import { TASK_LZ_WIRE_OAPP } from '@layerzerolabs/ua-utils-evm-hardhat' -import { deployOApp } from '../../__utils__/oapp' +import { deployOAppFixture } from '../../__utils__/oapp' +import { cwd } from 'process' jest.mock('@layerzerolabs/io-utils', () => { const original = jest.requireActual('@layerzerolabs/io-utils') @@ -31,7 +32,7 @@ describe('task/oapp/wire', () => { describe('with invalid configs', () => { beforeAll(async () => { - await deployOApp() + await deployOAppFixture() }) it('should fail if the config file does not exist', async () => { @@ -77,7 +78,7 @@ describe('task/oapp/wire', () => { describe('with valid configs', () => { beforeEach(async () => { - await deployOApp() + await deployOAppFixture() }) it('should exit if there is nothing to wire', async () => { @@ -88,6 +89,15 @@ describe('task/oapp/wire', () => { expect(promptToContinueMock).not.toHaveBeenCalled() }) + it('should work with relative paths', async () => { + const oappConfigAbsolute = configPathFixture('valid.config.empty.js') + const oappConfig = relative(cwd(), oappConfigAbsolute) + + await hre.run(TASK_LZ_WIRE_OAPP, { oappConfig }) + + expect(promptToContinueMock).not.toHaveBeenCalled() + }) + it('should have debug output if requested (so called eye test, check the test output)', async () => { const oappConfig = configPathFixture('valid.config.connected.js') diff --git a/packages/ua-utils-evm-hardhat/src/tasks/oapp/getDefaultConfig.ts b/packages/ua-utils-evm-hardhat/src/tasks/oapp/getDefaultConfig.ts index e9c798ac3..04c3e2c68 100644 --- a/packages/ua-utils-evm-hardhat/src/tasks/oapp/getDefaultConfig.ts +++ b/packages/ua-utils-evm-hardhat/src/tasks/oapp/getDefaultConfig.ts @@ -29,15 +29,17 @@ export const getDefaultConfig: ActionType = async (taskArgs) => { receiveUlnConfig, } - printRecord({ - localNetworkName, - remoteNetworkName, - sendLibrary, - receiveLibrary, - sendUlnConfig, - sendExecutorConfig, - receiveUlnConfig, - }) + console.log( + printRecord({ + localNetworkName, + remoteNetworkName, + sendLibrary, + receiveLibrary, + sendUlnConfig, + sendExecutorConfig, + receiveUlnConfig, + }) + ) } } return configs diff --git a/packages/ua-utils-evm-hardhat/src/tasks/oapp/getOAppConfig.ts b/packages/ua-utils-evm-hardhat/src/tasks/oapp/getOAppConfig.ts index 1e3a9b441..9405b4ccc 100644 --- a/packages/ua-utils-evm-hardhat/src/tasks/oapp/getOAppConfig.ts +++ b/packages/ua-utils-evm-hardhat/src/tasks/oapp/getOAppConfig.ts @@ -39,15 +39,17 @@ export const getOAppConfig: ActionType = async (taskArgs) => { receiveUlnConfig, } - printRecord({ - localNetworkName, - remoteNetworkName, - sendLibrary, - receiveLibrary, - sendUlnConfig, - sendExecutorConfig, - receiveUlnConfig, - }) + console.log( + printRecord({ + localNetworkName, + remoteNetworkName, + sendLibrary, + receiveLibrary, + sendUlnConfig, + sendExecutorConfig, + receiveUlnConfig, + }) + ) } } return configs diff --git a/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts b/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts index bae7b6ab8..5b6dfc38a 100644 --- a/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts +++ b/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts @@ -15,6 +15,7 @@ import { createOAppFactory } from '@layerzerolabs/ua-utils-evm' import { OmniGraphBuilderHardhat, createConnectedContractFactory } from '@layerzerolabs/utils-evm-hardhat' import { OmniTransaction } from '@layerzerolabs/utils' import { printTransactions } from '@layerzerolabs/utils' +import { resolve } from 'path' interface TaskArgs { oappConfig: string @@ -44,7 +45,7 @@ const action: ActionType = async ({ oappConfig: oappConfigPath, logLev try { logger.verbose(`Loading config file '${oappConfigPath}'`) - rawConfig = require(oappConfigPath) + rawConfig = require(resolve(oappConfigPath)) } catch (error) { throw new Error(`Unable to read config file '${oappConfigPath}': ${error}`) }