@@ -4,15 +4,62 @@ import { assertIsBlockhash, type Blockhash } from '@solana/rpc-types';
4
4
import { TransactionMessageWithDurableNonceLifetime } from './durable-nonce' ;
5
5
import { BaseTransactionMessage } from './transaction-message' ;
6
6
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
+ */
7
15
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
+ */
8
22
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
+ */
9
27
lastValidBlockHeight : bigint ;
10
28
} > ;
11
29
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
+ */
12
38
export interface TransactionMessageWithBlockhashLifetime {
13
39
readonly lifetimeConstraint : BlockhashLifetimeConstraint ;
14
40
}
15
41
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
+ */
16
63
export function isTransactionMessageWithBlockhashLifetime (
17
64
transactionMessage : BaseTransactionMessage | ( BaseTransactionMessage & TransactionMessageWithBlockhashLifetime ) ,
18
65
) : transactionMessage is BaseTransactionMessage & TransactionMessageWithBlockhashLifetime {
@@ -29,6 +76,28 @@ export function isTransactionMessageWithBlockhashLifetime(
29
76
}
30
77
}
31
78
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
+ */
32
101
export function assertIsTransactionMessageWithBlockhashLifetime (
33
102
transactionMessage : BaseTransactionMessage | ( BaseTransactionMessage & TransactionMessageWithBlockhashLifetime ) ,
34
103
) : asserts transactionMessage is BaseTransactionMessage & TransactionMessageWithBlockhashLifetime {
@@ -37,6 +106,19 @@ export function assertIsTransactionMessageWithBlockhashLifetime(
37
106
}
38
107
}
39
108
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
+ */
40
122
export function setTransactionMessageLifetimeUsingBlockhash <
41
123
TTransactionMessage extends BaseTransactionMessage & TransactionMessageWithDurableNonceLifetime ,
42
124
> (
0 commit comments