From c7e8dacf082cbbdb59fff6a8e292af7bb8b12ef7 Mon Sep 17 00:00:00 2001 From: Bhavi Dhingra Date: Thu, 22 Oct 2026 13:47:26 +0530 Subject: [PATCH] feat(sdk-core): forward SOL intent wire version (Refs: CHALO-1603) prebuildTransaction builds the payment intent from an explicit literal, so version was dropped before populateIntent and every v1 payment request silently built a v0 envelope. Add version (0 | 1) to PrebuildTransactionOptions, PrebuildTransactionWithIntentOptions and PopulatedIntent, forward it in the payment literal, and copy it onto the intent in Sol.setCoinSpecificFieldsInIntent (the only coin-level seam populateIntent exposes). --- .../src/lib/v1CustomInstructionBuilder.ts | 18 +++++++++---- modules/sdk-coin-sol/src/sol.ts | 6 +++++ .../test/unit/solIntentVersion.ts | 27 +++++++++++++++++++ .../sdk-core/src/bitgo/utils/tss/baseTypes.ts | 9 +++++++ modules/sdk-core/src/bitgo/wallet/iWallet.ts | 6 +++++ modules/sdk-core/src/bitgo/wallet/wallet.ts | 2 ++ 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 modules/sdk-coin-sol/test/unit/solIntentVersion.ts diff --git a/modules/sdk-coin-sol/src/lib/v1CustomInstructionBuilder.ts b/modules/sdk-coin-sol/src/lib/v1CustomInstructionBuilder.ts index 8d8717ed6c8..c87a2c54186 100644 --- a/modules/sdk-coin-sol/src/lib/v1CustomInstructionBuilder.ts +++ b/modules/sdk-coin-sol/src/lib/v1CustomInstructionBuilder.ts @@ -5,15 +5,23 @@ import { V1TransactionBuilder } from './v1TransactionBuilder'; /** * Transaction builder for Solana v1 (SIMD-0296/0385) custom instructions. * - * Concrete subclass of the abstract {@link V1TransactionBuilder} for `customTx` - * intents — the surface Wallet Platform instantiates to assemble v1 transactions - * from a client-supplied envelope: feed each envelope instruction as a web3.js - * `TransactionInstruction` via {@link V1TransactionBuilder.addInstruction}, set the - * fee payer via {@link V1TransactionBuilder.sender}, optional durable nonce via + * Concrete subclass of the abstract {@link V1TransactionBuilder} for locally-built + * `customTx` transactions: feed each instruction as a web3.js `TransactionInstruction` + * via {@link V1TransactionBuilder.addInstruction}, set the fee payer via + * {@link V1TransactionBuilder.sender}, optional durable nonce via * {@link V1TransactionBuilder.nonce}, and the v1 config via * {@link V1TransactionBuilder.transactionConfig}. The builder owns the * `AdvanceNonceAccount` injection, the message compile, and the message-signer-order * signature assembly. + * + * @remarks NOT reachable through Wallet Platform. Platform-mediated sends reject + * client-supplied v1 envelopes fail-closed (`solVersionedTransactionData.version === 1` + * → 400 "v1 customTx envelopes are not supported"), and the platform never built a v1 + * customTx wire: even before that rejection the route validated the envelope and threw + * "v1 transaction build/submit not yet supported". For platform sends, put `version: 1` + * on a structured payment / confidentialTransfer intent — the platform builds v1 + * server-side via {@link V1PaymentBuilder} / `ConfidentialTransferBuilder`. This builder + * is only for direct-SDK callers that sign and broadcast themselves. */ export class V1CustomInstructionBuilder extends V1TransactionBuilder { constructor(_coinConfig: Readonly) { diff --git a/modules/sdk-coin-sol/src/sol.ts b/modules/sdk-coin-sol/src/sol.ts index a2f7844315b..09a5fff3b74 100644 --- a/modules/sdk-coin-sol/src/sol.ts +++ b/modules/sdk-coin-sol/src/sol.ts @@ -2255,5 +2255,11 @@ export class Sol extends BaseCoin { if (params.solVersionedTransactionData) { intent.solVersionedTransactionData = params.solVersionedTransactionData; } + + // Wire-version marker for structured intents (SIMD-0296/0385). Wallet Platform + // selects the v1 server-side builder when the payment intent carries version: 1. + if (params.version !== undefined) { + intent.version = params.version; + } } } diff --git a/modules/sdk-coin-sol/test/unit/solIntentVersion.ts b/modules/sdk-coin-sol/test/unit/solIntentVersion.ts new file mode 100644 index 00000000000..9de4d9ba8f0 --- /dev/null +++ b/modules/sdk-coin-sol/test/unit/solIntentVersion.ts @@ -0,0 +1,27 @@ +import * as should from 'should'; +import { BitGoAPI } from '@bitgo/sdk-api'; +import { Tsol } from '../../src'; + +describe('Sol.setCoinSpecificFieldsInIntent — SIMD-0296/0385 wire version', function () { + const bitgo = new BitGoAPI({ env: 'test' }); + bitgo.register('tsol', Tsol.createInstance); + const sol = bitgo.coin('tsol') as any; + + it('forwards version: 1 onto the intent', function () { + const intent: any = { intentType: 'payment' }; + sol.setCoinSpecificFieldsInIntent(intent, { intentType: 'payment', version: 1 } as any); + should.equal(intent.version, 1); + }); + + it('forwards version: 0 explicitly (v0 stays selectable)', function () { + const intent: any = { intentType: 'payment' }; + sol.setCoinSpecificFieldsInIntent(intent, { intentType: 'payment', version: 0 } as any); + should.equal(intent.version, 0); + }); + + it('leaves the intent without a version key when the option is absent', function () { + const intent: any = { intentType: 'payment' }; + sol.setCoinSpecificFieldsInIntent(intent, { intentType: 'payment' } as any); + should.equal('version' in intent, false); + }); +}); diff --git a/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts b/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts index b4b691c4241..2c0007d78e2 100644 --- a/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts +++ b/modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts @@ -382,6 +382,11 @@ export interface PrebuildTransactionWithIntentOptions extends IntentOptionsBase * Contains compiled instructions, Address Lookup Tables, and static account keys. */ solVersionedTransactionData?: SolVersionedTransactionData; + /** + * Solana wire-version marker for structured intents (SIMD-0296/0385): 1 selects the + * v1 envelope. Forwarded to the intent as `version`. + */ + version?: 0 | 1; /** * Custom transaction parameters for Aptos entry function calls. * Used with the customTx intent type for Aptos smart contract interactions. @@ -507,6 +512,10 @@ export interface PopulatedIntent extends PopulatedIntentBase, DefiIntentFields { * Contains compiled instructions, Address Lookup Tables, and static account keys. */ solVersionedTransactionData?: SolVersionedTransactionData; + /** + * Solana wire-version marker for structured intents (SIMD-0296/0385): 1 = v1 envelope. + */ + version?: 0 | 1; /** * Custom Aptos transaction for use with the customTx intent type. */ diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index c36c894977f..de5accf7614 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -173,6 +173,12 @@ export interface PrebuildTransactionOptions { * This feature is supported only for specific coins, like ADA. */ senderAddress?: string; + /** + * Solana wire-version marker for structured intents (SIMD-0296/0385): 1 builds the + * v1 envelope server-side, 0/absent keeps the v0 path. Forwarded to the intent as + * `version`; only the SOL coin consumes it. + */ + version?: 0 | 1; /** * User IDs of the Video ID approvers selected for this withdrawal. Each must be in the enterprise's diff --git a/modules/sdk-core/src/bitgo/wallet/wallet.ts b/modules/sdk-core/src/bitgo/wallet/wallet.ts index 1e05ebd6f06..d241bc57546 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -4540,6 +4540,8 @@ export class Wallet implements IWallet { feeOptions, feeToken: params.feeToken, custodianTransactionId: params.custodianTransactionId, + // SIMD-0296/0385 wire version for structured intents (SOL only). + version: params.version, unspents: params.unspents, senderAddress: params.senderAddress, isTestTransaction: params.isTestTransaction,