diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..76a20094b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +# CI/CD files +.changeset +.github +.husky + +# Dependencies & deployments +node_modules +deployments + +# Metadata +*.md + +# Docker files +docker-compose.templates.yaml \ No newline at end of file diff --git a/.github/workflows/reusable-test.yaml b/.github/workflows/reusable-test.yaml index 3afb45d83..582ec4249 100644 --- a/.github/workflows/reusable-test.yaml +++ b/.github/workflows/reusable-test.yaml @@ -59,3 +59,8 @@ jobs: - name: Test run: yarn test + # Since we're running the E2E tests in docker, we'll need to reinstall + # the node modules. This is a temporary solution to bridge us between + # non-containerized and containerized development + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..71a801e1e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,83 @@ +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Base node image with project dependencies +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +FROM node:18.16.0 as dependencies + +ARG NPM_TOKEN +ENV YARN_CACHE_FOLDER=/tmp/yarn_cache + +# Update the system packages +RUN apt-get update +RUN apt-get install -y \ + # Get the envsubst command (see below) + gettext-base + +WORKDIR /app + +# Get the source code +# +# Oh god why yarn, paleolithic technology +# +# This would normally only copy package.json and/or lockfile +# and install the dependencies from lockfile in order not to break the cache +# everytime a file changes +COPY . . + +# Get the .npmrc under a different name since envsubst will not work in place +# due to how pipes work on linux +# +# envsubst is a neat little thing that can substitute environment variables in a string +# and we can use it to keep NPM_TOKEN secret +# +# What we do is : +# +# - We pass the NPM_TOKEN as ARG +# - Set it as ENV variable only for the envsubst command so that it does not hang in the environment +# - Replace the environment variables in .npmrctemplate +# - Pipe the result to .npmrc +# +# We cannot do it in place (i.e. envsubst < .npmrc > .npmrc) because how linux works +# (it will create the output .npmrc file first, the pipe to it - but since it is now empty nothing will be piped) +COPY .npmrc .npmrctemplate + +RUN \ + # Mount yarn cache + --mount=type=cache,target=/tmp/yarn_cache \ + # Substitute NPM_TOKEN in .npmrc + NPM_TOKEN=$NPM_TOKEN envsubst < .npmrctemplate > .npmrc && \ + # Install dependencies (fail if we forgot to update the lockfile) + yarn install --prefer-offline --frozen-lockfile --non-interactive && \ + # Remove .npmrc immediately + rm -rf .npmrc + +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Image that builds the project +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +FROM dependencies as build + +# Let's now add some fancy shit to compensate for the yarn fail above +# +# Turborepo allows us to be specific about the scope of the scripts +# using the --filter flag - see more here https://turbo.build/repo/docs/core-concepts/monorepos/filtering +ARG FILTER + +WORKDIR /app + +# Since our FILTER arg can be empty, we only want to pass the --filter +# flag to turborepo if FILTER is actually used +# +# This is nicely accomplished by the + alternate value substitution +# and results in something like --filter=my-filter +RUN yarn build ${FILTER:+--filter=$FILTER} \ No newline at end of file diff --git a/docker-compose.templates.yaml b/docker-compose.templates.yaml new file mode 100644 index 000000000..54ce52e40 --- /dev/null +++ b/docker-compose.templates.yaml @@ -0,0 +1,18 @@ +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Reusable services for docker compose +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +version: "3.9" + +services: + # Service that can build the whole project + project: + build: + context: . + args: + NPM_TOKEN: $NPM_TOKEN diff --git a/packages/hardhat-utils/package.json b/packages/hardhat-utils/package.json index f34f20c8e..ad97f3624 100644 --- a/packages/hardhat-utils/package.json +++ b/packages/hardhat-utils/package.json @@ -35,6 +35,7 @@ "@layerzerolabs/lz-definitions": "~1.5.58", "@layerzerolabs/lz-evm-sdk-v1": "~1.5.58", "@types/chai-as-promised": "^7.1.7", + "@types/mocha": "^10.0.1", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", "hardhat": "^2.9.9", diff --git a/packages/ua-utils-test-v2/.gitignore b/packages/ua-utils-test-v2/.gitignore index 5e4659675..1213f1f3e 100644 --- a/packages/ua-utils-test-v2/.gitignore +++ b/packages/ua-utils-test-v2/.gitignore @@ -1 +1,2 @@ -cache \ No newline at end of file +cache +deployments \ No newline at end of file diff --git a/packages/ua-utils-test-v2/deploy/001_bootstrap.ts b/packages/ua-utils-test-v2/deploy/001_bootstrap.ts new file mode 100644 index 000000000..854b86595 --- /dev/null +++ b/packages/ua-utils-test-v2/deploy/001_bootstrap.ts @@ -0,0 +1,26 @@ +import { type DeployFunction } from "hardhat-deploy/types" +import { AddressZero } from "@ethersproject/constants" +import assert from "assert" + +/** + * This deploy function will deploy and configure LayerZero endpoint + * + * @param env `HardhatRuntimeEnvironment` + */ +const deploy: DeployFunction = async ({ getUnnamedAccounts, deployments, network }) => { + assert(network.config.endpointId != null, `Missing endpoint ID for network ${network.name}`) + + const [deployer] = await getUnnamedAccounts() + const endpointV2Deployment = await deployments.deploy("EndpointV2", { + from: deployer, + args: [network.config.endpointId, AddressZero], + }) + + console.table({ + EndpointV2: endpointV2Deployment.address, + }) +} + +deploy.tags = ["Bootstrap", "EndpointV2"] + +export default deploy diff --git a/packages/ua-utils-test-v2/docker-compose.templates.yaml b/packages/ua-utils-test-v2/docker-compose.templates.yaml new file mode 100644 index 000000000..ea6d8a326 --- /dev/null +++ b/packages/ua-utils-test-v2/docker-compose.templates.yaml @@ -0,0 +1,33 @@ +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Reusable services for docker compose +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +version: "3.9" + +services: + # Service that can build this package + package: + build: + args: + FILTER: ua-utils-test-v2... + extends: + file: ../../docker-compose.templates.yaml + service: project + working_dir: /app/packages/ua-utils-test-v2 + volumes: + - ./:/app/packages/ua-utils-test-v2 + + # Hardhat node started on port 8545 + node: + extends: + service: package + expose: + - 8545 + command: ["npx", "hardhat", "node", "--hostname", "0.0.0.0", "--no-deploy"] + healthcheck: + test: ["CMD", "curl", "-f", "http://0.0.0.0:8545/"] diff --git a/packages/ua-utils-test-v2/docker-compose.yaml b/packages/ua-utils-test-v2/docker-compose.yaml new file mode 100644 index 000000000..119ef83b8 --- /dev/null +++ b/packages/ua-utils-test-v2/docker-compose.yaml @@ -0,0 +1,67 @@ +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +# +# Docker compose for running E2E tests +# +# .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.- +# / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ +# `-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' +version: "3.9" + +services: + # ~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + # + # Network nodes, one for every hardhat network + # + # .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo. + network-vengaboys: + extends: + file: docker-compose.templates.yaml + service: node + + network-britney: + extends: + file: docker-compose.templates.yaml + service: node + + # ~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + # + # Bootstrap script that deploys all the networks + # + # .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo. + bootstrap: + extends: + file: docker-compose.templates.yaml + service: package + depends_on: + network-vengaboys: + condition: service_healthy + network-britney: + condition: service_healthy + # Can't say I love the fact that the deploy scripts are inlined here + # but at least it's all in this file that bootstraps the whole environment + # + # The "&" at the end of the lines and "wait" work together to execute the deployments + # in parallel and wait until they are all complete + command: + - /bin/bash + - -c + - | + npx hardhat --network vengaboys deploy --reset & + npx hardhat --network britney deploy --reset & + wait + + # ~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + # + # The actual tests + # + # .oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo. + tests: + extends: + file: docker-compose.templates.yaml + service: package + depends_on: + bootstrap: + condition: service_completed_successfully + command: ["npx", "hardhat", "test"] diff --git a/packages/ua-utils-test-v2/hardhat.config.ts b/packages/ua-utils-test-v2/hardhat.config.ts index ece417c3a..423d04fdd 100644 --- a/packages/ua-utils-test-v2/hardhat.config.ts +++ b/packages/ua-utils-test-v2/hardhat.config.ts @@ -1,19 +1,33 @@ +import "hardhat-deploy" import { withLayerZeroArtifacts } from "@layerzerolabs/hardhat-utils" +import { EndpointId } from "@layerzerolabs/lz-definitions" import { HardhatUserConfig } from "hardhat/types" +const MNEMONIC = "test test test test test test test test test test test test" + /** * This is a dummy hardhat config that enables us to test * hardhat functionality without mocking too much */ const config: HardhatUserConfig = { networks: { - "ethereum-mainnet": { - url: "https://eth.llamarpc.com", + hardhat: { + accounts: { + mnemonic: MNEMONIC, + }, + }, + vengaboys: { + endpointId: EndpointId.ETHEREUM_MAINNET, + url: "http://network-vengaboys:8545", + accounts: { + mnemonic: MNEMONIC, + }, }, - "bsc-testnet": { - url: "https://bsc-testnet.publicnode.com", + britney: { + endpointId: EndpointId.AVALANCHE_MAINNET, + url: "http://network-britney:8545", accounts: { - mnemonic: "test test test test test test test test test test test junk", + mnemonic: MNEMONIC, }, }, }, diff --git a/packages/ua-utils-test-v2/package.json b/packages/ua-utils-test-v2/package.json index a1b28d910..8a4d53df8 100644 --- a/packages/ua-utils-test-v2/package.json +++ b/packages/ua-utils-test-v2/package.json @@ -6,7 +6,7 @@ "private": true, "scripts": { "lint": "npx eslint '**/*.{js,ts,json}'", - "test": "npx hardhat test" + "test": "docker compose run --rm tests" }, "repository": { "type": "git", @@ -15,6 +15,7 @@ }, "devDependencies": { "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/constants": "^5.7.0", "@ethersproject/providers": "^5.7.0", "@ethersproject/wallet": "^5.7.0", "@gnosis.pm/safe-core-sdk": "^2.0.0", @@ -25,12 +26,12 @@ "@layerzerolabs/lz-definitions": "~1.5.58", "@layerzerolabs/lz-evm-sdk-v1": "~1.5.58", "@layerzerolabs/lz-evm-sdk-v2": "~1.5.58", - "@layerzerolabs/ua-utils": "~0.0.15", - "@types/chai-as-promised": "^7.1.7", "@nomiclabs/hardhat-ethers": "^2.2.3", - "ethers": "^5.7.0", + "@types/chai-as-promised": "^7.1.7", + "@types/mocha": "^10.0.1", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", + "ethers": "^5.7.0", "hardhat": "^2.9.9", "hardhat-deploy": "^0.11.22", "sinon": "^17.0.1", diff --git a/packages/ua-utils-test-v2/test/config.test.ts b/packages/ua-utils-test-v2/test/config.test.ts index c74f63286..d0b3839e5 100644 --- a/packages/ua-utils-test-v2/test/config.test.ts +++ b/packages/ua-utils-test-v2/test/config.test.ts @@ -1,8 +1,28 @@ +import hre from "hardhat" import { expect } from "chai" import { describe } from "mocha" +import { NetworkEnvironment, createGetNetworkEnvironment } from "@layerzerolabs/hardhat-utils" + +const NETWORK_NAMES = ["vengaboys", "britney"] describe("config", () => { - it("should always succeed", () => { - expect(1).to.equal(1) + NETWORK_NAMES.forEach((networkName) => { + const getEnvironment = createGetNetworkEnvironment(hre) + + describe(`Network '${networkName}`, () => { + let environment: NetworkEnvironment + + before(async () => { + environment = await getEnvironment(networkName) + }) + + it("should have an endpoint deployed", async () => { + const endpoint = await environment.getContract("EndpointV2", environment.provider) + const endpointId = await endpoint.eid() + + expect(environment.network.config.endpointId).to.be.a("number") + expect(endpointId).to.eql(environment.network.config.endpointId) + }) + }) }) }) diff --git a/packages/ua-utils-test-v2/tsconfig.json b/packages/ua-utils-test-v2/tsconfig.json index 084db5958..3df851287 100644 --- a/packages/ua-utils-test-v2/tsconfig.json +++ b/packages/ua-utils-test-v2/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "exclude": ["dist", "node_modules"], - "include": ["src", "test", "*.config.ts"], + "include": ["src", "test", "deploy", "*.config.ts"], "compilerOptions": { "module": "commonjs", "types": ["node", "mocha"] diff --git a/tsconfig.json b/tsconfig.json index 3aea6981c..30aae84ab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,7 @@ "allowSyntheticDefaultImports": true, "allowJs": true, "resolveJsonModule": true, - "types": ["node"] + "types": ["node"], + "skipLibCheck": true } }