From 3bb4d5ac2480ea4110ba2d212a57cadb94132265 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:49:18 -0800 Subject: [PATCH 01/10] include audit links --- docs/EXAMPLES_SPECS.md | 4 ++++ examples/oft-solana/README.md | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/docs/EXAMPLES_SPECS.md b/docs/EXAMPLES_SPECS.md index 4f45924ac8..e016767c19 100644 --- a/docs/EXAMPLES_SPECS.md +++ b/docs/EXAMPLES_SPECS.md @@ -122,6 +122,10 @@ Currently, this document will only detail the structure for the READMEs of the e - Goal: Resolve errors and setup issues - Contents: Link to general troubleshooting + local fixes + 16.7. **Audits** _(include only if audits exist)_ + - Goal: Link to audit reports for transparency + - Contents: Commit hash audited + links to audit report PDFs + Any sections that don't appear in the above list should be considered for removal. Before removing, ask the user for confirmation. diff --git a/examples/oft-solana/README.md b/examples/oft-solana/README.md index b773a558cd..721f07b969 100644 --- a/examples/oft-solana/README.md +++ b/examples/oft-solana/README.md @@ -537,3 +537,14 @@ Refer to [Verify the OFT Program](https://docs.layerzero.network/v2/developers/s ### Troubleshooting Refer to the [Solana Troubleshooting page on the LayerZero Docs](https://docs.layerzero.network/v2/developers/solana/troubleshooting/common-errors) to see how to solve common error when deploying Solana OFTs. + +### Audits + +For the Solana OFT program, the last change was via commit [6a07bb7](https://github.com/LayerZero-Labs/devtools/commit/6a07bb7e089349995ce4b30978512aff001cc131) + +The `6a07bb7` commit hash audited in the following 2 reports: + 1. SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf + 2. SolanaOFTandDevTools-Pashov-17SEPT2024.pdf + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Pashov-17SEPT2024.pdf + \ No newline at end of file From ae4939082cfc2ba66a103b76c96bd9ef3ad4d8d6 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:33:06 -0800 Subject: [PATCH 02/10] try removing --- examples/oapp-solana/hardhat.config.ts | 7 ------- examples/oft-solana/hardhat.config.ts | 7 ------- 2 files changed, 14 deletions(-) diff --git a/examples/oapp-solana/hardhat.config.ts b/examples/oapp-solana/hardhat.config.ts index e735ada7e8..0b31f5a97b 100644 --- a/examples/oapp-solana/hardhat.config.ts +++ b/examples/oapp-solana/hardhat.config.ts @@ -1,10 +1,3 @@ -// Force ts-node to use CommonJS mode -// This must be set before any imports -process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ - module: 'commonjs', - esModuleInterop: true, -}) - // Get the environment configuration from .env file // // To make use of automatic environment setup: diff --git a/examples/oft-solana/hardhat.config.ts b/examples/oft-solana/hardhat.config.ts index 9b21b274c8..1b5fc29d08 100644 --- a/examples/oft-solana/hardhat.config.ts +++ b/examples/oft-solana/hardhat.config.ts @@ -1,10 +1,3 @@ -// Force ts-node to use CommonJS mode -// This must be set before any imports -process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ - module: 'commonjs', - esModuleInterop: true, -}) - // Get the environment configuration from .env file // // To make use of automatic environment setup: From 7263ee4080b9d03c59d0bc082ac93d5938fa3488 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:48:15 -0800 Subject: [PATCH 03/10] lint fix --- examples/oft-solana/README.md | 11 ++++++++--- turbo.json | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/oft-solana/README.md b/examples/oft-solana/README.md index 721f07b969..b4d0b9db83 100644 --- a/examples/oft-solana/README.md +++ b/examples/oft-solana/README.md @@ -543,8 +543,13 @@ Refer to the [Solana Troubleshooting page on the LayerZero Docs](https://docs.la For the Solana OFT program, the last change was via commit [6a07bb7](https://github.com/LayerZero-Labs/devtools/commit/6a07bb7e089349995ce4b30978512aff001cc131) The `6a07bb7` commit hash audited in the following 2 reports: - 1. SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf + +1. SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf + + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf - 2. SolanaOFTandDevTools-Pashov-17SEPT2024.pdf + +2. SolanaOFTandDevTools-Pashov-17SEPT2024.pdf + + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Pashov-17SEPT2024.pdf - \ No newline at end of file diff --git a/turbo.json b/turbo.json index 420acc6970..b46c1fab48 100644 --- a/turbo.json +++ b/turbo.json @@ -49,6 +49,8 @@ "globalDependencies": ["tsconfig.json"], "globalEnv": ["NODE_ENV"], "globalPassThroughEnv": [ + "TS_NODE_FILES", + "TS_NODE_PROJECT", "LZ_DEVTOOLS_ENABLE_DEPLOY_LOGGING", "LZ_DEVTOOLS_ENABLE_SOLANA_TESTS", "LZ_ENABLE_EXPERIMENTAL_BATCHED_SEND", From 48f134ee3177ef092481de9b946124f777c41ff2 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:54:39 -0800 Subject: [PATCH 04/10] lint --- examples/oft-solana/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/oft-solana/README.md b/examples/oft-solana/README.md index b4d0b9db83..d9d812e5ef 100644 --- a/examples/oft-solana/README.md +++ b/examples/oft-solana/README.md @@ -546,10 +546,8 @@ The `6a07bb7` commit hash audited in the following 2 reports: 1. SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf - - - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Ottersec-24SEPT2024.pdf 2. SolanaOFTandDevTools-Pashov-17SEPT2024.pdf - - - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Pashov-17SEPT2024.pdf + - https://github.com/LayerZero-Labs/Audits/blob/main/audits/SolanaOFTandDevTools-Pashov-17SEPT2024.pdf From 8b44af39304590f35bee190757eafe1e8907a78f Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:05:47 -0800 Subject: [PATCH 05/10] fix 1155 --- .../lzapp-migration/tasks/solana/initConfig.ts | 14 ++++++++------ examples/oft-solana/tasks/solana/initConfig.ts | 14 ++++++++------ packages/devtools/src/flows/wire.ts | 8 +++++++- .../src/tasks/oapp/wire/index.ts | 7 +++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/examples/lzapp-migration/tasks/solana/initConfig.ts b/examples/lzapp-migration/tasks/solana/initConfig.ts index 794a4dbf21..95107d7ce3 100644 --- a/examples/lzapp-migration/tasks/solana/initConfig.ts +++ b/examples/lzapp-migration/tasks/solana/initConfig.ts @@ -25,9 +25,11 @@ interface Args { // This task will use the `initOFTAccounts` configurator that initializes the Solana accounts const initConfigTask = wireLikeTask('lz:oft:solana:init-config') as ConfigurableTaskDefinition -// This task will use the `initOFTAccounts` configurator that initializes the Solana accounts -initConfigTask - .setDescription('Initialize OFT accounts for Solana') - .setAction(async (args: Args, hre) => - hre.run(TASK_LZ_OAPP_WIRE, { ...args, isSolanaInitConfig: true, internalConfigurator: initOFTAccounts }) - ) +initConfigTask.setDescription('Initialize OFT accounts for Solana').setAction(async (args: Args, hre) => + hre.run(TASK_LZ_OAPP_WIRE, { + ...args, + isSolanaInitConfig: true, + internalConfigurator: initOFTAccounts, + noActionMessage: 'Pathway config already initialized, no action is necessary', + }) +) diff --git a/examples/oft-solana/tasks/solana/initConfig.ts b/examples/oft-solana/tasks/solana/initConfig.ts index 202d18a367..25b369098b 100644 --- a/examples/oft-solana/tasks/solana/initConfig.ts +++ b/examples/oft-solana/tasks/solana/initConfig.ts @@ -23,9 +23,11 @@ interface Args { // This task will use the `initOFTAccounts` configurator that initializes the Solana accounts const initConfigTask = wireLikeTask('lz:oft:solana:init-config') as ConfigurableTaskDefinition -// TODO: currently the message for 'already done' state is "OApp is already wired." which is misleading -> should be changed to "Pathway Config already initialized" -initConfigTask - .setDescription('Initialize OFT accounts for Solana') - .setAction(async (args: Args, hre) => - hre.run(TASK_LZ_OAPP_WIRE, { ...args, internalConfigurator: initOFTAccounts, isSolanaInitConfig: true }) - ) +initConfigTask.setDescription('Initialize OFT accounts for Solana').setAction(async (args: Args, hre) => + hre.run(TASK_LZ_OAPP_WIRE, { + ...args, + internalConfigurator: initOFTAccounts, + isSolanaInitConfig: true, + noActionMessage: 'Pathway config already initialized, no action is necessary', + }) +) diff --git a/packages/devtools/src/flows/wire.ts b/packages/devtools/src/flows/wire.ts index 2568201915..84500bb517 100644 --- a/packages/devtools/src/flows/wire.ts +++ b/packages/devtools/src/flows/wire.ts @@ -11,6 +11,11 @@ export interface CreateWireFlowArgs { logger?: Logger executeConfig: ConfigExecuteFlow signAndSend: SignAndSendFlow + /** + * Custom message to display when no transactions are needed. + * Defaults to "The OApp is wired, no action is necessary" + */ + noActionMessage?: string } export interface WireFlowArgs { @@ -25,6 +30,7 @@ export const createWireFlow = logger = createLogger(), executeConfig, signAndSend, + noActionMessage = 'The OApp is wired, no action is necessary', }: CreateWireFlowArgs) => async ({ graph, @@ -55,7 +61,7 @@ export const createWireFlow = // If there are no transactions that need to be executed, we'll just exit if (transactions.length === 0) { - logger.info(`The OApp is wired, no action is necessary`) + logger.info(noActionMessage) return [[], [], []] } diff --git a/packages/ua-devtools-evm-hardhat/src/tasks/oapp/wire/index.ts b/packages/ua-devtools-evm-hardhat/src/tasks/oapp/wire/index.ts index 4d345fd153..16207f73e8 100644 --- a/packages/ua-devtools-evm-hardhat/src/tasks/oapp/wire/index.ts +++ b/packages/ua-devtools-evm-hardhat/src/tasks/oapp/wire/index.ts @@ -58,6 +58,11 @@ interface TaskArgs { * Exclude connections that originate from the specified EndpointIds. */ skipConnectionsFromEids?: string[] + /** + * Custom message to display when no transactions are needed. + * Defaults to "The OApp is wired, no action is necessary" + */ + noActionMessage?: string } const action: ActionType = async ( @@ -74,6 +79,7 @@ const action: ActionType = async ( signAndSendSubtask = SUBTASK_LZ_SIGN_AND_SEND, outputFilename, skipConnectionsFromEids, + noActionMessage, }, hre ): Promise => { @@ -105,6 +111,7 @@ const action: ActionType = async ( // Then create the wire flow const wireFlow = createWireFlow({ logger, + noActionMessage, // We use hardhat subtasks to provide the option to override certain behaviors on a more granular level executeConfig: ({ graph }) => hre.run(configureSubtask, { graph } satisfies SubtaskConfigureTaskArgs), signAndSend: ({ transactions }) => { From 954f1d5a0cdee32e377a6ae3128de70a6bde5228 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:06:30 -0800 Subject: [PATCH 06/10] changeset --- .changeset/gorgeous-cobras-pull.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/gorgeous-cobras-pull.md diff --git a/.changeset/gorgeous-cobras-pull.md b/.changeset/gorgeous-cobras-pull.md new file mode 100644 index 0000000000..253cc4079d --- /dev/null +++ b/.changeset/gorgeous-cobras-pull.md @@ -0,0 +1,9 @@ +--- +"@layerzerolabs/ua-devtools-evm-hardhat": patch +"@layerzerolabs/lzapp-migration-example": patch +"@layerzerolabs/oapp-solana-example": patch +"@layerzerolabs/oft-solana-example": patch +"@layerzerolabs/devtools": patch +--- + +fix misleading message after running init-config From 9b9c9a8268c6dcb67b1ba4e5661f13b625e1fc50 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:27:43 -0800 Subject: [PATCH 07/10] update message --- examples/lzapp-migration/tasks/solana/initConfig.ts | 2 +- examples/oft-solana/tasks/solana/initConfig.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/lzapp-migration/tasks/solana/initConfig.ts b/examples/lzapp-migration/tasks/solana/initConfig.ts index 95107d7ce3..e49163070c 100644 --- a/examples/lzapp-migration/tasks/solana/initConfig.ts +++ b/examples/lzapp-migration/tasks/solana/initConfig.ts @@ -30,6 +30,6 @@ initConfigTask.setDescription('Initialize OFT accounts for Solana').setAction(as ...args, isSolanaInitConfig: true, internalConfigurator: initOFTAccounts, - noActionMessage: 'Pathway config already initialized, no action is necessary', + noActionMessage: 'Pathway config already initialized', }) ) diff --git a/examples/oft-solana/tasks/solana/initConfig.ts b/examples/oft-solana/tasks/solana/initConfig.ts index 25b369098b..c041cbcbe2 100644 --- a/examples/oft-solana/tasks/solana/initConfig.ts +++ b/examples/oft-solana/tasks/solana/initConfig.ts @@ -28,6 +28,6 @@ initConfigTask.setDescription('Initialize OFT accounts for Solana').setAction(as ...args, internalConfigurator: initOFTAccounts, isSolanaInitConfig: true, - noActionMessage: 'Pathway config already initialized, no action is necessary', + noActionMessage: 'Pathway config already initialized', }) ) From e7b05af7fcf1ac038662251ad6edeae5e6535549 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:28:10 -0800 Subject: [PATCH 08/10] fix --- examples/oapp-solana/tasks/solana/initConfig.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/oapp-solana/tasks/solana/initConfig.ts b/examples/oapp-solana/tasks/solana/initConfig.ts index c1b01905a7..95a65a62c1 100644 --- a/examples/oapp-solana/tasks/solana/initConfig.ts +++ b/examples/oapp-solana/tasks/solana/initConfig.ts @@ -24,9 +24,11 @@ interface Args { // This task will use the `initOFTAccounts` configurator that initializes the Solana accounts const initConfigTask = wireLikeTask('lz:oapp:solana:init-config') as ConfigurableTaskDefinition -// TODO: currently the message for 'already done' state is "OApp is already wired." which is misleading -> should be changed to "Pathway Config already initialized" -initConfigTask - .setDescription('Initialize OApp accounts for Solana') - .setAction(async (args: Args, hre) => - hre.run(TASK_LZ_OAPP_WIRE, { ...args, internalConfigurator: initOAppAccounts, isSolanaInitConfig: true }) - ) +initConfigTask.setDescription('Initialize OApp accounts for Solana').setAction(async (args: Args, hre) => + hre.run(TASK_LZ_OAPP_WIRE, { + ...args, + internalConfigurator: initOAppAccounts, + isSolanaInitConfig: true, + noActionMessage: 'Pathway config already initialized, no action is necessary', + }) +) From ab680e55ec0680d8fae5a9702e536cbdd35c8412 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:33:28 -0800 Subject: [PATCH 09/10] message --- examples/oapp-solana/tasks/solana/initConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/oapp-solana/tasks/solana/initConfig.ts b/examples/oapp-solana/tasks/solana/initConfig.ts index 95a65a62c1..d4dd6ca1cf 100644 --- a/examples/oapp-solana/tasks/solana/initConfig.ts +++ b/examples/oapp-solana/tasks/solana/initConfig.ts @@ -29,6 +29,6 @@ initConfigTask.setDescription('Initialize OApp accounts for Solana').setAction(a ...args, internalConfigurator: initOAppAccounts, isSolanaInitConfig: true, - noActionMessage: 'Pathway config already initialized, no action is necessary', + noActionMessage: 'Pathway config already initialized', }) ) From 607c6e1535bb68b0e55aa6465c3e246b595ab5e3 Mon Sep 17 00:00:00 2001 From: nazreen <10964594+nazreen@users.noreply.github.com> Date: Tue, 20 Jan 2026 10:39:01 -0800 Subject: [PATCH 10/10] when none deployed --- .../devtools-evm-hardhat/src/tasks/deploy.ts | 77 ++++++++++++++++++- .../deploy-all-missing-tag.exp | 3 +- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/packages/devtools-evm-hardhat/src/tasks/deploy.ts b/packages/devtools-evm-hardhat/src/tasks/deploy.ts index d45c83843a..d2ed0091e7 100644 --- a/packages/devtools-evm-hardhat/src/tasks/deploy.ts +++ b/packages/devtools-evm-hardhat/src/tasks/deploy.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config' -import type { ActionType } from 'hardhat/types' +import type { ActionType, HardhatRuntimeEnvironment } from 'hardhat/types' import { TASK_COMPILE } from 'hardhat/builtin-tasks/task-names' import { TASK_LZ_DEPLOY } from '@/constants/tasks' import { @@ -17,11 +17,57 @@ import { formatEid } from '@layerzerolabs/devtools' import { getEidsByNetworkName, getHreByNetworkName } from '@/runtime' import { types } from '@/cli' import { promptForText } from '@layerzerolabs/io-devtools' -import { Deployment } from 'hardhat-deploy/dist/types' +import { Deployment, DeployFunction } from 'hardhat-deploy/dist/types' import { assertDefinedNetworks, assertHardhatDeploy } from '@/internal/assertions' import { splitCommaSeparated } from '@layerzerolabs/devtools' import { isDeepEqual } from '@layerzerolabs/devtools' import { Stage, endpointIdToStage } from '@layerzerolabs/lz-definitions' +import { readdirSync, statSync } from 'fs' +import { join, extname } from 'path' + +/** + * Get all available tags from deploy scripts in the given deploy paths. + * Uses require() with ts-node/esm loader to handle TypeScript files. + */ +const getAvailableTagsFromDeployScripts = async (hre: HardhatRuntimeEnvironment): Promise> => { + const tags = new Set() + const deployPaths = hre.config.paths.deploy + + for (const deployPath of deployPaths) { + try { + const files = readdirSync(deployPath) + for (const file of files) { + const filePath = join(deployPath, file) + // Skip directories and non-script files + if (statSync(filePath).isDirectory()) { + continue + } + const ext = extname(file) + if (!['.js', '.ts'].includes(ext)) { + continue + } + + try { + // Use require which works with ts-node/register in hardhat context + // eslint-disable-next-line @typescript-eslint/no-var-requires + const deployScript = require(filePath) + const deployFunc: DeployFunction = deployScript.default ?? deployScript + if (deployFunc?.tags) { + for (const tag of deployFunc.tags) { + tags.add(tag) + } + } + } catch { + // Skip files that can't be imported + } + } + } catch { + // Skip paths that don't exist + } + } + + return tags +} interface TaskArgs { networks?: string[] @@ -166,6 +212,16 @@ const action: ActionType = async ( logger.warn(`Will use all deployment scripts`) } else { logger.info(`Will use deploy scripts tagged with ${selectedTags.join(', ')}`) + + // Check if selected tags match any available deploy script tags + const availableTags = await getAvailableTagsFromDeployScripts(hre) + const unmatchedTags = selectedTags.filter((tag) => !availableTags.has(tag)) + + if (unmatchedTags.length > 0) { + logger.warn( + `The following tags do not match any deploy scripts: ${unmatchedTags.join(', ')}. Available tags: ${[...availableTags].join(', ') || 'none'}` + ) + } } // Now we confirm with the user that they want to continue @@ -261,8 +317,23 @@ const action: ActionType = async ( error == null ? [] : [{ networkName, error }] ) - // If nothing went wrong we just exit + // We check whether any contracts were actually deployed + const totalContractsDeployed = Object.values(results).reduce( + (sum, { contracts }) => sum + Object.keys(contracts ?? {}).length, + 0 + ) + + // If nothing went wrong we check if any contracts were deployed if (errors.length === 0) { + if (totalContractsDeployed === 0) { + return ( + logger.warn( + `${printBoolean(false)} No contracts were deployed. This could mean the deploy script tags don't match any scripts, or all contracts were already deployed.` + ), + results + ) + } + return logger.info(`${printBoolean(true)} Your contracts are now deployed`), results } diff --git a/tests/devtools-evm-hardhat-test/test/task/deploy.test.expectations/deploy-all-missing-tag.exp b/tests/devtools-evm-hardhat-test/test/task/deploy.test.expectations/deploy-all-missing-tag.exp index fb6a053772..9ee5e380be 100755 --- a/tests/devtools-evm-hardhat-test/test/task/deploy.test.expectations/deploy-all-missing-tag.exp +++ b/tests/devtools-evm-hardhat-test/test/task/deploy.test.expectations/deploy-all-missing-tag.exp @@ -40,10 +40,11 @@ send -- "\r" expect "Will deploy 3 networks: britney, tango, vengaboys" expect "Will use deploy scripts tagged with MeNoExist" +expect "do not match any deploy scripts" expect "Do you want to continue?" send -- "\r" expect "Deploying..." -expect "Your contracts are now deployed" +expect "No contracts were deployed" expect eof