@solana/transactions 2.0.0-experimental.0a6605f → 2.0.0-experimental.0ba8f21
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 +1 -1
- package/README.md +276 -5
- package/dist/index.browser.cjs +529 -305
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +512 -306
- package/dist/index.browser.js.map +1 -1
- package/dist/index.native.js +512 -306
- package/dist/index.native.js.map +1 -1
- package/dist/index.node.cjs +527 -305
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +514 -306
- 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 +5 -7
- 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 +2 -2
- package/dist/types/compile-instructions.d.ts.map +1 -0
- package/dist/types/compile-lifetime-token.d.ts +1 -1
- 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 +11 -10
- package/dist/types/durable-nonce.d.ts.map +1 -0
- package/dist/types/fee-payer.d.ts +6 -5
- package/dist/types/fee-payer.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -8
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/instructions.d.ts +4 -2
- 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 -3
- package/dist/types/serializers/address-table-lookup.d.ts.map +1 -0
- package/dist/types/serializers/header.d.ts +5 -3
- package/dist/types/serializers/header.d.ts.map +1 -0
- package/dist/types/serializers/index.d.ts +3 -0
- package/dist/types/serializers/index.d.ts.map +1 -0
- package/dist/types/serializers/instruction.d.ts +5 -3
- 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 +10 -5
- package/dist/types/signatures.d.ts.map +1 -0
- package/dist/types/types.d.ts +13 -13
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/unsigned-transaction.d.ts +1 -1
- package/dist/types/unsigned-transaction.d.ts.map +1 -0
- package/dist/types/wire-transaction.d.ts +3 -3
- package/dist/types/wire-transaction.d.ts.map +1 -0
- package/package.json +21 -38
- package/dist/index.development.js +0 -1323
- package/dist/index.development.js.map +0 -1
- package/dist/index.production.min.js +0 -20
- package/dist/types/serializers/unimplemented.d.ts +0 -3
package/dist/index.native.js
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if ("signatures" in transaction) {
|
|
10
|
-
const {
|
|
11
|
-
signatures: _,
|
|
12
|
-
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
13
|
-
...unsignedTransaction
|
|
14
|
-
} = transaction;
|
|
15
|
-
return unsignedTransaction;
|
|
16
|
-
} else {
|
|
17
|
-
return transaction;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
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__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';
|
|
8
|
+
import { signBytes } from '@solana/keys';
|
|
20
9
|
|
|
21
10
|
// src/blockhash.ts
|
|
11
|
+
var base58Encoder;
|
|
22
12
|
function assertIsBlockhash(putativeBlockhash) {
|
|
13
|
+
if (!base58Encoder)
|
|
14
|
+
base58Encoder = getBase58Encoder();
|
|
23
15
|
try {
|
|
24
16
|
if (
|
|
25
17
|
// Lowest value (32 bytes of zeroes)
|
|
@@ -28,8 +20,8 @@ function assertIsBlockhash(putativeBlockhash) {
|
|
|
28
20
|
) {
|
|
29
21
|
throw new Error("Expected input string to decode to a byte array of length 32.");
|
|
30
22
|
}
|
|
31
|
-
const
|
|
32
|
-
const numBytes =
|
|
23
|
+
const bytes = base58Encoder.encode(putativeBlockhash);
|
|
24
|
+
const numBytes = bytes.byteLength;
|
|
33
25
|
if (numBytes !== 32) {
|
|
34
26
|
throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
|
|
35
27
|
}
|
|
@@ -39,6 +31,38 @@ function assertIsBlockhash(putativeBlockhash) {
|
|
|
39
31
|
});
|
|
40
32
|
}
|
|
41
33
|
}
|
|
34
|
+
|
|
35
|
+
// src/unsigned-transaction.ts
|
|
36
|
+
function getUnsignedTransaction(transaction) {
|
|
37
|
+
if ("signatures" in transaction) {
|
|
38
|
+
const {
|
|
39
|
+
signatures: _,
|
|
40
|
+
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
41
|
+
...unsignedTransaction
|
|
42
|
+
} = transaction;
|
|
43
|
+
return unsignedTransaction;
|
|
44
|
+
} else {
|
|
45
|
+
return transaction;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/blockhash.ts
|
|
50
|
+
function isTransactionWithBlockhashLifetime(transaction) {
|
|
51
|
+
const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
|
|
52
|
+
if (!lifetimeConstraintShapeMatches)
|
|
53
|
+
return false;
|
|
54
|
+
try {
|
|
55
|
+
assertIsBlockhash(transaction.lifetimeConstraint.blockhash);
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function assertIsTransactionWithBlockhashLifetime(transaction) {
|
|
62
|
+
if (!isTransactionWithBlockhashLifetime(transaction)) {
|
|
63
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_BLOCKHASH_LIFETIME);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
function setTransactionLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
|
|
43
67
|
if ("lifetimeConstraint" in transaction && transaction.lifetimeConstraint.blockhash === blockhashLifetimeConstraint.blockhash && transaction.lifetimeConstraint.lastValidBlockHeight === blockhashLifetimeConstraint.lastValidBlockHeight) {
|
|
44
68
|
return transaction;
|
|
@@ -85,13 +109,11 @@ function isWritableRole(role) {
|
|
|
85
109
|
function mergeRoles(roleA, roleB) {
|
|
86
110
|
return roleA | roleB;
|
|
87
111
|
}
|
|
88
|
-
|
|
89
|
-
// src/durable-nonce.ts
|
|
90
112
|
var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
|
|
91
113
|
var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
92
114
|
function assertIsDurableNonceTransaction(transaction) {
|
|
93
115
|
if (!isDurableNonceTransaction(transaction)) {
|
|
94
|
-
throw new
|
|
116
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_NONCE_LIFETIME);
|
|
95
117
|
}
|
|
96
118
|
}
|
|
97
119
|
function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
|
|
@@ -114,7 +136,7 @@ function isAdvanceNonceAccountInstruction(instruction) {
|
|
|
114
136
|
instruction.accounts?.length === 3 && // First account is nonce account address
|
|
115
137
|
instruction.accounts[0].address != null && instruction.accounts[0].role === AccountRole.WRITABLE && // Second account is recent blockhashes sysvar
|
|
116
138
|
instruction.accounts[1].address === RECENT_BLOCKHASHES_SYSVAR_ADDRESS && instruction.accounts[1].role === AccountRole.READONLY && // Third account is nonce authority account
|
|
117
|
-
instruction.accounts[2].address != null && instruction.accounts[2].role
|
|
139
|
+
instruction.accounts[2].address != null && isSignerRole(instruction.accounts[2].role);
|
|
118
140
|
}
|
|
119
141
|
function isAdvanceNonceAccountInstructionData(data) {
|
|
120
142
|
return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;
|
|
@@ -122,21 +144,38 @@ function isAdvanceNonceAccountInstructionData(data) {
|
|
|
122
144
|
function isDurableNonceTransaction(transaction) {
|
|
123
145
|
return "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.nonce === "string" && transaction.instructions[0] != null && isAdvanceNonceAccountInstruction(transaction.instructions[0]);
|
|
124
146
|
}
|
|
147
|
+
function isAdvanceNonceAccountInstructionForNonce(instruction, nonceAccountAddress, nonceAuthorityAddress) {
|
|
148
|
+
return instruction.accounts[0].address === nonceAccountAddress && instruction.accounts[2].address === nonceAuthorityAddress;
|
|
149
|
+
}
|
|
125
150
|
function setTransactionLifetimeUsingDurableNonce({
|
|
126
151
|
nonce,
|
|
127
152
|
nonceAccountAddress,
|
|
128
153
|
nonceAuthorityAddress
|
|
129
154
|
}, transaction) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
155
|
+
let newInstructions;
|
|
156
|
+
const firstInstruction = transaction.instructions[0];
|
|
157
|
+
if (firstInstruction && isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
158
|
+
if (isAdvanceNonceAccountInstructionForNonce(firstInstruction, nonceAccountAddress, nonceAuthorityAddress)) {
|
|
159
|
+
if (isDurableNonceTransaction(transaction) && transaction.lifetimeConstraint.nonce === nonce) {
|
|
160
|
+
return transaction;
|
|
161
|
+
} else {
|
|
162
|
+
newInstructions = [firstInstruction, ...transaction.instructions.slice(1)];
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
newInstructions = [
|
|
166
|
+
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
167
|
+
...transaction.instructions.slice(1)
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
newInstructions = [
|
|
172
|
+
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
173
|
+
...transaction.instructions
|
|
174
|
+
];
|
|
133
175
|
}
|
|
134
176
|
const out = {
|
|
135
177
|
...getUnsignedTransaction(transaction),
|
|
136
|
-
instructions:
|
|
137
|
-
createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
|
|
138
|
-
...isAlreadyDurableNonceTransaction ? transaction.instructions.slice(1) : transaction.instructions
|
|
139
|
-
],
|
|
178
|
+
instructions: newInstructions,
|
|
140
179
|
lifetimeConstraint: {
|
|
141
180
|
nonce
|
|
142
181
|
}
|
|
@@ -160,21 +199,181 @@ function setTransactionFeePayer(feePayer, transaction) {
|
|
|
160
199
|
|
|
161
200
|
// src/instructions.ts
|
|
162
201
|
function appendTransactionInstruction(instruction, transaction) {
|
|
202
|
+
return appendTransactionInstructions([instruction], transaction);
|
|
203
|
+
}
|
|
204
|
+
function appendTransactionInstructions(instructions, transaction) {
|
|
163
205
|
const out = {
|
|
164
206
|
...getUnsignedTransaction(transaction),
|
|
165
|
-
instructions: [...transaction.instructions,
|
|
207
|
+
instructions: [...transaction.instructions, ...instructions]
|
|
166
208
|
};
|
|
167
209
|
Object.freeze(out);
|
|
168
210
|
return out;
|
|
169
211
|
}
|
|
170
212
|
function prependTransactionInstruction(instruction, transaction) {
|
|
213
|
+
return prependTransactionInstructions([instruction], transaction);
|
|
214
|
+
}
|
|
215
|
+
function prependTransactionInstructions(instructions, transaction) {
|
|
171
216
|
const out = {
|
|
172
217
|
...getUnsignedTransaction(transaction),
|
|
173
|
-
instructions: [
|
|
218
|
+
instructions: [...instructions, ...transaction.instructions]
|
|
174
219
|
};
|
|
175
220
|
Object.freeze(out);
|
|
176
221
|
return out;
|
|
177
222
|
}
|
|
223
|
+
|
|
224
|
+
// src/decompile-transaction.ts
|
|
225
|
+
function getAccountMetas(message) {
|
|
226
|
+
const { header } = message;
|
|
227
|
+
const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
|
|
228
|
+
const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
|
|
229
|
+
const accountMetas = [];
|
|
230
|
+
let accountIndex = 0;
|
|
231
|
+
for (let i = 0; i < numWritableSignerAccounts; i++) {
|
|
232
|
+
accountMetas.push({
|
|
233
|
+
address: message.staticAccounts[accountIndex],
|
|
234
|
+
role: AccountRole.WRITABLE_SIGNER
|
|
235
|
+
});
|
|
236
|
+
accountIndex++;
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
|
|
239
|
+
accountMetas.push({
|
|
240
|
+
address: message.staticAccounts[accountIndex],
|
|
241
|
+
role: AccountRole.READONLY_SIGNER
|
|
242
|
+
});
|
|
243
|
+
accountIndex++;
|
|
244
|
+
}
|
|
245
|
+
for (let i = 0; i < numWritableNonSignerAccounts; i++) {
|
|
246
|
+
accountMetas.push({
|
|
247
|
+
address: message.staticAccounts[accountIndex],
|
|
248
|
+
role: AccountRole.WRITABLE
|
|
249
|
+
});
|
|
250
|
+
accountIndex++;
|
|
251
|
+
}
|
|
252
|
+
for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
|
|
253
|
+
accountMetas.push({
|
|
254
|
+
address: message.staticAccounts[accountIndex],
|
|
255
|
+
role: AccountRole.READONLY
|
|
256
|
+
});
|
|
257
|
+
accountIndex++;
|
|
258
|
+
}
|
|
259
|
+
return accountMetas;
|
|
260
|
+
}
|
|
261
|
+
function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTableAddress) {
|
|
262
|
+
const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
|
|
263
|
+
const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
|
|
264
|
+
if (missing.length > 0) {
|
|
265
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, {
|
|
266
|
+
lookupTableAddresses: missing
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const readOnlyMetas = [];
|
|
270
|
+
const writableMetas = [];
|
|
271
|
+
for (const lookup of compiledAddressTableLookups) {
|
|
272
|
+
const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
|
|
273
|
+
const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
|
|
274
|
+
if (highestIndex >= addresses.length) {
|
|
275
|
+
throw new SolanaError(
|
|
276
|
+
SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE,
|
|
277
|
+
{
|
|
278
|
+
highestKnownIndex: addresses.length - 1,
|
|
279
|
+
highestRequestedIndex: highestIndex,
|
|
280
|
+
lookupTableAddress: lookup.lookupTableAddress
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
const readOnlyForLookup = lookup.readableIndices.map((r) => ({
|
|
285
|
+
address: addresses[r],
|
|
286
|
+
addressIndex: r,
|
|
287
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
288
|
+
role: AccountRole.READONLY
|
|
289
|
+
}));
|
|
290
|
+
readOnlyMetas.push(...readOnlyForLookup);
|
|
291
|
+
const writableForLookup = lookup.writableIndices.map((w) => ({
|
|
292
|
+
address: addresses[w],
|
|
293
|
+
addressIndex: w,
|
|
294
|
+
lookupTableAddress: lookup.lookupTableAddress,
|
|
295
|
+
role: AccountRole.WRITABLE
|
|
296
|
+
}));
|
|
297
|
+
writableMetas.push(...writableForLookup);
|
|
298
|
+
}
|
|
299
|
+
return [...writableMetas, ...readOnlyMetas];
|
|
300
|
+
}
|
|
301
|
+
function convertInstruction(instruction, accountMetas) {
|
|
302
|
+
const programAddress = accountMetas[instruction.programAddressIndex]?.address;
|
|
303
|
+
if (!programAddress) {
|
|
304
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, {
|
|
305
|
+
index: instruction.programAddressIndex
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
|
|
309
|
+
const { data } = instruction;
|
|
310
|
+
return {
|
|
311
|
+
programAddress,
|
|
312
|
+
...accounts && accounts.length ? { accounts } : {},
|
|
313
|
+
...data && data.length ? { data } : {}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
|
|
317
|
+
if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
|
|
318
|
+
return {
|
|
319
|
+
blockhash: messageLifetimeToken,
|
|
320
|
+
lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
|
|
321
|
+
// U64 MAX
|
|
322
|
+
};
|
|
323
|
+
} else {
|
|
324
|
+
const nonceAccountAddress = firstInstruction.accounts[0].address;
|
|
325
|
+
assertIsAddress(nonceAccountAddress);
|
|
326
|
+
const nonceAuthorityAddress = firstInstruction.accounts[2].address;
|
|
327
|
+
assertIsAddress(nonceAuthorityAddress);
|
|
328
|
+
return {
|
|
329
|
+
nonce: messageLifetimeToken,
|
|
330
|
+
nonceAccountAddress,
|
|
331
|
+
nonceAuthorityAddress
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function convertSignatures(compiledTransaction) {
|
|
336
|
+
const {
|
|
337
|
+
compiledMessage: { staticAccounts },
|
|
338
|
+
signatures
|
|
339
|
+
} = compiledTransaction;
|
|
340
|
+
return signatures.reduce((acc, sig, index) => {
|
|
341
|
+
const allZeros = sig.every((byte) => byte === 0);
|
|
342
|
+
if (allZeros)
|
|
343
|
+
return acc;
|
|
344
|
+
const address = staticAccounts[index];
|
|
345
|
+
return { ...acc, [address]: sig };
|
|
346
|
+
}, {});
|
|
347
|
+
}
|
|
348
|
+
function decompileTransaction(compiledTransaction, config) {
|
|
349
|
+
const { compiledMessage } = compiledTransaction;
|
|
350
|
+
const feePayer = compiledMessage.staticAccounts[0];
|
|
351
|
+
if (!feePayer) {
|
|
352
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_FEE_PAYER_MISSING);
|
|
353
|
+
}
|
|
354
|
+
const accountMetas = getAccountMetas(compiledMessage);
|
|
355
|
+
const accountLookupMetas = "addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups !== void 0 && compiledMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(compiledMessage.addressTableLookups, config?.addressesByLookupTableAddress ?? {}) : [];
|
|
356
|
+
const transactionMetas = [...accountMetas, ...accountLookupMetas];
|
|
357
|
+
const instructions = compiledMessage.instructions.map(
|
|
358
|
+
(compiledInstruction) => convertInstruction(compiledInstruction, transactionMetas)
|
|
359
|
+
);
|
|
360
|
+
const firstInstruction = instructions[0];
|
|
361
|
+
const lifetimeConstraint = getLifetimeConstraint(
|
|
362
|
+
compiledMessage.lifetimeToken,
|
|
363
|
+
firstInstruction,
|
|
364
|
+
config?.lastValidBlockHeight
|
|
365
|
+
);
|
|
366
|
+
const signatures = convertSignatures(compiledTransaction);
|
|
367
|
+
return pipe(
|
|
368
|
+
createTransaction({ version: compiledMessage.version }),
|
|
369
|
+
(tx) => setTransactionFeePayer(feePayer, tx),
|
|
370
|
+
(tx) => instructions.reduce((acc, instruction) => {
|
|
371
|
+
return appendTransactionInstruction(instruction, acc);
|
|
372
|
+
}, tx),
|
|
373
|
+
(tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
|
|
374
|
+
(tx) => Object.keys(signatures).length > 0 ? { ...tx, signatures } : tx
|
|
375
|
+
);
|
|
376
|
+
}
|
|
178
377
|
function upsert(addressMap, address, update) {
|
|
179
378
|
addressMap[address] = update(addressMap[address] ?? { role: AccountRole.READONLY });
|
|
180
379
|
}
|
|
@@ -191,13 +390,13 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
191
390
|
if (isWritableRole(entry.role)) {
|
|
192
391
|
switch (entry[TYPE]) {
|
|
193
392
|
case 0 /* FEE_PAYER */:
|
|
194
|
-
throw new
|
|
195
|
-
|
|
196
|
-
);
|
|
393
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
|
|
394
|
+
programAddress: instruction.programAddress
|
|
395
|
+
});
|
|
197
396
|
default:
|
|
198
|
-
throw new
|
|
199
|
-
|
|
200
|
-
);
|
|
397
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
|
|
398
|
+
programAddress: instruction.programAddress
|
|
399
|
+
});
|
|
201
400
|
}
|
|
202
401
|
}
|
|
203
402
|
if (entry[TYPE] === 2 /* STATIC */) {
|
|
@@ -227,7 +426,7 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
227
426
|
const shouldReplaceEntry = (
|
|
228
427
|
// Consider using the new LOOKUP_TABLE if its address is different...
|
|
229
428
|
entry.lookupTableAddress !== accountMeta.lookupTableAddress && // ...and sorts before the existing one.
|
|
230
|
-
(addressComparator
|
|
429
|
+
(addressComparator ||= getAddressComparator())(
|
|
231
430
|
accountMeta.lookupTableAddress,
|
|
232
431
|
entry.lookupTableAddress
|
|
233
432
|
) < 0
|
|
@@ -262,8 +461,11 @@ function getAddressMapFromInstructions(feePayer, instructions) {
|
|
|
262
461
|
addressesOfInvokedPrograms.has(account.address)
|
|
263
462
|
) {
|
|
264
463
|
if (isWritableRole(accountMeta.role)) {
|
|
265
|
-
throw new
|
|
266
|
-
|
|
464
|
+
throw new SolanaError(
|
|
465
|
+
SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
|
|
466
|
+
{
|
|
467
|
+
programAddress: account.address
|
|
468
|
+
}
|
|
267
469
|
);
|
|
268
470
|
}
|
|
269
471
|
if (entry.role !== nextRole) {
|
|
@@ -333,7 +535,7 @@ function getOrderedAccountsFromAddressMap(addressMap) {
|
|
|
333
535
|
if (leftIsWritable !== isWritableRole(rightEntry.role)) {
|
|
334
536
|
return leftIsWritable ? -1 : 1;
|
|
335
537
|
}
|
|
336
|
-
addressComparator
|
|
538
|
+
addressComparator ||= getAddressComparator();
|
|
337
539
|
if (leftEntry[TYPE] === 1 /* LOOKUP_TABLE */ && rightEntry[TYPE] === 1 /* LOOKUP_TABLE */ && leftEntry.lookupTableAddress !== rightEntry.lookupTableAddress) {
|
|
338
540
|
return addressComparator(leftEntry.lookupTableAddress, rightEntry.lookupTableAddress);
|
|
339
541
|
} else {
|
|
@@ -346,23 +548,22 @@ function getOrderedAccountsFromAddressMap(addressMap) {
|
|
|
346
548
|
return orderedAccounts;
|
|
347
549
|
}
|
|
348
550
|
function getCompiledAddressTableLookups(orderedAccounts) {
|
|
349
|
-
var _a;
|
|
350
551
|
const index = {};
|
|
351
552
|
for (const account of orderedAccounts) {
|
|
352
553
|
if (!("lookupTableAddress" in account)) {
|
|
353
554
|
continue;
|
|
354
555
|
}
|
|
355
|
-
const entry = index[
|
|
556
|
+
const entry = index[account.lookupTableAddress] ||= {
|
|
356
557
|
readableIndices: [],
|
|
357
558
|
writableIndices: []
|
|
358
|
-
}
|
|
559
|
+
};
|
|
359
560
|
if (account.role === AccountRole.WRITABLE) {
|
|
360
561
|
entry.writableIndices.push(account.addressIndex);
|
|
361
562
|
} else {
|
|
362
563
|
entry.readableIndices.push(account.addressIndex);
|
|
363
564
|
}
|
|
364
565
|
}
|
|
365
|
-
return Object.keys(index).sort(
|
|
566
|
+
return Object.keys(index).sort(getAddressComparator()).map((lookupTableAddress) => ({
|
|
366
567
|
lookupTableAddress,
|
|
367
568
|
...index[lookupTableAddress]
|
|
368
569
|
}));
|
|
@@ -441,266 +642,220 @@ function compileMessage(transaction) {
|
|
|
441
642
|
version: transaction.version
|
|
442
643
|
};
|
|
443
644
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
getBase58EncodedAddressCodec(
|
|
450
|
-
__DEV__ ? {
|
|
451
|
-
description: "The address of the address lookup table account from which instruction addresses should be looked up"
|
|
452
|
-
} : void 0
|
|
453
|
-
)
|
|
454
|
-
],
|
|
645
|
+
var memoizedAddressTableLookupEncoder;
|
|
646
|
+
function getAddressTableLookupEncoder() {
|
|
647
|
+
if (!memoizedAddressTableLookupEncoder) {
|
|
648
|
+
memoizedAddressTableLookupEncoder = getStructEncoder([
|
|
649
|
+
["lookupTableAddress", getAddressEncoder()],
|
|
455
650
|
[
|
|
456
651
|
"writableIndices",
|
|
457
|
-
|
|
458
|
-
...__DEV__ ? {
|
|
459
|
-
description: "The indices of the accounts in the lookup table that should be loaded as writeable"
|
|
460
|
-
} : null,
|
|
461
|
-
size: shortU16()
|
|
462
|
-
})
|
|
652
|
+
getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
|
|
463
653
|
],
|
|
464
654
|
[
|
|
465
655
|
"readableIndices",
|
|
466
|
-
|
|
467
|
-
...__DEV__ ? {
|
|
468
|
-
description: "The indices of the accounts in the lookup table that should be loaded as read-only"
|
|
469
|
-
} : void 0,
|
|
470
|
-
size: shortU16()
|
|
471
|
-
})
|
|
656
|
+
getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
|
|
472
657
|
]
|
|
473
|
-
]
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
658
|
+
]);
|
|
659
|
+
}
|
|
660
|
+
return memoizedAddressTableLookupEncoder;
|
|
661
|
+
}
|
|
662
|
+
var memoizedAddressTableLookupDecoder;
|
|
663
|
+
function getAddressTableLookupDecoder() {
|
|
664
|
+
if (!memoizedAddressTableLookupDecoder) {
|
|
665
|
+
memoizedAddressTableLookupDecoder = getStructDecoder([
|
|
666
|
+
["lookupTableAddress", getAddressDecoder()],
|
|
667
|
+
["writableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
|
|
668
|
+
["readableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })]
|
|
669
|
+
]);
|
|
670
|
+
}
|
|
671
|
+
return memoizedAddressTableLookupDecoder;
|
|
672
|
+
}
|
|
673
|
+
var memoizedU8Encoder;
|
|
674
|
+
function getMemoizedU8Encoder() {
|
|
675
|
+
if (!memoizedU8Encoder)
|
|
676
|
+
memoizedU8Encoder = getU8Encoder();
|
|
677
|
+
return memoizedU8Encoder;
|
|
678
|
+
}
|
|
679
|
+
var memoizedU8Decoder;
|
|
680
|
+
function getMemoizedU8Decoder() {
|
|
681
|
+
if (!memoizedU8Decoder)
|
|
682
|
+
memoizedU8Decoder = getU8Decoder();
|
|
683
|
+
return memoizedU8Decoder;
|
|
684
|
+
}
|
|
685
|
+
function getMessageHeaderEncoder() {
|
|
686
|
+
return getStructEncoder([
|
|
687
|
+
["numSignerAccounts", getMemoizedU8Encoder()],
|
|
688
|
+
["numReadonlySignerAccounts", getMemoizedU8Encoder()],
|
|
689
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Encoder()]
|
|
690
|
+
]);
|
|
478
691
|
}
|
|
479
|
-
function
|
|
480
|
-
return
|
|
481
|
-
[
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
__DEV__ ? {
|
|
486
|
-
description: "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction"
|
|
487
|
-
} : void 0
|
|
488
|
-
)
|
|
489
|
-
],
|
|
490
|
-
[
|
|
491
|
-
"numReadonlySignerAccounts",
|
|
492
|
-
u8(
|
|
493
|
-
__DEV__ ? {
|
|
494
|
-
description: "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"
|
|
495
|
-
} : void 0
|
|
496
|
-
)
|
|
497
|
-
],
|
|
498
|
-
[
|
|
499
|
-
"numReadonlyNonSignerAccounts",
|
|
500
|
-
u8(
|
|
501
|
-
__DEV__ ? {
|
|
502
|
-
description: "The expected number of addresses in the static address list belonging to accounts that are neither signers, nor writable"
|
|
503
|
-
} : void 0
|
|
504
|
-
)
|
|
505
|
-
]
|
|
506
|
-
],
|
|
507
|
-
__DEV__ ? {
|
|
508
|
-
description: "The transaction message header containing counts of the signer, readonly-signer, and readonly-nonsigner account addresses"
|
|
509
|
-
} : void 0
|
|
510
|
-
);
|
|
692
|
+
function getMessageHeaderDecoder() {
|
|
693
|
+
return getStructDecoder([
|
|
694
|
+
["numSignerAccounts", getMemoizedU8Decoder()],
|
|
695
|
+
["numReadonlySignerAccounts", getMemoizedU8Decoder()],
|
|
696
|
+
["numReadonlyNonSignerAccounts", getMemoizedU8Decoder()]
|
|
697
|
+
]);
|
|
511
698
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
699
|
+
var memoizedGetInstructionEncoder;
|
|
700
|
+
function getInstructionEncoder() {
|
|
701
|
+
if (!memoizedGetInstructionEncoder) {
|
|
702
|
+
memoizedGetInstructionEncoder = mapEncoder(
|
|
703
|
+
getStructEncoder([
|
|
704
|
+
["programAddressIndex", getU8Encoder()],
|
|
705
|
+
["accountIndices", getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })],
|
|
706
|
+
["data", getBytesEncoder({ size: getShortU16Encoder() })]
|
|
707
|
+
]),
|
|
708
|
+
// Convert an instruction to have all fields defined
|
|
709
|
+
(instruction) => {
|
|
710
|
+
if (instruction.accountIndices !== void 0 && instruction.data !== void 0) {
|
|
711
|
+
return instruction;
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
...instruction,
|
|
715
|
+
accountIndices: instruction.accountIndices ?? [],
|
|
716
|
+
data: instruction.data ?? new Uint8Array(0)
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
return memoizedGetInstructionEncoder;
|
|
722
|
+
}
|
|
723
|
+
var memoizedGetInstructionDecoder;
|
|
724
|
+
function getInstructionDecoder() {
|
|
725
|
+
if (!memoizedGetInstructionDecoder) {
|
|
726
|
+
memoizedGetInstructionDecoder = mapDecoder(
|
|
727
|
+
getStructDecoder([
|
|
728
|
+
["programAddressIndex", getU8Decoder()],
|
|
729
|
+
["accountIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
|
|
730
|
+
["data", getBytesDecoder({ size: getShortU16Decoder() })]
|
|
731
|
+
]),
|
|
732
|
+
// Convert an instruction to exclude optional fields if they are empty
|
|
733
|
+
(instruction) => {
|
|
734
|
+
if (instruction.accountIndices.length && instruction.data.byteLength) {
|
|
735
|
+
return instruction;
|
|
736
|
+
}
|
|
737
|
+
const { accountIndices, data, ...rest } = instruction;
|
|
738
|
+
return {
|
|
739
|
+
...rest,
|
|
740
|
+
...accountIndices.length ? { accountIndices } : null,
|
|
741
|
+
...data.byteLength ? { data } : null
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
return memoizedGetInstructionDecoder;
|
|
747
|
+
}
|
|
748
|
+
var VERSION_FLAG_MASK = 128;
|
|
749
|
+
function getTransactionVersionEncoder() {
|
|
750
|
+
return createEncoder({
|
|
751
|
+
getSizeFromValue: (value) => value === "legacy" ? 0 : 1,
|
|
752
|
+
maxSize: 1,
|
|
753
|
+
write: (value, bytes, offset) => {
|
|
754
|
+
if (value === "legacy") {
|
|
755
|
+
return offset;
|
|
756
|
+
}
|
|
757
|
+
if (value < 0 || value > 127) {
|
|
758
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_VERSION_NUMBER_OUT_OF_RANGE, {
|
|
759
|
+
actualVersion: value
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
bytes.set([value | VERSION_FLAG_MASK], offset);
|
|
763
|
+
return offset + 1;
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
function getTransactionVersionDecoder() {
|
|
768
|
+
return createDecoder({
|
|
769
|
+
maxSize: 1,
|
|
770
|
+
read: (bytes, offset) => {
|
|
771
|
+
const firstByte = bytes[offset];
|
|
772
|
+
if ((firstByte & VERSION_FLAG_MASK) === 0) {
|
|
773
|
+
return ["legacy", offset];
|
|
774
|
+
} else {
|
|
775
|
+
const version = firstByte ^ VERSION_FLAG_MASK;
|
|
776
|
+
return [version, offset + 1];
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/serializers/message.ts
|
|
783
|
+
function getCompiledMessageLegacyEncoder() {
|
|
784
|
+
return getStructEncoder(getPreludeStructEncoderTuple());
|
|
785
|
+
}
|
|
786
|
+
function getCompiledMessageVersionedEncoder() {
|
|
787
|
+
return mapEncoder(
|
|
788
|
+
getStructEncoder([
|
|
789
|
+
...getPreludeStructEncoderTuple(),
|
|
790
|
+
["addressTableLookups", getAddressTableLookupArrayEncoder()]
|
|
542
791
|
]),
|
|
543
792
|
(value) => {
|
|
544
|
-
if (value.
|
|
793
|
+
if (value.version === "legacy") {
|
|
545
794
|
return value;
|
|
546
795
|
}
|
|
547
796
|
return {
|
|
548
797
|
...value,
|
|
549
|
-
|
|
550
|
-
data: value.data ?? new Uint8Array(0)
|
|
551
|
-
};
|
|
552
|
-
},
|
|
553
|
-
(value) => {
|
|
554
|
-
if (value.addressIndices.length && value.data.byteLength) {
|
|
555
|
-
return value;
|
|
556
|
-
}
|
|
557
|
-
const { addressIndices, data, ...rest } = value;
|
|
558
|
-
return {
|
|
559
|
-
...rest,
|
|
560
|
-
...addressIndices.length ? { addressIndices } : null,
|
|
561
|
-
...data.byteLength ? { data } : null
|
|
798
|
+
addressTableLookups: value.addressTableLookups ?? []
|
|
562
799
|
};
|
|
563
800
|
}
|
|
564
801
|
);
|
|
565
802
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
function getUnimplementedDecoder(name) {
|
|
575
|
-
return () => {
|
|
576
|
-
throw getError("decoder", name);
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
// src/serializers/transaction-version.ts
|
|
581
|
-
var VERSION_FLAG_MASK = 128;
|
|
582
|
-
var BASE_CONFIG = {
|
|
583
|
-
description: __DEV__ ? "A single byte that encodes the version of the transaction" : "",
|
|
584
|
-
fixedSize: null,
|
|
585
|
-
maxSize: 1
|
|
586
|
-
};
|
|
587
|
-
function deserialize(bytes3, offset = 0) {
|
|
588
|
-
const firstByte = bytes3[offset];
|
|
589
|
-
if ((firstByte & VERSION_FLAG_MASK) === 0) {
|
|
590
|
-
return ["legacy", offset];
|
|
591
|
-
} else {
|
|
592
|
-
const version = firstByte ^ VERSION_FLAG_MASK;
|
|
593
|
-
return [version, offset + 1];
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
function serialize(value) {
|
|
597
|
-
if (value === "legacy") {
|
|
598
|
-
return new Uint8Array();
|
|
599
|
-
}
|
|
600
|
-
if (value < 0 || value > 127) {
|
|
601
|
-
throw new Error(`Transaction version must be in the range [0, 127]. \`${value}\` given.`);
|
|
602
|
-
}
|
|
603
|
-
return new Uint8Array([value | VERSION_FLAG_MASK]);
|
|
604
|
-
}
|
|
605
|
-
function getTransactionVersionCodec() {
|
|
606
|
-
return {
|
|
607
|
-
...BASE_CONFIG,
|
|
608
|
-
deserialize,
|
|
609
|
-
serialize
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// src/serializers/message.ts
|
|
614
|
-
var BASE_CONFIG2 = {
|
|
615
|
-
description: __DEV__ ? "The wire format of a Solana transaction message" : "",
|
|
616
|
-
fixedSize: null,
|
|
617
|
-
maxSize: null
|
|
618
|
-
};
|
|
619
|
-
function serialize2(compiledMessage) {
|
|
620
|
-
if (compiledMessage.version === "legacy") {
|
|
621
|
-
return struct(getPreludeStructSerializerTuple()).serialize(compiledMessage);
|
|
622
|
-
} else {
|
|
623
|
-
return mapSerializer(
|
|
624
|
-
struct([
|
|
625
|
-
...getPreludeStructSerializerTuple(),
|
|
626
|
-
["addressTableLookups", getAddressTableLookupsSerializer()]
|
|
627
|
-
]),
|
|
628
|
-
(value) => {
|
|
629
|
-
if (value.version === "legacy") {
|
|
630
|
-
return value;
|
|
631
|
-
}
|
|
632
|
-
return {
|
|
633
|
-
...value,
|
|
634
|
-
addressTableLookups: value.addressTableLookups ?? []
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
).serialize(compiledMessage);
|
|
638
|
-
}
|
|
803
|
+
function getPreludeStructEncoderTuple() {
|
|
804
|
+
return [
|
|
805
|
+
["version", getTransactionVersionEncoder()],
|
|
806
|
+
["header", getMessageHeaderEncoder()],
|
|
807
|
+
["staticAccounts", getArrayEncoder(getAddressEncoder(), { size: getShortU16Encoder() })],
|
|
808
|
+
["lifetimeToken", getStringEncoder({ encoding: getBase58Encoder(), size: 32 })],
|
|
809
|
+
["instructions", getArrayEncoder(getInstructionEncoder(), { size: getShortU16Encoder() })]
|
|
810
|
+
];
|
|
639
811
|
}
|
|
640
|
-
function
|
|
812
|
+
function getPreludeStructDecoderTuple() {
|
|
641
813
|
return [
|
|
642
|
-
["version",
|
|
643
|
-
["header",
|
|
644
|
-
[
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
size: shortU16()
|
|
649
|
-
})
|
|
650
|
-
],
|
|
651
|
-
[
|
|
652
|
-
"lifetimeToken",
|
|
653
|
-
string({
|
|
654
|
-
description: __DEV__ ? "A 32-byte token that specifies the lifetime of this transaction (eg. a recent blockhash, or a durable nonce)" : "",
|
|
655
|
-
encoding: base58,
|
|
656
|
-
size: 32
|
|
657
|
-
})
|
|
658
|
-
],
|
|
659
|
-
[
|
|
660
|
-
"instructions",
|
|
661
|
-
array(getInstructionCodec(), {
|
|
662
|
-
description: __DEV__ ? "A compact-array of instructions belonging to this transaction" : "",
|
|
663
|
-
size: shortU16()
|
|
664
|
-
})
|
|
665
|
-
]
|
|
814
|
+
["version", getTransactionVersionDecoder()],
|
|
815
|
+
["header", getMessageHeaderDecoder()],
|
|
816
|
+
["staticAccounts", getArrayDecoder(getAddressDecoder(), { size: getShortU16Decoder() })],
|
|
817
|
+
["lifetimeToken", getStringDecoder({ encoding: getBase58Decoder(), size: 32 })],
|
|
818
|
+
["instructions", getArrayDecoder(getInstructionDecoder(), { size: getShortU16Decoder() })],
|
|
819
|
+
["addressTableLookups", getAddressTableLookupArrayDecoder()]
|
|
666
820
|
];
|
|
667
821
|
}
|
|
668
|
-
function
|
|
669
|
-
return
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
});
|
|
822
|
+
function getAddressTableLookupArrayEncoder() {
|
|
823
|
+
return getArrayEncoder(getAddressTableLookupEncoder(), { size: getShortU16Encoder() });
|
|
824
|
+
}
|
|
825
|
+
function getAddressTableLookupArrayDecoder() {
|
|
826
|
+
return getArrayDecoder(getAddressTableLookupDecoder(), { size: getShortU16Decoder() });
|
|
673
827
|
}
|
|
674
828
|
function getCompiledMessageEncoder() {
|
|
675
|
-
return {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
829
|
+
return createEncoder({
|
|
830
|
+
getSizeFromValue: (compiledMessage) => {
|
|
831
|
+
if (compiledMessage.version === "legacy") {
|
|
832
|
+
return getCompiledMessageLegacyEncoder().getSizeFromValue(compiledMessage);
|
|
833
|
+
} else {
|
|
834
|
+
return getCompiledMessageVersionedEncoder().getSizeFromValue(compiledMessage);
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
write: (compiledMessage, bytes, offset) => {
|
|
838
|
+
if (compiledMessage.version === "legacy") {
|
|
839
|
+
return getCompiledMessageLegacyEncoder().write(compiledMessage, bytes, offset);
|
|
840
|
+
} else {
|
|
841
|
+
return getCompiledMessageVersionedEncoder().write(compiledMessage, bytes, offset);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
});
|
|
680
845
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
846
|
+
function getCompiledMessageDecoder() {
|
|
847
|
+
return mapDecoder(
|
|
848
|
+
getStructDecoder(getPreludeStructDecoderTuple()),
|
|
849
|
+
({ addressTableLookups, ...restOfMessage }) => {
|
|
850
|
+
if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
|
|
851
|
+
return restOfMessage;
|
|
852
|
+
}
|
|
853
|
+
return { ...restOfMessage, addressTableLookups };
|
|
854
|
+
}
|
|
855
|
+
);
|
|
687
856
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const [signerPublicKey, signature] = await Promise.all([
|
|
691
|
-
getBase58EncodedAddressFromPublicKey(keyPair.publicKey),
|
|
692
|
-
getCompiledMessageSignature(compiledMessage, keyPair.privateKey)
|
|
693
|
-
]);
|
|
694
|
-
const nextSignatures = {
|
|
695
|
-
..."signatures" in transaction ? transaction.signatures : null,
|
|
696
|
-
...{ [signerPublicKey]: signature }
|
|
697
|
-
};
|
|
698
|
-
const out = {
|
|
699
|
-
...transaction,
|
|
700
|
-
signatures: nextSignatures
|
|
701
|
-
};
|
|
702
|
-
Object.freeze(out);
|
|
703
|
-
return out;
|
|
857
|
+
function getCompiledMessageCodec() {
|
|
858
|
+
return combineCodec(getCompiledMessageEncoder(), getCompiledMessageDecoder());
|
|
704
859
|
}
|
|
705
860
|
|
|
706
861
|
// src/compile-transaction.ts
|
|
@@ -722,40 +877,91 @@ function getCompiledTransaction(transaction) {
|
|
|
722
877
|
}
|
|
723
878
|
|
|
724
879
|
// src/serializers/transaction.ts
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
return
|
|
880
|
+
function getCompiledTransactionEncoder() {
|
|
881
|
+
return getStructEncoder([
|
|
882
|
+
["signatures", getArrayEncoder(getBytesEncoder({ size: 64 }), { size: getShortU16Encoder() })],
|
|
883
|
+
["compiledMessage", getCompiledMessageEncoder()]
|
|
884
|
+
]);
|
|
885
|
+
}
|
|
886
|
+
function getCompiledTransactionDecoder() {
|
|
887
|
+
return getStructDecoder([
|
|
733
888
|
[
|
|
734
889
|
"signatures",
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
size: shortU16()
|
|
890
|
+
getArrayDecoder(getBytesDecoder({ size: 64 }), {
|
|
891
|
+
size: getShortU16Decoder()
|
|
738
892
|
})
|
|
739
893
|
],
|
|
740
|
-
["compiledMessage",
|
|
741
|
-
])
|
|
894
|
+
["compiledMessage", getCompiledMessageDecoder()]
|
|
895
|
+
]);
|
|
742
896
|
}
|
|
743
897
|
function getTransactionEncoder() {
|
|
744
|
-
return
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
898
|
+
return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
|
|
899
|
+
}
|
|
900
|
+
function getTransactionDecoder(config) {
|
|
901
|
+
return mapDecoder(
|
|
902
|
+
getCompiledTransactionDecoder(),
|
|
903
|
+
(compiledTransaction) => decompileTransaction(compiledTransaction, config)
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
function getTransactionCodec(config) {
|
|
907
|
+
return combineCodec(getTransactionEncoder(), getTransactionDecoder(config));
|
|
908
|
+
}
|
|
909
|
+
var base58Decoder;
|
|
910
|
+
function getSignatureFromTransaction(transaction) {
|
|
911
|
+
if (!base58Decoder)
|
|
912
|
+
base58Decoder = getBase58Decoder();
|
|
913
|
+
const signatureBytes = transaction.signatures[transaction.feePayer];
|
|
914
|
+
if (!signatureBytes) {
|
|
915
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE);
|
|
916
|
+
}
|
|
917
|
+
const transactionSignature = base58Decoder.decode(signatureBytes);
|
|
918
|
+
return transactionSignature;
|
|
919
|
+
}
|
|
920
|
+
async function partiallySignTransaction(keyPairs, transaction) {
|
|
921
|
+
const compiledMessage = compileMessage(transaction);
|
|
922
|
+
const nextSignatures = "signatures" in transaction ? { ...transaction.signatures } : {};
|
|
923
|
+
const wireMessageBytes = getCompiledMessageEncoder().encode(compiledMessage);
|
|
924
|
+
const publicKeySignaturePairs = await Promise.all(
|
|
925
|
+
keyPairs.map(
|
|
926
|
+
(keyPair) => Promise.all([getAddressFromPublicKey(keyPair.publicKey), signBytes(keyPair.privateKey, wireMessageBytes)])
|
|
927
|
+
)
|
|
928
|
+
);
|
|
929
|
+
for (const [signerPublicKey, signature] of publicKeySignaturePairs) {
|
|
930
|
+
nextSignatures[signerPublicKey] = signature;
|
|
931
|
+
}
|
|
932
|
+
const out = {
|
|
933
|
+
...transaction,
|
|
934
|
+
signatures: nextSignatures
|
|
748
935
|
};
|
|
936
|
+
Object.freeze(out);
|
|
937
|
+
return out;
|
|
749
938
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
939
|
+
async function signTransaction(keyPairs, transaction) {
|
|
940
|
+
const out = await partiallySignTransaction(keyPairs, transaction);
|
|
941
|
+
assertTransactionIsFullySigned(out);
|
|
942
|
+
Object.freeze(out);
|
|
943
|
+
return out;
|
|
944
|
+
}
|
|
945
|
+
function assertTransactionIsFullySigned(transaction) {
|
|
946
|
+
const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
|
|
947
|
+
const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
|
|
948
|
+
const missingSigs = [];
|
|
949
|
+
requiredSigners.forEach((address) => {
|
|
950
|
+
if (!transaction.signatures[address]) {
|
|
951
|
+
missingSigs.push(address);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
if (missingSigs.length > 0) {
|
|
955
|
+
throw new SolanaError(SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, {
|
|
956
|
+
addresses: missingSigs
|
|
957
|
+
});
|
|
756
958
|
}
|
|
757
959
|
}
|
|
960
|
+
function getBase64EncodedWireTransaction(transaction) {
|
|
961
|
+
const wireTransactionBytes = getTransactionEncoder().encode(transaction);
|
|
962
|
+
return getBase64Decoder().decode(wireTransactionBytes);
|
|
963
|
+
}
|
|
758
964
|
|
|
759
|
-
export { appendTransactionInstruction,
|
|
965
|
+
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 };
|
|
760
966
|
//# sourceMappingURL=out.js.map
|
|
761
967
|
//# sourceMappingURL=index.native.js.map
|