diff --git a/.changeset/sixty-radios-rest.md b/.changeset/sixty-radios-rest.md
new file mode 100644
index 000000000..c59c76273
--- /dev/null
+++ b/.changeset/sixty-radios-rest.md
@@ -0,0 +1,6 @@
+---
+"@layerzerolabs/toolbox-hardhat": patch
+"@layerzerolabs/metadata-tools": patch
+---
+
+add metadata-tools package
diff --git a/packages/metadata-tools/.eslintignore b/packages/metadata-tools/.eslintignore
new file mode 100644
index 000000000..db4c6d9b6
--- /dev/null
+++ b/packages/metadata-tools/.eslintignore
@@ -0,0 +1,2 @@
+dist
+node_modules
\ No newline at end of file
diff --git a/packages/metadata-tools/.eslintrc.json b/packages/metadata-tools/.eslintrc.json
new file mode 100644
index 000000000..be97c53fb
--- /dev/null
+++ b/packages/metadata-tools/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../.eslintrc.json"
+}
diff --git a/packages/metadata-tools/.gitignore b/packages/metadata-tools/.gitignore
new file mode 100644
index 000000000..06cf65390
--- /dev/null
+++ b/packages/metadata-tools/.gitignore
@@ -0,0 +1 @@
+cache
diff --git a/packages/metadata-tools/.prettierignore b/packages/metadata-tools/.prettierignore
new file mode 100644
index 000000000..763301fc0
--- /dev/null
+++ b/packages/metadata-tools/.prettierignore
@@ -0,0 +1,2 @@
+dist/
+node_modules/
\ No newline at end of file
diff --git a/packages/metadata-tools/README.md b/packages/metadata-tools/README.md
new file mode 100644
index 000000000..396005d25
--- /dev/null
+++ b/packages/metadata-tools/README.md
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+@layerzerolabs/metadata-tools
+
+
+
+
+
+
+
+
+
+
+
+## Installation
+
+```bash
+yarn add @layerzerolabs/metadata-tools
+
+pnpm add @layerzerolabs/metadata-tools
+
+npm install @layerzerolabs/metadata-tools
+```
+
+## Usage
+
+```typescript
+import { generateConnectionsConfig } from "@layerzerolabs/metadata-tools";
+
+// [srcContract, dstContract, [requiredDVNs, [optionalDVNs, threshold]], [srcToDstConfirmations, dstToSrcConfirmations]], [enforcedOptionsSrcToDst, enforcedOptionsDstToSrc]
+const connections = await generateConnectionsConfig([
+ [avalancheContract, polygonContract, [['LayerZero'], []], [1, 1], [EVM_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS]],
+]);
+```
diff --git a/packages/metadata-tools/jest.config.js b/packages/metadata-tools/jest.config.js
new file mode 100644
index 000000000..ff88d2a0a
--- /dev/null
+++ b/packages/metadata-tools/jest.config.js
@@ -0,0 +1,12 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+ cache: false,
+ reporters: [['github-actions', { silent: false }], 'default'],
+ testEnvironment: 'node',
+ moduleNameMapper: {
+ '^@/(.*)$': '/src/$1',
+ },
+ transform: {
+ '^.+\\.(t|j)sx?$': '@swc/jest',
+ },
+};
diff --git a/packages/metadata-tools/package.json b/packages/metadata-tools/package.json
new file mode 100644
index 000000000..92460528f
--- /dev/null
+++ b/packages/metadata-tools/package.json
@@ -0,0 +1,56 @@
+{
+ "name": "@layerzerolabs/metadata-tools",
+ "version": "0.0.1",
+ "description": "LayerZero metadata API tools",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/LayerZero-Labs/devtools.git",
+ "directory": "packages/metadata-tools"
+ },
+ "license": "MIT",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "require": "./dist/index.js",
+ "import": "./dist/index.mjs"
+ },
+ "./*": {
+ "types": "./dist/*.d.ts",
+ "require": "./dist/*.js",
+ "import": "./dist/*.mjs"
+ }
+ },
+ "main": "./dist/index.js",
+ "module": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "prebuild": "$npm_execpath tsc --noEmit",
+ "build": "$npm_execpath tsup",
+ "clean": "rm -rf dist",
+ "dev": "$npm_execpath tsup --watch",
+ "lint": "$npm_execpath eslint '**/*.{js,ts,json}'",
+ "lint:fix": "eslint --fix '**/*.{js,ts,json}'",
+ "test": "jest"
+ },
+ "devDependencies": {
+ "@layerzerolabs/devtools-evm-hardhat": "~2.0.3",
+ "@layerzerolabs/ua-devtools": "~3.0.1",
+ "@swc/core": "^1.4.0",
+ "@swc/jest": "^0.2.36",
+ "@types/jest": "^29.5.12",
+ "jest": "^29.7.0",
+ "tslib": "~2.6.2",
+ "tsup": "~8.0.1",
+ "typescript": "^5.4.4"
+ },
+ "peerDependencies": {
+ "@layerzerolabs/devtools-evm-hardhat": "~2.0.3",
+ "@layerzerolabs/ua-devtools": "~3.0.1"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/metadata-tools/src/config-metadata.ts b/packages/metadata-tools/src/config-metadata.ts
new file mode 100644
index 000000000..b8f089194
--- /dev/null
+++ b/packages/metadata-tools/src/config-metadata.ts
@@ -0,0 +1,208 @@
+import type { OmniEdgeHardhat } from '@layerzerolabs/devtools-evm-hardhat'
+import type { OAppEdgeConfig } from '@layerzerolabs/ua-devtools'
+import { IMetadata } from './types'
+import { TwoWayConfig } from './types'
+
+const METADATA_URL = process.env.LZ_METADATA_URL || 'https://metadata.layerzero-api.com/v1/metadata'
+
+function getEndpointIdDeployment(eid: number, metadata: IMetadata) {
+ const srcEidString = eid.toString()
+ for (const objectKey in metadata) {
+ const entry = metadata[objectKey]
+
+ if (typeof entry?.deployments !== 'undefined') {
+ for (const deployment of entry.deployments) {
+ if (srcEidString === deployment.eid) {
+ return deployment
+ }
+ }
+ }
+ }
+
+ throw new Error(`Can't find endpoint with eid: "${eid}",`)
+}
+
+export function DVNsToAddresses(dvns: string[], chainKey: string, metadata: IMetadata) {
+ if (dvns.length === 0) {
+ return []
+ }
+
+ const dvnAddresses: string[] = []
+ const seenDVNs = new Set()
+
+ if (!metadata[chainKey]?.dvns) {
+ throw new Error(`Can't find DVNs for chainKey: "${chainKey}".`)
+ }
+
+ const metadataDVNs = Object.entries(metadata[chainKey].dvns)
+
+ for (const dvn of dvns) {
+ if (seenDVNs.has(dvn)) {
+ throw new Error(`Duplicate DVN name found: "${dvn}".`)
+ }
+ seenDVNs.add(dvn)
+
+ let i = 0
+ for (const [dvnAddress, dvnDetails] of metadataDVNs) {
+ if (dvnDetails.canonicalName === dvn && !dvnDetails.lzReadCompatible) {
+ if (dvnDetails.deprecated) {
+ console.log(`Warning: DVN "${dvn}" is deprecated.`)
+ }
+
+ dvnAddresses.push(dvnAddress)
+ break
+ }
+
+ if (i === metadataDVNs.length - 1) {
+ throw new Error(
+ `Can't find DVN: "${dvn}" on chainKey: "${chainKey}". Double check you're using valid DVN canonical name (not an address).`
+ )
+ }
+
+ i++
+ }
+ }
+
+ if (dvns.length !== dvnAddresses.length) {
+ throw new Error(`Can't find all DVNs: "${dvns.join(', ')}".`)
+ }
+
+ return dvnAddresses.sort()
+}
+
+export async function translatePathwayToConfig(
+ pathway: TwoWayConfig,
+ metadata: IMetadata
+): Promise[]> {
+ const configs: OmniEdgeHardhat[] = []
+
+ const sourceContract = pathway[0]
+ const destinationContract = pathway[1]
+ const [requiredDVNs, optionalDVNConfig] = pathway[2]
+ const [sourceToDestinationConfirmations, destinationToSourceConfirmations] = pathway[3]
+ const [enforcedOptionsSrcToDst, enforcedOptionsDstToSrc] = pathway[4]
+
+ const optionalDVNs = optionalDVNConfig[0]
+ const optionalDVNThreshold = optionalDVNConfig[1] || 0
+
+ if (optionalDVNThreshold > (optionalDVNs?.length || 0)) {
+ throw new Error(`Optional DVN threshold is greater than the number of optional DVNs.`)
+ }
+
+ const sourceLZDeployment = getEndpointIdDeployment(sourceContract.eid, metadata)
+ const destinationLZDeployment = getEndpointIdDeployment(destinationContract.eid, metadata)
+
+ const sourceRequiredDVNs = DVNsToAddresses(requiredDVNs, sourceLZDeployment.chainKey, metadata)
+ const destinationRequiredDVNs = DVNsToAddresses(requiredDVNs, destinationLZDeployment.chainKey, metadata)
+
+ let sourceOptionalDVNs: string[] = []
+ let destinationOptionalDVNs: string[] = []
+
+ if (optionalDVNs) {
+ sourceOptionalDVNs = DVNsToAddresses(optionalDVNs, sourceLZDeployment.chainKey, metadata)
+ destinationOptionalDVNs = DVNsToAddresses(optionalDVNs, destinationLZDeployment.chainKey, metadata)
+ }
+
+ if (!sourceLZDeployment.sendUln302 || !sourceLZDeployment.receiveUln302 || !sourceLZDeployment.executor) {
+ throw new Error(
+ `Can't find sendUln302, receiveUln302 or executor for source endpoint with eid: "${sourceContract.eid}".`
+ )
+ }
+
+ if (
+ !destinationLZDeployment.sendUln302 ||
+ !destinationLZDeployment.receiveUln302 ||
+ !destinationLZDeployment.executor
+ ) {
+ throw new Error(
+ `Can't find sendUln302, receiveUln302 or executor for destination endpoint with eid: "${destinationContract.eid}".`
+ )
+ }
+
+ const sourceToDestinationConfig: OmniEdgeHardhat = {
+ from: sourceContract,
+ to: destinationContract,
+ config: {
+ sendLibrary: sourceLZDeployment.sendUln302.address,
+ receiveLibraryConfig: {
+ receiveLibrary: sourceLZDeployment.receiveUln302.address,
+ gracePeriod: BigInt(0),
+ },
+ sendConfig: {
+ executorConfig: {
+ maxMessageSize: 10000,
+ executor: sourceLZDeployment.executor.address,
+ },
+ ulnConfig: {
+ confirmations: BigInt(sourceToDestinationConfirmations),
+ requiredDVNs: sourceRequiredDVNs,
+ optionalDVNs: sourceOptionalDVNs,
+ optionalDVNThreshold,
+ },
+ },
+ enforcedOptions: enforcedOptionsSrcToDst,
+ },
+ }
+
+ const destinationToSourceConfig: OmniEdgeHardhat = {
+ from: destinationContract,
+ to: sourceContract,
+ config: {
+ sendLibrary: destinationLZDeployment.sendUln302.address,
+ receiveLibraryConfig: {
+ receiveLibrary: destinationLZDeployment.receiveUln302.address,
+ gracePeriod: BigInt(0),
+ },
+ receiveConfig: {
+ ulnConfig: {
+ confirmations: BigInt(sourceToDestinationConfirmations),
+ requiredDVNs: destinationRequiredDVNs,
+ optionalDVNs: destinationOptionalDVNs,
+ optionalDVNThreshold,
+ },
+ },
+ },
+ }
+
+ if (destinationToSourceConfirmations) {
+ sourceToDestinationConfig.config.receiveConfig = {
+ ulnConfig: {
+ confirmations: BigInt(destinationToSourceConfirmations),
+ requiredDVNs: sourceRequiredDVNs,
+ optionalDVNs: sourceOptionalDVNs,
+ optionalDVNThreshold,
+ },
+ }
+
+ destinationToSourceConfig.config.enforcedOptions = enforcedOptionsDstToSrc
+
+ destinationToSourceConfig.config.sendConfig = {
+ executorConfig: {
+ maxMessageSize: 10000,
+ executor: destinationLZDeployment.executor.address,
+ },
+ ulnConfig: {
+ confirmations: BigInt(destinationToSourceConfirmations),
+ requiredDVNs: destinationRequiredDVNs,
+ optionalDVNs: destinationOptionalDVNs,
+ optionalDVNThreshold,
+ },
+ }
+ }
+
+ configs.push(sourceToDestinationConfig)
+ configs.push(destinationToSourceConfig)
+
+ return configs
+}
+
+export async function generateConnectionsConfig(pathways: TwoWayConfig[]) {
+ const metadata = (await fetch(METADATA_URL).then((res) => res.json())) as IMetadata
+ const connections: OmniEdgeHardhat[] = []
+
+ for (const pathway of pathways) {
+ connections.push(...(await translatePathwayToConfig(pathway, metadata)))
+ }
+
+ return connections
+}
diff --git a/packages/metadata-tools/src/index.ts b/packages/metadata-tools/src/index.ts
new file mode 100644
index 000000000..a0a0d111c
--- /dev/null
+++ b/packages/metadata-tools/src/index.ts
@@ -0,0 +1,2 @@
+export * from './config-metadata'
+export * from './types'
diff --git a/packages/metadata-tools/src/types.ts b/packages/metadata-tools/src/types.ts
new file mode 100644
index 000000000..2ccca4e14
--- /dev/null
+++ b/packages/metadata-tools/src/types.ts
@@ -0,0 +1,91 @@
+import type { OmniPointHardhat } from '@layerzerolabs/devtools-evm-hardhat'
+import type { OAppEnforcedOption } from '@layerzerolabs/ua-devtools'
+
+// [srcContract, dstContract, [requiredDVNs, [optionalDVNs, threshold]], [srcToDstConfirmations, dstToSrcConfirmations]], [enforcedOptionsSrcToDst, enforcedOptionsDstToSrc]
+export type TwoWayConfig = [
+ OmniPointHardhat, // srcContract
+ OmniPointHardhat, // dstContract
+ [string[], [string[], number] | []], // [requiredDVNs, [optionalDVNs, threshold]]
+ [number, number | undefined], // [srcToDstConfirmations, dstToSrcConfirmations]
+ [OAppEnforcedOption[] | undefined, OAppEnforcedOption[] | undefined], // [enforcedOptionsSrcToDst, enforcedOptionsDstToSrc]
+]
+
+export interface IMetadata {
+ [key: string]: {
+ created: string
+ updated: string
+ tableName: string
+ environment: string
+ blockExplorers?: { url: string }[]
+ deployments?: {
+ eid: string
+ chainKey: string
+ stage: string
+ version: number
+ endpoint?: { address: string }
+ relayerV2?: { address: string }
+ ultraLightNodeV2?: { address: string }
+ nonceContract?: { address: string }
+ executor?: { address: string }
+ deadDVN?: { address: string }
+ endpointV2?: { address: string }
+ sendUln302?: { address: string }
+ lzExecutor?: { address: string }
+ sendUln301?: { address: string }
+ receiveUln301?: { address: string }
+ receiveUln302?: { address: string }
+ }[]
+ chainDetails?: {
+ chainType: string
+ chainKey: string
+ nativeChainId?: number
+ chainLayer: string
+ chainStack?: string
+ nativeCurrency: {
+ name?: string
+ symbol: string
+ cgId?: string
+ cmcId: number
+ decimals: number
+ }
+ cgNetworkId?: string
+ shortName?: string
+ mainnetChainName?: string
+ name?: string
+ }
+ dvns?: {
+ [address: string]: {
+ version: number
+ canonicalName: string
+ id: string
+ deprecated?: boolean
+ lzReadCompatible?: boolean
+ }
+ }
+ rpcs?: { url: string; weight?: number }[]
+ addressToOApp?: {
+ [address: string]: {
+ id: string
+ canonicalName: string
+ type?: string
+ }
+ }
+ chainName: string
+ tokens?: {
+ [address: string]: {
+ symbol: string
+ cgId?: string
+ cmcId?: number
+ type: string
+ decimals: number
+ peggedTo?: {
+ symbol: string
+ chainName: string
+ address: string
+ programaticallyPegged?: boolean
+ }
+ }
+ }
+ chainKey: string
+ }
+}
diff --git a/packages/metadata-tools/test/__snapshots__/config-metadata.test.ts.snap b/packages/metadata-tools/test/__snapshots__/config-metadata.test.ts.snap
new file mode 100644
index 000000000..63a37c699
--- /dev/null
+++ b/packages/metadata-tools/test/__snapshots__/config-metadata.test.ts.snap
@@ -0,0 +1,90 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`config-metadata translatePathwayToConfig should be able to translate a pathway to a config 1`] = `
+[
+ {
+ "config": {
+ "enforcedOptions": undefined,
+ "receiveConfig": {
+ "ulnConfig": {
+ "confirmations": 1n,
+ "optionalDVNThreshold": 0,
+ "optionalDVNs": [],
+ "requiredDVNs": [
+ "0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467",
+ ],
+ },
+ },
+ "receiveLibraryConfig": {
+ "gracePeriod": 0n,
+ "receiveLibrary": "0x819F0FAF2cb1Fba15b9cB24c9A2BDaDb0f895daf",
+ },
+ "sendConfig": {
+ "executorConfig": {
+ "executor": "0xa7BFA9D51032F82D649A501B6a1f922FC2f7d4e3",
+ "maxMessageSize": 10000,
+ },
+ "ulnConfig": {
+ "confirmations": 1n,
+ "optionalDVNThreshold": 0,
+ "optionalDVNs": [],
+ "requiredDVNs": [
+ "0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467",
+ ],
+ },
+ },
+ "sendLibrary": "0x69BF5f48d2072DfeBc670A1D19dff91D0F4E8170",
+ },
+ "from": {
+ "contractName": "MyOFT",
+ "eid": 40106,
+ },
+ "to": {
+ "address": "HBTWw2VKNLuDBjg9e5dArxo5axJRX8csCEBcCo3CFdAy",
+ "eid": 40168,
+ },
+ },
+ {
+ "config": {
+ "enforcedOptions": undefined,
+ "receiveConfig": {
+ "ulnConfig": {
+ "confirmations": 1n,
+ "optionalDVNThreshold": 0,
+ "optionalDVNs": [],
+ "requiredDVNs": [
+ "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb",
+ ],
+ },
+ },
+ "receiveLibraryConfig": {
+ "gracePeriod": 0n,
+ "receiveLibrary": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH",
+ },
+ "sendConfig": {
+ "executorConfig": {
+ "executor": "AwrbHeCyniXaQhiJZkLhgWdUCteeWSGaSN1sTfLiY7xK",
+ "maxMessageSize": 10000,
+ },
+ "ulnConfig": {
+ "confirmations": 1n,
+ "optionalDVNThreshold": 0,
+ "optionalDVNs": [],
+ "requiredDVNs": [
+ "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb",
+ ],
+ },
+ },
+ "sendLibrary": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH",
+ },
+ "from": {
+ "address": "HBTWw2VKNLuDBjg9e5dArxo5axJRX8csCEBcCo3CFdAy",
+ "eid": 40168,
+ },
+ "to": {
+ "contractName": "MyOFT",
+ "eid": 40106,
+ },
+ },
+]
+`;
diff --git a/packages/metadata-tools/test/config-metadata.test.ts b/packages/metadata-tools/test/config-metadata.test.ts
new file mode 100644
index 000000000..67a4b8042
--- /dev/null
+++ b/packages/metadata-tools/test/config-metadata.test.ts
@@ -0,0 +1,108 @@
+import { DVNsToAddresses, translatePathwayToConfig } from '@/config-metadata'
+import { IMetadata } from '@/types'
+
+import fujiMetadata from './data/fuji.json'
+import solanaMainnetMetadata from './data/solana-mainnet.json'
+import solanaTestnetMetadata from './data/solana-testnet.json'
+
+describe('config-metadata', () => {
+ const metadata: IMetadata = {
+ fuji: fujiMetadata,
+ solana: solanaMainnetMetadata,
+ 'solana-testnet': solanaTestnetMetadata,
+ }
+
+ describe('translatePathwayToConfig', () => {
+ it('should be able to translate a pathway to a config', async () => {
+ const avalancheContract = {
+ eid: 40106,
+ contractName: 'MyOFT',
+ }
+
+ const solanaContract = {
+ eid: 40168,
+ address: 'HBTWw2VKNLuDBjg9e5dArxo5axJRX8csCEBcCo3CFdAy',
+ }
+
+ const translatedConfig = await translatePathwayToConfig(
+ [avalancheContract, solanaContract, [['LayerZero Labs'], []], [1, 1], [undefined, undefined]],
+ metadata
+ )
+
+ expect(translatedConfig).toMatchSnapshot()
+ })
+ })
+
+ describe('DVNsToAddresses', () => {
+ it('returns an empty array if no DVNs are provided', () => {
+ expect(DVNsToAddresses([], 'fuji', metadata)).toStrictEqual([])
+ })
+
+ it('should correctly parse DVN addresses', () => {
+ expect(DVNsToAddresses(['LayerZero Labs'], 'fuji', metadata)).toStrictEqual([
+ '0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467',
+ ])
+ })
+
+ it('sorts the EVM addresses', () => {
+ expect(
+ DVNsToAddresses(['LayerZero Labs', 'Nethermind', 'Google', 'Gitcoin'], 'fuji', metadata)
+ ).toStrictEqual([
+ '0x071fbf35b35d48afc3edf84f0397980c25531560',
+ '0x7883f83ea40a56137a63baf93bfee5b9b8c1c447',
+ '0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467',
+ '0xa4652582077afc447ea7c9e984d656ee4963fe95',
+ ])
+ })
+
+ it('sorts the Solana addresses', () => {
+ expect(
+ DVNsToAddresses(['LayerZero Labs', 'Nethermind', 'Paxos', 'Horizen', 'Google'], 'solana', metadata)
+ ).toStrictEqual([
+ '4HxXbLv37XrivKukEbofybpHr7C8HUGJzd4B5T9USpGh',
+ '4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb',
+ 'F7gu9kLcpn4bSTZn183mhn2RXUuMy7zckdxJZdUjuALw',
+ 'GPjyWr8vCotGuFubDpTxDxy9Vj1ZeEN4F2dwRmFiaGab',
+ 'HR9NQKK1ynW9NzgdM37dU5CBtqRHTukmbMKS7qkwSkHX',
+ ])
+ })
+
+ it('should not support hex string addresses', () => {
+ expect(() =>
+ DVNsToAddresses(['0xa4652582077afc447ea7c9e984d656ee4963fe95', 'LayerZero Labs'], 'fuji', metadata)
+ ).toThrow(
+ `Can't find DVN: "0xa4652582077afc447ea7c9e984d656ee4963fe95" on chainKey: "fuji". Double check you're using valid DVN canonical name (not an address).`
+ )
+ })
+
+ it('should not support Solana addresses', () => {
+ expect(() => DVNsToAddresses(['4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb'], 'solana', metadata)).toThrow(
+ `Can't find DVN: "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb" on chainKey: "solana". Double check you're using valid DVN canonical name (not an address).`
+ )
+ })
+
+ it('should throw error for invalid chain key', () => {
+ expect(() => DVNsToAddresses(['LayerZero Labs'], 'invalid_chain', metadata)).toThrow(
+ `Can't find DVNs for chainKey: "invalid_chain".`
+ )
+ })
+
+ it('should throw error for non-existent DVN name', () => {
+ expect(() => DVNsToAddresses(['Non Existent DVN'], 'fuji', metadata)).toThrow(
+ `Can't find DVN: "Non Existent DVN" on chainKey: "fuji". Double check you're using valid DVN canonical name (not an address).`
+ )
+ })
+
+ it('should be case sensitive for DVN names', () => {
+ expect(() => DVNsToAddresses(['layerzero labs'], 'fuji', metadata)).toThrow(
+ `Can't find DVN: "layerzero labs" on chainKey: "fuji". Double check you're using valid DVN canonical name (not an address).`
+ )
+ })
+
+ it('should handle duplicate DVN names', () => {
+ expect(() => DVNsToAddresses(['LayerZero Labs', 'LayerZero Labs'], 'fuji', metadata)).toThrow(
+ `Duplicate DVN name found: "LayerZero Labs".`
+ )
+ })
+ })
+})
diff --git a/packages/metadata-tools/test/data/fuji.json b/packages/metadata-tools/test/data/fuji.json
new file mode 100644
index 000000000..089cb6eeb
--- /dev/null
+++ b/packages/metadata-tools/test/data/fuji.json
@@ -0,0 +1,346 @@
+{
+ "created": "2024-12-12T03:31:20.000Z",
+ "updated": "2024-12-12T03:31:20.000Z",
+ "tableName": "layerzero-chain_metadata",
+ "environment": "testnet",
+ "blockExplorers": [
+ {
+ "url": "https://cchain.explorer.avax-test.network"
+ }
+ ],
+ "deployments": [
+ {
+ "ultraLightNode": {
+ "address": "0x0848B8AD17D4003dDe1f1B7eF1FdBA4B629Da97e"
+ },
+ "eid": "10106",
+ "relayer": {
+ "address": "0xd035e64324bc470ee872062D508DA9c2772f14b5"
+ },
+ "endpoint": {
+ "address": "0x93f54D755A063cE7bB9e6Ac47Eccc8e33411d706"
+ },
+ "chainKey": "fuji",
+ "stage": "testnet",
+ "relayerV2": {
+ "address": "0xA30444B26C171B27c6B3698544490Affa2e12119"
+ },
+ "ultraLightNodeV2": {
+ "address": "0xfDDAFFa49e71dA3ef0419a303a6888F94bB5Ba18"
+ },
+ "version": 1,
+ "nonceContract": {
+ "address": "0xB401d261F971E550FAeE4Bb0D28f92a30E812105"
+ }
+ },
+ {
+ "eid": "40106",
+ "chainKey": "fuji",
+ "stage": "testnet",
+ "executor": {
+ "address": "0xa7BFA9D51032F82D649A501B6a1f922FC2f7d4e3"
+ },
+ "endpointV2": {
+ "address": "0x6EDCE65403992e310A62460808c4b910D972f10f"
+ },
+ "sendUln302": {
+ "address": "0x69BF5f48d2072DfeBc670A1D19dff91D0F4E8170"
+ },
+ "lzExecutor": {
+ "address": "0x1356D9201036A216836925803512649d6BB2395e"
+ },
+ "sendUln301": {
+ "address": "0x184e24e31657Cf853602589fe5304b144a826c85"
+ },
+ "receiveUln301": {
+ "address": "0x91df17bF1Ced54c6169e1E24722C0a88a447cBAf"
+ },
+ "version": 2,
+ "receiveUln302": {
+ "address": "0x819F0FAF2cb1Fba15b9cB24c9A2BDaDb0f895daf"
+ }
+ }
+ ],
+ "chainDetails": {
+ "chainKey": "fuji",
+ "nativeChainId": 43113,
+ "chainLayer": "L1",
+ "nativeCurrency": {
+ "name": "Avalanche Token",
+ "symbol": "AVAX",
+ "cgId": "avalanche-2",
+ "cmcId": 5805,
+ "decimals": 18
+ },
+ "name": "Fuji",
+ "chainType": "evm",
+ "shortName": "Avalanche"
+ },
+ "dvns": {
+ "0xca5ab7adcd3ea879f1a1c4eee81eaccd250173e4": {
+ "version": 2,
+ "canonicalName": "Switchboard",
+ "id": "switchboard"
+ },
+ "0x8ca279897cde74350bd880737fd60c047d6d3d64": {
+ "version": 2,
+ "canonicalName": "Bitgo",
+ "id": "bitgo"
+ },
+ "0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467": {
+ "version": 2,
+ "canonicalName": "LayerZero Labs",
+ "id": "layerzero-labs"
+ },
+ "0x92cfdb3789693c2ae7225fcc2c263de94d630be4": {
+ "version": 1,
+ "canonicalName": "TSS",
+ "id": "tss"
+ },
+ "0xe0f3389bf8a8aa1576b420d888cd462483fdc2a0": {
+ "version": 2,
+ "canonicalName": "Delegate",
+ "id": "delegate"
+ },
+ "0xfde647565009b33b1df02689d5873bffff15d907": {
+ "version": 2,
+ "canonicalName": "Stablelab",
+ "id": "stablelab"
+ },
+ "0xdbec329a5e6d7fb0113eb0a098750d2afd61e9ae": {
+ "version": 2,
+ "canonicalName": "P2P",
+ "id": "p2p"
+ },
+ "0xefdd92121acb3acd6e2f09dd810752d8da3dfdaf": {
+ "version": 2,
+ "canonicalName": "Republic",
+ "id": "republic-crypto"
+ },
+ "0x071fbf35b35d48afc3edf84f0397980c25531560": {
+ "version": 2,
+ "canonicalName": "Gitcoin",
+ "id": "gitcoin"
+ },
+ "0xa4652582077afc447ea7c9e984d656ee4963fe95": {
+ "version": 2,
+ "canonicalName": "Google",
+ "id": "google-cloud"
+ },
+ "0x7883f83ea40a56137a63baf93bfee5b9b8c1c447": {
+ "version": 2,
+ "canonicalName": "Nethermind",
+ "id": "nethermind"
+ },
+ "0x0d88ab4c8e8f89d8d758cbd5a6373f86f7bd737b": {
+ "version": 2,
+ "canonicalName": "BWare",
+ "id": "bware-labs"
+ }
+ },
+ "rpcs": [
+ {
+ "url": "https://api.avax-test.network/ext/bc/C/rpc"
+ },
+ {
+ "url": "https://rpc.ankr.com/avalanche_fuji"
+ }
+ ],
+ "addressToOApp": {
+ "0x5164db46a18c8680393b6df36c0bcc724078a4d9": {
+ "id": "shibx",
+ "canonicalName": "SHIBX"
+ },
+ "0x88fee109bc31132ca518165e4383f927cb140eca": {
+ "id": "dexalot",
+ "canonicalName": "Dexalot"
+ },
+ "0xe9e30a0ad0d8af5cf2606ea720052e28d6fcbaaf": {
+ "id": "holograph",
+ "canonicalName": "Holograph"
+ },
+ "0xa4125191e017cdf143255371a9e056f83a839b42": {
+ "id": "beam-bridge",
+ "canonicalName": "Beam Bridge"
+ },
+ "0xc2b5190c4e766212eb0a7065acb623a4c003a4bc": {
+ "id": "swapsicle",
+ "canonicalName": "Swapsicle"
+ },
+ "0xc360540950f50376e20ec3c06a5d93adf2728daf": {
+ "id": "beam-bridge",
+ "canonicalName": "Beam Bridge"
+ },
+ "0xfa12ffef9d6f0b3f18c60b3d219b9e5136b81926": {
+ "id": "tradable",
+ "canonicalName": "Tradable"
+ },
+ "0x9038f55ca0e2af8c4413bfe2855b912116ee0be7": {
+ "id": "synthr",
+ "canonicalName": "SYNTHR"
+ },
+ "0xa67a22d0227a92fb40ed5b4d6aa8ed01e09e4b94": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0xd315ead5c0fc0fb87fdb8b1bb48323fb2ad7adaf": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x6f484eacd997d9880205af22f6a4881ea0e1ccd7": {
+ "id": "holograph",
+ "canonicalName": "Holograph"
+ },
+ "0x034697223c82c3abec358d0ccd68f5713fc21011": {
+ "id": "gh0stly-gh0sts",
+ "canonicalName": "Gh0stly Gh0sts"
+ },
+ "0x225436ba1b4096afb14c374b8d1c6fd666e2fb41": {
+ "id": "synthr",
+ "canonicalName": "SYNTHR"
+ },
+ "0x7e562c90c2ad0295e837b2b4a4b42301e19faa33": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x777c19834a1a2ff6353a1e9cfb7c799ed7943a11": {
+ "id": "holograph",
+ "canonicalName": "Holograph"
+ },
+ "0xbdb2d676b35ee4ed0862614572e9f375b06c4a9a": {
+ "id": "orderly-network",
+ "canonicalName": "Orderly Network"
+ },
+ "0x6175a322e284e6a5ff5f8bcdbe82d30b047e22d4": {
+ "id": "canto",
+ "canonicalName": "Canto"
+ },
+ "0x803305930c1bbae396d03f496a7bf53ad7fd4303": {
+ "id": "holograph",
+ "canonicalName": "Holograph"
+ },
+ "0xc9de4ee312b90d42e53377a0ca7ffc5c8bf2b490": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x9722c903eb9847bb88cd1e2391105171627ffc61": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x991a8980d07cc48e531727095b7145b662449f9f": {
+ "id": "hourglass",
+ "canonicalName": "Hourglass"
+ },
+ "0xa4c2ad773b62e42b577d96865af4608fc77b58f3": {
+ "id": "hourglass",
+ "canonicalName": "Hourglass"
+ },
+ "0xeadf4c87fa5ebdc5e925c09e989316199d42f108": {
+ "id": "volta-club",
+ "canonicalName": "Volta Club"
+ },
+ "0xb86dd73015590dc0bee11740aec3492727e44953": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x66cdc567924d04e94abaa4d8bbbb33ef73d7713a": {
+ "id": "beam-bridge",
+ "canonicalName": "Beam Bridge"
+ },
+ "0xc173624557f5c9b9c682eb82a04e1407d3794da6": {
+ "id": "lendvest",
+ "canonicalName": "Lendvest"
+ },
+ "0xa30444b26c171b27c6b3698544490affa2e12119": {
+ "id": "toinou-oft",
+ "canonicalName": "TOINOU OFT"
+ },
+ "0xf7a7fbf4edd64c9d0d8ff1149c1229cd38b2a261": {
+ "id": "tide-exchange",
+ "canonicalName": "Tide Exchange"
+ },
+ "0xcfa841d8bb654c4c23bf60a39428f170a7035f29": {
+ "id": "ethenanova-space",
+ "canonicalName": "Ethenanova Space"
+ },
+ "0x0b0f01f9214680cf1a67efabdd31d8281dc29551": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0xc9264255e1ae0cc80ceadd0056c63dc1caed28ad": {
+ "id": "holograph",
+ "canonicalName": "Holograph"
+ },
+ "0xdae4fa5e4a831931a94ef865ceb08f3d8640c6a0": {
+ "id": "beam-bridge",
+ "canonicalName": "Beam Bridge"
+ },
+ "0xeef44c57d2fe281f5e10592ae2db7f45a463ea3d": {
+ "id": "betswirl",
+ "canonicalName": "BetSwirl"
+ },
+ "0x1e9bc397180eb625b28f3464eade1c928df2a33b": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0x0936a04505ea9c6ede026c81ec4e3d527388b706": {
+ "id": "tapiocadao",
+ "canonicalName": "TapiocaDAO"
+ },
+ "0xb92de63eb7d8a652bf80385906812f92d49c5139": {
+ "id": "synthr",
+ "canonicalName": "SYNTHR"
+ },
+ "0xe42bd199bfe8beb3fb0cdcce72bbcd512b2ba35d": {
+ "id": "beam-bridge",
+ "canonicalName": "Beam Bridge"
+ },
+ "0x29fbc4e4092db862218c62a888a00f9521619230": {
+ "id": "stargate",
+ "canonicalName": "Stargate"
+ },
+ "0x18fac63ab1576141a9163b4d9cf3867123a6cead": {
+ "id": "hourglass",
+ "canonicalName": "Hourglass"
+ },
+ "0xf1e06e45913ec0dc5856232e022e0f003c7b2b3f": {
+ "id": "tutorial",
+ "canonicalName": "LayerZero Tutorial"
+ },
+ "0x24e77cd450cb18eb71762273412d1a59d6df425b": {
+ "id": "term-finance",
+ "canonicalName": "Term Finance"
+ },
+ "0x42443226e8f55f27c5bd4e33a0138f9fd21b0de8": {
+ "id": "layersync",
+ "canonicalName": "LayerSync"
+ },
+ "0xc27a0e3e938ea734c379635b0107a8fe7d520f33": {
+ "id": "synthr",
+ "canonicalName": "SYNTHR"
+ },
+ "0x40174bf6df1a49d8faa84dd1c6440ab59371116e": {
+ "id": "swapsicle",
+ "canonicalName": "Swapsicle"
+ },
+ "0x0b78fd46cfae0ab2d3463ae7a384b81ff6e1bb43": {
+ "id": "tradable",
+ "canonicalName": "Tradable"
+ },
+ "0x4a339b39fe35913f8e809949eeff6bc96796820d": {
+ "id": "layer3",
+ "canonicalName": "Layer3"
+ },
+ "0x5788ecaa5e93485bb657828580d18790794729e7": {
+ "id": "hourglass",
+ "canonicalName": "Hourglass"
+ },
+ "0xbec70f2e023c823442cf2d21b95ea21ff7575267": {
+ "id": "cashmere",
+ "canonicalName": "CashmereLabs"
+ }
+ },
+ "chainName": "avalanche",
+ "tokens": {},
+ "chainKey": "fuji"
+}
diff --git a/packages/metadata-tools/test/data/solana-mainnet.json b/packages/metadata-tools/test/data/solana-mainnet.json
new file mode 100644
index 000000000..36745da49
--- /dev/null
+++ b/packages/metadata-tools/test/data/solana-mainnet.json
@@ -0,0 +1,117 @@
+{
+ "created": "2024-12-12T03:31:22.000Z",
+ "updated": "2024-12-12T03:31:22.000Z",
+ "tableName": "layerzero-chain_metadata",
+ "environment": "mainnet",
+ "blockExplorers": [
+ {
+ "url": "https://explorer.solana.com"
+ }
+ ],
+ "deployments": [
+ {
+ "eid": "30168",
+ "chainKey": "solana",
+ "stage": "mainnet",
+ "pricefeed": {
+ "address": "8ahPGPjEbpgGaZx2NV1iG5Shj7TDwvsjkEDcGWjt94TP"
+ },
+ "executor": {
+ "address": "AwrbHeCyniXaQhiJZkLhgWdUCteeWSGaSN1sTfLiY7xK"
+ },
+ "endpointV2": {
+ "address": "76y77prsiCMvXMjuoZ5VRrhG5qYBrUMYTE5WgHqgjEn6"
+ },
+ "sendUln302": {
+ "address": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH"
+ },
+ "blocked_messagelib": {
+ "address": "2XrYqmhBMPJgDsb4SVbjV1PnJBprurd5bzRCkHwiFCJB"
+ },
+ "version": 2,
+ "receiveUln302": {
+ "address": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH"
+ },
+ "dvn": {
+ "address": "HtEYV4xB4wvsj5fgTkcfuChYpvGYzgzwvNhgDZQNh7wW"
+ }
+ }
+ ],
+ "chainDetails": {
+ "chainType": "solana",
+ "chainKey": "solana",
+ "chainLayer": "L1",
+ "nativeCurrency": {
+ "symbol": "SOL",
+ "cgId": "solana",
+ "cmcId": 5426,
+ "decimals": 9
+ },
+ "cgNetworkId": "solana"
+ },
+ "dvns": {
+ "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb": {
+ "version": 2,
+ "canonicalName": "LayerZero Labs",
+ "id": "layerzero-labs"
+ },
+ "GPjyWr8vCotGuFubDpTxDxy9Vj1ZeEN4F2dwRmFiaGab": {
+ "version": 2,
+ "canonicalName": "Nethermind",
+ "id": "nethermind"
+ },
+ "4HxXbLv37XrivKukEbofybpHr7C8HUGJzd4B5T9USpGh": {
+ "version": 2,
+ "canonicalName": "Paxos",
+ "id": "paxos"
+ },
+ "HR9NQKK1ynW9NzgdM37dU5CBtqRHTukmbMKS7qkwSkHX": {
+ "version": 2,
+ "canonicalName": "Horizen",
+ "id": "horizen-labs"
+ },
+ "F7gu9kLcpn4bSTZn183mhn2RXUuMy7zckdxJZdUjuALw": {
+ "version": 2,
+ "canonicalName": "Google",
+ "id": "google-cloud"
+ }
+ },
+ "rpcs": [
+ {
+ "url": "https://api.mainnet-beta.solana.com"
+ }
+ ],
+ "addressToOApp": {
+ "auvw19qwit2bxzqcspgzlsbq2ziqosvrytnxe8uzsegh": {
+ "id": "paypal",
+ "canonicalName": "PayPal"
+ },
+ "4x3oqtx4mhjtkgbexdzbttslz9cuwo5wan2uchauthts": {
+ "id": "ethena",
+ "canonicalName": "Ethena"
+ },
+ "2uib9iipugq6rqyapftnydtpdfkaod2hmwpl9s1fs2ew": {
+ "id": "ox-fun",
+ "canonicalName": "OX.Fun"
+ },
+ "anq6ibnkc2xayc2goqhnzrsodh2kfqtejj7s3j8je7js": {
+ "id": "dogwifhat",
+ "canonicalName": "DogWifHat ($WIF)"
+ },
+ "9su66tvuugjjabajvnmfumz3zzhfrzdrsccxqqd1myaq": {
+ "id": "metalcore",
+ "canonicalName": "MetalCore"
+ },
+ "d27yp9ir2uagd8bkbbwrhek6moosqu353njm3svmevxw": {
+ "id": "ethena",
+ "canonicalName": "Ethena"
+ },
+ "d2hziynfqns9ygnrodtk7zajkjxc68139niz1mmd8aae": {
+ "id": "ethena",
+ "canonicalName": "Ethena"
+ }
+ },
+ "chainName": "solana",
+ "tokens": {},
+ "chainKey": "solana"
+}
diff --git a/packages/metadata-tools/test/data/solana-testnet.json b/packages/metadata-tools/test/data/solana-testnet.json
new file mode 100644
index 000000000..321fe1619
--- /dev/null
+++ b/packages/metadata-tools/test/data/solana-testnet.json
@@ -0,0 +1,74 @@
+{
+ "created": "2024-12-12T03:31:22.000Z",
+ "updated": "2024-12-12T03:31:22.000Z",
+ "tableName": "layerzero-chain_metadata",
+ "environment": "testnet",
+ "blockExplorers": [
+ {
+ "url": "https://explorer.solana.com"
+ }
+ ],
+ "deployments": [
+ {
+ "eid": "40168",
+ "chainKey": "solana-testnet",
+ "stage": "testnet",
+ "pricefeed": {
+ "address": "8ahPGPjEbpgGaZx2NV1iG5Shj7TDwvsjkEDcGWjt94TP"
+ },
+ "executor": {
+ "address": "AwrbHeCyniXaQhiJZkLhgWdUCteeWSGaSN1sTfLiY7xK"
+ },
+ "endpointV2": {
+ "address": "76y77prsiCMvXMjuoZ5VRrhG5qYBrUMYTE5WgHqgjEn6"
+ },
+ "sendUln302": {
+ "address": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH"
+ },
+ "blocked_messagelib": {
+ "address": "2XrYqmhBMPJgDsb4SVbjV1PnJBprurd5bzRCkHwiFCJB"
+ },
+ "version": 2,
+ "receiveUln302": {
+ "address": "7a4WjyR8VZ7yZz5XJAKm39BUGn5iT9CKcv2pmG9tdXVH"
+ },
+ "dvn": {
+ "address": "HtEYV4xB4wvsj5fgTkcfuChYpvGYzgzwvNhgDZQNh7wW"
+ }
+ }
+ ],
+ "chainDetails": {
+ "chainKey": "solana-testnet",
+ "nativeChainId": 2,
+ "chainLayer": "L1",
+ "nativeCurrency": {
+ "name": "SOL",
+ "symbol": "SOL",
+ "cgId": "solana",
+ "cmcId": 5426,
+ "decimals": 9
+ },
+ "name": "Solana",
+ "chainType": "solana",
+ "shortName": "Solana testnet"
+ },
+ "dvns": {
+ "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb": {
+ "version": 2,
+ "canonicalName": "LayerZero Labs",
+ "id": "layerzero-labs"
+ },
+ "4HxXbLv37XrivKukEbofybpHr7C8HUGJzd4B5T9USpGh": {
+ "version": 2,
+ "canonicalName": "Paxos",
+ "id": "paxos"
+ }
+ },
+ "rpcs": [
+ {
+ "url": "https://api.devnet.solana.com"
+ }
+ ],
+ "chainName": "solana",
+ "chainKey": "solana-testnet"
+}
diff --git a/packages/metadata-tools/tsconfig.json b/packages/metadata-tools/tsconfig.json
new file mode 100644
index 000000000..76ada60be
--- /dev/null
+++ b/packages/metadata-tools/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../../tsconfig.json",
+ "exclude": ["dist", "node_modules"],
+ "include": ["src", "test", "*.config.ts"],
+ "compilerOptions": {
+ "module": "commonjs",
+ "types": ["node", "jest"],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "files": []
+}
diff --git a/packages/metadata-tools/tsup.config.ts b/packages/metadata-tools/tsup.config.ts
new file mode 100644
index 000000000..ff3c6da84
--- /dev/null
+++ b/packages/metadata-tools/tsup.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from 'tsup'
+
+export default defineConfig([
+ {
+ entry: ['src/index.ts', 'src/type-extensions.ts', 'src/tasks/index.ts'],
+ outDir: './dist',
+ clean: true,
+ dts: true,
+ sourcemap: true,
+ splitting: false,
+ treeshake: true,
+ format: ['esm', 'cjs'],
+ loader: {
+ '.conf': 'text',
+ },
+ },
+])
diff --git a/packages/toolbox-hardhat/types/index.d.ts b/packages/toolbox-hardhat/types/index.d.ts
index 7558145da..69566b51a 100644
--- a/packages/toolbox-hardhat/types/index.d.ts
+++ b/packages/toolbox-hardhat/types/index.d.ts
@@ -19,6 +19,7 @@ export type {
// We also re-export all the relevant types from ua-devtools
export type {
OwnableNodeConfig,
+ OAppEnforcedOption,
OAppReceiveConfig,
OAppReceiveLibraryConfig,
OAppSendConfig,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b5a4edb7f..38bffa64b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1544,7 +1544,7 @@ importers:
version: 10.9.2(@swc/core@1.4.0)(@types/node@18.18.14)(typescript@5.5.3)
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -1678,7 +1678,7 @@ importers:
version: 10.9.2(@swc/core@1.4.0)(@types/node@18.18.14)(typescript@5.5.3)
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -1791,7 +1791,7 @@ importers:
version: 10.9.2(@swc/core@1.4.0)(@types/node@18.18.14)(typescript@5.5.3)
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -2233,6 +2233,36 @@ importers:
specifier: ^3.22.4
version: 3.22.4
+ packages/metadata-tools:
+ devDependencies:
+ '@layerzerolabs/devtools-evm-hardhat':
+ specifier: ~2.0.3
+ version: link:../devtools-evm-hardhat
+ '@layerzerolabs/ua-devtools':
+ specifier: ~3.0.1
+ version: link:../ua-devtools
+ '@swc/core':
+ specifier: ^1.4.0
+ version: 1.4.0
+ '@swc/jest':
+ specifier: ^0.2.36
+ version: 0.2.36(@swc/core@1.4.0)
+ '@types/jest':
+ specifier: ^29.5.12
+ version: 29.5.12
+ jest:
+ specifier: ^29.7.0
+ version: 29.7.0(@types/node@18.18.14)(ts-node@10.9.2)
+ tslib:
+ specifier: ~2.6.2
+ version: 2.6.3
+ tsup:
+ specifier: ~8.0.1
+ version: 8.0.1(@swc/core@1.4.0)(typescript@5.5.3)
+ typescript:
+ specifier: ^5.4.4
+ version: 5.5.3
+
packages/oapp-alt-evm:
dependencies:
ethers:
@@ -2781,7 +2811,7 @@ importers:
version: 2.6.2
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -2863,7 +2893,7 @@ importers:
version: 2.6.2
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -2887,7 +2917,7 @@ importers:
version: 2.6.3
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -3908,7 +3938,7 @@ importers:
version: 2.6.2
tsup:
specifier: ~8.0.1
- version: 8.0.1(ts-node@10.9.2)(typescript@5.5.3)
+ version: 8.0.1(@swc/core@1.4.0)(ts-node@10.9.2)(typescript@5.5.3)
typescript:
specifier: ^5.4.4
version: 5.5.3
@@ -13276,7 +13306,7 @@ packages:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.2
- ignore: 5.3.1
+ ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
dev: true
@@ -18366,46 +18396,7 @@ packages:
bundle-require: 4.0.2(esbuild@0.19.11)
cac: 6.7.14
chokidar: 3.6.0
- debug: 4.3.5
- esbuild: 0.19.11
- execa: 5.1.1
- globby: 11.1.0
- joycon: 3.1.1
- postcss-load-config: 4.0.2(ts-node@10.9.2)
- resolve-from: 5.0.0
- rollup: 4.9.6
- source-map: 0.8.0-beta.0
- sucrase: 3.35.0
- tree-kill: 1.2.2
- typescript: 5.5.3
- transitivePeerDependencies:
- - supports-color
- - ts-node
- dev: true
-
- /tsup@8.0.1(ts-node@10.9.2)(typescript@5.5.3):
- resolution: {integrity: sha512-hvW7gUSG96j53ZTSlT4j/KL0q1Q2l6TqGBFc6/mu/L46IoNWqLLUzLRLP1R8Q7xrJTmkDxxDoojV5uCVs1sVOg==}
- engines: {node: '>=18'}
- hasBin: true
- peerDependencies:
- '@microsoft/api-extractor': ^7.36.0
- '@swc/core': ^1
- postcss: ^8.4.12
- typescript: '>=4.5.0'
- peerDependenciesMeta:
- '@microsoft/api-extractor':
- optional: true
- '@swc/core':
- optional: true
- postcss:
- optional: true
- typescript:
- optional: true
- dependencies:
- bundle-require: 4.0.2(esbuild@0.19.11)
- cac: 6.7.14
- chokidar: 3.6.0
- debug: 4.3.5
+ debug: 4.3.7
esbuild: 0.19.11
execa: 5.1.1
globby: 11.1.0
diff --git a/turbo.json b/turbo.json
index 95af4caa5..0565ae9a3 100644
--- a/turbo.json
+++ b/turbo.json
@@ -53,6 +53,7 @@
"LZ_ENABLE_NATIVE_EXAMPLE",
"LZ_ENABLE_MINTBURN_EXAMPLE",
"LZ_ENABLE_UPGRADEABLE_EXAMPLE",
+ "LZ_METADATA_URL",
"LAYERZERO_EXAMPLES_REPOSITORY_URL",
"LAYERZERO_EXAMPLES_REPOSITORY_REF",