From 4a1b720343317a4f36d6650e907f7b363f5bae06 Mon Sep 17 00:00:00 2001 From: bangyro <229454856+bangyro@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:01:20 +0800 Subject: [PATCH 1/3] feat: legacy tx --- README.md | 3 +++ clients/js/src/cli/options.ts | 12 ++++++++++-- clients/js/src/cli/utils.ts | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 59cdeba..f243f9c 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ Using a buffer account you can split the metadata update into the uploading of t - `--rpc `: Custom RPC URL - `--export [address]`: Export transactions instead of running them. Optionally specify an override authority address. - `--export-encoding `: How to encode exported transactions. Choices: none, utf8, base58, base64 (default: base64) +- `--legacy`: Export legacy transactions instead of version 0 transactions. Requires `--export`. - `-h, --help`: Show help for command #### Squads Multisig @@ -143,6 +144,8 @@ npx @solana-program/program-metadata@latest set-buffer-authority --buffer --export --export-encoding base58 --close-buffer ``` +If your multisig only accepts legacy transactions, add `--legacy` to the export command. + 4. Sign the transaction in your multisig and send it ### Examples diff --git a/clients/js/src/cli/options.ts b/clients/js/src/cli/options.ts index 7d10b99..f74a20a 100644 --- a/clients/js/src/cli/options.ts +++ b/clients/js/src/cli/options.ts @@ -11,7 +11,8 @@ export type GlobalOptions = KeypairOption & PriorityFeesOption & RpcOption & ExportOption & - ExportEncodingOption; + ExportEncodingOption & + LegacyOption; export function setGlobalOptions(command: CustomCommand) { command @@ -20,7 +21,8 @@ export function setGlobalOptions(command: CustomCommand) { .addOption(priorityFeesOption) .addOption(rpcOption) .addOption(exportOption) - .addOption(exportEncodingOption); + .addOption(exportEncodingOption) + .addOption(legacyOption); } export type KeypairOption = { keypair?: string }; @@ -66,6 +68,12 @@ export const exportEncodingOption = new Option( (value: string): ExportEncoding => (value === 'instruction-list' ? 'instruction-list' : encodingParser(value)), ); +export type LegacyOption = { legacy: boolean }; +export const legacyOption = new Option( + '--legacy', + 'Export legacy transactions instead of version 0 transactions. Requires `--export`.', +).default(false); + export type WriteOptions = TextOption & UrlOption & AccountOption & diff --git a/clients/js/src/cli/utils.ts b/clients/js/src/cli/utils.ts index d8d9793..337acef 100644 --- a/clients/js/src/cli/utils.ts +++ b/clients/js/src/cli/utils.ts @@ -80,6 +80,10 @@ export class CustomCommand extends Command { export type Client = Awaited>; export async function getClient(options: GlobalOptions) { + if (options.legacy && !options.export) { + logErrorAndExit('The `--legacy` option requires the `--export` option.'); + } + const configs = getSolanaConfigs(); const rpcUrl = getRpcUrl(options, configs); const rpcSubscriptionsUrl = getRpcSubscriptionsUrl(rpcUrl, configs); @@ -92,7 +96,10 @@ export async function getClient(options: GlobalOptions) { solanaRpc({ rpcUrl, rpcSubscriptionsUrl, - transactionConfig: { microLamportsPerComputeUnit: options.priorityFees }, + transactionConfig: { + microLamportsPerComputeUnit: options.priorityFees, + version: options.legacy ? 'legacy' : 0, + }, }), ) .use(programMetadataProgram()) From eabd70b4ec2a749844f9538052ecbd640efc3deb Mon Sep 17 00:00:00 2001 From: bangyro <229454856+bangyro@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:19:15 +0800 Subject: [PATCH 2/3] docs: squads v3 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f243f9c..1f2c6ad 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,11 @@ npx @solana-program/program-metadata@latest set-buffer-authority --buffer --export --export-encoding base58 --close-buffer ``` -If your multisig only accepts legacy transactions, add `--legacy` to the export command. +Squads v3 only accepts legacy transactions. If your multisig is on Squads v3, add the `--legacy` flag so the exported transaction is a legacy transaction instead of a version 0 transaction: + +```bash +npx @solana-program/program-metadata@latest write idl --buffer --export --export-encoding base58 --close-buffer --legacy +``` 4. Sign the transaction in your multisig and send it From 654811b636dc0178355748cef907b0f7106e19dc Mon Sep 17 00:00:00 2001 From: bangyro <229454856+bangyro@users.noreply.github.com> Date: Wed, 26 Aug 2026 17:03:28 +0700 Subject: [PATCH 3/3] feat: change to tx version --- README.md | 6 +++--- clients/js/src/cli/options.ts | 29 +++++++++++++++++++++-------- clients/js/src/cli/utils.ts | 25 ++++++++++++++++--------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1f2c6ad..a55cf9e 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ Using a buffer account you can split the metadata update into the uploading of t - `--rpc `: Custom RPC URL - `--export [address]`: Export transactions instead of running them. Optionally specify an override authority address. - `--export-encoding `: How to encode exported transactions. Choices: none, utf8, base58, base64 (default: base64) -- `--legacy`: Export legacy transactions instead of version 0 transactions. Requires `--export`. +- `--tx-version `: Transaction version to build. Choices: legacy, 0 (default: 0) - `-h, --help`: Show help for command #### Squads Multisig @@ -144,10 +144,10 @@ npx @solana-program/program-metadata@latest set-buffer-authority --buffer --export --export-encoding base58 --close-buffer ``` -Squads v3 only accepts legacy transactions. If your multisig is on Squads v3, add the `--legacy` flag so the exported transaction is a legacy transaction instead of a version 0 transaction: +Squads v3 only accepts legacy transactions. If your multisig is on Squads v3, add `--tx-version legacy` so the exported transaction is a legacy transaction instead of a version 0 transaction: ```bash -npx @solana-program/program-metadata@latest write idl --buffer --export --export-encoding base58 --close-buffer --legacy +npx @solana-program/program-metadata@latest write idl --buffer --export --export-encoding base58 --close-buffer --tx-version legacy ``` 4. Sign the transaction in your multisig and send it diff --git a/clients/js/src/cli/options.ts b/clients/js/src/cli/options.ts index f74a20a..6a05545 100644 --- a/clients/js/src/cli/options.ts +++ b/clients/js/src/cli/options.ts @@ -1,5 +1,5 @@ import { type Address, type MicroLamports } from '@solana/kit'; -import { Option } from 'commander'; +import { InvalidArgumentError, Option } from 'commander'; import { Compression, Encoding, Format } from '../generated'; import { logErrorAndExit } from './logs'; @@ -12,7 +12,7 @@ export type GlobalOptions = KeypairOption & RpcOption & ExportOption & ExportEncodingOption & - LegacyOption; + TransactionVersionOption; export function setGlobalOptions(command: CustomCommand) { command @@ -22,7 +22,7 @@ export function setGlobalOptions(command: CustomCommand) { .addOption(rpcOption) .addOption(exportOption) .addOption(exportEncodingOption) - .addOption(legacyOption); + .addOption(transactionVersionOption); } export type KeypairOption = { keypair?: string }; @@ -68,11 +68,24 @@ export const exportEncodingOption = new Option( (value: string): ExportEncoding => (value === 'instruction-list' ? 'instruction-list' : encodingParser(value)), ); -export type LegacyOption = { legacy: boolean }; -export const legacyOption = new Option( - '--legacy', - 'Export legacy transactions instead of version 0 transactions. Requires `--export`.', -).default(false); +export type TransactionVersion = 'legacy' | 0; +export type TransactionVersionOption = { txVersion: TransactionVersion }; +export const transactionVersionOption = new Option( + '--tx-version ', + 'Transaction version to build. Squads v3 only accepts legacy transactions.', +) + .choices(['legacy', '0']) + .default(0, '0') + .argParser((value: string): TransactionVersion => { + switch (value) { + case 'legacy': + return 'legacy'; + case '0': + return 0; + default: + throw new InvalidArgumentError('Allowed choices are legacy, 0.'); + } + }); export type WriteOptions = TextOption & UrlOption & diff --git a/clients/js/src/cli/utils.ts b/clients/js/src/cli/utils.ts index 337acef..04fe533 100644 --- a/clients/js/src/cli/utils.ts +++ b/clients/js/src/cli/utils.ts @@ -35,7 +35,7 @@ import { TransactionPlanExecutor, TransactionSigner, } from '@solana/kit'; -import { solanaRpc } from '@solana/kit-plugin-rpc'; +import { solanaRpc, TransactionPlannerConfig } from '@solana/kit-plugin-rpc'; import { identity, payer } from '@solana/kit-plugin-signer'; import { Command } from 'commander'; import picocolors from 'picocolors'; @@ -80,10 +80,6 @@ export class CustomCommand extends Command { export type Client = Awaited>; export async function getClient(options: GlobalOptions) { - if (options.legacy && !options.export) { - logErrorAndExit('The `--legacy` option requires the `--export` option.'); - } - const configs = getSolanaConfigs(); const rpcUrl = getRpcUrl(options, configs); const rpcSubscriptionsUrl = getRpcSubscriptionsUrl(rpcUrl, configs); @@ -96,10 +92,7 @@ export async function getClient(options: GlobalOptions) { solanaRpc({ rpcUrl, rpcSubscriptionsUrl, - transactionConfig: { - microLamportsPerComputeUnit: options.priorityFees, - version: options.legacy ? 'legacy' : 0, - }, + transactionConfig: getTransactionConfig(options), }), ) .use(programMetadataProgram()) @@ -107,6 +100,20 @@ export async function getClient(options: GlobalOptions) { .use(cliRunOrExport(options)); } +/** + * Builds the transaction planner config for the requested transaction version. + * The config shape is discriminated by `version`: legacy and version 0 + * transactions express priority fees per compute unit, while version 1 will + * use a total fee in lamports. + */ +function getTransactionConfig(options: GlobalOptions): TransactionPlannerConfig { + switch (options.txVersion) { + case 'legacy': + case 0: + return { microLamportsPerComputeUnit: options.priorityFees, version: options.txVersion }; + } +} + /** * Plugin that attaches the parsed `~/.config/solana/cli/config.yml` to the * client so commands that need to introspect Solana config defaults can read