Skip to content

Commit

Permalink
Convert packages from CJS to ESM (#3531)
Browse files Browse the repository at this point in the history
### Description

- Reconfigure tsconfig and package.json for the utils, core, sdk, and helloworld packages
- Update imports to use ESM syntax
- Add patch for typechain to address [issue 898](dethcrypto/TypeChain#898)

### Drive-by changes

Improve package Readme content

### Related issues

Fixes #1354

### Backward compatibility

No: package consumers using CJS will need to modify their imports or
update to ESM. See [this popular
gist](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#pure-esm-package)
for details.

### Testing

- [x] CI test coverage which invokes a lot of code via the CLI e2e
- [x] Manually test in Warp UI by copying packages
- [x] Publish beta packages and test in a few popular bundlers
  • Loading branch information
jmrossy authored and yorhodes committed Apr 14, 2024
1 parent d0c5cb1 commit 8494a32
Show file tree
Hide file tree
Showing 327 changed files with 2,558 additions and 2,187 deletions.
9 changes: 9 additions & 0 deletions .changeset/kind-panthers-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@hyperlane-xyz/helloworld': minor
'@hyperlane-xyz/utils': minor
'@hyperlane-xyz/cli': minor
'@hyperlane-xyz/sdk': minor
'@hyperlane-xyz/core': minor
---

Convert all public hyperlane npm packages from CJS to pure ESM
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
coverage
coverage
*.cts
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
"importOrder": ["^@hyperlane-xyz/(.*)$", "^../(.*)$", "^./(.*)$"],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderParserPlugins": ["importAssertions", "typescript", "jsx"],
"plugins": ["prettier-plugin-solidity", "@trivago/prettier-plugin-sort-imports"]
}
23 changes: 23 additions & 0 deletions .yarn/patches/typechain-npm-8.3.2-b02e27439e.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
diff --git a/dist/codegen/createBarrelFiles.js b/dist/codegen/createBarrelFiles.js
index 4bf574d7f6701bc5a8fcb2c281b5c63f31923e79..7f9cbdbd0491d4fa6338a10b23d06c2665c9d968 100644
--- a/dist/codegen/createBarrelFiles.js
+++ b/dist/codegen/createBarrelFiles.js
@@ -38,15 +38,13 @@ function createBarrelFiles(paths, { typeOnly, postfix = '', moduleSuffix = '' })
const namespacesExports = nestedDirs
.map((p) => {
const namespaceIdentifier = (0, normalizeDirName_1.normalizeDirName)(p);
+ const fromFilePath = moduleSuffix ? `'./${p}/index${moduleSuffix}'` : `'./${p}'`
if (typeOnly)
return [
- `import type * as ${namespaceIdentifier} from './${p}';`,
+ `import type * as ${namespaceIdentifier} from ${fromFilePath};`,
`export type { ${namespaceIdentifier} };`,
].join('\n');
- if (moduleSuffix) {
- return `export * as ${namespaceIdentifier} from './${p}/index${moduleSuffix}';`;
- }
- return `export * as ${namespaceIdentifier} from './${p}';`;
+ return `export * as ${namespaceIdentifier} from ${fromFilePath};`;
})
.join('\n');
const contracts = (fileReexports[path] || []).sort();
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ WORKDIR /hyperlane-monorepo

RUN apk add --update --no-cache git g++ make py3-pip jq

RUN yarn set version 4.0.1
RUN yarn set version 4.0.2

# Copy package.json and friends
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn/plugins ./.yarn/plugins
COPY .yarn/releases ./.yarn/releases
COPY .yarn/patches ./.yarn/patches
COPY typescript/utils/package.json ./typescript/utils/
COPY typescript/sdk/package.json ./typescript/sdk/
COPY typescript/helloworld/package.json ./typescript/helloworld/
Expand Down
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
"version": "0.0.0",
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"husky": "^8.0.0",
"lint-staged": "^12.4.3",
"prettier": "^2.8.8"
"prettier": "^2.8.8",
"tsx": "^4.7.1"
},
"dependencies": {
"@changesets/cli": "^2.26.2"
Expand Down Expand Up @@ -42,6 +43,8 @@
"recursive-readdir": "^2.2.3",
"underscore": "^1.13",
"undici": "^5.11",
"@trivago/prettier-plugin-sort-imports/@babel/parser": "^7.22.7"
"@trivago/prettier-plugin-sort-imports/@babel/parser": "^7.22.7",
"@typechain/ethers-v5": "11.1.2",
"typechain@npm:^8.0.0": "patch:typechain@npm%3A8.3.2#~/.yarn/patches/typechain-npm-8.3.2-b02e27439e.patch"
}
}
20 changes: 12 additions & 8 deletions solidity/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# Hyperlane Solidity
# Hyperlane Core

On-chain implementations of Hyperlane in Solidity.
Hyperlane Core contains the contracts and typechain artifacts for the Hyperlane implementation for EVM.

## Setup
## Install

- `yarn install`
```bash
# Install with NPM
npm install @hyperlane-xyz/utils

## Build
# Or with Yarn
yarn add @hyperlane-xyz/utils
```

- `yarn build`
Note, this package uses [ESM Modules](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#pure-esm-package)

## Test
## License

- `yarn test`
Apache 2.0
2 changes: 2 additions & 0 deletions solidity/hardhat.config.ts → solidity/hardhat.config.cts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ module.exports = {
outDir: './types',
target: 'ethers-v5',
alwaysGenerateOverloads: true,
node16Modules: true,
},
mocha: {
bail: true,
import: 'tsx',
},
};
47 changes: 29 additions & 18 deletions solidity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,68 @@
},
"devDependencies": {
"@layerzerolabs/solidity-examples": "^1.1.0",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"@typechain/ethers-v5": "^10.0.0",
"@typechain/hardhat": "^6.0.0",
"@typechain/ethers-v5": "^11.1.2",
"@typechain/hardhat": "^9.1.0",
"chai": "^4.3.6",
"ethereum-waffle": "^4.0.10",
"ethers": "^5.7.2",
"hardhat": "^2.19.0",
"hardhat": "^2.22.2",
"hardhat-gas-reporter": "^1.0.9",
"prettier": "^2.8.8",
"prettier-plugin-solidity": "^1.1.3",
"solhint": "^4.0.0",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.8.3",
"ts-generator": "^0.1.1",
"typechain": "^8.3.2",
"typescript": "5.1.6"
"ts-node": "^10.8.0",
"typechain": "patch:typechain@npm%3A8.3.2#~/.yarn/patches/typechain-npm-8.3.2-b02e27439e.patch",
"typescript": "5.3.3"
},
"directories": {
"test": "test"
},
"type": "module",
"exports": {
".": "./dist/index.js",
"./mailbox": "./dist/contracts/Mailbox.js",
"./buildArtifact.json": "./buildArtifact.json",
"./contracts": "./contracts"
},
"types": "./dist/index.d.ts",
"files": [
"/buildArtifact.json",
"/dist",
"/contracts",
"/interfaces",
"/docs"
"/contracts"
],
"engines": {
"node": ">=16"
},
"homepage": "https://www.hyperlane.xyz",
"repository": "https://github.com/hyperlane-xyz/hyperlane-monorepo",
"keywords": [
"Hyperlane",
"Solidity"
],
"license": "Apache-2.0",
"main": "dist/index.js",
"repository": "https://github.com/hyperlane-xyz/hyperlane-monorepo",
"scripts": {
"build": "hardhat compile && ./exportBuildArtifact.sh && tsc",
"build": "yarn hardhat-esm compile && ./exportBuildArtifact.sh && tsc",
"lint": "solhint contracts/**/*.sol",
"clean": "hardhat clean && rm -rf ./dist ./cache ./types ./coverage",
"clean": "yarn hardhat-esm clean && rm -rf ./dist ./cache ./types ./coverage ./out ./forge-cache",
"coverage": "./coverage.sh",
"docs": "forge doc",
"storage": "./storage.sh",
"hardhat-esm": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning' hardhat --config hardhat.config.cts",
"prettier": "prettier --write ./contracts ./test",
"test": "hardhat test && forge test -vvv",
"test:ci": "hardhat test && forge test --no-match-test testFork -vvv",
"test": "yarn hardhat-esm test && yarn test:forge",
"test:hardhat": "yarn hardhat-esm test",
"test:forge": "forge test -vvv",
"test:ci": "yarn test:hardhat && yarn test:forge --no-match-test testFork",
"gas": "forge snapshot",
"gas-ci": "yarn gas --check --tolerance 2 || (echo 'Manually update gas snapshot' && exit 1)",
"slither": "slither ."
"slither": "slither .",
"storage": "./storage.sh"
},
"types": "dist/index.d.ts",
"peerDependencies": {
"@ethersproject/abi": "*",
"@ethersproject/providers": "*",
Expand Down
10 changes: 6 additions & 4 deletions solidity/test/merkle.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';
import { utils } from 'ethers';

import merkleTestCases from '../../vectors/merkle.json';
import merkleTestCases from '../../vectors/merkle.json' assert { type: 'json' };
import { TestMerkle, TestMerkle__factory } from '../types';

import { getSigner } from './signer';

describe('Merkle', async () => {
for (const testCase of merkleTestCases) {
const { testName, leaves, expectedRoot, proofs } = testCase;
Expand All @@ -12,14 +14,14 @@ describe('Merkle', async () => {
let merkle: TestMerkle;

before(async () => {
const [signer] = await ethers.getSigners();
const signer = await getSigner();

const merkleFactory = new TestMerkle__factory(signer);
merkle = await merkleFactory.deploy();

//insert the leaves
for (const leaf of leaves) {
const leafHash = ethers.utils.hashMessage(leaf);
const leafHash = utils.hashMessage(leaf);
await merkle.insert(leafHash);
}
});
Expand Down
14 changes: 8 additions & 6 deletions solidity/test/message.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';
import { utils } from 'ethers';

import {
addressToBytes32,
formatMessage,
messageId,
} from '@hyperlane-xyz/utils';

import testCases from '../../vectors/message.json';
import testCases from '../../vectors/message.json' assert { type: 'json' };
import { Mailbox__factory, TestMessage, TestMessage__factory } from '../types';

import { getSigner, getSigners } from './signer';

const remoteDomain = 1000;
const localDomain = 2000;
const nonce = 11;
Expand All @@ -19,7 +21,7 @@ describe('Message', async () => {
let version: number;

before(async () => {
const [signer] = await ethers.getSigners();
const signer = await getSigner();

const Message = new TestMessage__factory(signer);
messageLib = await Message.deploy();
Expand All @@ -31,8 +33,8 @@ describe('Message', async () => {
});

it('Returns fields from a message', async () => {
const [sender, recipient] = await ethers.getSigners();
const body = ethers.utils.formatBytes32String('message');
const [sender, recipient] = await getSigners();
const body = utils.formatBytes32String('message');

const message = formatMessage(
version,
Expand Down Expand Up @@ -64,7 +66,7 @@ describe('Message', async () => {
for (const test of testCases) {
const { origin, sender, destination, recipient, body, nonce, id } = test;

const hexBody = ethers.utils.hexlify(body);
const hexBody = utils.hexlify(body);

const hyperlaneMessage = formatMessage(
version,
Expand Down
10 changes: 6 additions & 4 deletions solidity/test/mockMailbox.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';
import { utils } from 'ethers';

import { addressToBytes32 } from '@hyperlane-xyz/utils';

import { MockMailbox__factory, TestRecipient__factory } from '../types';

import { getSigner } from './signer';

const ORIGIN_DOMAIN = 1000;
const DESTINATION_DOMAIN = 2000;

describe('MockMailbox', function () {
it('should be able to mock sending and receiving a message', async function () {
const [signer] = await ethers.getSigners();
const signer = await getSigner();
const mailboxFactory = new MockMailbox__factory(signer);
const testRecipientFactory = new TestRecipient__factory(signer);
const originMailbox = await mailboxFactory.deploy(ORIGIN_DOMAIN);
Expand All @@ -21,7 +23,7 @@ describe('MockMailbox', function () {
);
const recipient = await testRecipientFactory.deploy();

const body = ethers.utils.toUtf8Bytes('This is a test message');
const body = utils.toUtf8Bytes('This is a test message');

await originMailbox['dispatch(uint32,bytes32,bytes)'](
DESTINATION_DOMAIN,
Expand All @@ -31,6 +33,6 @@ describe('MockMailbox', function () {
await destinationMailbox.processNextInboundMessage();

const dataReceived = await recipient.lastData();
expect(dataReceived).to.eql(ethers.utils.hexlify(body));
expect(dataReceived).to.eql(utils.hexlify(body));
});
});
12 changes: 12 additions & 0 deletions solidity/test/signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Wallet } from 'ethers';
import hre from 'hardhat';

export async function getSigners(): Promise<Wallet[]> {
// @ts-ignore Hardhat type overrides from @nomiclabs/hardhat-ethers don't work
return hre.ethers.getSigners();
}

export async function getSigner(): Promise<Wallet> {
const [signer] = await getSigners();
return signer;
}
8 changes: 5 additions & 3 deletions solidity/test/testrecipient.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';
import { utils } from 'ethers';

import { addressToBytes32 } from '@hyperlane-xyz/utils';

import { TestRecipient, TestRecipient__factory } from '../types';

const testData = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('test'));
import { getSigner } from './signer';

const testData = utils.hexlify(utils.toUtf8Bytes('test'));
describe('TestRecipient', () => {
let recipient: TestRecipient;
let signerAddress: string;

before(async () => {
const [signer] = await ethers.getSigners();
const signer = await getSigner();
signerAddress = await signer.getAddress();
const recipientFactory = new TestRecipient__factory(signer);
recipient = await recipientFactory.deploy();
Expand Down
4 changes: 2 additions & 2 deletions solidity/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./types"
},
"exclude": ["./test", "hardhat.config.ts", "./dist"],
"extends": "../tsconfig.json"
"exclude": ["./test", "hardhat.config.cts", "./dist"]
}
Loading

0 comments on commit 8494a32

Please sign in to comment.