diff --git a/.changeset/three-nights-decide.md b/.changeset/three-nights-decide.md new file mode 100644 index 000000000..297255c49 --- /dev/null +++ b/.changeset/three-nights-decide.md @@ -0,0 +1,11 @@ +--- +'@solana/transaction-messages': minor +'@solana/instruction-plans': minor +'@solana/transactions': minor +'@solana/signers': minor +'@solana/kit': minor +--- + +Return more precise types from transaction message functions + +Deprecate `BaseTransactionMessage` in favour of `TransactionMessage` diff --git a/packages/kit/src/__typetests__/scenarios/transaction-message-decompile-modify-typetest.ts b/packages/kit/src/__typetests__/scenarios/transaction-message-decompile-modify-typetest.ts new file mode 100644 index 000000000..ef8779a41 --- /dev/null +++ b/packages/kit/src/__typetests__/scenarios/transaction-message-decompile-modify-typetest.ts @@ -0,0 +1,66 @@ +// [DESCRIBE] A scenario testing the types of transaction-message functionality +// Based on discussion/examples from https://github.com/anza-xyz/kit/pull/1103 + +import { Address } from '@solana/addresses'; +import { pipe } from '@solana/functional'; +import { Instruction } from '@solana/instructions'; +import { GetMultipleAccountsApi, Rpc } from '@solana/rpc'; +import { setTransactionMessageFeePayerSigner, TransactionSigner } from '@solana/signers'; +import { + appendTransactionMessageInstruction, + appendTransactionMessageInstructions, + BlockhashLifetimeConstraint, + CompiledTransactionMessage, + CompiledTransactionMessageWithLifetime, + prependTransactionMessageInstruction, + prependTransactionMessageInstructions, + setTransactionMessageFeePayer, + setTransactionMessageLifetimeUsingBlockhash, + setTransactionMessageLifetimeUsingDurableNonce, + TransactionMessage, +} from '@solana/transaction-messages'; + +import { decompileTransactionMessageFetchingLookupTables } from '../../decompile-transaction-message-fetching-lookup-tables'; + +const compiledTransactionMessage = null as unknown as CompiledTransactionMessage & + CompiledTransactionMessageWithLifetime; +const rpc = null as unknown as Rpc; + +type TransactionMessageNotLegacy = Exclude; + +void (async () => { + const transactionMessage = await decompileTransactionMessageFetchingLookupTables(compiledTransactionMessage, rpc); + + // @ts-expect-error Transaction has an unknown version + transactionMessage satisfies TransactionMessageNotLegacy; + if (transactionMessage.version === 0) { + // It typechecks when the transaction message is known to be v0 + transactionMessage satisfies TransactionMessageNotLegacy; + } + + // We update the transaction message using update functions to ensure the types flow correctly + const blockhash = null as unknown as BlockhashLifetimeConstraint; + const durableNonce = null as unknown as Parameters[0]; + const feePayer = null as unknown as Address; + const instruction = null as unknown as Instruction; + const signer = null as unknown as TransactionSigner; + + const updatedMessage = pipe( + transactionMessage, + m => setTransactionMessageLifetimeUsingBlockhash(blockhash, m), + m => setTransactionMessageLifetimeUsingDurableNonce(durableNonce, m), + m => setTransactionMessageFeePayer(feePayer, m), + m => appendTransactionMessageInstruction(instruction, m), + m => appendTransactionMessageInstructions([instruction], m), + m => prependTransactionMessageInstruction(instruction, m), + m => prependTransactionMessageInstructions([instruction], m), + m => setTransactionMessageFeePayerSigner(signer, m), + ); + + // @ts-expect-error Transaction has an unknown version + updatedMessage satisfies TransactionMessageNotLegacy; + if (updatedMessage.version === 0) { + // It typechecks when the transaction message is known to be v0 + updatedMessage satisfies TransactionMessageNotLegacy; + } +})();