Skip to content

Commit 71cd84c

Browse files
committed
Document @solana/transaction-messages with TypeDoc
1 parent 6d5d34e commit 71cd84c

16 files changed

+523
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import { Address } from '@solana/addresses';
22

3+
/**
4+
* Represents a mapping of lookup table addresses to the addresses of the accounts that are stored
5+
* in them.
6+
*/
37
export type AddressesByLookupTableAddress = { [lookupTableAddress: Address]: Address[] };

Diff for: packages/transaction-messages/src/blockhash.ts

+82
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,62 @@ import { assertIsBlockhash, type Blockhash } from '@solana/rpc-types';
44
import { TransactionMessageWithDurableNonceLifetime } from './durable-nonce';
55
import { BaseTransactionMessage } from './transaction-message';
66

7+
/**
8+
* A constraint which, when applied to a transaction message, makes that transaction message
9+
* eligible to land on the network. The transaction message will continue to be eligible to land
10+
* until the network considers the `blockhash` to be expired.
11+
*
12+
* This can happen when the network proceeds past the `lastValidBlockHeight` for which the blockhash
13+
* is considered valid, or when the network switches to a fork where that blockhash is not present.
14+
*/
715
type BlockhashLifetimeConstraint = Readonly<{
16+
/**
17+
* A recent blockhash observed by the transaction proposer.
18+
*
19+
* The transaction message will be considered eligible to land until the network determines this
20+
* blockhash to be too old, or has switched to a fork where it is not present.
21+
*/
822
blockhash: Blockhash;
23+
/**
24+
* This is the block height beyond which the network will consider the blockhash to be too old
25+
* to make a transaction message eligible to land.
26+
*/
927
lastValidBlockHeight: bigint;
1028
}>;
1129

30+
/**
31+
* Represents a transaction message whose lifetime is defined by the age of the blockhash it
32+
* includes.
33+
*
34+
* Such a transaction can only be landed on the network if the current block height of the network
35+
* is less than or equal to the value of
36+
* `TransactionMessageWithBlockhashLifetime['lifetimeConstraint']['lastValidBlockHeight']`.
37+
*/
1238
export interface TransactionMessageWithBlockhashLifetime {
1339
readonly lifetimeConstraint: BlockhashLifetimeConstraint;
1440
}
1541

42+
/**
43+
* A type guard that returns `true` if the transaction message conforms to the
44+
* {@link TransactionMessageWithBlockhashLifetime} type, and refines its type for use in your
45+
* program.
46+
*
47+
* @example
48+
* ```ts
49+
* import { isTransactionMessageWithBlockhashLifetime } from '@solana/transaction-messages';
50+
*
51+
* if (isTransactionMessageWithBlockhashLifetime(message)) {
52+
* // At this point, `message` has been refined to a `TransactionMessageWithBlockhashLifetime`.
53+
* const { blockhash } = message.lifetimeConstraint;
54+
* const { value: blockhashIsValid } = await rpc.isBlockhashValid(blockhash).send();
55+
* setBlockhashIsValid(blockhashIsValid);
56+
* } else {
57+
* setError(
58+
* `${getSignatureFromTransaction(transaction)} does not have a blockhash-based lifetime`,
59+
* );
60+
* }
61+
* ```
62+
*/
1663
export function isTransactionMessageWithBlockhashLifetime(
1764
transactionMessage: BaseTransactionMessage | (BaseTransactionMessage & TransactionMessageWithBlockhashLifetime),
1865
): transactionMessage is BaseTransactionMessage & TransactionMessageWithBlockhashLifetime {
@@ -29,6 +76,28 @@ export function isTransactionMessageWithBlockhashLifetime(
2976
}
3077
}
3178

79+
/**
80+
* From time to time you might acquire a transaction message, that you expect to have a
81+
* blockhash-based lifetime, from an untrusted network API or user input. Use this function to
82+
* assert that such a transaction message actually has a blockhash-based lifetime.
83+
*
84+
* @example
85+
* ```ts
86+
* import { assertIsTransactionMessageWithBlockhashLifetime } from '@solana/transaction-messages';
87+
*
88+
* try {
89+
* // If this type assertion function doesn't throw, then
90+
* // Typescript will upcast `message` to `TransactionMessageWithBlockhashLifetime`.
91+
* assertIsTransactionMessageWithBlockhashLifetime(message);
92+
* // At this point, `message` is a `TransactionMessageWithBlockhashLifetime` that can be used
93+
* // with the RPC.
94+
* const { blockhash } = message.lifetimeConstraint;
95+
* const { value: blockhashIsValid } = await rpc.isBlockhashValid(blockhash).send();
96+
* } catch (e) {
97+
* // `message` turned out not to have a blockhash-based lifetime
98+
* }
99+
* ```
100+
*/
32101
export function assertIsTransactionMessageWithBlockhashLifetime(
33102
transactionMessage: BaseTransactionMessage | (BaseTransactionMessage & TransactionMessageWithBlockhashLifetime),
34103
): asserts transactionMessage is BaseTransactionMessage & TransactionMessageWithBlockhashLifetime {
@@ -37,6 +106,19 @@ export function assertIsTransactionMessageWithBlockhashLifetime(
37106
}
38107
}
39108

109+
/**
110+
* Given a blockhash and the last block height at which that blockhash is considered usable to land
111+
* transactions, this method will return a new transaction message having the same type as the one
112+
* supplied plus the `TransactionMessageWithBlockhashLifetime` type.
113+
*
114+
* @example
115+
* ```ts
116+
* import { setTransactionMessageLifetimeUsingBlockhash } from '@solana/transaction-messages';
117+
*
118+
* const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
119+
* const txMessageWithBlockhashLifetime = setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, txMessage);
120+
* ```
121+
*/
40122
export function setTransactionMessageLifetimeUsingBlockhash<
41123
TTransactionMessage extends BaseTransactionMessage & TransactionMessageWithDurableNonceLifetime,
42124
>(

Diff for: packages/transaction-messages/src/codecs/message.ts

+20
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ function getAddressTableLookupArrayDecoder() {
7373
return getArrayDecoder(getAddressTableLookupDecoder(), { size: getShortU16Decoder() });
7474
}
7575

76+
/**
77+
* Returns an encoder that you can use to encode a {@link CompiledTransactionMessage} to a byte
78+
* array.
79+
*
80+
* The wire format of a Solana transaction consists of signatures followed by a compiled transaction
81+
* message. The byte array produced by this encoder is the message part.
82+
*/
7683
export function getCompiledTransactionMessageEncoder(): VariableSizeEncoder<CompiledTransactionMessage> {
7784
return createEncoder({
7885
getSizeFromValue: (compiledMessage: CompiledTransactionMessage) => {
@@ -92,6 +99,13 @@ export function getCompiledTransactionMessageEncoder(): VariableSizeEncoder<Comp
9299
});
93100
}
94101

102+
/**
103+
* Returns a decoder that you can use to decode a byte array representing a
104+
* {@link CompiledTransactionMessage}.
105+
*
106+
* The wire format of a Solana transaction consists of signatures followed by a compiled transaction
107+
* message. You can use this decoder to decode the message part.
108+
*/
95109
export function getCompiledTransactionMessageDecoder(): VariableSizeDecoder<CompiledTransactionMessage> {
96110
return transformDecoder(
97111
getStructDecoder(getPreludeStructDecoderTuple()) as VariableSizeDecoder<
@@ -109,6 +123,12 @@ export function getCompiledTransactionMessageDecoder(): VariableSizeDecoder<Comp
109123
);
110124
}
111125

126+
/**
127+
* Returns a codec that you can use to encode from or decode to {@link CompiledTransactionMessage}
128+
*
129+
* @see {@link getCompiledTransactionMessageDecoder}
130+
* @see {@link getCompiledTransactionMessageEncoder}
131+
*/
112132
export function getCompiledTransactionMessageCodec(): VariableSizeCodec<CompiledTransactionMessage> {
113133
return combineCodec(getCompiledTransactionMessageEncoder(), getCompiledTransactionMessageDecoder());
114134
}

Diff for: packages/transaction-messages/src/codecs/transaction-version.ts

+19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import { TransactionVersion } from '../transaction-message';
1212

1313
const VERSION_FLAG_MASK = 0x80;
1414

15+
/**
16+
* Returns an encoder that you can use to encode a {@link TransactionVersion} to a byte array.
17+
*
18+
* Legacy messages will produce an empty array and will not advance the offset. Versioned messages
19+
* will produce an array with a single byte.
20+
*/
1521
export function getTransactionVersionEncoder(): VariableSizeEncoder<TransactionVersion> {
1622
return createEncoder({
1723
getSizeFromValue: value => (value === 'legacy' ? 0 : 1),
@@ -31,6 +37,13 @@ export function getTransactionVersionEncoder(): VariableSizeEncoder<TransactionV
3137
});
3238
}
3339

40+
/**
41+
* Returns a decoder that you can use to decode a byte array representing a
42+
* {@link TransactionVersion}.
43+
*
44+
* When the byte at the current offset is determined to represent a legacy transaction, this decoder
45+
* will return `'legacy'` and will not advance the offset.
46+
*/
3447
export function getTransactionVersionDecoder(): VariableSizeDecoder<TransactionVersion> {
3548
return createDecoder({
3649
maxSize: 1,
@@ -47,6 +60,12 @@ export function getTransactionVersionDecoder(): VariableSizeDecoder<TransactionV
4760
});
4861
}
4962

63+
/**
64+
* Returns a codec that you can use to encode from or decode to {@link TransactionVersion}
65+
*
66+
* @see {@link getTransactionVersionDecoder}
67+
* @see {@link getTransactionVersionEncoder}
68+
*/
5069
export function getTransactionVersionCodec(): VariableSizeCodec<TransactionVersion> {
5170
return combineCodec(getTransactionVersionEncoder(), getTransactionVersionDecoder());
5271
}

Diff for: packages/transaction-messages/src/compilable-transaction-message.ts

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import { TransactionMessageWithDurableNonceLifetime } from './durable-nonce';
55
import { ITransactionMessageWithFeePayer } from './fee-payer';
66
import { BaseTransactionMessage, TransactionVersion } from './transaction-message';
77

8+
/**
9+
* A transaction message having sufficient detail to be compiled for execution on the network.
10+
*
11+
* In essence, this means that it has at minimum a version, a fee payer, and a lifetime constraint.
12+
*/
813
export type CompilableTransactionMessage<
914
TVersion extends TransactionVersion = TransactionVersion,
1015
TInstruction extends IInstruction = IInstruction,

Diff for: packages/transaction-messages/src/compile/address-table-lookups.ts

+3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import { AccountRole } from '@solana/instructions';
44
import { OrderedAccounts } from '../compile/accounts';
55

66
type AddressTableLookup = Readonly<{
7+
/** The address of the address lookup table account. */
78
lookupTableAddress: Address;
9+
/** Indices of accounts in a lookup table to load as read-only. */
810
readableIndices: readonly number[];
11+
/** Indices of accounts in a lookup table to load as writable. */
912
writableIndices: readonly number[];
1013
}>;
1114

Diff for: packages/transaction-messages/src/compile/header.ts

+24
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,32 @@ import { isSignerRole, isWritableRole } from '@solana/instructions';
33
import { OrderedAccounts } from '../compile/accounts';
44

55
type MessageHeader = Readonly<{
6+
/**
7+
* The number of accounts in the static accounts list that are neither writable nor
8+
* signers.
9+
*
10+
* Adding this number to `numSignerAccounts` yields the index of the first read-only non-signer
11+
* account in the static accounts list.
12+
*/
613
numReadonlyNonSignerAccounts: number;
14+
/**
15+
* The number of read-only accounts in the static accounts list that must sign this
16+
* transaction.
17+
*
18+
* Subtracting this number from `numSignerAccounts` yields the index of the first read-only
19+
* signer account in the static accounts list.
20+
*/
721
numReadonlySignerAccounts: number;
22+
/**
23+
* The number of accounts in the static accounts list that must sign this transaction.
24+
*
25+
* Subtracting `numReadonlySignerAccounts` from this number yields the number of
26+
* writable signer accounts in the static accounts list. Writable signer accounts always
27+
* begin at index zero in the static accounts list.
28+
*
29+
* This number itself is the index of the first non-signer account in the static
30+
* accounts list.
31+
*/
832
numSignerAccounts: number;
933
}>;
1034

Diff for: packages/transaction-messages/src/compile/instructions.ts

+9
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@ import { IInstruction } from '@solana/instructions';
55
import { OrderedAccounts } from './accounts';
66

77
type CompiledInstruction = Readonly<{
8+
/**
9+
* An ordered list of indices that indicate which accounts in the transaction message's
10+
* accounts list are loaded by this instruction.
11+
*/
812
accountIndices?: number[];
13+
/** The input to the invoked program */
914
data?: ReadonlyUint8Array;
15+
/**
16+
* The index of the address in the transaction message's accounts list associated with the
17+
* program to invoke.
18+
*/
1019
programAddressIndex: number;
1120
}>;
1221

Diff for: packages/transaction-messages/src/compile/message.ts

+31
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,31 @@ import { getCompiledLifetimeToken } from './lifetime-token';
77
import { getCompiledStaticAccounts } from './static-accounts';
88

99
type BaseCompiledTransactionMessage = Readonly<{
10+
/**
11+
* Information about the version of the transaction message and the role of the accounts it
12+
* loads.
13+
*/
1014
header: ReturnType<typeof getCompiledMessageHeader>;
1115
instructions: ReturnType<typeof getCompiledInstructions>;
16+
/**
17+
* 32 bytes of data observed by the transaction proposed that makes a transaction eligible to
18+
* land on the network.
19+
*
20+
* In the case of a transaction message with a nonce lifetime constraint, this will be the value
21+
* of the nonce itself. In all other cases this will be a recent blockhash.
22+
*/
1223
lifetimeToken: ReturnType<typeof getCompiledLifetimeToken>;
24+
/** A list of addresses indicating which accounts to load */
1325
staticAccounts: ReturnType<typeof getCompiledStaticAccounts>;
1426
}>;
1527

28+
/**
29+
* A transaction message in a form suitable for encoding for execution on the network.
30+
*
31+
* You can not fully reconstruct a source message from a compiled message without extra information.
32+
* In particular, supporting details about the lifetime constraint and the concrete addresses of
33+
* accounts sourced from account lookup tables are lost to compilation.
34+
*/
1635
export type CompiledTransactionMessage = LegacyCompiledTransactionMessage | VersionedCompiledTransactionMessage;
1736

1837
type LegacyCompiledTransactionMessage = BaseCompiledTransactionMessage &
@@ -22,10 +41,22 @@ type LegacyCompiledTransactionMessage = BaseCompiledTransactionMessage &
2241

2342
type VersionedCompiledTransactionMessage = BaseCompiledTransactionMessage &
2443
Readonly<{
44+
/** A list of address tables and the accounts that this transaction loads from them */
2545
addressTableLookups?: ReturnType<typeof getCompiledAddressTableLookups>;
2646
version: number;
2747
}>;
2848

49+
/**
50+
* Converts the type of transaction message data structure that you create in your application to
51+
* the type of transaction message data structure that can be encoded for execution on the network.
52+
*
53+
* This is a lossy process; you can not fully reconstruct a source message from a compiled message
54+
* without extra information. In particular, supporting details about the lifetime constraint and
55+
* the concrete addresses of accounts sourced from account lookup tables will be lost to
56+
* compilation.
57+
*
58+
* @see {@link decompileTransactionMessage}
59+
*/
2960
export function compileTransactionMessage(
3061
transactionMessage: CompilableTransactionMessage & Readonly<{ version: 'legacy' }>,
3162
): LegacyCompiledTransactionMessage;

Diff for: packages/transaction-messages/src/compress-transaction-message.ts

+28
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,34 @@ type WidenTransactionMessageInstructions<TTransactionMessage extends Transaction
5454
>
5555
: TTransactionMessage;
5656

57+
/**
58+
* Given a transaction message and a mapping of lookup tables to the addresses stored in them, this
59+
* function will return a new transaction message with the same instructions but with all non-signer
60+
* accounts that are found in the given lookup tables represented by an {@link IAccountLookupMeta}
61+
* instead of an {@link IAccountMeta}.
62+
*
63+
* This means that these accounts will take up less space in the compiled transaction message. This
64+
* size reduction is most significant when the transaction includes many accounts from the same
65+
* lookup table.
66+
*
67+
* @example
68+
* ```ts
69+
* import { address } from '@solana/addresses';
70+
* import { compressTransactionMessageUsingAddressLookupTables } from '@solana/transaction-messages';
71+
*
72+
* const lookupTableAddress = address('4QwSwNriKPrz8DLW4ju5uxC2TN5cksJx6tPUPj7DGLAW');
73+
* const accountAddress = address('5n2ADjHPsqB4EVUNEX48xRqtnmuLu5XSHDwkJRR98qpM');
74+
* const lookupTableAddresses: AddressesByLookupTableAddress = {
75+
* [lookupTableAddress]: [accountAddress],
76+
* };
77+
*
78+
* const compressedTransactionMessage = compressTransactionMessageUsingAddressLookupTables(
79+
* transactionMessage,
80+
* lookupTableAddresses,
81+
* );
82+
* ```
83+
*
84+
*/
5785
export function compressTransactionMessageUsingAddressLookupTables<
5886
TTransactionMessage extends TransactionMessageNotLegacy = TransactionMessageNotLegacy,
5987
>(

Diff for: packages/transaction-messages/src/create-transaction-message.ts

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ type TransactionConfig<TVersion extends TransactionVersion> = Readonly<{
44
version: TVersion;
55
}>;
66

7+
/**
8+
* Given a {@link TransactionVersion} this method will return an empty transaction having the
9+
* capabilities of that version.
10+
*
11+
* @example
12+
* ```ts
13+
* import { createTransactionMessage } from '@solana/transaction-messages';
14+
*
15+
* const message = createTransactionMessage({ version: 0 });
16+
* ```
17+
*/
718
export function createTransactionMessage<TVersion extends TransactionVersion>(
819
config: TransactionConfig<TVersion>,
920
): Extract<TransactionMessage, { version: TVersion }>;

0 commit comments

Comments
 (0)