@solana/transactions 2.0.0-experimental.ba9b4c7 → 2.0.0-experimental.bab191b
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 +276 -5
- package/dist/index.browser.cjs +466 -356
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +457 -357
- package/dist/index.browser.js.map +1 -1
- package/dist/index.native.js +457 -357
- package/dist/index.native.js.map +1 -1
- package/dist/index.node.cjs +464 -356
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +457 -357
- package/dist/index.node.js.map +1 -1
- package/dist/types/accounts.d.ts +3 -3
- package/dist/types/accounts.d.ts.map +1 -0
- package/dist/types/blockhash.d.ts +7 -9
- package/dist/types/blockhash.d.ts.map +1 -0
- package/dist/types/compilable-transaction.d.ts +7 -0
- package/dist/types/compilable-transaction.d.ts.map +1 -0
- package/dist/types/compile-address-table-lookups.d.ts +3 -3
- package/dist/types/compile-address-table-lookups.d.ts.map +1 -0
- package/dist/types/compile-header.d.ts +1 -1
- package/dist/types/compile-header.d.ts.map +1 -0
- package/dist/types/compile-instructions.d.ts +1 -1
- package/dist/types/compile-instructions.d.ts.map +1 -0
- package/dist/types/compile-lifetime-token.d.ts +2 -2
- package/dist/types/compile-lifetime-token.d.ts.map +1 -0
- package/dist/types/compile-static-accounts.d.ts +3 -3
- package/dist/types/compile-static-accounts.d.ts.map +1 -0
- package/dist/types/compile-transaction.d.ts +6 -7
- package/dist/types/compile-transaction.d.ts.map +1 -0
- package/dist/types/create-transaction.d.ts +1 -1
- package/dist/types/create-transaction.d.ts.map +1 -0
- package/dist/types/decompile-transaction.d.ts +13 -0
- package/dist/types/decompile-transaction.d.ts.map +1 -0
- package/dist/types/durable-nonce.d.ts +8 -9
- package/dist/types/durable-nonce.d.ts.map +1 -0
- package/dist/types/fee-payer.d.ts +6 -6
- package/dist/types/fee-payer.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -9
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/instructions.d.ts +6 -4
- package/dist/types/instructions.d.ts.map +1 -0
- package/dist/types/message.d.ts +6 -10
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/serializers/address-table-lookup.d.ts +5 -5
- package/dist/types/serializers/address-table-lookup.d.ts.map +1 -0
- package/dist/types/serializers/header.d.ts +5 -5
- package/dist/types/serializers/header.d.ts.map +1 -0
- package/dist/types/serializers/index.d.ts +2 -1
- package/dist/types/serializers/index.d.ts.map +1 -0
- package/dist/types/serializers/instruction.d.ts +5 -5
- package/dist/types/serializers/instruction.d.ts.map +1 -0
- package/dist/types/serializers/message.d.ts +5 -5
- package/dist/types/serializers/message.d.ts.map +1 -0
- package/dist/types/serializers/transaction-version.d.ts +5 -5
- package/dist/types/serializers/transaction-version.d.ts.map +1 -0
- package/dist/types/serializers/transaction.d.ts +9 -5
- package/dist/types/serializers/transaction.d.ts.map +1 -0
- package/dist/types/signatures.d.ts +9 -13
- package/dist/types/signatures.d.ts.map +1 -0
- package/dist/types/types.d.ts +6 -13
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/unsigned-transaction.d.ts +2 -2
- package/dist/types/unsigned-transaction.d.ts.map +1 -0
- package/dist/types/wire-transaction.d.ts +2 -2
- package/dist/types/wire-transaction.d.ts.map +1 -0
- package/package.json +18 -38
- package/dist/index.development.js +0 -2042
- package/dist/index.development.js.map +0 -1
- package/dist/index.production.min.js +0 -26
- package/dist/types/serializers/unimplemented.d.ts +0 -3
package/dist/index.browser.js
CHANGED
|
@@ -1,12 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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__FEE_PAYER_SIGNATURE_MISSING, SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING, 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__INVALID_BLOCKHASH_BYTE_LENGTH, 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';
|
|
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';
|
|
6
8
|
import { signBytes } from '@solana/keys';
|
|
7
9
|
|
|
8
|
-
//
|
|
9
|
-
var
|
|
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__INVALID_BLOCKHASH_BYTE_LENGTH, {
|
|
28
|
+
actualLength: numBytes
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
10
32
|
|
|
11
33
|
// src/unsigned-transaction.ts
|
|
12
34
|
function getUnsignedTransaction(transaction) {
|
|
@@ -23,24 +45,20 @@ function getUnsignedTransaction(transaction) {
|
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
// src/blockhash.ts
|
|
26
|
-
function
|
|
48
|
+
function isTransactionWithBlockhashLifetime(transaction) {
|
|
49
|
+
const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
|
|
50
|
+
if (!lifetimeConstraintShapeMatches)
|
|
51
|
+
return false;
|
|
27
52
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (numBytes !== 32) {
|
|
38
|
-
throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
|
|
39
|
-
}
|
|
40
|
-
} catch (e) {
|
|
41
|
-
throw new Error(`\`${putativeBlockhash}\` is not a blockhash`, {
|
|
42
|
-
cause: e
|
|
43
|
-
});
|
|
53
|
+
assertIsBlockhash(transaction.lifetimeConstraint.blockhash);
|
|
54
|
+
return true;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function assertIsTransactionWithBlockhashLifetime(transaction) {
|
|
60
|
+
if (!isTransactionWithBlockhashLifetime(transaction)) {
|
|
61
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXPECTED_BLOCKHASH_LIFETIME);
|
|
44
62
|
}
|
|
45
63
|
}
|
|
46
64
|
function setTransactionLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
|
|
@@ -66,8 +84,6 @@ function createTransaction({
|
|
|
66
84
|
Object.freeze(out);
|
|
67
85
|
return out;
|
|
68
86
|
}
|
|
69
|
-
|
|
70
|
-
// ../instructions/dist/index.browser.js
|
|
71
87
|
var AccountRole = /* @__PURE__ */ ((AccountRole2) => {
|
|
72
88
|
AccountRole2[AccountRole2["WRITABLE_SIGNER"] = /* 3 */
|
|
73
89
|
3] = "WRITABLE_SIGNER";
|
|
@@ -89,13 +105,11 @@ function isWritableRole(role) {
|
|
|
89
105
|
function mergeRoles(roleA, roleB) {
|
|
90
106
|
return roleA | roleB;
|
|
91
107
|
}
|
|
92
|
-
|
|
93
|
-
// src/durable-nonce.ts
|
|
94
108
|
var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
|
|
95
109
|
var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
96
110
|
function assertIsDurableNonceTransaction(transaction) {
|
|
97
111
|
if (!isDurableNonceTransaction(transaction)) {
|
|
98
|
-
throw new
|
|
112
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXPECTED_NONCE_LIFETIME);
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
115
|
function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
|
|
@@ -118,7 +132,7 @@ function isAdvanceNonceAccountInstruction(instruction) {
|
|
|
118
132
|
instruction.accounts?.length === 3 && // First account is nonce account address
|
|
119
133
|
instruction.accounts[0].address != null && instruction.accounts[0].role === AccountRole.WRITABLE && // Second account is recent blockhashes sysvar
|
|
120
134
|
instruction.accounts[1].address === RECENT_BLOCKHASHES_SYSVAR_ADDRESS && instruction.accounts[1].role === AccountRole.READONLY && // Third account is nonce authority account
|
|
121
|
-
instruction.accounts[2].address != null && instruction.accounts[2].role
|
|
135
|
+
instruction.accounts[2].address != null && isSignerRole(instruction.accounts[2].role);
|
|
122
136
|
}
|
|
123
137
|
function isAdvanceNonceAccountInstructionData(data) {
|
|
124
138
|
return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;
|
|
@@ -126,21 +140,38 @@ function isAdvanceNonceAccountInstructionData(data) {
|
|
|
126
140
|
function isDurableNonceTransaction(transaction) {
|
|
127
141
|
return "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.nonce === "string" && transaction.instructions[0] != null && isAdvanceNonceAccountInstruction(transaction.instructions[0]);
|
|
128
142
|
}
|
|
143
|
+
function isAdvanceNonceAccountInstructionForNonce(instruction, nonceAccountAddress, nonceAuthorityAddress) {
|
|
144
|
+
return instruction.accounts[0].address === nonceAccountAddress && instruction.accounts[2].address === nonceAuthorityAddress;
|
|
145
|
+
}
|
|
129
146
|
function setTransactionLifetimeUsingDurableNonce({
|
|
130
147
|
nonce,
|
|
131
148
|
nonceAccountAddress,
|
|
132
149
|
nonceAuthorityAddress
|
|
133
150
|
}, transaction) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
let newInstructions;
|
|
152
|
+
const firstInstruction = transaction.instructions[0];
|
|
153
|
+
if (firstInstruction && isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
154
|
+
if (isAdvanceNonceAccountInstructionForNonce(firstInstruction, nonceAccountAddress, nonceAuthorityAddress)) {
|
|
155
|
+
if (isDurableNonceTransaction(transaction) && transaction.lifetimeConstraint.nonce === nonce) {
|
|
156
|
+
return transaction;
|
|
157
|
+
} else {
|
|
158
|
+
newInstructions = [firstInstruction, ...transaction.instructions.slice(1)];
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
newInstructions = [
|
|
162
|
+
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
163
|
+
...transaction.instructions.slice(1)
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
newInstructions = [
|
|
168
|
+
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
169
|
+
...transaction.instructions
|
|
170
|
+
];
|
|
137
171
|
}
|
|
138
172
|
const out = {
|
|
139
173
|
...getUnsignedTransaction(transaction),
|
|
140
|
-
instructions:
|
|
141
|
-
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
142
|
-
...isAlreadyDurableNonceTransaction ? transaction.instructions.slice(1) : transaction.instructions
|
|
143
|
-
],
|
|
174
|
+
instructions: newInstructions,
|
|
144
175
|
lifetimeConstraint: {
|
|
145
176
|
nonce
|
|
146
177
|
}
|
|
@@ -164,21 +195,181 @@ function setTransactionFeePayer(feePayer, transaction) {
|
|
|
164
195
|
|
|
165
196
|
// src/instructions.ts
|
|
166
197
|
function appendTransactionInstruction(instruction, transaction) {
|
|
198
|
+
return appendTransactionInstructions([instruction], transaction);
|
|
199
|
+
}
|
|
200
|
+
function appendTransactionInstructions(instructions, transaction) {
|
|
167
201
|
const out = {
|
|
168
202
|
...getUnsignedTransaction(transaction),
|
|
169
|
-
instructions: [...transaction.instructions,
|
|
203
|
+
instructions: [...transaction.instructions, ...instructions]
|
|
170
204
|
};
|
|
171
205
|
Object.freeze(out);
|
|
172
206
|
return out;
|
|
173
207
|
}
|
|
174
208
|
function prependTransactionInstruction(instruction, transaction) {
|
|
209
|
+
return prependTransactionInstructions([instruction], transaction);
|
|
210
|
+
}
|
|
211
|
+
function prependTransactionInstructions(instructions, transaction) {
|
|
175
212
|
const out = {
|
|
176
213
|
...getUnsignedTransaction(transaction),
|
|
177
|
-
instructions: [
|
|
214
|
+
instructions: [...instructions, ...transaction.instructions]
|
|
178
215
|
};
|
|
179
216
|
Object.freeze(out);
|
|
180
217
|
return out;
|
|
181
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
|
+
}
|
|
182
373
|
function upsert(addressMap, address, update) {
|
|
183
374
|
addressMap[address] = update(addressMap[address] ?? { role: AccountRole.READONLY });
|
|
184
375
|
}
|
|
@@ -195,13 +386,13 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
195
386
|
if (isWritableRole(entry.role)) {
|
|
196
387
|
switch (entry[TYPE]) {
|
|
197
388
|
case 0 /* FEE_PAYER */:
|
|
198
|
-
throw new
|
|
199
|
-
|
|
200
|
-
);
|
|
389
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
|
|
390
|
+
programAddress: instruction.programAddress
|
|
391
|
+
});
|
|
201
392
|
default:
|
|
202
|
-
throw new
|
|
203
|
-
|
|
204
|
-
);
|
|
393
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
|
|
394
|
+
programAddress: instruction.programAddress
|
|
395
|
+
});
|
|
205
396
|
}
|
|
206
397
|
}
|
|
207
398
|
if (entry[TYPE] === 2 /* STATIC */) {
|
|
@@ -231,7 +422,7 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
231
422
|
const shouldReplaceEntry = (
|
|
232
423
|
// Consider using the new LOOKUP_TABLE if its address is different...
|
|
233
424
|
entry.lookupTableAddress !== accountMeta.lookupTableAddress && // ...and sorts before the existing one.
|
|
234
|
-
(addressComparator
|
|
425
|
+
(addressComparator ||= getAddressComparator())(
|
|
235
426
|
accountMeta.lookupTableAddress,
|
|
236
427
|
entry.lookupTableAddress
|
|
237
428
|
) < 0
|
|
@@ -266,8 +457,11 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
266
457
|
addressesOfInvokedPrograms.has(account.address)
|
|
267
458
|
) {
|
|
268
459
|
if (isWritableRole(accountMeta.role)) {
|
|
269
|
-
throw new
|
|
270
|
-
|
|
460
|
+
throw new SolanaError(
|
|
461
|
+
SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
|
|
462
|
+
{
|
|
463
|
+
programAddress: account.address
|
|
464
|
+
}
|
|
271
465
|
);
|
|
272
466
|
}
|
|
273
467
|
if (entry.role !== nextRole) {
|
|
@@ -337,7 +531,7 @@ function getOrderedAccountsFromAddressMap(addressMap) {
|
|
|
337
531
|
if (leftIsWritable !== isWritableRole(rightEntry.role)) {
|
|
338
532
|
return leftIsWritable ? -1 : 1;
|
|
339
533
|
}
|
|
340
|
-
addressComparator
|
|
534
|
+
addressComparator ||= getAddressComparator();
|
|
341
535
|
if (leftEntry[TYPE] === 1 /* LOOKUP_TABLE */ && rightEntry[TYPE] === 1 /* LOOKUP_TABLE */ && leftEntry.lookupTableAddress !== rightEntry.lookupTableAddress) {
|
|
342
536
|
return addressComparator(leftEntry.lookupTableAddress, rightEntry.lookupTableAddress);
|
|
343
537
|
} else {
|
|
@@ -350,16 +544,15 @@ function getOrderedAccountsFromAddressMap(addressMap) {
|
|
|
350
544
|
return orderedAccounts;
|
|
351
545
|
}
|
|
352
546
|
function getCompiledAddressTableLookups(orderedAccounts) {
|
|
353
|
-
var _a;
|
|
354
547
|
const index = {};
|
|
355
548
|
for (const account of orderedAccounts) {
|
|
356
549
|
if (!("lookupTableAddress" in account)) {
|
|
357
550
|
continue;
|
|
358
551
|
}
|
|
359
|
-
const entry = index[
|
|
552
|
+
const entry = index[account.lookupTableAddress] ||= {
|
|
360
553
|
readableIndices: [],
|
|
361
554
|
writableIndices: []
|
|
362
|
-
}
|
|
555
|
+
};
|
|
363
556
|
if (account.role === AccountRole.WRITABLE) {
|
|
364
557
|
entry.writableIndices.push(account.addressIndex);
|
|
365
558
|
} else {
|
|
@@ -445,130 +638,68 @@ function compileMessage(transaction) {
|
|
|
445
638
|
version: transaction.version
|
|
446
639
|
};
|
|
447
640
|
}
|
|
448
|
-
|
|
449
|
-
// src/compile-transaction.ts
|
|
450
|
-
function getCompiledTransaction(transaction) {
|
|
451
|
-
const compiledMessage = compileMessage(transaction);
|
|
452
|
-
let signatures;
|
|
453
|
-
if ("signatures" in transaction) {
|
|
454
|
-
signatures = [];
|
|
455
|
-
for (let ii = 0; ii < compiledMessage.header.numSignerAccounts; ii++) {
|
|
456
|
-
signatures[ii] = transaction.signatures[compiledMessage.staticAccounts[ii]] ?? new Uint8Array(Array(64).fill(0));
|
|
457
|
-
}
|
|
458
|
-
} else {
|
|
459
|
-
signatures = Array(compiledMessage.header.numSignerAccounts).fill(new Uint8Array(Array(64).fill(0)));
|
|
460
|
-
}
|
|
461
|
-
return {
|
|
462
|
-
compiledMessage,
|
|
463
|
-
signatures
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
var lookupTableAddressDescription = __DEV__ ? "The address of the address lookup table account from which instruction addresses should be looked up" : "lookupTableAddress";
|
|
467
|
-
var writableIndicesDescription = __DEV__ ? "The indices of the accounts in the lookup table that should be loaded as writeable" : "writableIndices";
|
|
468
|
-
var readableIndicesDescription = __DEV__ ? "The indices of the accounts in the lookup table that should be loaded as read-only" : "readableIndices";
|
|
469
|
-
var addressTableLookupDescription = __DEV__ ? "A pointer to the address of an address lookup table, along with the readonly/writeable indices of the addresses that should be loaded from it" : "addressTableLookup";
|
|
470
641
|
var memoizedAddressTableLookupEncoder;
|
|
471
642
|
function getAddressTableLookupEncoder() {
|
|
472
643
|
if (!memoizedAddressTableLookupEncoder) {
|
|
473
|
-
memoizedAddressTableLookupEncoder = getStructEncoder(
|
|
644
|
+
memoizedAddressTableLookupEncoder = getStructEncoder([
|
|
645
|
+
["lookupTableAddress", getAddressEncoder()],
|
|
474
646
|
[
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
"writableIndices",
|
|
478
|
-
getArrayEncoder(getU8Encoder(), {
|
|
479
|
-
description: writableIndicesDescription,
|
|
480
|
-
size: getShortU16Encoder()
|
|
481
|
-
})
|
|
482
|
-
],
|
|
483
|
-
[
|
|
484
|
-
"readableIndices",
|
|
485
|
-
getArrayEncoder(getU8Encoder(), {
|
|
486
|
-
description: readableIndicesDescription,
|
|
487
|
-
size: getShortU16Encoder()
|
|
488
|
-
})
|
|
489
|
-
]
|
|
647
|
+
"writableIndices",
|
|
648
|
+
getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
|
|
490
649
|
],
|
|
491
|
-
|
|
492
|
-
|
|
650
|
+
[
|
|
651
|
+
"readableIndices",
|
|
652
|
+
getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
|
|
653
|
+
]
|
|
654
|
+
]);
|
|
493
655
|
}
|
|
494
656
|
return memoizedAddressTableLookupEncoder;
|
|
495
657
|
}
|
|
496
658
|
var memoizedAddressTableLookupDecoder;
|
|
497
659
|
function getAddressTableLookupDecoder() {
|
|
498
660
|
if (!memoizedAddressTableLookupDecoder) {
|
|
499
|
-
memoizedAddressTableLookupDecoder = getStructDecoder(
|
|
500
|
-
[
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
getArrayDecoder(getU8Decoder(), {
|
|
505
|
-
description: writableIndicesDescription,
|
|
506
|
-
size: getShortU16Decoder()
|
|
507
|
-
})
|
|
508
|
-
],
|
|
509
|
-
[
|
|
510
|
-
"readableIndices",
|
|
511
|
-
getArrayDecoder(getU8Decoder(), {
|
|
512
|
-
description: readableIndicesDescription,
|
|
513
|
-
size: getShortU16Decoder()
|
|
514
|
-
})
|
|
515
|
-
]
|
|
516
|
-
],
|
|
517
|
-
{ description: addressTableLookupDescription }
|
|
518
|
-
);
|
|
661
|
+
memoizedAddressTableLookupDecoder = getStructDecoder([
|
|
662
|
+
["lookupTableAddress", getAddressDecoder()],
|
|
663
|
+
["writableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
|
|
664
|
+
["readableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })]
|
|
665
|
+
]);
|
|
519
666
|
}
|
|
520
667
|
return memoizedAddressTableLookupDecoder;
|
|
521
668
|
}
|
|
522
|
-
|
|
523
|
-
|
|
669
|
+
var memoizedU8Encoder;
|
|
670
|
+
function getMemoizedU8Encoder() {
|
|
671
|
+
if (!memoizedU8Encoder)
|
|
672
|
+
memoizedU8Encoder = getU8Encoder();
|
|
673
|
+
return memoizedU8Encoder;
|
|
674
|
+
}
|
|
675
|
+
var memoizedU8Decoder;
|
|
676
|
+
function getMemoizedU8Decoder() {
|
|
677
|
+
if (!memoizedU8Decoder)
|
|
678
|
+
memoizedU8Decoder = getU8Decoder();
|
|
679
|
+
return memoizedU8Decoder;
|
|
680
|
+
}
|
|
681
|
+
function getMessageHeaderEncoder() {
|
|
682
|
+
return getStructEncoder([
|
|
683
|
+
["numSignerAccounts", getMemoizedU8Encoder()],
|
|
684
|
+
["numReadonlySignerAccounts", getMemoizedU8Encoder()],
|
|
685
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Encoder()]
|
|
686
|
+
]);
|
|
687
|
+
}
|
|
688
|
+
function getMessageHeaderDecoder() {
|
|
689
|
+
return getStructDecoder([
|
|
690
|
+
["numSignerAccounts", getMemoizedU8Decoder()],
|
|
691
|
+
["numReadonlySignerAccounts", getMemoizedU8Decoder()],
|
|
692
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Decoder()]
|
|
693
|
+
]);
|
|
524
694
|
}
|
|
525
|
-
var memoizedU8Codec;
|
|
526
|
-
function getMemoizedU8Codec() {
|
|
527
|
-
if (!memoizedU8Codec)
|
|
528
|
-
memoizedU8Codec = getU8Codec();
|
|
529
|
-
return memoizedU8Codec;
|
|
530
|
-
}
|
|
531
|
-
function getMemoizedU8CodecDescription(description) {
|
|
532
|
-
const codec = getMemoizedU8Codec();
|
|
533
|
-
return {
|
|
534
|
-
...codec,
|
|
535
|
-
description: description ?? codec.description
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
var numSignerAccountsDescription = __DEV__ ? "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction" : void 0;
|
|
539
|
-
var numReadonlySignerAccountsDescription = __DEV__ ? "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction, but may not be writable" : void 0;
|
|
540
|
-
var numReadonlyNonSignerAccountsDescription = __DEV__ ? "The expected number of addresses in the static address list belonging to accounts that are neither signers, nor writable" : void 0;
|
|
541
|
-
var messageHeaderDescription = __DEV__ ? "The transaction message header containing counts of the signer, readonly-signer, and readonly-nonsigner account addresses" : void 0;
|
|
542
|
-
function getMessageHeaderCodec() {
|
|
543
|
-
return getStructCodec(
|
|
544
|
-
[
|
|
545
|
-
["numSignerAccounts", getMemoizedU8CodecDescription(numSignerAccountsDescription)],
|
|
546
|
-
["numReadonlySignerAccounts", getMemoizedU8CodecDescription(numReadonlySignerAccountsDescription)],
|
|
547
|
-
["numReadonlyNonSignerAccounts", getMemoizedU8CodecDescription(numReadonlyNonSignerAccountsDescription)]
|
|
548
|
-
],
|
|
549
|
-
{
|
|
550
|
-
description: messageHeaderDescription
|
|
551
|
-
}
|
|
552
|
-
);
|
|
553
|
-
}
|
|
554
|
-
var programAddressIndexDescription = __DEV__ ? "The index of the program being called, according to the well-ordered accounts list for this transaction" : "programAddressIndex";
|
|
555
|
-
var accountIndexDescription = __DEV__ ? "The index of an account, according to the well-ordered accounts list for this transaction" : void 0;
|
|
556
|
-
var accountIndicesDescription = __DEV__ ? "An optional list of account indices, according to the well-ordered accounts list for this transaction, in the order in which the program being called expects them" : "accountIndices";
|
|
557
|
-
var dataDescription = __DEV__ ? "An optional buffer of data passed to the instruction" : "data";
|
|
558
695
|
var memoizedGetInstructionEncoder;
|
|
559
696
|
function getInstructionEncoder() {
|
|
560
697
|
if (!memoizedGetInstructionEncoder) {
|
|
561
698
|
memoizedGetInstructionEncoder = mapEncoder(
|
|
562
699
|
getStructEncoder([
|
|
563
|
-
["programAddressIndex", getU8Encoder(
|
|
564
|
-
[
|
|
565
|
-
|
|
566
|
-
getArrayEncoder(getU8Encoder({ description: accountIndexDescription }), {
|
|
567
|
-
description: accountIndicesDescription,
|
|
568
|
-
size: getShortU16Encoder()
|
|
569
|
-
})
|
|
570
|
-
],
|
|
571
|
-
["data", getBytesEncoder({ description: dataDescription, size: getShortU16Encoder() })]
|
|
700
|
+
["programAddressIndex", getU8Encoder()],
|
|
701
|
+
["accountIndices", getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })],
|
|
702
|
+
["data", getBytesEncoder({ size: getShortU16Encoder() })]
|
|
572
703
|
]),
|
|
573
704
|
// Convert an instruction to have all fields defined
|
|
574
705
|
(instruction) => {
|
|
@@ -590,15 +721,9 @@ function getInstructionDecoder() {
|
|
|
590
721
|
if (!memoizedGetInstructionDecoder) {
|
|
591
722
|
memoizedGetInstructionDecoder = mapDecoder(
|
|
592
723
|
getStructDecoder([
|
|
593
|
-
["programAddressIndex", getU8Decoder(
|
|
594
|
-
[
|
|
595
|
-
|
|
596
|
-
getArrayDecoder(getU8Decoder({ description: accountIndexDescription }), {
|
|
597
|
-
description: accountIndicesDescription,
|
|
598
|
-
size: getShortU16Decoder()
|
|
599
|
-
})
|
|
600
|
-
],
|
|
601
|
-
["data", getBytesDecoder({ description: dataDescription, size: getShortU16Decoder() })]
|
|
724
|
+
["programAddressIndex", getU8Decoder()],
|
|
725
|
+
["accountIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
|
|
726
|
+
["data", getBytesDecoder({ size: getShortU16Decoder() })]
|
|
602
727
|
]),
|
|
603
728
|
// Convert an instruction to exclude optional fields if they are empty
|
|
604
729
|
(instruction) => {
|
|
@@ -616,225 +741,185 @@ function getInstructionDecoder() {
|
|
|
616
741
|
}
|
|
617
742
|
return memoizedGetInstructionDecoder;
|
|
618
743
|
}
|
|
619
|
-
function getInstructionCodec() {
|
|
620
|
-
return combineCodec(getInstructionEncoder(), getInstructionDecoder());
|
|
621
|
-
}
|
|
622
744
|
var VERSION_FLAG_MASK = 128;
|
|
623
|
-
var BASE_CONFIG = {
|
|
624
|
-
description: __DEV__ ? "A single byte that encodes the version of the transaction" : "",
|
|
625
|
-
fixedSize: null,
|
|
626
|
-
maxSize: 1
|
|
627
|
-
};
|
|
628
|
-
function decode(bytes2, offset = 0) {
|
|
629
|
-
const firstByte = bytes2[offset];
|
|
630
|
-
if ((firstByte & VERSION_FLAG_MASK) === 0) {
|
|
631
|
-
return ["legacy", offset];
|
|
632
|
-
} else {
|
|
633
|
-
const version = firstByte ^ VERSION_FLAG_MASK;
|
|
634
|
-
return [version, offset + 1];
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
function encode(value) {
|
|
638
|
-
if (value === "legacy") {
|
|
639
|
-
return new Uint8Array();
|
|
640
|
-
}
|
|
641
|
-
if (value < 0 || value > 127) {
|
|
642
|
-
throw new Error(`Transaction version must be in the range [0, 127]. \`${value}\` given.`);
|
|
643
|
-
}
|
|
644
|
-
return new Uint8Array([value | VERSION_FLAG_MASK]);
|
|
645
|
-
}
|
|
646
|
-
function getTransactionVersionDecoder() {
|
|
647
|
-
return {
|
|
648
|
-
...BASE_CONFIG,
|
|
649
|
-
decode
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
745
|
function getTransactionVersionEncoder() {
|
|
653
|
-
return {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
746
|
+
return createEncoder({
|
|
747
|
+
getSizeFromValue: (value) => value === "legacy" ? 0 : 1,
|
|
748
|
+
maxSize: 1,
|
|
749
|
+
write: (value, bytes, offset) => {
|
|
750
|
+
if (value === "legacy") {
|
|
751
|
+
return offset;
|
|
752
|
+
}
|
|
753
|
+
if (value < 0 || value > 127) {
|
|
754
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__VERSION_NUMBER_OUT_OF_RANGE, {
|
|
755
|
+
actualVersion: value
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
bytes.set([value | VERSION_FLAG_MASK], offset);
|
|
759
|
+
return offset + 1;
|
|
760
|
+
}
|
|
761
|
+
});
|
|
668
762
|
}
|
|
669
|
-
function
|
|
670
|
-
return (
|
|
671
|
-
|
|
672
|
-
|
|
763
|
+
function getTransactionVersionDecoder() {
|
|
764
|
+
return createDecoder({
|
|
765
|
+
maxSize: 1,
|
|
766
|
+
read: (bytes, offset) => {
|
|
767
|
+
const firstByte = bytes[offset];
|
|
768
|
+
if ((firstByte & VERSION_FLAG_MASK) === 0) {
|
|
769
|
+
return ["legacy", offset];
|
|
770
|
+
} else {
|
|
771
|
+
const version = firstByte ^ VERSION_FLAG_MASK;
|
|
772
|
+
return [version, offset + 1];
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
});
|
|
673
776
|
}
|
|
674
777
|
|
|
675
778
|
// src/serializers/message.ts
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
["addressTableLookups", getAddressTableLookupsSerializer()]
|
|
689
|
-
]),
|
|
690
|
-
(value) => {
|
|
691
|
-
if (value.version === "legacy") {
|
|
692
|
-
return value;
|
|
693
|
-
}
|
|
694
|
-
return {
|
|
695
|
-
...value,
|
|
696
|
-
addressTableLookups: value.addressTableLookups ?? []
|
|
697
|
-
};
|
|
779
|
+
function getCompiledMessageLegacyEncoder() {
|
|
780
|
+
return getStructEncoder(getPreludeStructEncoderTuple());
|
|
781
|
+
}
|
|
782
|
+
function getCompiledMessageVersionedEncoder() {
|
|
783
|
+
return mapEncoder(
|
|
784
|
+
getStructEncoder([
|
|
785
|
+
...getPreludeStructEncoderTuple(),
|
|
786
|
+
["addressTableLookups", getAddressTableLookupArrayEncoder()]
|
|
787
|
+
]),
|
|
788
|
+
(value) => {
|
|
789
|
+
if (value.version === "legacy") {
|
|
790
|
+
return value;
|
|
698
791
|
}
|
|
699
|
-
|
|
700
|
-
|
|
792
|
+
return {
|
|
793
|
+
...value,
|
|
794
|
+
addressTableLookups: value.addressTableLookups ?? []
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
);
|
|
701
798
|
}
|
|
702
|
-
function
|
|
703
|
-
return
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
799
|
+
function getPreludeStructEncoderTuple() {
|
|
800
|
+
return [
|
|
801
|
+
["version", getTransactionVersionEncoder()],
|
|
802
|
+
["header", getMessageHeaderEncoder()],
|
|
803
|
+
["staticAccounts", getArrayEncoder(getAddressEncoder(), { size: getShortU16Encoder() })],
|
|
804
|
+
["lifetimeToken", getStringEncoder({ encoding: getBase58Encoder(), size: 32 })],
|
|
805
|
+
["instructions", getArrayEncoder(getInstructionEncoder(), { size: getShortU16Encoder() })]
|
|
806
|
+
];
|
|
710
807
|
}
|
|
711
|
-
function
|
|
808
|
+
function getPreludeStructDecoderTuple() {
|
|
712
809
|
return [
|
|
713
|
-
["version",
|
|
714
|
-
["header",
|
|
715
|
-
[
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
size: shortU16()
|
|
720
|
-
})
|
|
721
|
-
],
|
|
722
|
-
[
|
|
723
|
-
"lifetimeToken",
|
|
724
|
-
string({
|
|
725
|
-
description: __DEV__ ? "A 32-byte token that specifies the lifetime of this transaction (eg. a recent blockhash, or a durable nonce)" : "",
|
|
726
|
-
encoding: base58,
|
|
727
|
-
size: 32
|
|
728
|
-
})
|
|
729
|
-
],
|
|
730
|
-
[
|
|
731
|
-
"instructions",
|
|
732
|
-
array(toSerializer(getInstructionCodec()), {
|
|
733
|
-
description: __DEV__ ? "A compact-array of instructions belonging to this transaction" : "",
|
|
734
|
-
size: shortU16()
|
|
735
|
-
})
|
|
736
|
-
]
|
|
810
|
+
["version", getTransactionVersionDecoder()],
|
|
811
|
+
["header", getMessageHeaderDecoder()],
|
|
812
|
+
["staticAccounts", getArrayDecoder(getAddressDecoder(), { size: getShortU16Decoder() })],
|
|
813
|
+
["lifetimeToken", getStringDecoder({ encoding: getBase58Decoder(), size: 32 })],
|
|
814
|
+
["instructions", getArrayDecoder(getInstructionDecoder(), { size: getShortU16Decoder() })],
|
|
815
|
+
["addressTableLookups", getAddressTableLookupArrayDecoder()]
|
|
737
816
|
];
|
|
738
817
|
}
|
|
739
|
-
function
|
|
740
|
-
return
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
});
|
|
818
|
+
function getAddressTableLookupArrayEncoder() {
|
|
819
|
+
return getArrayEncoder(getAddressTableLookupEncoder(), { size: getShortU16Encoder() });
|
|
820
|
+
}
|
|
821
|
+
function getAddressTableLookupArrayDecoder() {
|
|
822
|
+
return getArrayDecoder(getAddressTableLookupDecoder(), { size: getShortU16Decoder() });
|
|
744
823
|
}
|
|
745
824
|
function getCompiledMessageEncoder() {
|
|
825
|
+
return createEncoder({
|
|
826
|
+
getSizeFromValue: (compiledMessage) => {
|
|
827
|
+
if (compiledMessage.version === "legacy") {
|
|
828
|
+
return getCompiledMessageLegacyEncoder().getSizeFromValue(compiledMessage);
|
|
829
|
+
} else {
|
|
830
|
+
return getCompiledMessageVersionedEncoder().getSizeFromValue(compiledMessage);
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
write: (compiledMessage, bytes, offset) => {
|
|
834
|
+
if (compiledMessage.version === "legacy") {
|
|
835
|
+
return getCompiledMessageLegacyEncoder().write(compiledMessage, bytes, offset);
|
|
836
|
+
} else {
|
|
837
|
+
return getCompiledMessageVersionedEncoder().write(compiledMessage, bytes, offset);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
function getCompiledMessageDecoder() {
|
|
843
|
+
return mapDecoder(
|
|
844
|
+
getStructDecoder(getPreludeStructDecoderTuple()),
|
|
845
|
+
({ addressTableLookups, ...restOfMessage }) => {
|
|
846
|
+
if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
|
|
847
|
+
return restOfMessage;
|
|
848
|
+
}
|
|
849
|
+
return { ...restOfMessage, addressTableLookups };
|
|
850
|
+
}
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
function getCompiledMessageCodec() {
|
|
854
|
+
return combineCodec(getCompiledMessageEncoder(), getCompiledMessageDecoder());
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/compile-transaction.ts
|
|
858
|
+
function getCompiledTransaction(transaction) {
|
|
859
|
+
const compiledMessage = compileMessage(transaction);
|
|
860
|
+
let signatures;
|
|
861
|
+
if ("signatures" in transaction) {
|
|
862
|
+
signatures = [];
|
|
863
|
+
for (let ii = 0; ii < compiledMessage.header.numSignerAccounts; ii++) {
|
|
864
|
+
signatures[ii] = transaction.signatures[compiledMessage.staticAccounts[ii]] ?? new Uint8Array(Array(64).fill(0));
|
|
865
|
+
}
|
|
866
|
+
} else {
|
|
867
|
+
signatures = Array(compiledMessage.header.numSignerAccounts).fill(new Uint8Array(Array(64).fill(0)));
|
|
868
|
+
}
|
|
746
869
|
return {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
serialize
|
|
870
|
+
compiledMessage,
|
|
871
|
+
signatures
|
|
750
872
|
};
|
|
751
873
|
}
|
|
752
874
|
|
|
753
875
|
// src/serializers/transaction.ts
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
return
|
|
876
|
+
function getCompiledTransactionEncoder() {
|
|
877
|
+
return getStructEncoder([
|
|
878
|
+
["signatures", getArrayEncoder(getBytesEncoder({ size: 64 }), { size: getShortU16Encoder() })],
|
|
879
|
+
["compiledMessage", getCompiledMessageEncoder()]
|
|
880
|
+
]);
|
|
881
|
+
}
|
|
882
|
+
function getCompiledTransactionDecoder() {
|
|
883
|
+
return getStructDecoder([
|
|
762
884
|
[
|
|
763
885
|
"signatures",
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
size: shortU16()
|
|
886
|
+
getArrayDecoder(getBytesDecoder({ size: 64 }), {
|
|
887
|
+
size: getShortU16Decoder()
|
|
767
888
|
})
|
|
768
889
|
],
|
|
769
|
-
["compiledMessage",
|
|
770
|
-
])
|
|
890
|
+
["compiledMessage", getCompiledMessageDecoder()]
|
|
891
|
+
]);
|
|
771
892
|
}
|
|
772
893
|
function getTransactionEncoder() {
|
|
773
|
-
return
|
|
774
|
-
...BASE_CONFIG3,
|
|
775
|
-
deserialize: getUnimplementedDecoder("CompiledMessage"),
|
|
776
|
-
serialize: serialize2
|
|
777
|
-
};
|
|
894
|
+
return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
|
|
778
895
|
}
|
|
779
|
-
function
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
putativeTransactionSignature.length > 88
|
|
785
|
-
) {
|
|
786
|
-
throw new Error("Expected input string to decode to a byte array of length 64.");
|
|
787
|
-
}
|
|
788
|
-
const bytes2 = base58.serialize(putativeTransactionSignature);
|
|
789
|
-
const numBytes = bytes2.byteLength;
|
|
790
|
-
if (numBytes !== 64) {
|
|
791
|
-
throw new Error(`Expected input string to decode to a byte array of length 64. Actual length: ${numBytes}`);
|
|
792
|
-
}
|
|
793
|
-
} catch (e) {
|
|
794
|
-
throw new Error(`\`${putativeTransactionSignature}\` is not a transaction signature`, {
|
|
795
|
-
cause: e
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
function isTransactionSignature(putativeTransactionSignature) {
|
|
800
|
-
if (
|
|
801
|
-
// Lowest value (64 bytes of zeroes)
|
|
802
|
-
putativeTransactionSignature.length < 64 || // Highest value (64 bytes of 255)
|
|
803
|
-
putativeTransactionSignature.length > 88
|
|
804
|
-
) {
|
|
805
|
-
return false;
|
|
806
|
-
}
|
|
807
|
-
const bytes2 = base58.serialize(putativeTransactionSignature);
|
|
808
|
-
const numBytes = bytes2.byteLength;
|
|
809
|
-
if (numBytes !== 64) {
|
|
810
|
-
return false;
|
|
811
|
-
}
|
|
812
|
-
return true;
|
|
896
|
+
function getTransactionDecoder(config) {
|
|
897
|
+
return mapDecoder(
|
|
898
|
+
getCompiledTransactionDecoder(),
|
|
899
|
+
(compiledTransaction) => decompileTransaction(compiledTransaction, config)
|
|
900
|
+
);
|
|
813
901
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const signature = await signBytes(secretKey, wireMessageBytes);
|
|
817
|
-
return signature;
|
|
902
|
+
function getTransactionCodec(config) {
|
|
903
|
+
return combineCodec(getTransactionEncoder(), getTransactionDecoder(config));
|
|
818
904
|
}
|
|
905
|
+
var base58Decoder;
|
|
819
906
|
function getSignatureFromTransaction(transaction) {
|
|
907
|
+
if (!base58Decoder)
|
|
908
|
+
base58Decoder = getBase58Decoder();
|
|
820
909
|
const signatureBytes = transaction.signatures[transaction.feePayer];
|
|
821
910
|
if (!signatureBytes) {
|
|
822
|
-
throw new
|
|
823
|
-
"Could not determine this transaction's signature. Make sure that the transaction has been signed by its fee payer."
|
|
824
|
-
);
|
|
911
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING);
|
|
825
912
|
}
|
|
826
|
-
const
|
|
827
|
-
return
|
|
913
|
+
const transactionSignature = base58Decoder.decode(signatureBytes);
|
|
914
|
+
return transactionSignature;
|
|
828
915
|
}
|
|
829
|
-
async function
|
|
916
|
+
async function partiallySignTransaction(keyPairs, transaction) {
|
|
830
917
|
const compiledMessage = compileMessage(transaction);
|
|
831
918
|
const nextSignatures = "signatures" in transaction ? { ...transaction.signatures } : {};
|
|
919
|
+
const wireMessageBytes = getCompiledMessageEncoder().encode(compiledMessage);
|
|
832
920
|
const publicKeySignaturePairs = await Promise.all(
|
|
833
921
|
keyPairs.map(
|
|
834
|
-
(keyPair) => Promise.all([
|
|
835
|
-
getAddressFromPublicKey(keyPair.publicKey),
|
|
836
|
-
getCompiledMessageSignature(compiledMessage, keyPair.privateKey)
|
|
837
|
-
])
|
|
922
|
+
(keyPair) => Promise.all([getAddressFromPublicKey(keyPair.publicKey), signBytes(keyPair.privateKey, wireMessageBytes)])
|
|
838
923
|
)
|
|
839
924
|
);
|
|
840
925
|
for (const [signerPublicKey, signature] of publicKeySignaturePairs) {
|
|
@@ -847,17 +932,32 @@ async function signTransaction(keyPairs, transaction) {
|
|
|
847
932
|
Object.freeze(out);
|
|
848
933
|
return out;
|
|
849
934
|
}
|
|
850
|
-
function
|
|
851
|
-
|
|
852
|
-
|
|
935
|
+
async function signTransaction(keyPairs, transaction) {
|
|
936
|
+
const out = await partiallySignTransaction(keyPairs, transaction);
|
|
937
|
+
assertTransactionIsFullySigned(out);
|
|
938
|
+
Object.freeze(out);
|
|
939
|
+
return out;
|
|
853
940
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
const
|
|
858
|
-
{
|
|
859
|
-
|
|
941
|
+
function assertTransactionIsFullySigned(transaction) {
|
|
942
|
+
const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
|
|
943
|
+
const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
|
|
944
|
+
const missingSigs = [];
|
|
945
|
+
requiredSigners.forEach((address) => {
|
|
946
|
+
if (!transaction.signatures[address]) {
|
|
947
|
+
missingSigs.push(address);
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
if (missingSigs.length > 0) {
|
|
951
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING, {
|
|
952
|
+
addresses: missingSigs
|
|
953
|
+
});
|
|
860
954
|
}
|
|
861
955
|
}
|
|
956
|
+
function getBase64EncodedWireTransaction(transaction) {
|
|
957
|
+
const wireTransactionBytes = getTransactionEncoder().encode(transaction);
|
|
958
|
+
return getBase64Decoder().decode(wireTransactionBytes);
|
|
959
|
+
}
|
|
862
960
|
|
|
863
|
-
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 };
|
|
962
|
+
//# sourceMappingURL=out.js.map
|
|
963
|
+
//# sourceMappingURL=index.browser.js.map
|