diff --git a/README.md b/README.md index 59cdeba..a55cf9e 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) +- `--tx-version `: Transaction version to build. Choices: legacy, 0 (default: 0) - `-h, --help`: Show help for command #### Squads Multisig @@ -143,6 +144,12 @@ 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 `--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 --tx-version legacy +``` + 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..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'; @@ -11,7 +11,8 @@ export type GlobalOptions = KeypairOption & PriorityFeesOption & RpcOption & ExportOption & - ExportEncodingOption; + ExportEncodingOption & + TransactionVersionOption; 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(transactionVersionOption); } export type KeypairOption = { keypair?: string }; @@ -66,6 +68,25 @@ export const exportEncodingOption = new Option( (value: string): ExportEncoding => (value === 'instruction-list' ? 'instruction-list' : encodingParser(value)), ); +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 & AccountOption & diff --git a/clients/js/src/cli/utils.ts b/clients/js/src/cli/utils.ts index d8d9793..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'; @@ -92,7 +92,7 @@ export async function getClient(options: GlobalOptions) { solanaRpc({ rpcUrl, rpcSubscriptionsUrl, - transactionConfig: { microLamportsPerComputeUnit: options.priorityFees }, + transactionConfig: getTransactionConfig(options), }), ) .use(programMetadataProgram()) @@ -100,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