@solana/transactions 2.0.0-experimental.e1ca396 → 2.0.0-experimental.e374ac6
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/README.md +7 -3
- package/dist/index.browser.cjs +226 -165
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +226 -169
- package/dist/index.browser.js.map +1 -1
- package/dist/index.native.js +226 -169
- package/dist/index.native.js.map +1 -1
- package/dist/index.node.cjs +226 -165
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +228 -169
- package/dist/index.node.js.map +1 -1
- package/dist/types/accounts.d.ts.map +1 -1
- package/dist/types/blockhash.d.ts +4 -7
- package/dist/types/blockhash.d.ts.map +1 -1
- package/dist/types/compilable-transaction.d.ts +4 -4
- package/dist/types/compile-address-table-lookups.d.ts +1 -1
- package/dist/types/compile-header.d.ts +1 -1
- package/dist/types/compile-instructions.d.ts +1 -1
- package/dist/types/compile-lifetime-token.d.ts +1 -1
- package/dist/types/compile-static-accounts.d.ts +1 -1
- package/dist/types/compile-transaction.d.ts +3 -3
- package/dist/types/create-transaction.d.ts +1 -1
- package/dist/types/decompile-transaction.d.ts +12 -4
- package/dist/types/decompile-transaction.d.ts.map +1 -1
- package/dist/types/durable-nonce.d.ts +2 -2
- package/dist/types/durable-nonce.d.ts.map +1 -1
- package/dist/types/fee-payer.d.ts +2 -2
- package/dist/types/index.d.ts +13 -11
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/instructions.d.ts +4 -2
- package/dist/types/instructions.d.ts.map +1 -1
- package/dist/types/message.d.ts +6 -6
- package/dist/types/serializers/address-table-lookup.d.ts +1 -1
- package/dist/types/serializers/header.d.ts +1 -1
- package/dist/types/serializers/index.d.ts +2 -2
- package/dist/types/serializers/instruction.d.ts +1 -1
- package/dist/types/serializers/message.d.ts +1 -1
- package/dist/types/serializers/message.d.ts.map +1 -1
- package/dist/types/serializers/transaction-version.d.ts +1 -1
- package/dist/types/serializers/transaction-version.d.ts.map +1 -1
- package/dist/types/serializers/transaction.d.ts +7 -4
- package/dist/types/serializers/transaction.d.ts.map +1 -1
- package/dist/types/signatures.d.ts +2 -2
- package/dist/types/signatures.d.ts.map +1 -1
- package/dist/types/unsigned-transaction.d.ts +1 -1
- package/dist/types/wire-transaction.d.ts +1 -1
- package/package.json +18 -39
- package/dist/index.development.js +0 -1628
- package/dist/index.development.js.map +0 -1
- package/dist/index.production.min.js +0 -32
package/dist/index.browser.js
CHANGED
|
@@ -1,12 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getStructDecoder, getStructEncoder, getArrayEncoder, getArrayDecoder, getBytesEncoder, getBytesDecoder } from '@solana/codecs-data-structures';
|
|
5
|
-
import { getShortU16Encoder, getShortU16Decoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
|
|
1
|
+
import { SolanaError, SOLANA_ERROR__TRANSACTION_EXPECTED_BLOCKHASH_LIFETIME, SOLANA_ERROR__TRANSACTION_EXPECTED_NONCE_LIFETIME, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_FEE_PAYER_MISSING, SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE, SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, SOLANA_ERROR__BLOCKHASH_STRING_LENGTH_OUT_OF_RANGE, SOLANA_ERROR__BLOCKHASH_BYTE_LENGTH_OUT_OF_RANGE, SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_CANNOT_PAY_FEES, SOLANA_ERROR__TRANSACTION_VERSION_NUMBER_OUT_OF_RANGE } from '@solana/errors';
|
|
2
|
+
import { getBase58Decoder, getBase64Decoder, getStringEncoder, getBase58Encoder, getStringDecoder } from '@solana/codecs-strings';
|
|
3
|
+
import { getAddressFromPublicKey, assertIsAddress, getAddressComparator, getAddressEncoder, getAddressDecoder } from '@solana/addresses';
|
|
6
4
|
import { pipe } from '@solana/functional';
|
|
5
|
+
import { createEncoder, mapDecoder, combineCodec, mapEncoder, createDecoder } from '@solana/codecs-core';
|
|
6
|
+
import { getStructDecoder, getArrayDecoder, getBytesDecoder, getStructEncoder, getArrayEncoder, getBytesEncoder } from '@solana/codecs-data-structures';
|
|
7
|
+
import { getShortU16Decoder, getShortU16Encoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
|
|
7
8
|
import { signBytes } from '@solana/keys';
|
|
8
9
|
|
|
9
10
|
// src/blockhash.ts
|
|
11
|
+
var base58Encoder;
|
|
12
|
+
function assertIsBlockhash(putativeBlockhash) {
|
|
13
|
+
if (!base58Encoder)
|
|
14
|
+
base58Encoder = getBase58Encoder();
|
|
15
|
+
if (
|
|
16
|
+
// Lowest value (32 bytes of zeroes)
|
|
17
|
+
putativeBlockhash.length < 32 || // Highest value (32 bytes of 255)
|
|
18
|
+
putativeBlockhash.length > 44
|
|
19
|
+
) {
|
|
20
|
+
throw new SolanaError(SOLANA_ERROR__BLOCKHASH_STRING_LENGTH_OUT_OF_RANGE, {
|
|
21
|
+
actualLength: putativeBlockhash.length
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const bytes = base58Encoder.encode(putativeBlockhash);
|
|
25
|
+
const numBytes = bytes.byteLength;
|
|
26
|
+
if (numBytes !== 32) {
|
|
27
|
+
throw new SolanaError(SOLANA_ERROR__BLOCKHASH_BYTE_LENGTH_OUT_OF_RANGE, {
|
|
28
|
+
actualLength: numBytes
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
10
32
|
|
|
11
33
|
// src/unsigned-transaction.ts
|
|
12
34
|
function getUnsignedTransaction(transaction) {
|
|
@@ -23,29 +45,6 @@ function getUnsignedTransaction(transaction) {
|
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
// src/blockhash.ts
|
|
26
|
-
var base58Encoder;
|
|
27
|
-
function assertIsBlockhash(putativeBlockhash) {
|
|
28
|
-
if (!base58Encoder)
|
|
29
|
-
base58Encoder = getBase58Encoder();
|
|
30
|
-
try {
|
|
31
|
-
if (
|
|
32
|
-
// Lowest value (32 bytes of zeroes)
|
|
33
|
-
putativeBlockhash.length < 32 || // Highest value (32 bytes of 255)
|
|
34
|
-
putativeBlockhash.length > 44
|
|
35
|
-
) {
|
|
36
|
-
throw new Error("Expected input string to decode to a byte array of length 32.");
|
|
37
|
-
}
|
|
38
|
-
const bytes = base58Encoder.encode(putativeBlockhash);
|
|
39
|
-
const numBytes = bytes.byteLength;
|
|
40
|
-
if (numBytes !== 32) {
|
|
41
|
-
throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
|
|
42
|
-
}
|
|
43
|
-
} catch (e) {
|
|
44
|
-
throw new Error(`\`${putativeBlockhash}\` is not a blockhash`, {
|
|
45
|
-
cause: e
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
48
|
function isTransactionWithBlockhashLifetime(transaction) {
|
|
50
49
|
const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
|
|
51
50
|
if (!lifetimeConstraintShapeMatches)
|
|
@@ -59,7 +58,7 @@ function isTransactionWithBlockhashLifetime(transaction) {
|
|
|
59
58
|
}
|
|
60
59
|
function assertIsTransactionWithBlockhashLifetime(transaction) {
|
|
61
60
|
if (!isTransactionWithBlockhashLifetime(transaction)) {
|
|
62
|
-
throw new
|
|
61
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_BLOCKHASH_LIFETIME);
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
64
|
function setTransactionLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
|
|
@@ -85,8 +84,6 @@ function createTransaction({
|
|
|
85
84
|
Object.freeze(out);
|
|
86
85
|
return out;
|
|
87
86
|
}
|
|
88
|
-
|
|
89
|
-
// ../instructions/dist/index.browser.js
|
|
90
87
|
var AccountRole = /* @__PURE__ */ ((AccountRole2) => {
|
|
91
88
|
AccountRole2[AccountRole2["WRITABLE_SIGNER"] = /* 3 */
|
|
92
89
|
3] = "WRITABLE_SIGNER";
|
|
@@ -108,13 +105,11 @@ function isWritableRole(role) {
|
|
|
108
105
|
function mergeRoles(roleA, roleB) {
|
|
109
106
|
return roleA | roleB;
|
|
110
107
|
}
|
|
111
|
-
|
|
112
|
-
// src/durable-nonce.ts
|
|
113
108
|
var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
|
|
114
109
|
var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
115
110
|
function assertIsDurableNonceTransaction(transaction) {
|
|
116
111
|
if (!isDurableNonceTransaction(transaction)) {
|
|
117
|
-
throw new
|
|
112
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_NONCE_LIFETIME);
|
|
118
113
|
}
|
|
119
114
|
}
|
|
120
115
|
function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
|
|
@@ -200,21 +195,181 @@ function setTransactionFeePayer(feePayer, transaction) {
|
|
|
200
195
|
|
|
201
196
|
// src/instructions.ts
|
|
202
197
|
function appendTransactionInstruction(instruction, transaction) {
|
|
198
|
+
return appendTransactionInstructions([instruction], transaction);
|
|
199
|
+
}
|
|
200
|
+
function appendTransactionInstructions(instructions, transaction) {
|
|
203
201
|
const out = {
|
|
204
202
|
...getUnsignedTransaction(transaction),
|
|
205
|
-
instructions: [...transaction.instructions,
|
|
203
|
+
instructions: [...transaction.instructions, ...instructions]
|
|
206
204
|
};
|
|
207
205
|
Object.freeze(out);
|
|
208
206
|
return out;
|
|
209
207
|
}
|
|
210
208
|
function prependTransactionInstruction(instruction, transaction) {
|
|
209
|
+
return prependTransactionInstructions([instruction], transaction);
|
|
210
|
+
}
|
|
211
|
+
function prependTransactionInstructions(instructions, transaction) {
|
|
211
212
|
const out = {
|
|
212
213
|
...getUnsignedTransaction(transaction),
|
|
213
|
-
instructions: [
|
|
214
|
+
instructions: [...instructions, ...transaction.instructions]
|
|
214
215
|
};
|
|
215
216
|
Object.freeze(out);
|
|
216
217
|
return out;
|
|
217
218
|
}
|
|
219
|
+
|
|
220
|
+
// src/decompile-transaction.ts
|
|
221
|
+
function getAccountMetas(message) {
|
|
222
|
+
const { header } = message;
|
|
223
|
+
const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
|
|
224
|
+
const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
|
|
225
|
+
const accountMetas = [];
|
|
226
|
+
let accountIndex = 0;
|
|
227
|
+
for (let i = 0; i < numWritableSignerAccounts; i++) {
|
|
228
|
+
accountMetas.push({
|
|
229
|
+
address: message.staticAccounts[accountIndex],
|
|
230
|
+
role: AccountRole.WRITABLE_SIGNER
|
|
231
|
+
});
|
|
232
|
+
accountIndex++;
|
|
233
|
+
}
|
|
234
|
+
for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
|
|
235
|
+
accountMetas.push({
|
|
236
|
+
address: message.staticAccounts[accountIndex],
|
|
237
|
+
role: AccountRole.READONLY_SIGNER
|
|
238
|
+
});
|
|
239
|
+
accountIndex++;
|
|
240
|
+
}
|
|
241
|
+
for (let i = 0; i < numWritableNonSignerAccounts; i++) {
|
|
242
|
+
accountMetas.push({
|
|
243
|
+
address: message.staticAccounts[accountIndex],
|
|
244
|
+
role: AccountRole.WRITABLE
|
|
245
|
+
});
|
|
246
|
+
accountIndex++;
|
|
247
|
+
}
|
|
248
|
+
for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
|
|
249
|
+
accountMetas.push({
|
|
250
|
+
address: message.staticAccounts[accountIndex],
|
|
251
|
+
role: AccountRole.READONLY
|
|
252
|
+
});
|
|
253
|
+
accountIndex++;
|
|
254
|
+
}
|
|
255
|
+
return accountMetas;
|
|
256
|
+
}
|
|
257
|
+
function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTableAddress) {
|
|
258
|
+
const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
|
|
259
|
+
const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
|
|
260
|
+
if (missing.length > 0) {
|
|
261
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, {
|
|
262
|
+
lookupTableAddresses: missing
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const readOnlyMetas = [];
|
|
266
|
+
const writableMetas = [];
|
|
267
|
+
for (const lookup of compiledAddressTableLookups) {
|
|
268
|
+
const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
|
|
269
|
+
const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
|
|
270
|
+
if (highestIndex >= addresses.length) {
|
|
271
|
+
throw new SolanaError(
|
|
272
|
+
SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE,
|
|
273
|
+
{
|
|
274
|
+
highestKnownIndex: addresses.length - 1,
|
|
275
|
+
highestRequestedIndex: highestIndex,
|
|
276
|
+
lookupTableAddress: lookup.lookupTableAddress
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
const readOnlyForLookup = lookup.readableIndices.map((r) => ({
|
|
281
|
+
address: addresses[r],
|
|
282
|
+
addressIndex: r,
|
|
283
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
284
|
+
role: AccountRole.READONLY
|
|
285
|
+
}));
|
|
286
|
+
readOnlyMetas.push(...readOnlyForLookup);
|
|
287
|
+
const writableForLookup = lookup.writableIndices.map((w) => ({
|
|
288
|
+
address: addresses[w],
|
|
289
|
+
addressIndex: w,
|
|
290
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
291
|
+
role: AccountRole.WRITABLE
|
|
292
|
+
}));
|
|
293
|
+
writableMetas.push(...writableForLookup);
|
|
294
|
+
}
|
|
295
|
+
return [...writableMetas, ...readOnlyMetas];
|
|
296
|
+
}
|
|
297
|
+
function convertInstruction(instruction, accountMetas) {
|
|
298
|
+
const programAddress = accountMetas[instruction.programAddressIndex]?.address;
|
|
299
|
+
if (!programAddress) {
|
|
300
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, {
|
|
301
|
+
index: instruction.programAddressIndex
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
|
|
305
|
+
const { data } = instruction;
|
|
306
|
+
return {
|
|
307
|
+
programAddress,
|
|
308
|
+
...accounts && accounts.length ? { accounts } : {},
|
|
309
|
+
...data && data.length ? { data } : {}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
|
|
313
|
+
if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
314
|
+
return {
|
|
315
|
+
blockhash: messageLifetimeToken,
|
|
316
|
+
lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
|
|
317
|
+
// U64 MAX
|
|
318
|
+
};
|
|
319
|
+
} else {
|
|
320
|
+
const nonceAccountAddress = firstInstruction.accounts[0].address;
|
|
321
|
+
assertIsAddress(nonceAccountAddress);
|
|
322
|
+
const nonceAuthorityAddress = firstInstruction.accounts[2].address;
|
|
323
|
+
assertIsAddress(nonceAuthorityAddress);
|
|
324
|
+
return {
|
|
325
|
+
nonce: messageLifetimeToken,
|
|
326
|
+
nonceAccountAddress,
|
|
327
|
+
nonceAuthorityAddress
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function convertSignatures(compiledTransaction) {
|
|
332
|
+
const {
|
|
333
|
+
compiledMessage: { staticAccounts },
|
|
334
|
+
signatures
|
|
335
|
+
} = compiledTransaction;
|
|
336
|
+
return signatures.reduce((acc, sig, index) => {
|
|
337
|
+
const allZeros = sig.every((byte) => byte === 0);
|
|
338
|
+
if (allZeros)
|
|
339
|
+
return acc;
|
|
340
|
+
const address = staticAccounts[index];
|
|
341
|
+
return { ...acc, [address]: sig };
|
|
342
|
+
}, {});
|
|
343
|
+
}
|
|
344
|
+
function decompileTransaction(compiledTransaction, config) {
|
|
345
|
+
const { compiledMessage } = compiledTransaction;
|
|
346
|
+
const feePayer = compiledMessage.staticAccounts[0];
|
|
347
|
+
if (!feePayer) {
|
|
348
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_FEE_PAYER_MISSING);
|
|
349
|
+
}
|
|
350
|
+
const accountMetas = getAccountMetas(compiledMessage);
|
|
351
|
+
const accountLookupMetas = "addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups !== void 0 && compiledMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(compiledMessage.addressTableLookups, config?.addressesByLookupTableAddress ?? {}) : [];
|
|
352
|
+
const transactionMetas = [...accountMetas, ...accountLookupMetas];
|
|
353
|
+
const instructions = compiledMessage.instructions.map(
|
|
354
|
+
(compiledInstruction) => convertInstruction(compiledInstruction, transactionMetas)
|
|
355
|
+
);
|
|
356
|
+
const firstInstruction = instructions[0];
|
|
357
|
+
const lifetimeConstraint = getLifetimeConstraint(
|
|
358
|
+
compiledMessage.lifetimeToken,
|
|
359
|
+
firstInstruction,
|
|
360
|
+
config?.lastValidBlockHeight
|
|
361
|
+
);
|
|
362
|
+
const signatures = convertSignatures(compiledTransaction);
|
|
363
|
+
return pipe(
|
|
364
|
+
createTransaction({ version: compiledMessage.version }),
|
|
365
|
+
(tx) => setTransactionFeePayer(feePayer, tx),
|
|
366
|
+
(tx) => instructions.reduce((acc, instruction) => {
|
|
367
|
+
return appendTransactionInstruction(instruction, acc);
|
|
368
|
+
}, tx),
|
|
369
|
+
(tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
|
|
370
|
+
(tx) => Object.keys(signatures).length > 0 ? { ...tx, signatures } : tx
|
|
371
|
+
);
|
|
372
|
+
}
|
|
218
373
|
function upsert(addressMap, address, update) {
|
|
219
374
|
addressMap[address] = update(addressMap[address] ?? { role: AccountRole.READONLY });
|
|
220
375
|
}
|
|
@@ -231,13 +386,13 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
231
386
|
if (isWritableRole(entry.role)) {
|
|
232
387
|
switch (entry[TYPE]) {
|
|
233
388
|
case 0 /* FEE_PAYER */:
|
|
234
|
-
throw new
|
|
235
|
-
|
|
236
|
-
);
|
|
389
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
|
|
390
|
+
programAddress: instruction.programAddress
|
|
391
|
+
});
|
|
237
392
|
default:
|
|
238
|
-
throw new
|
|
239
|
-
|
|
240
|
-
);
|
|
393
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
|
|
394
|
+
programAddress: instruction.programAddress
|
|
395
|
+
});
|
|
241
396
|
}
|
|
242
397
|
}
|
|
243
398
|
if (entry[TYPE] === 2 /* STATIC */) {
|
|
@@ -302,8 +457,11 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
302
457
|
addressesOfInvokedPrograms.has(account.address)
|
|
303
458
|
) {
|
|
304
459
|
if (isWritableRole(accountMeta.role)) {
|
|
305
|
-
throw new
|
|
306
|
-
|
|
460
|
+
throw new SolanaError(
|
|
461
|
+
SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
|
|
462
|
+
{
|
|
463
|
+
programAddress: account.address
|
|
464
|
+
}
|
|
307
465
|
);
|
|
308
466
|
}
|
|
309
467
|
if (entry.role !== nextRole) {
|
|
@@ -593,7 +751,9 @@ function getTransactionVersionEncoder() {
|
|
|
593
751
|
return offset;
|
|
594
752
|
}
|
|
595
753
|
if (value < 0 || value > 127) {
|
|
596
|
-
throw new
|
|
754
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_VERSION_NUMBER_OUT_OF_RANGE, {
|
|
755
|
+
actualVersion: value
|
|
756
|
+
});
|
|
597
757
|
}
|
|
598
758
|
bytes.set([value | VERSION_FLAG_MASK], offset);
|
|
599
759
|
return offset + 1;
|
|
@@ -680,12 +840,15 @@ function getCompiledMessageEncoder() {
|
|
|
680
840
|
});
|
|
681
841
|
}
|
|
682
842
|
function getCompiledMessageDecoder() {
|
|
683
|
-
return mapDecoder(
|
|
684
|
-
|
|
685
|
-
|
|
843
|
+
return mapDecoder(
|
|
844
|
+
getStructDecoder(getPreludeStructDecoderTuple()),
|
|
845
|
+
({ addressTableLookups, ...restOfMessage }) => {
|
|
846
|
+
if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
|
|
847
|
+
return restOfMessage;
|
|
848
|
+
}
|
|
849
|
+
return { ...restOfMessage, addressTableLookups };
|
|
686
850
|
}
|
|
687
|
-
|
|
688
|
-
});
|
|
851
|
+
);
|
|
689
852
|
}
|
|
690
853
|
function getCompiledMessageCodec() {
|
|
691
854
|
return combineCodec(getCompiledMessageEncoder(), getCompiledMessageDecoder());
|
|
@@ -708,116 +871,6 @@ function getCompiledTransaction(transaction) {
|
|
|
708
871
|
signatures
|
|
709
872
|
};
|
|
710
873
|
}
|
|
711
|
-
function getAccountMetas(message) {
|
|
712
|
-
const { header } = message;
|
|
713
|
-
const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
|
|
714
|
-
const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
|
|
715
|
-
const accountMetas = [];
|
|
716
|
-
let accountIndex = 0;
|
|
717
|
-
for (let i = 0; i < numWritableSignerAccounts; i++) {
|
|
718
|
-
accountMetas.push({
|
|
719
|
-
address: message.staticAccounts[accountIndex],
|
|
720
|
-
role: AccountRole.WRITABLE_SIGNER
|
|
721
|
-
});
|
|
722
|
-
accountIndex++;
|
|
723
|
-
}
|
|
724
|
-
for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
|
|
725
|
-
accountMetas.push({
|
|
726
|
-
address: message.staticAccounts[accountIndex],
|
|
727
|
-
role: AccountRole.READONLY_SIGNER
|
|
728
|
-
});
|
|
729
|
-
accountIndex++;
|
|
730
|
-
}
|
|
731
|
-
for (let i = 0; i < numWritableNonSignerAccounts; i++) {
|
|
732
|
-
accountMetas.push({
|
|
733
|
-
address: message.staticAccounts[accountIndex],
|
|
734
|
-
role: AccountRole.WRITABLE
|
|
735
|
-
});
|
|
736
|
-
accountIndex++;
|
|
737
|
-
}
|
|
738
|
-
for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
|
|
739
|
-
accountMetas.push({
|
|
740
|
-
address: message.staticAccounts[accountIndex],
|
|
741
|
-
role: AccountRole.READONLY
|
|
742
|
-
});
|
|
743
|
-
accountIndex++;
|
|
744
|
-
}
|
|
745
|
-
return accountMetas;
|
|
746
|
-
}
|
|
747
|
-
function convertInstruction(instruction, accountMetas) {
|
|
748
|
-
const programAddress = accountMetas[instruction.programAddressIndex]?.address;
|
|
749
|
-
if (!programAddress) {
|
|
750
|
-
throw new Error(`Could not find program address at index ${instruction.programAddressIndex}`);
|
|
751
|
-
}
|
|
752
|
-
const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
|
|
753
|
-
const { data } = instruction;
|
|
754
|
-
return {
|
|
755
|
-
programAddress,
|
|
756
|
-
...accounts && accounts.length ? { accounts } : {},
|
|
757
|
-
...data && data.length ? { data } : {}
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
|
|
761
|
-
if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
762
|
-
return {
|
|
763
|
-
blockhash: messageLifetimeToken,
|
|
764
|
-
lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
|
|
765
|
-
// U64 MAX
|
|
766
|
-
};
|
|
767
|
-
} else {
|
|
768
|
-
const nonceAccountAddress = firstInstruction.accounts[0].address;
|
|
769
|
-
assertIsAddress(nonceAccountAddress);
|
|
770
|
-
const nonceAuthorityAddress = firstInstruction.accounts[2].address;
|
|
771
|
-
assertIsAddress(nonceAuthorityAddress);
|
|
772
|
-
return {
|
|
773
|
-
nonce: messageLifetimeToken,
|
|
774
|
-
nonceAccountAddress,
|
|
775
|
-
nonceAuthorityAddress
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
function convertSignatures(compiledTransaction) {
|
|
780
|
-
const {
|
|
781
|
-
compiledMessage: { staticAccounts },
|
|
782
|
-
signatures
|
|
783
|
-
} = compiledTransaction;
|
|
784
|
-
return signatures.reduce((acc, sig, index) => {
|
|
785
|
-
const allZeros = sig.every((byte) => byte === 0);
|
|
786
|
-
if (allZeros)
|
|
787
|
-
return acc;
|
|
788
|
-
const address = staticAccounts[index];
|
|
789
|
-
return { ...acc, [address]: sig };
|
|
790
|
-
}, {});
|
|
791
|
-
}
|
|
792
|
-
function decompileTransaction(compiledTransaction, lastValidBlockHeight) {
|
|
793
|
-
const { compiledMessage } = compiledTransaction;
|
|
794
|
-
if ("addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups.length > 0) {
|
|
795
|
-
throw new Error("Cannot convert transaction with addressTableLookups");
|
|
796
|
-
}
|
|
797
|
-
const feePayer = compiledMessage.staticAccounts[0];
|
|
798
|
-
if (!feePayer)
|
|
799
|
-
throw new Error("No fee payer set in CompiledTransaction");
|
|
800
|
-
const accountMetas = getAccountMetas(compiledMessage);
|
|
801
|
-
const instructions = compiledMessage.instructions.map(
|
|
802
|
-
(compiledInstruction) => convertInstruction(compiledInstruction, accountMetas)
|
|
803
|
-
);
|
|
804
|
-
const firstInstruction = instructions[0];
|
|
805
|
-
const lifetimeConstraint = getLifetimeConstraint(
|
|
806
|
-
compiledMessage.lifetimeToken,
|
|
807
|
-
firstInstruction,
|
|
808
|
-
lastValidBlockHeight
|
|
809
|
-
);
|
|
810
|
-
const signatures = convertSignatures(compiledTransaction);
|
|
811
|
-
return pipe(
|
|
812
|
-
createTransaction({ version: compiledMessage.version }),
|
|
813
|
-
(tx) => setTransactionFeePayer(feePayer, tx),
|
|
814
|
-
(tx) => instructions.reduce((acc, instruction) => {
|
|
815
|
-
return appendTransactionInstruction(instruction, acc);
|
|
816
|
-
}, tx),
|
|
817
|
-
(tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
|
|
818
|
-
(tx) => compiledTransaction.signatures.length ? { ...tx, signatures } : tx
|
|
819
|
-
);
|
|
820
|
-
}
|
|
821
874
|
|
|
822
875
|
// src/serializers/transaction.ts
|
|
823
876
|
function getCompiledTransactionEncoder() {
|
|
@@ -840,14 +893,14 @@ function getCompiledTransactionDecoder() {
|
|
|
840
893
|
function getTransactionEncoder() {
|
|
841
894
|
return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
|
|
842
895
|
}
|
|
843
|
-
function getTransactionDecoder(
|
|
896
|
+
function getTransactionDecoder(config) {
|
|
844
897
|
return mapDecoder(
|
|
845
898
|
getCompiledTransactionDecoder(),
|
|
846
|
-
(compiledTransaction) => decompileTransaction(compiledTransaction,
|
|
899
|
+
(compiledTransaction) => decompileTransaction(compiledTransaction, config)
|
|
847
900
|
);
|
|
848
901
|
}
|
|
849
|
-
function getTransactionCodec(
|
|
850
|
-
return combineCodec(getTransactionEncoder(), getTransactionDecoder(
|
|
902
|
+
function getTransactionCodec(config) {
|
|
903
|
+
return combineCodec(getTransactionEncoder(), getTransactionDecoder(config));
|
|
851
904
|
}
|
|
852
905
|
var base58Decoder;
|
|
853
906
|
function getSignatureFromTransaction(transaction) {
|
|
@@ -855,9 +908,7 @@ function getSignatureFromTransaction(transaction) {
|
|
|
855
908
|
base58Decoder = getBase58Decoder();
|
|
856
909
|
const signatureBytes = transaction.signatures[transaction.feePayer];
|
|
857
910
|
if (!signatureBytes) {
|
|
858
|
-
throw new
|
|
859
|
-
"Could not determine this transaction's signature. Make sure that the transaction has been signed by its fee payer."
|
|
860
|
-
);
|
|
911
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE);
|
|
861
912
|
}
|
|
862
913
|
const transactionSignature = base58Decoder.decode(signatureBytes);
|
|
863
914
|
return transactionSignature;
|
|
@@ -890,17 +941,23 @@ async function signTransaction(keyPairs, transaction) {
|
|
|
890
941
|
function assertTransactionIsFullySigned(transaction) {
|
|
891
942
|
const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
|
|
892
943
|
const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
|
|
944
|
+
const missingSigs = [];
|
|
893
945
|
requiredSigners.forEach((address) => {
|
|
894
946
|
if (!transaction.signatures[address]) {
|
|
895
|
-
|
|
947
|
+
missingSigs.push(address);
|
|
896
948
|
}
|
|
897
949
|
});
|
|
950
|
+
if (missingSigs.length > 0) {
|
|
951
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, {
|
|
952
|
+
addresses: missingSigs
|
|
953
|
+
});
|
|
954
|
+
}
|
|
898
955
|
}
|
|
899
956
|
function getBase64EncodedWireTransaction(transaction) {
|
|
900
957
|
const wireTransactionBytes = getTransactionEncoder().encode(transaction);
|
|
901
958
|
return getBase64Decoder().decode(wireTransactionBytes);
|
|
902
959
|
}
|
|
903
960
|
|
|
904
|
-
export { appendTransactionInstruction,
|
|
961
|
+
export { appendTransactionInstruction, appendTransactionInstructions, assertIsDurableNonceTransaction, assertIsTransactionWithBlockhashLifetime, assertTransactionIsFullySigned, compileMessage, createTransaction, decompileTransaction, getBase64EncodedWireTransaction, getCompiledMessageCodec, getCompiledMessageDecoder, getCompiledMessageEncoder, getCompiledTransactionDecoder, getSignatureFromTransaction, getTransactionCodec, getTransactionDecoder, getTransactionEncoder, getUnsignedTransaction, isAdvanceNonceAccountInstruction, partiallySignTransaction, prependTransactionInstruction, prependTransactionInstructions, setTransactionFeePayer, setTransactionLifetimeUsingBlockhash, setTransactionLifetimeUsingDurableNonce, signTransaction };
|
|
905
962
|
//# sourceMappingURL=out.js.map
|
|
906
963
|
//# sourceMappingURL=index.browser.js.map
|