@solana/transaction-messages 2.0.0-20241006045741
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +226 -0
- package/dist/index.browser.cjs +928 -0
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.mjs +905 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.native.mjs +905 -0
- package/dist/index.native.mjs.map +1 -0
- package/dist/index.node.cjs +928 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.mjs +905 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/types/addresses-by-lookup-table-address.d.ts +5 -0
- package/dist/types/addresses-by-lookup-table-address.d.ts.map +1 -0
- package/dist/types/blockhash.d.ts +16 -0
- package/dist/types/blockhash.d.ts.map +1 -0
- package/dist/types/codecs/address-table-lookup.d.ts +8 -0
- package/dist/types/codecs/address-table-lookup.d.ts.map +1 -0
- package/dist/types/codecs/header.d.ts +8 -0
- package/dist/types/codecs/header.d.ts.map +1 -0
- package/dist/types/codecs/index.d.ts +3 -0
- package/dist/types/codecs/index.d.ts.map +1 -0
- package/dist/types/codecs/instruction.d.ts +8 -0
- package/dist/types/codecs/instruction.d.ts.map +1 -0
- package/dist/types/codecs/message.d.ts +6 -0
- package/dist/types/codecs/message.d.ts.map +1 -0
- package/dist/types/codecs/transaction-version.d.ts +6 -0
- package/dist/types/codecs/transaction-version.d.ts.map +1 -0
- package/dist/types/compilable-transaction-message.d.ts +7 -0
- package/dist/types/compilable-transaction-message.d.ts.map +1 -0
- package/dist/types/compile/accounts.d.ts +28 -0
- package/dist/types/compile/accounts.d.ts.map +1 -0
- package/dist/types/compile/address-table-lookups.d.ts +10 -0
- package/dist/types/compile/address-table-lookups.d.ts.map +1 -0
- package/dist/types/compile/header.d.ts +9 -0
- package/dist/types/compile/header.d.ts.map +1 -0
- package/dist/types/compile/index.d.ts +2 -0
- package/dist/types/compile/index.d.ts.map +1 -0
- package/dist/types/compile/instructions.d.ts +10 -0
- package/dist/types/compile/instructions.d.ts.map +1 -0
- package/dist/types/compile/lifetime-token.d.ts +3 -0
- package/dist/types/compile/lifetime-token.d.ts.map +1 -0
- package/dist/types/compile/message.d.ts +26 -0
- package/dist/types/compile/message.d.ts.map +1 -0
- package/dist/types/compile/static-accounts.d.ts +4 -0
- package/dist/types/compile/static-accounts.d.ts.map +1 -0
- package/dist/types/compress-transaction-message.d.ts +14 -0
- package/dist/types/compress-transaction-message.d.ts.map +1 -0
- package/dist/types/create-transaction-message.d.ts +9 -0
- package/dist/types/create-transaction-message.d.ts.map +1 -0
- package/dist/types/decompile-message.d.ts +9 -0
- package/dist/types/decompile-message.d.ts.map +1 -0
- package/dist/types/durable-nonce.d.ts +35 -0
- package/dist/types/durable-nonce.d.ts.map +1 -0
- package/dist/types/fee-payer.d.ts +7 -0
- package/dist/types/fee-payer.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/instructions.d.ts +6 -0
- package/dist/types/instructions.d.ts.map +1 -0
- package/dist/types/transaction-message.d.ts +12 -0
- package/dist/types/transaction-message.d.ts.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@solana/errors');
|
|
4
|
+
var rpcTypes = require('@solana/rpc-types');
|
|
5
|
+
var addresses = require('@solana/addresses');
|
|
6
|
+
var codecsCore = require('@solana/codecs-core');
|
|
7
|
+
var codecsDataStructures = require('@solana/codecs-data-structures');
|
|
8
|
+
var codecsNumbers = require('@solana/codecs-numbers');
|
|
9
|
+
var instructions = require('@solana/instructions');
|
|
10
|
+
var functional = require('@solana/functional');
|
|
11
|
+
|
|
12
|
+
// src/blockhash.ts
|
|
13
|
+
function isTransactionMessageWithBlockhashLifetime(transaction) {
|
|
14
|
+
const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
|
|
15
|
+
if (!lifetimeConstraintShapeMatches) return false;
|
|
16
|
+
try {
|
|
17
|
+
rpcTypes.assertIsBlockhash(transaction.lifetimeConstraint.blockhash);
|
|
18
|
+
return true;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function assertIsTransactionMessageWithBlockhashLifetime(transaction) {
|
|
24
|
+
if (!isTransactionMessageWithBlockhashLifetime(transaction)) {
|
|
25
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__EXPECTED_BLOCKHASH_LIFETIME);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function setTransactionMessageLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
|
|
29
|
+
if ("lifetimeConstraint" in transaction && transaction.lifetimeConstraint.blockhash === blockhashLifetimeConstraint.blockhash && transaction.lifetimeConstraint.lastValidBlockHeight === blockhashLifetimeConstraint.lastValidBlockHeight) {
|
|
30
|
+
return transaction;
|
|
31
|
+
}
|
|
32
|
+
const out = {
|
|
33
|
+
...transaction,
|
|
34
|
+
lifetimeConstraint: Object.freeze(blockhashLifetimeConstraint)
|
|
35
|
+
};
|
|
36
|
+
Object.freeze(out);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function assertValidBaseString(alphabet4, testValue, givenValue = testValue) {
|
|
40
|
+
if (!testValue.match(new RegExp(`^[${alphabet4}]*$`))) {
|
|
41
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__CODECS__INVALID_STRING_FOR_BASE, {
|
|
42
|
+
alphabet: alphabet4,
|
|
43
|
+
base: alphabet4.length,
|
|
44
|
+
value: givenValue
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var getBaseXEncoder = (alphabet4) => {
|
|
49
|
+
return codecsCore.createEncoder({
|
|
50
|
+
getSizeFromValue: (value) => {
|
|
51
|
+
const [leadingZeroes, tailChars] = partitionLeadingZeroes(value, alphabet4[0]);
|
|
52
|
+
if (!tailChars) return value.length;
|
|
53
|
+
const base10Number = getBigIntFromBaseX(tailChars, alphabet4);
|
|
54
|
+
return leadingZeroes.length + Math.ceil(base10Number.toString(16).length / 2);
|
|
55
|
+
},
|
|
56
|
+
write(value, bytes, offset) {
|
|
57
|
+
assertValidBaseString(alphabet4, value);
|
|
58
|
+
if (value === "") return offset;
|
|
59
|
+
const [leadingZeroes, tailChars] = partitionLeadingZeroes(value, alphabet4[0]);
|
|
60
|
+
if (!tailChars) {
|
|
61
|
+
bytes.set(new Uint8Array(leadingZeroes.length).fill(0), offset);
|
|
62
|
+
return offset + leadingZeroes.length;
|
|
63
|
+
}
|
|
64
|
+
let base10Number = getBigIntFromBaseX(tailChars, alphabet4);
|
|
65
|
+
const tailBytes = [];
|
|
66
|
+
while (base10Number > 0n) {
|
|
67
|
+
tailBytes.unshift(Number(base10Number % 256n));
|
|
68
|
+
base10Number /= 256n;
|
|
69
|
+
}
|
|
70
|
+
const bytesToAdd = [...Array(leadingZeroes.length).fill(0), ...tailBytes];
|
|
71
|
+
bytes.set(bytesToAdd, offset);
|
|
72
|
+
return offset + bytesToAdd.length;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
var getBaseXDecoder = (alphabet4) => {
|
|
77
|
+
return codecsCore.createDecoder({
|
|
78
|
+
read(rawBytes, offset) {
|
|
79
|
+
const bytes = offset === 0 ? rawBytes : rawBytes.slice(offset);
|
|
80
|
+
if (bytes.length === 0) return ["", 0];
|
|
81
|
+
let trailIndex = bytes.findIndex((n) => n !== 0);
|
|
82
|
+
trailIndex = trailIndex === -1 ? bytes.length : trailIndex;
|
|
83
|
+
const leadingZeroes = alphabet4[0].repeat(trailIndex);
|
|
84
|
+
if (trailIndex === bytes.length) return [leadingZeroes, rawBytes.length];
|
|
85
|
+
const base10Number = bytes.slice(trailIndex).reduce((sum, byte) => sum * 256n + BigInt(byte), 0n);
|
|
86
|
+
const tailChars = getBaseXFromBigInt(base10Number, alphabet4);
|
|
87
|
+
return [leadingZeroes + tailChars, rawBytes.length];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
function partitionLeadingZeroes(value, zeroCharacter) {
|
|
92
|
+
const [leadingZeros, tailChars] = value.split(new RegExp(`((?!${zeroCharacter}).*)`));
|
|
93
|
+
return [leadingZeros, tailChars];
|
|
94
|
+
}
|
|
95
|
+
function getBigIntFromBaseX(value, alphabet4) {
|
|
96
|
+
const base = BigInt(alphabet4.length);
|
|
97
|
+
let sum = 0n;
|
|
98
|
+
for (const char of value) {
|
|
99
|
+
sum *= base;
|
|
100
|
+
sum += BigInt(alphabet4.indexOf(char));
|
|
101
|
+
}
|
|
102
|
+
return sum;
|
|
103
|
+
}
|
|
104
|
+
function getBaseXFromBigInt(value, alphabet4) {
|
|
105
|
+
const base = BigInt(alphabet4.length);
|
|
106
|
+
const tailChars = [];
|
|
107
|
+
while (value > 0n) {
|
|
108
|
+
tailChars.unshift(alphabet4[Number(value % base)]);
|
|
109
|
+
value /= base;
|
|
110
|
+
}
|
|
111
|
+
return tailChars.join("");
|
|
112
|
+
}
|
|
113
|
+
var alphabet2 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
114
|
+
var getBase58Encoder = () => getBaseXEncoder(alphabet2);
|
|
115
|
+
var getBase58Decoder = () => getBaseXDecoder(alphabet2);
|
|
116
|
+
var memoizedAddressTableLookupEncoder;
|
|
117
|
+
function getAddressTableLookupEncoder() {
|
|
118
|
+
if (!memoizedAddressTableLookupEncoder) {
|
|
119
|
+
memoizedAddressTableLookupEncoder = codecsDataStructures.getStructEncoder([
|
|
120
|
+
["lookupTableAddress", addresses.getAddressEncoder()],
|
|
121
|
+
[
|
|
122
|
+
"writableIndices",
|
|
123
|
+
codecsDataStructures.getArrayEncoder(codecsNumbers.getU8Encoder(), { size: codecsNumbers.getShortU16Encoder() })
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
"readableIndices",
|
|
127
|
+
codecsDataStructures.getArrayEncoder(codecsNumbers.getU8Encoder(), { size: codecsNumbers.getShortU16Encoder() })
|
|
128
|
+
]
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
return memoizedAddressTableLookupEncoder;
|
|
132
|
+
}
|
|
133
|
+
var memoizedAddressTableLookupDecoder;
|
|
134
|
+
function getAddressTableLookupDecoder() {
|
|
135
|
+
if (!memoizedAddressTableLookupDecoder) {
|
|
136
|
+
memoizedAddressTableLookupDecoder = codecsDataStructures.getStructDecoder([
|
|
137
|
+
["lookupTableAddress", addresses.getAddressDecoder()],
|
|
138
|
+
["writableIndices", codecsDataStructures.getArrayDecoder(codecsNumbers.getU8Decoder(), { size: codecsNumbers.getShortU16Decoder() })],
|
|
139
|
+
["readableIndices", codecsDataStructures.getArrayDecoder(codecsNumbers.getU8Decoder(), { size: codecsNumbers.getShortU16Decoder() })]
|
|
140
|
+
]);
|
|
141
|
+
}
|
|
142
|
+
return memoizedAddressTableLookupDecoder;
|
|
143
|
+
}
|
|
144
|
+
var memoizedU8Encoder;
|
|
145
|
+
function getMemoizedU8Encoder() {
|
|
146
|
+
if (!memoizedU8Encoder) memoizedU8Encoder = codecsNumbers.getU8Encoder();
|
|
147
|
+
return memoizedU8Encoder;
|
|
148
|
+
}
|
|
149
|
+
var memoizedU8Decoder;
|
|
150
|
+
function getMemoizedU8Decoder() {
|
|
151
|
+
if (!memoizedU8Decoder) memoizedU8Decoder = codecsNumbers.getU8Decoder();
|
|
152
|
+
return memoizedU8Decoder;
|
|
153
|
+
}
|
|
154
|
+
function getMessageHeaderEncoder() {
|
|
155
|
+
return codecsDataStructures.getStructEncoder([
|
|
156
|
+
["numSignerAccounts", getMemoizedU8Encoder()],
|
|
157
|
+
["numReadonlySignerAccounts", getMemoizedU8Encoder()],
|
|
158
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Encoder()]
|
|
159
|
+
]);
|
|
160
|
+
}
|
|
161
|
+
function getMessageHeaderDecoder() {
|
|
162
|
+
return codecsDataStructures.getStructDecoder([
|
|
163
|
+
["numSignerAccounts", getMemoizedU8Decoder()],
|
|
164
|
+
["numReadonlySignerAccounts", getMemoizedU8Decoder()],
|
|
165
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Decoder()]
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
var memoizedGetInstructionEncoder;
|
|
169
|
+
function getInstructionEncoder() {
|
|
170
|
+
if (!memoizedGetInstructionEncoder) {
|
|
171
|
+
memoizedGetInstructionEncoder = codecsCore.transformEncoder(
|
|
172
|
+
codecsDataStructures.getStructEncoder([
|
|
173
|
+
["programAddressIndex", codecsNumbers.getU8Encoder()],
|
|
174
|
+
["accountIndices", codecsDataStructures.getArrayEncoder(codecsNumbers.getU8Encoder(), { size: codecsNumbers.getShortU16Encoder() })],
|
|
175
|
+
["data", codecsCore.addEncoderSizePrefix(codecsDataStructures.getBytesEncoder(), codecsNumbers.getShortU16Encoder())]
|
|
176
|
+
]),
|
|
177
|
+
// Convert an instruction to have all fields defined
|
|
178
|
+
(instruction) => {
|
|
179
|
+
if (instruction.accountIndices !== void 0 && instruction.data !== void 0) {
|
|
180
|
+
return instruction;
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
...instruction,
|
|
184
|
+
accountIndices: instruction.accountIndices ?? [],
|
|
185
|
+
data: instruction.data ?? new Uint8Array(0)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return memoizedGetInstructionEncoder;
|
|
191
|
+
}
|
|
192
|
+
var memoizedGetInstructionDecoder;
|
|
193
|
+
function getInstructionDecoder() {
|
|
194
|
+
if (!memoizedGetInstructionDecoder) {
|
|
195
|
+
memoizedGetInstructionDecoder = codecsCore.transformDecoder(
|
|
196
|
+
codecsDataStructures.getStructDecoder([
|
|
197
|
+
["programAddressIndex", codecsNumbers.getU8Decoder()],
|
|
198
|
+
["accountIndices", codecsDataStructures.getArrayDecoder(codecsNumbers.getU8Decoder(), { size: codecsNumbers.getShortU16Decoder() })],
|
|
199
|
+
[
|
|
200
|
+
"data",
|
|
201
|
+
codecsCore.addDecoderSizePrefix(codecsDataStructures.getBytesDecoder(), codecsNumbers.getShortU16Decoder())
|
|
202
|
+
]
|
|
203
|
+
]),
|
|
204
|
+
// Convert an instruction to exclude optional fields if they are empty
|
|
205
|
+
(instruction) => {
|
|
206
|
+
if (instruction.accountIndices.length && instruction.data.byteLength) {
|
|
207
|
+
return instruction;
|
|
208
|
+
}
|
|
209
|
+
const { accountIndices, data, ...rest } = instruction;
|
|
210
|
+
return {
|
|
211
|
+
...rest,
|
|
212
|
+
...accountIndices.length ? { accountIndices } : null,
|
|
213
|
+
...data.byteLength ? { data } : null
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
return memoizedGetInstructionDecoder;
|
|
219
|
+
}
|
|
220
|
+
var VERSION_FLAG_MASK = 128;
|
|
221
|
+
function getTransactionVersionEncoder() {
|
|
222
|
+
return codecsCore.createEncoder({
|
|
223
|
+
getSizeFromValue: (value) => value === "legacy" ? 0 : 1,
|
|
224
|
+
maxSize: 1,
|
|
225
|
+
write: (value, bytes, offset) => {
|
|
226
|
+
if (value === "legacy") {
|
|
227
|
+
return offset;
|
|
228
|
+
}
|
|
229
|
+
if (value < 0 || value > 127) {
|
|
230
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__VERSION_NUMBER_OUT_OF_RANGE, {
|
|
231
|
+
actualVersion: value
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
bytes.set([value | VERSION_FLAG_MASK], offset);
|
|
235
|
+
return offset + 1;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function getTransactionVersionDecoder() {
|
|
240
|
+
return codecsCore.createDecoder({
|
|
241
|
+
maxSize: 1,
|
|
242
|
+
read: (bytes, offset) => {
|
|
243
|
+
const firstByte = bytes[offset];
|
|
244
|
+
if ((firstByte & VERSION_FLAG_MASK) === 0) {
|
|
245
|
+
return ["legacy", offset];
|
|
246
|
+
} else {
|
|
247
|
+
const version = firstByte ^ VERSION_FLAG_MASK;
|
|
248
|
+
return [version, offset + 1];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function getTransactionVersionCodec() {
|
|
254
|
+
return codecsCore.combineCodec(getTransactionVersionEncoder(), getTransactionVersionDecoder());
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/codecs/message.ts
|
|
258
|
+
function getCompiledMessageLegacyEncoder() {
|
|
259
|
+
return codecsDataStructures.getStructEncoder(getPreludeStructEncoderTuple());
|
|
260
|
+
}
|
|
261
|
+
function getCompiledMessageVersionedEncoder() {
|
|
262
|
+
return codecsCore.transformEncoder(
|
|
263
|
+
codecsDataStructures.getStructEncoder([
|
|
264
|
+
...getPreludeStructEncoderTuple(),
|
|
265
|
+
["addressTableLookups", getAddressTableLookupArrayEncoder()]
|
|
266
|
+
]),
|
|
267
|
+
(value) => {
|
|
268
|
+
if (value.version === "legacy") {
|
|
269
|
+
return value;
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
...value,
|
|
273
|
+
addressTableLookups: value.addressTableLookups ?? []
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
function getPreludeStructEncoderTuple() {
|
|
279
|
+
return [
|
|
280
|
+
["version", getTransactionVersionEncoder()],
|
|
281
|
+
["header", getMessageHeaderEncoder()],
|
|
282
|
+
["staticAccounts", codecsDataStructures.getArrayEncoder(addresses.getAddressEncoder(), { size: codecsNumbers.getShortU16Encoder() })],
|
|
283
|
+
["lifetimeToken", codecsCore.fixEncoderSize(getBase58Encoder(), 32)],
|
|
284
|
+
["instructions", codecsDataStructures.getArrayEncoder(getInstructionEncoder(), { size: codecsNumbers.getShortU16Encoder() })]
|
|
285
|
+
];
|
|
286
|
+
}
|
|
287
|
+
function getPreludeStructDecoderTuple() {
|
|
288
|
+
return [
|
|
289
|
+
["version", getTransactionVersionDecoder()],
|
|
290
|
+
["header", getMessageHeaderDecoder()],
|
|
291
|
+
["staticAccounts", codecsDataStructures.getArrayDecoder(addresses.getAddressDecoder(), { size: codecsNumbers.getShortU16Decoder() })],
|
|
292
|
+
["lifetimeToken", codecsCore.fixDecoderSize(getBase58Decoder(), 32)],
|
|
293
|
+
["instructions", codecsDataStructures.getArrayDecoder(getInstructionDecoder(), { size: codecsNumbers.getShortU16Decoder() })],
|
|
294
|
+
["addressTableLookups", getAddressTableLookupArrayDecoder()]
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
function getAddressTableLookupArrayEncoder() {
|
|
298
|
+
return codecsDataStructures.getArrayEncoder(getAddressTableLookupEncoder(), { size: codecsNumbers.getShortU16Encoder() });
|
|
299
|
+
}
|
|
300
|
+
function getAddressTableLookupArrayDecoder() {
|
|
301
|
+
return codecsDataStructures.getArrayDecoder(getAddressTableLookupDecoder(), { size: codecsNumbers.getShortU16Decoder() });
|
|
302
|
+
}
|
|
303
|
+
function getCompiledTransactionMessageEncoder() {
|
|
304
|
+
return codecsCore.createEncoder({
|
|
305
|
+
getSizeFromValue: (compiledMessage) => {
|
|
306
|
+
if (compiledMessage.version === "legacy") {
|
|
307
|
+
return getCompiledMessageLegacyEncoder().getSizeFromValue(compiledMessage);
|
|
308
|
+
} else {
|
|
309
|
+
return getCompiledMessageVersionedEncoder().getSizeFromValue(compiledMessage);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
write: (compiledMessage, bytes, offset) => {
|
|
313
|
+
if (compiledMessage.version === "legacy") {
|
|
314
|
+
return getCompiledMessageLegacyEncoder().write(compiledMessage, bytes, offset);
|
|
315
|
+
} else {
|
|
316
|
+
return getCompiledMessageVersionedEncoder().write(compiledMessage, bytes, offset);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function getCompiledTransactionMessageDecoder() {
|
|
322
|
+
return codecsCore.transformDecoder(
|
|
323
|
+
codecsDataStructures.getStructDecoder(getPreludeStructDecoderTuple()),
|
|
324
|
+
({ addressTableLookups, ...restOfMessage }) => {
|
|
325
|
+
if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
|
|
326
|
+
return restOfMessage;
|
|
327
|
+
}
|
|
328
|
+
return { ...restOfMessage, addressTableLookups };
|
|
329
|
+
}
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
function getCompiledTransactionMessageCodec() {
|
|
333
|
+
return codecsCore.combineCodec(getCompiledTransactionMessageEncoder(), getCompiledTransactionMessageDecoder());
|
|
334
|
+
}
|
|
335
|
+
function upsert(addressMap, address, update) {
|
|
336
|
+
addressMap[address] = update(addressMap[address] ?? { role: instructions.AccountRole.READONLY });
|
|
337
|
+
}
|
|
338
|
+
var TYPE = Symbol("AddressMapTypeProperty");
|
|
339
|
+
function getAddressMapFromInstructions(feePayer, instructions$1) {
|
|
340
|
+
const addressMap = {
|
|
341
|
+
[feePayer]: { [TYPE]: 0 /* FEE_PAYER */, role: instructions.AccountRole.WRITABLE_SIGNER }
|
|
342
|
+
};
|
|
343
|
+
const addressesOfInvokedPrograms = /* @__PURE__ */ new Set();
|
|
344
|
+
for (const instruction of instructions$1) {
|
|
345
|
+
upsert(addressMap, instruction.programAddress, (entry) => {
|
|
346
|
+
addressesOfInvokedPrograms.add(instruction.programAddress);
|
|
347
|
+
if (TYPE in entry) {
|
|
348
|
+
if (instructions.isWritableRole(entry.role)) {
|
|
349
|
+
switch (entry[TYPE]) {
|
|
350
|
+
case 0 /* FEE_PAYER */:
|
|
351
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
|
|
352
|
+
programAddress: instruction.programAddress
|
|
353
|
+
});
|
|
354
|
+
default:
|
|
355
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
|
|
356
|
+
programAddress: instruction.programAddress
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (entry[TYPE] === 2 /* STATIC */) {
|
|
361
|
+
return entry;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return { [TYPE]: 2 /* STATIC */, role: instructions.AccountRole.READONLY };
|
|
365
|
+
});
|
|
366
|
+
let addressComparator;
|
|
367
|
+
if (!instruction.accounts) {
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
for (const account of instruction.accounts) {
|
|
371
|
+
upsert(addressMap, account.address, (entry) => {
|
|
372
|
+
const {
|
|
373
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
374
|
+
address: _,
|
|
375
|
+
...accountMeta
|
|
376
|
+
} = account;
|
|
377
|
+
if (TYPE in entry) {
|
|
378
|
+
switch (entry[TYPE]) {
|
|
379
|
+
case 0 /* FEE_PAYER */:
|
|
380
|
+
return entry;
|
|
381
|
+
case 1 /* LOOKUP_TABLE */: {
|
|
382
|
+
const nextRole = instructions.mergeRoles(entry.role, accountMeta.role);
|
|
383
|
+
if ("lookupTableAddress" in accountMeta) {
|
|
384
|
+
const shouldReplaceEntry = (
|
|
385
|
+
// Consider using the new LOOKUP_TABLE if its address is different...
|
|
386
|
+
entry.lookupTableAddress !== accountMeta.lookupTableAddress && // ...and sorts before the existing one.
|
|
387
|
+
(addressComparator ||= addresses.getAddressComparator())(
|
|
388
|
+
accountMeta.lookupTableAddress,
|
|
389
|
+
entry.lookupTableAddress
|
|
390
|
+
) < 0
|
|
391
|
+
);
|
|
392
|
+
if (shouldReplaceEntry) {
|
|
393
|
+
return {
|
|
394
|
+
[TYPE]: 1 /* LOOKUP_TABLE */,
|
|
395
|
+
...accountMeta,
|
|
396
|
+
role: nextRole
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
} else if (instructions.isSignerRole(accountMeta.role)) {
|
|
400
|
+
return {
|
|
401
|
+
[TYPE]: 2 /* STATIC */,
|
|
402
|
+
role: nextRole
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (entry.role !== nextRole) {
|
|
406
|
+
return {
|
|
407
|
+
...entry,
|
|
408
|
+
role: nextRole
|
|
409
|
+
};
|
|
410
|
+
} else {
|
|
411
|
+
return entry;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
case 2 /* STATIC */: {
|
|
415
|
+
const nextRole = instructions.mergeRoles(entry.role, accountMeta.role);
|
|
416
|
+
if (
|
|
417
|
+
// Check to see if this address represents a program that is invoked
|
|
418
|
+
// in this transaction.
|
|
419
|
+
addressesOfInvokedPrograms.has(account.address)
|
|
420
|
+
) {
|
|
421
|
+
if (instructions.isWritableRole(accountMeta.role)) {
|
|
422
|
+
throw new errors.SolanaError(
|
|
423
|
+
errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
|
|
424
|
+
{
|
|
425
|
+
programAddress: account.address
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
if (entry.role !== nextRole) {
|
|
430
|
+
return {
|
|
431
|
+
...entry,
|
|
432
|
+
role: nextRole
|
|
433
|
+
};
|
|
434
|
+
} else {
|
|
435
|
+
return entry;
|
|
436
|
+
}
|
|
437
|
+
} else if ("lookupTableAddress" in accountMeta && // Static accounts can be 'upgraded' to lookup table accounts as
|
|
438
|
+
// long as they are not require to sign the transaction.
|
|
439
|
+
!instructions.isSignerRole(entry.role)) {
|
|
440
|
+
return {
|
|
441
|
+
...accountMeta,
|
|
442
|
+
[TYPE]: 1 /* LOOKUP_TABLE */,
|
|
443
|
+
role: nextRole
|
|
444
|
+
};
|
|
445
|
+
} else {
|
|
446
|
+
if (entry.role !== nextRole) {
|
|
447
|
+
return {
|
|
448
|
+
...entry,
|
|
449
|
+
role: nextRole
|
|
450
|
+
};
|
|
451
|
+
} else {
|
|
452
|
+
return entry;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if ("lookupTableAddress" in accountMeta) {
|
|
459
|
+
return {
|
|
460
|
+
...accountMeta,
|
|
461
|
+
[TYPE]: 1 /* LOOKUP_TABLE */
|
|
462
|
+
};
|
|
463
|
+
} else {
|
|
464
|
+
return {
|
|
465
|
+
...accountMeta,
|
|
466
|
+
[TYPE]: 2 /* STATIC */
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return addressMap;
|
|
473
|
+
}
|
|
474
|
+
function getOrderedAccountsFromAddressMap(addressMap) {
|
|
475
|
+
let addressComparator;
|
|
476
|
+
const orderedAccounts = Object.entries(addressMap).sort(([leftAddress, leftEntry], [rightAddress, rightEntry]) => {
|
|
477
|
+
if (leftEntry[TYPE] !== rightEntry[TYPE]) {
|
|
478
|
+
if (leftEntry[TYPE] === 0 /* FEE_PAYER */) {
|
|
479
|
+
return -1;
|
|
480
|
+
} else if (rightEntry[TYPE] === 0 /* FEE_PAYER */) {
|
|
481
|
+
return 1;
|
|
482
|
+
} else if (leftEntry[TYPE] === 2 /* STATIC */) {
|
|
483
|
+
return -1;
|
|
484
|
+
} else if (rightEntry[TYPE] === 2 /* STATIC */) {
|
|
485
|
+
return 1;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const leftIsSigner = instructions.isSignerRole(leftEntry.role);
|
|
489
|
+
if (leftIsSigner !== instructions.isSignerRole(rightEntry.role)) {
|
|
490
|
+
return leftIsSigner ? -1 : 1;
|
|
491
|
+
}
|
|
492
|
+
const leftIsWritable = instructions.isWritableRole(leftEntry.role);
|
|
493
|
+
if (leftIsWritable !== instructions.isWritableRole(rightEntry.role)) {
|
|
494
|
+
return leftIsWritable ? -1 : 1;
|
|
495
|
+
}
|
|
496
|
+
addressComparator ||= addresses.getAddressComparator();
|
|
497
|
+
if (leftEntry[TYPE] === 1 /* LOOKUP_TABLE */ && rightEntry[TYPE] === 1 /* LOOKUP_TABLE */ && leftEntry.lookupTableAddress !== rightEntry.lookupTableAddress) {
|
|
498
|
+
return addressComparator(leftEntry.lookupTableAddress, rightEntry.lookupTableAddress);
|
|
499
|
+
} else {
|
|
500
|
+
return addressComparator(leftAddress, rightAddress);
|
|
501
|
+
}
|
|
502
|
+
}).map(([address, addressMeta]) => ({
|
|
503
|
+
address,
|
|
504
|
+
...addressMeta
|
|
505
|
+
}));
|
|
506
|
+
return orderedAccounts;
|
|
507
|
+
}
|
|
508
|
+
function getCompiledAddressTableLookups(orderedAccounts) {
|
|
509
|
+
const index = {};
|
|
510
|
+
for (const account of orderedAccounts) {
|
|
511
|
+
if (!("lookupTableAddress" in account)) {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
const entry = index[account.lookupTableAddress] ||= {
|
|
515
|
+
readableIndices: [],
|
|
516
|
+
writableIndices: []
|
|
517
|
+
};
|
|
518
|
+
if (account.role === instructions.AccountRole.WRITABLE) {
|
|
519
|
+
entry.writableIndices.push(account.addressIndex);
|
|
520
|
+
} else {
|
|
521
|
+
entry.readableIndices.push(account.addressIndex);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return Object.keys(index).sort(addresses.getAddressComparator()).map((lookupTableAddress) => ({
|
|
525
|
+
lookupTableAddress,
|
|
526
|
+
...index[lookupTableAddress]
|
|
527
|
+
}));
|
|
528
|
+
}
|
|
529
|
+
function getCompiledMessageHeader(orderedAccounts) {
|
|
530
|
+
let numReadonlyNonSignerAccounts = 0;
|
|
531
|
+
let numReadonlySignerAccounts = 0;
|
|
532
|
+
let numSignerAccounts = 0;
|
|
533
|
+
for (const account of orderedAccounts) {
|
|
534
|
+
if ("lookupTableAddress" in account) {
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
const accountIsWritable = instructions.isWritableRole(account.role);
|
|
538
|
+
if (instructions.isSignerRole(account.role)) {
|
|
539
|
+
numSignerAccounts++;
|
|
540
|
+
if (!accountIsWritable) {
|
|
541
|
+
numReadonlySignerAccounts++;
|
|
542
|
+
}
|
|
543
|
+
} else if (!accountIsWritable) {
|
|
544
|
+
numReadonlyNonSignerAccounts++;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
numReadonlyNonSignerAccounts,
|
|
549
|
+
numReadonlySignerAccounts,
|
|
550
|
+
numSignerAccounts
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/compile/instructions.ts
|
|
555
|
+
function getAccountIndex(orderedAccounts) {
|
|
556
|
+
const out = {};
|
|
557
|
+
for (const [index, account] of orderedAccounts.entries()) {
|
|
558
|
+
out[account.address] = index;
|
|
559
|
+
}
|
|
560
|
+
return out;
|
|
561
|
+
}
|
|
562
|
+
function getCompiledInstructions(instructions, orderedAccounts) {
|
|
563
|
+
const accountIndex = getAccountIndex(orderedAccounts);
|
|
564
|
+
return instructions.map(({ accounts, data, programAddress }) => {
|
|
565
|
+
return {
|
|
566
|
+
programAddressIndex: accountIndex[programAddress],
|
|
567
|
+
...accounts ? { accountIndices: accounts.map(({ address }) => accountIndex[address]) } : null,
|
|
568
|
+
...data ? { data } : null
|
|
569
|
+
};
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/compile/lifetime-token.ts
|
|
574
|
+
function getCompiledLifetimeToken(lifetimeConstraint) {
|
|
575
|
+
if ("nonce" in lifetimeConstraint) {
|
|
576
|
+
return lifetimeConstraint.nonce;
|
|
577
|
+
}
|
|
578
|
+
return lifetimeConstraint.blockhash;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/compile/static-accounts.ts
|
|
582
|
+
function getCompiledStaticAccounts(orderedAccounts) {
|
|
583
|
+
const firstLookupTableAccountIndex = orderedAccounts.findIndex((account) => "lookupTableAddress" in account);
|
|
584
|
+
const orderedStaticAccounts = firstLookupTableAccountIndex === -1 ? orderedAccounts : orderedAccounts.slice(0, firstLookupTableAccountIndex);
|
|
585
|
+
return orderedStaticAccounts.map(({ address }) => address);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/compile/message.ts
|
|
589
|
+
function compileTransactionMessage(transaction) {
|
|
590
|
+
const addressMap = getAddressMapFromInstructions(transaction.feePayer, transaction.instructions);
|
|
591
|
+
const orderedAccounts = getOrderedAccountsFromAddressMap(addressMap);
|
|
592
|
+
return {
|
|
593
|
+
...transaction.version !== "legacy" ? { addressTableLookups: getCompiledAddressTableLookups(orderedAccounts) } : null,
|
|
594
|
+
header: getCompiledMessageHeader(orderedAccounts),
|
|
595
|
+
instructions: getCompiledInstructions(transaction.instructions, orderedAccounts),
|
|
596
|
+
lifetimeToken: getCompiledLifetimeToken(transaction.lifetimeConstraint),
|
|
597
|
+
staticAccounts: getCompiledStaticAccounts(orderedAccounts),
|
|
598
|
+
version: transaction.version
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function findAddressInLookupTables(address, role, addressesByLookupTableAddress) {
|
|
602
|
+
for (const [lookupTableAddress, addresses] of Object.entries(addressesByLookupTableAddress)) {
|
|
603
|
+
for (let i = 0; i < addresses.length; i++) {
|
|
604
|
+
if (address === addresses[i]) {
|
|
605
|
+
return {
|
|
606
|
+
address,
|
|
607
|
+
addressIndex: i,
|
|
608
|
+
lookupTableAddress,
|
|
609
|
+
role
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function compressTransactionMessageUsingAddressLookupTables(transactionMessage, addressesByLookupTableAddress) {
|
|
616
|
+
const lookupTableAddresses = new Set(Object.values(addressesByLookupTableAddress).flatMap((a) => a));
|
|
617
|
+
const newInstructions = [];
|
|
618
|
+
let updatedAnyInstructions = false;
|
|
619
|
+
for (const instruction of transactionMessage.instructions) {
|
|
620
|
+
if (!instruction.accounts) {
|
|
621
|
+
newInstructions.push(instruction);
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
const newAccounts = [];
|
|
625
|
+
let updatedAnyAccounts = false;
|
|
626
|
+
for (const account of instruction.accounts) {
|
|
627
|
+
if ("lookupTableAddress" in account || !lookupTableAddresses.has(account.address) || instructions.isSignerRole(account.role)) {
|
|
628
|
+
newAccounts.push(account);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
const lookupMetaAccount = findAddressInLookupTables(
|
|
632
|
+
account.address,
|
|
633
|
+
account.role,
|
|
634
|
+
addressesByLookupTableAddress
|
|
635
|
+
);
|
|
636
|
+
newAccounts.push(Object.freeze(lookupMetaAccount));
|
|
637
|
+
updatedAnyAccounts = true;
|
|
638
|
+
updatedAnyInstructions = true;
|
|
639
|
+
}
|
|
640
|
+
newInstructions.push(
|
|
641
|
+
Object.freeze(updatedAnyAccounts ? { ...instruction, accounts: newAccounts } : instruction)
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
return Object.freeze(
|
|
645
|
+
updatedAnyInstructions ? { ...transactionMessage, instructions: newInstructions } : transactionMessage
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/create-transaction-message.ts
|
|
650
|
+
function createTransactionMessage({
|
|
651
|
+
version
|
|
652
|
+
}) {
|
|
653
|
+
return Object.freeze({
|
|
654
|
+
instructions: Object.freeze([]),
|
|
655
|
+
version
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
|
|
659
|
+
var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
660
|
+
function assertIsDurableNonceTransactionMessage(transaction) {
|
|
661
|
+
if (!isDurableNonceTransaction(transaction)) {
|
|
662
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__EXPECTED_NONCE_LIFETIME);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
|
|
666
|
+
return {
|
|
667
|
+
accounts: [
|
|
668
|
+
{ address: nonceAccountAddress, role: instructions.AccountRole.WRITABLE },
|
|
669
|
+
{
|
|
670
|
+
address: RECENT_BLOCKHASHES_SYSVAR_ADDRESS,
|
|
671
|
+
role: instructions.AccountRole.READONLY
|
|
672
|
+
},
|
|
673
|
+
{ address: nonceAuthorityAddress, role: instructions.AccountRole.READONLY_SIGNER }
|
|
674
|
+
],
|
|
675
|
+
data: new Uint8Array([4, 0, 0, 0]),
|
|
676
|
+
programAddress: SYSTEM_PROGRAM_ADDRESS
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function isAdvanceNonceAccountInstruction(instruction) {
|
|
680
|
+
return instruction.programAddress === SYSTEM_PROGRAM_ADDRESS && // Test for `AdvanceNonceAccount` instruction data
|
|
681
|
+
instruction.data != null && isAdvanceNonceAccountInstructionData(instruction.data) && // Test for exactly 3 accounts
|
|
682
|
+
instruction.accounts?.length === 3 && // First account is nonce account address
|
|
683
|
+
instruction.accounts[0].address != null && instruction.accounts[0].role === instructions.AccountRole.WRITABLE && // Second account is recent blockhashes sysvar
|
|
684
|
+
instruction.accounts[1].address === RECENT_BLOCKHASHES_SYSVAR_ADDRESS && instruction.accounts[1].role === instructions.AccountRole.READONLY && // Third account is nonce authority account
|
|
685
|
+
instruction.accounts[2].address != null && instructions.isSignerRole(instruction.accounts[2].role);
|
|
686
|
+
}
|
|
687
|
+
function isAdvanceNonceAccountInstructionData(data) {
|
|
688
|
+
return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;
|
|
689
|
+
}
|
|
690
|
+
function isDurableNonceTransaction(transaction) {
|
|
691
|
+
return "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.nonce === "string" && transaction.instructions[0] != null && isAdvanceNonceAccountInstruction(transaction.instructions[0]);
|
|
692
|
+
}
|
|
693
|
+
function isAdvanceNonceAccountInstructionForNonce(instruction, nonceAccountAddress, nonceAuthorityAddress) {
|
|
694
|
+
return instruction.accounts[0].address === nonceAccountAddress && instruction.accounts[2].address === nonceAuthorityAddress;
|
|
695
|
+
}
|
|
696
|
+
function setTransactionMessageLifetimeUsingDurableNonce({
|
|
697
|
+
nonce,
|
|
698
|
+
nonceAccountAddress,
|
|
699
|
+
nonceAuthorityAddress
|
|
700
|
+
}, transaction) {
|
|
701
|
+
let newInstructions;
|
|
702
|
+
const firstInstruction = transaction.instructions[0];
|
|
703
|
+
if (firstInstruction && isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
704
|
+
if (isAdvanceNonceAccountInstructionForNonce(firstInstruction, nonceAccountAddress, nonceAuthorityAddress)) {
|
|
705
|
+
if (isDurableNonceTransaction(transaction) && transaction.lifetimeConstraint.nonce === nonce) {
|
|
706
|
+
return transaction;
|
|
707
|
+
} else {
|
|
708
|
+
newInstructions = [firstInstruction, ...transaction.instructions.slice(1)];
|
|
709
|
+
}
|
|
710
|
+
} else {
|
|
711
|
+
newInstructions = [
|
|
712
|
+
Object.freeze(createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress)),
|
|
713
|
+
...transaction.instructions.slice(1)
|
|
714
|
+
];
|
|
715
|
+
}
|
|
716
|
+
} else {
|
|
717
|
+
newInstructions = [
|
|
718
|
+
Object.freeze(createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress)),
|
|
719
|
+
...transaction.instructions
|
|
720
|
+
];
|
|
721
|
+
}
|
|
722
|
+
return Object.freeze({
|
|
723
|
+
...transaction,
|
|
724
|
+
instructions: Object.freeze(newInstructions),
|
|
725
|
+
lifetimeConstraint: Object.freeze({
|
|
726
|
+
nonce
|
|
727
|
+
})
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/fee-payer.ts
|
|
732
|
+
function setTransactionMessageFeePayer(feePayer, transaction) {
|
|
733
|
+
if ("feePayer" in transaction && feePayer === transaction.feePayer) {
|
|
734
|
+
return transaction;
|
|
735
|
+
}
|
|
736
|
+
const out = {
|
|
737
|
+
...transaction,
|
|
738
|
+
feePayer
|
|
739
|
+
};
|
|
740
|
+
Object.freeze(out);
|
|
741
|
+
return out;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/instructions.ts
|
|
745
|
+
function appendTransactionMessageInstruction(instruction, transaction) {
|
|
746
|
+
return appendTransactionMessageInstructions([instruction], transaction);
|
|
747
|
+
}
|
|
748
|
+
function appendTransactionMessageInstructions(instructions, transaction) {
|
|
749
|
+
return Object.freeze({
|
|
750
|
+
...transaction,
|
|
751
|
+
instructions: Object.freeze([...transaction.instructions, ...instructions])
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
function prependTransactionMessageInstruction(instruction, transaction) {
|
|
755
|
+
return prependTransactionMessageInstructions([instruction], transaction);
|
|
756
|
+
}
|
|
757
|
+
function prependTransactionMessageInstructions(instructions, transaction) {
|
|
758
|
+
return Object.freeze({
|
|
759
|
+
...transaction,
|
|
760
|
+
instructions: Object.freeze([...instructions, ...transaction.instructions])
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// src/decompile-message.ts
|
|
765
|
+
function getAccountMetas(message) {
|
|
766
|
+
const { header } = message;
|
|
767
|
+
const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
|
|
768
|
+
const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
|
|
769
|
+
const accountMetas = [];
|
|
770
|
+
let accountIndex = 0;
|
|
771
|
+
for (let i = 0; i < numWritableSignerAccounts; i++) {
|
|
772
|
+
accountMetas.push({
|
|
773
|
+
address: message.staticAccounts[accountIndex],
|
|
774
|
+
role: instructions.AccountRole.WRITABLE_SIGNER
|
|
775
|
+
});
|
|
776
|
+
accountIndex++;
|
|
777
|
+
}
|
|
778
|
+
for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
|
|
779
|
+
accountMetas.push({
|
|
780
|
+
address: message.staticAccounts[accountIndex],
|
|
781
|
+
role: instructions.AccountRole.READONLY_SIGNER
|
|
782
|
+
});
|
|
783
|
+
accountIndex++;
|
|
784
|
+
}
|
|
785
|
+
for (let i = 0; i < numWritableNonSignerAccounts; i++) {
|
|
786
|
+
accountMetas.push({
|
|
787
|
+
address: message.staticAccounts[accountIndex],
|
|
788
|
+
role: instructions.AccountRole.WRITABLE
|
|
789
|
+
});
|
|
790
|
+
accountIndex++;
|
|
791
|
+
}
|
|
792
|
+
for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
|
|
793
|
+
accountMetas.push({
|
|
794
|
+
address: message.staticAccounts[accountIndex],
|
|
795
|
+
role: instructions.AccountRole.READONLY
|
|
796
|
+
});
|
|
797
|
+
accountIndex++;
|
|
798
|
+
}
|
|
799
|
+
return accountMetas;
|
|
800
|
+
}
|
|
801
|
+
function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTableAddress) {
|
|
802
|
+
const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
|
|
803
|
+
const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
|
|
804
|
+
if (missing.length > 0) {
|
|
805
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, {
|
|
806
|
+
lookupTableAddresses: missing
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
const readOnlyMetas = [];
|
|
810
|
+
const writableMetas = [];
|
|
811
|
+
for (const lookup of compiledAddressTableLookups) {
|
|
812
|
+
const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
|
|
813
|
+
const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
|
|
814
|
+
if (highestIndex >= addresses.length) {
|
|
815
|
+
throw new errors.SolanaError(
|
|
816
|
+
errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE,
|
|
817
|
+
{
|
|
818
|
+
highestKnownIndex: addresses.length - 1,
|
|
819
|
+
highestRequestedIndex: highestIndex,
|
|
820
|
+
lookupTableAddress: lookup.lookupTableAddress
|
|
821
|
+
}
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
const readOnlyForLookup = lookup.readableIndices.map((r) => ({
|
|
825
|
+
address: addresses[r],
|
|
826
|
+
addressIndex: r,
|
|
827
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
828
|
+
role: instructions.AccountRole.READONLY
|
|
829
|
+
}));
|
|
830
|
+
readOnlyMetas.push(...readOnlyForLookup);
|
|
831
|
+
const writableForLookup = lookup.writableIndices.map((w) => ({
|
|
832
|
+
address: addresses[w],
|
|
833
|
+
addressIndex: w,
|
|
834
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
835
|
+
role: instructions.AccountRole.WRITABLE
|
|
836
|
+
}));
|
|
837
|
+
writableMetas.push(...writableForLookup);
|
|
838
|
+
}
|
|
839
|
+
return [...writableMetas, ...readOnlyMetas];
|
|
840
|
+
}
|
|
841
|
+
function convertInstruction(instruction, accountMetas) {
|
|
842
|
+
const programAddress = accountMetas[instruction.programAddressIndex]?.address;
|
|
843
|
+
if (!programAddress) {
|
|
844
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, {
|
|
845
|
+
index: instruction.programAddressIndex
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
|
|
849
|
+
const { data } = instruction;
|
|
850
|
+
return Object.freeze({
|
|
851
|
+
programAddress,
|
|
852
|
+
...accounts && accounts.length ? { accounts: Object.freeze(accounts) } : {},
|
|
853
|
+
...data && data.length ? { data } : {}
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
|
|
857
|
+
if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
858
|
+
return {
|
|
859
|
+
blockhash: messageLifetimeToken,
|
|
860
|
+
lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
|
|
861
|
+
// U64 MAX
|
|
862
|
+
};
|
|
863
|
+
} else {
|
|
864
|
+
const nonceAccountAddress = firstInstruction.accounts[0].address;
|
|
865
|
+
addresses.assertIsAddress(nonceAccountAddress);
|
|
866
|
+
const nonceAuthorityAddress = firstInstruction.accounts[2].address;
|
|
867
|
+
addresses.assertIsAddress(nonceAuthorityAddress);
|
|
868
|
+
return {
|
|
869
|
+
nonce: messageLifetimeToken,
|
|
870
|
+
nonceAccountAddress,
|
|
871
|
+
nonceAuthorityAddress
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function decompileTransactionMessage(compiledTransactionMessage, config) {
|
|
876
|
+
const feePayer = compiledTransactionMessage.staticAccounts[0];
|
|
877
|
+
if (!feePayer) {
|
|
878
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_FEE_PAYER_MISSING);
|
|
879
|
+
}
|
|
880
|
+
const accountMetas = getAccountMetas(compiledTransactionMessage);
|
|
881
|
+
const accountLookupMetas = "addressTableLookups" in compiledTransactionMessage && compiledTransactionMessage.addressTableLookups !== void 0 && compiledTransactionMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(
|
|
882
|
+
compiledTransactionMessage.addressTableLookups,
|
|
883
|
+
config?.addressesByLookupTableAddress ?? {}
|
|
884
|
+
) : [];
|
|
885
|
+
const transactionMetas = [...accountMetas, ...accountLookupMetas];
|
|
886
|
+
const instructions = compiledTransactionMessage.instructions.map(
|
|
887
|
+
(compiledInstruction) => convertInstruction(compiledInstruction, transactionMetas)
|
|
888
|
+
);
|
|
889
|
+
const firstInstruction = instructions[0];
|
|
890
|
+
const lifetimeConstraint = getLifetimeConstraint(
|
|
891
|
+
compiledTransactionMessage.lifetimeToken,
|
|
892
|
+
firstInstruction,
|
|
893
|
+
config?.lastValidBlockHeight
|
|
894
|
+
);
|
|
895
|
+
return functional.pipe(
|
|
896
|
+
createTransactionMessage({ version: compiledTransactionMessage.version }),
|
|
897
|
+
(tx) => setTransactionMessageFeePayer(feePayer, tx),
|
|
898
|
+
(tx) => instructions.reduce((acc, instruction) => {
|
|
899
|
+
return appendTransactionMessageInstruction(instruction, acc);
|
|
900
|
+
}, tx),
|
|
901
|
+
(tx) => "blockhash" in lifetimeConstraint ? setTransactionMessageLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionMessageLifetimeUsingDurableNonce(lifetimeConstraint, tx)
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
exports.appendTransactionMessageInstruction = appendTransactionMessageInstruction;
|
|
906
|
+
exports.appendTransactionMessageInstructions = appendTransactionMessageInstructions;
|
|
907
|
+
exports.assertIsDurableNonceTransactionMessage = assertIsDurableNonceTransactionMessage;
|
|
908
|
+
exports.assertIsTransactionMessageWithBlockhashLifetime = assertIsTransactionMessageWithBlockhashLifetime;
|
|
909
|
+
exports.compileTransactionMessage = compileTransactionMessage;
|
|
910
|
+
exports.compressTransactionMessageUsingAddressLookupTables = compressTransactionMessageUsingAddressLookupTables;
|
|
911
|
+
exports.createTransactionMessage = createTransactionMessage;
|
|
912
|
+
exports.decompileTransactionMessage = decompileTransactionMessage;
|
|
913
|
+
exports.getCompiledTransactionMessageCodec = getCompiledTransactionMessageCodec;
|
|
914
|
+
exports.getCompiledTransactionMessageDecoder = getCompiledTransactionMessageDecoder;
|
|
915
|
+
exports.getCompiledTransactionMessageEncoder = getCompiledTransactionMessageEncoder;
|
|
916
|
+
exports.getTransactionVersionCodec = getTransactionVersionCodec;
|
|
917
|
+
exports.getTransactionVersionDecoder = getTransactionVersionDecoder;
|
|
918
|
+
exports.getTransactionVersionEncoder = getTransactionVersionEncoder;
|
|
919
|
+
exports.isAdvanceNonceAccountInstruction = isAdvanceNonceAccountInstruction;
|
|
920
|
+
exports.isDurableNonceTransaction = isDurableNonceTransaction;
|
|
921
|
+
exports.isTransactionMessageWithBlockhashLifetime = isTransactionMessageWithBlockhashLifetime;
|
|
922
|
+
exports.prependTransactionMessageInstruction = prependTransactionMessageInstruction;
|
|
923
|
+
exports.prependTransactionMessageInstructions = prependTransactionMessageInstructions;
|
|
924
|
+
exports.setTransactionMessageFeePayer = setTransactionMessageFeePayer;
|
|
925
|
+
exports.setTransactionMessageLifetimeUsingBlockhash = setTransactionMessageLifetimeUsingBlockhash;
|
|
926
|
+
exports.setTransactionMessageLifetimeUsingDurableNonce = setTransactionMessageLifetimeUsingDurableNonce;
|
|
927
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
928
|
+
//# sourceMappingURL=index.browser.cjs.map
|