@solana/web3.js 1.77.3 → 2.0.0-development
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 +56 -112
- package/dist/index.browser.cjs +158 -0
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.js +137 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.development.js +1044 -0
- package/dist/index.development.js.map +1 -0
- package/dist/index.native.js +139 -0
- package/dist/index.native.js.map +1 -0
- package/dist/index.node.cjs +158 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.js +139 -0
- package/dist/index.node.js.map +1 -0
- package/dist/index.production.min.js +25 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/rpc-default-config.d.ts +3 -0
- package/dist/types/rpc-integer-overflow-error.d.ts +8 -0
- package/dist/types/rpc-request-coalescer.d.ts +5 -0
- package/dist/types/rpc-request-deduplication.d.ts +2 -0
- package/dist/types/rpc-transport.d.ts +4 -0
- package/dist/types/rpc.d.ts +5 -0
- package/package.json +86 -110
- package/lib/index.browser.cjs.js +0 -9534
- package/lib/index.browser.cjs.js.map +0 -1
- package/lib/index.browser.esm.js +0 -9432
- package/lib/index.browser.esm.js.map +0 -1
- package/lib/index.cjs.js +0 -12058
- package/lib/index.cjs.js.map +0 -1
- package/lib/index.d.ts +0 -3891
- package/lib/index.esm.js +0 -11949
- package/lib/index.esm.js.map +0 -1
- package/lib/index.iife.js +0 -25985
- package/lib/index.iife.js.map +0 -1
- package/lib/index.iife.min.js +0 -20
- package/lib/index.iife.min.js.map +0 -1
- package/lib/index.native.js +0 -9534
- package/lib/index.native.js.map +0 -1
- package/src/__forks__/browser/fetch-impl.ts +0 -4
- package/src/__forks__/browser/rpc-websocket-factory.ts +0 -1
- package/src/__forks__/react-native/fetch-impl.ts +0 -4
- package/src/__forks__/react-native/rpc-websocket-factory.ts +0 -1
- package/src/account-data.ts +0 -39
- package/src/account.ts +0 -55
- package/src/blockhash.ts +0 -4
- package/src/bpf-loader-deprecated.ts +0 -5
- package/src/bpf-loader.ts +0 -45
- package/src/connection.ts +0 -6756
- package/src/epoch-schedule.ts +0 -102
- package/src/errors.ts +0 -50
- package/src/fee-calculator.ts +0 -18
- package/src/fetch-impl.ts +0 -13
- package/src/index.ts +0 -24
- package/src/instruction.ts +0 -58
- package/src/keypair.ts +0 -93
- package/src/layout.ts +0 -188
- package/src/loader.ts +0 -267
- package/src/message/account-keys.ts +0 -79
- package/src/message/compiled-keys.ts +0 -165
- package/src/message/index.ts +0 -47
- package/src/message/legacy.ts +0 -326
- package/src/message/v0.ts +0 -496
- package/src/message/versioned.ts +0 -36
- package/src/nonce-account.ts +0 -82
- package/src/programs/address-lookup-table/index.ts +0 -435
- package/src/programs/address-lookup-table/state.ts +0 -84
- package/src/programs/compute-budget.ts +0 -281
- package/src/programs/ed25519.ts +0 -157
- package/src/programs/index.ts +0 -7
- package/src/programs/secp256k1.ts +0 -228
- package/src/programs/stake.ts +0 -935
- package/src/programs/system.ts +0 -1048
- package/src/programs/vote.ts +0 -543
- package/src/publickey.ts +0 -259
- package/src/rpc-websocket-factory.ts +0 -4
- package/src/rpc-websocket.ts +0 -79
- package/src/sysvar.ts +0 -37
- package/src/timing.ts +0 -23
- package/src/transaction/constants.ts +0 -12
- package/src/transaction/expiry-custom-errors.ts +0 -48
- package/src/transaction/index.ts +0 -5
- package/src/transaction/legacy.ts +0 -918
- package/src/transaction/message.ts +0 -140
- package/src/transaction/versioned.ts +0 -126
- package/src/utils/assert.ts +0 -8
- package/src/utils/bigint.ts +0 -43
- package/src/utils/borsh-schema.ts +0 -38
- package/src/utils/cluster.ts +0 -31
- package/src/utils/ed25519.ts +0 -43
- package/src/utils/index.ts +0 -5
- package/src/utils/makeWebsocketUrl.ts +0 -26
- package/src/utils/promise-timeout.ts +0 -14
- package/src/utils/secp256k1.ts +0 -11
- package/src/utils/send-and-confirm-raw-transaction.ts +0 -102
- package/src/utils/send-and-confirm-transaction.ts +0 -98
- package/src/utils/shortvec-encoding.ts +0 -28
- package/src/utils/sleep.ts +0 -4
- package/src/utils/to-buffer.ts +0 -11
- package/src/validator-info.ts +0 -104
- package/src/vote-account.ts +0 -236
|
@@ -1,918 +0,0 @@
|
|
|
1
|
-
import bs58 from 'bs58';
|
|
2
|
-
import {Buffer} from 'buffer';
|
|
3
|
-
|
|
4
|
-
import {PACKET_DATA_SIZE, SIGNATURE_LENGTH_IN_BYTES} from './constants';
|
|
5
|
-
import {Connection} from '../connection';
|
|
6
|
-
import {Message} from '../message';
|
|
7
|
-
import {PublicKey} from '../publickey';
|
|
8
|
-
import * as shortvec from '../utils/shortvec-encoding';
|
|
9
|
-
import {toBuffer} from '../utils/to-buffer';
|
|
10
|
-
import invariant from '../utils/assert';
|
|
11
|
-
import type {Signer} from '../keypair';
|
|
12
|
-
import type {Blockhash} from '../blockhash';
|
|
13
|
-
import type {CompiledInstruction} from '../message';
|
|
14
|
-
import {sign, verify} from '../utils/ed25519';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Transaction signature as base-58 encoded string
|
|
18
|
-
*/
|
|
19
|
-
export type TransactionSignature = string;
|
|
20
|
-
|
|
21
|
-
export const enum TransactionStatus {
|
|
22
|
-
BLOCKHEIGHT_EXCEEDED,
|
|
23
|
-
PROCESSED,
|
|
24
|
-
TIMED_OUT,
|
|
25
|
-
NONCE_INVALID,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Default (empty) signature
|
|
30
|
-
*/
|
|
31
|
-
const DEFAULT_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Account metadata used to define instructions
|
|
35
|
-
*/
|
|
36
|
-
export type AccountMeta = {
|
|
37
|
-
/** An account's public key */
|
|
38
|
-
pubkey: PublicKey;
|
|
39
|
-
/** True if an instruction requires a transaction signature matching `pubkey` */
|
|
40
|
-
isSigner: boolean;
|
|
41
|
-
/** True if the `pubkey` can be loaded as a read-write account. */
|
|
42
|
-
isWritable: boolean;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* List of TransactionInstruction object fields that may be initialized at construction
|
|
47
|
-
*/
|
|
48
|
-
export type TransactionInstructionCtorFields = {
|
|
49
|
-
keys: Array<AccountMeta>;
|
|
50
|
-
programId: PublicKey;
|
|
51
|
-
data?: Buffer;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Configuration object for Transaction.serialize()
|
|
56
|
-
*/
|
|
57
|
-
export type SerializeConfig = {
|
|
58
|
-
/** Require all transaction signatures be present (default: true) */
|
|
59
|
-
requireAllSignatures?: boolean;
|
|
60
|
-
/** Verify provided signatures (default: true) */
|
|
61
|
-
verifySignatures?: boolean;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @internal
|
|
66
|
-
*/
|
|
67
|
-
export interface TransactionInstructionJSON {
|
|
68
|
-
keys: {
|
|
69
|
-
pubkey: string;
|
|
70
|
-
isSigner: boolean;
|
|
71
|
-
isWritable: boolean;
|
|
72
|
-
}[];
|
|
73
|
-
programId: string;
|
|
74
|
-
data: number[];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Transaction Instruction class
|
|
79
|
-
*/
|
|
80
|
-
export class TransactionInstruction {
|
|
81
|
-
/**
|
|
82
|
-
* Public keys to include in this transaction
|
|
83
|
-
* Boolean represents whether this pubkey needs to sign the transaction
|
|
84
|
-
*/
|
|
85
|
-
keys: Array<AccountMeta>;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Program Id to execute
|
|
89
|
-
*/
|
|
90
|
-
programId: PublicKey;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Program input
|
|
94
|
-
*/
|
|
95
|
-
data: Buffer = Buffer.alloc(0);
|
|
96
|
-
|
|
97
|
-
constructor(opts: TransactionInstructionCtorFields) {
|
|
98
|
-
this.programId = opts.programId;
|
|
99
|
-
this.keys = opts.keys;
|
|
100
|
-
if (opts.data) {
|
|
101
|
-
this.data = opts.data;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* @internal
|
|
107
|
-
*/
|
|
108
|
-
toJSON(): TransactionInstructionJSON {
|
|
109
|
-
return {
|
|
110
|
-
keys: this.keys.map(({pubkey, isSigner, isWritable}) => ({
|
|
111
|
-
pubkey: pubkey.toJSON(),
|
|
112
|
-
isSigner,
|
|
113
|
-
isWritable,
|
|
114
|
-
})),
|
|
115
|
-
programId: this.programId.toJSON(),
|
|
116
|
-
data: [...this.data],
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Pair of signature and corresponding public key
|
|
123
|
-
*/
|
|
124
|
-
export type SignaturePubkeyPair = {
|
|
125
|
-
signature: Buffer | null;
|
|
126
|
-
publicKey: PublicKey;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* List of Transaction object fields that may be initialized at construction
|
|
131
|
-
*/
|
|
132
|
-
export type TransactionCtorFields_DEPRECATED = {
|
|
133
|
-
/** Optional nonce information used for offline nonce'd transactions */
|
|
134
|
-
nonceInfo?: NonceInformation | null;
|
|
135
|
-
/** The transaction fee payer */
|
|
136
|
-
feePayer?: PublicKey | null;
|
|
137
|
-
/** One or more signatures */
|
|
138
|
-
signatures?: Array<SignaturePubkeyPair>;
|
|
139
|
-
/** A recent blockhash */
|
|
140
|
-
recentBlockhash?: Blockhash;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// For backward compatibility; an unfortunate consequence of being
|
|
144
|
-
// forced to over-export types by the documentation generator.
|
|
145
|
-
// See https://github.com/solana-labs/solana/pull/25820
|
|
146
|
-
export type TransactionCtorFields = TransactionCtorFields_DEPRECATED;
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Blockhash-based transactions have a lifetime that are defined by
|
|
150
|
-
* the blockhash they include. Any transaction whose blockhash is
|
|
151
|
-
* too old will be rejected.
|
|
152
|
-
*/
|
|
153
|
-
export type TransactionBlockhashCtor = {
|
|
154
|
-
/** The transaction fee payer */
|
|
155
|
-
feePayer?: PublicKey | null;
|
|
156
|
-
/** One or more signatures */
|
|
157
|
-
signatures?: Array<SignaturePubkeyPair>;
|
|
158
|
-
/** A recent blockhash */
|
|
159
|
-
blockhash: Blockhash;
|
|
160
|
-
/** the last block chain can advance to before tx is declared expired */
|
|
161
|
-
lastValidBlockHeight: number;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Use these options to construct a durable nonce transaction.
|
|
166
|
-
*/
|
|
167
|
-
export type TransactionNonceCtor = {
|
|
168
|
-
/** The transaction fee payer */
|
|
169
|
-
feePayer?: PublicKey | null;
|
|
170
|
-
minContextSlot: number;
|
|
171
|
-
nonceInfo: NonceInformation;
|
|
172
|
-
/** One or more signatures */
|
|
173
|
-
signatures?: Array<SignaturePubkeyPair>;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Nonce information to be used to build an offline Transaction.
|
|
178
|
-
*/
|
|
179
|
-
export type NonceInformation = {
|
|
180
|
-
/** The current blockhash stored in the nonce */
|
|
181
|
-
nonce: Blockhash;
|
|
182
|
-
/** AdvanceNonceAccount Instruction */
|
|
183
|
-
nonceInstruction: TransactionInstruction;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* @internal
|
|
188
|
-
*/
|
|
189
|
-
export interface TransactionJSON {
|
|
190
|
-
recentBlockhash: string | null;
|
|
191
|
-
feePayer: string | null;
|
|
192
|
-
nonceInfo: {
|
|
193
|
-
nonce: string;
|
|
194
|
-
nonceInstruction: TransactionInstructionJSON;
|
|
195
|
-
} | null;
|
|
196
|
-
instructions: TransactionInstructionJSON[];
|
|
197
|
-
signers: string[];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Transaction class
|
|
202
|
-
*/
|
|
203
|
-
export class Transaction {
|
|
204
|
-
/**
|
|
205
|
-
* Signatures for the transaction. Typically created by invoking the
|
|
206
|
-
* `sign()` method
|
|
207
|
-
*/
|
|
208
|
-
signatures: Array<SignaturePubkeyPair> = [];
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* The first (payer) Transaction signature
|
|
212
|
-
*/
|
|
213
|
-
get signature(): Buffer | null {
|
|
214
|
-
if (this.signatures.length > 0) {
|
|
215
|
-
return this.signatures[0].signature;
|
|
216
|
-
}
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* The transaction fee payer
|
|
222
|
-
*/
|
|
223
|
-
feePayer?: PublicKey;
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* The instructions to atomically execute
|
|
227
|
-
*/
|
|
228
|
-
instructions: Array<TransactionInstruction> = [];
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* A recent transaction id. Must be populated by the caller
|
|
232
|
-
*/
|
|
233
|
-
recentBlockhash?: Blockhash;
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* the last block chain can advance to before tx is declared expired
|
|
237
|
-
* */
|
|
238
|
-
lastValidBlockHeight?: number;
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Optional Nonce information. If populated, transaction will use a durable
|
|
242
|
-
* Nonce hash instead of a recentBlockhash. Must be populated by the caller
|
|
243
|
-
*/
|
|
244
|
-
nonceInfo?: NonceInformation;
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* If this is a nonce transaction this represents the minimum slot from which
|
|
248
|
-
* to evaluate if the nonce has advanced when attempting to confirm the
|
|
249
|
-
* transaction. This protects against a case where the transaction confirmation
|
|
250
|
-
* logic loads the nonce account from an old slot and assumes the mismatch in
|
|
251
|
-
* nonce value implies that the nonce has been advanced.
|
|
252
|
-
*/
|
|
253
|
-
minNonceContextSlot?: number;
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* @internal
|
|
257
|
-
*/
|
|
258
|
-
_message?: Message;
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* @internal
|
|
262
|
-
*/
|
|
263
|
-
_json?: TransactionJSON;
|
|
264
|
-
|
|
265
|
-
// Construct a transaction with a blockhash and lastValidBlockHeight
|
|
266
|
-
constructor(opts?: TransactionBlockhashCtor);
|
|
267
|
-
|
|
268
|
-
// Construct a transaction using a durable nonce
|
|
269
|
-
constructor(opts?: TransactionNonceCtor);
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* @deprecated `TransactionCtorFields` has been deprecated and will be removed in a future version.
|
|
273
|
-
* Please supply a `TransactionBlockhashCtor` instead.
|
|
274
|
-
*/
|
|
275
|
-
constructor(opts?: TransactionCtorFields_DEPRECATED);
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Construct an empty Transaction
|
|
279
|
-
*/
|
|
280
|
-
constructor(
|
|
281
|
-
opts?:
|
|
282
|
-
| TransactionBlockhashCtor
|
|
283
|
-
| TransactionNonceCtor
|
|
284
|
-
| TransactionCtorFields_DEPRECATED,
|
|
285
|
-
) {
|
|
286
|
-
if (!opts) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
if (opts.feePayer) {
|
|
290
|
-
this.feePayer = opts.feePayer;
|
|
291
|
-
}
|
|
292
|
-
if (opts.signatures) {
|
|
293
|
-
this.signatures = opts.signatures;
|
|
294
|
-
}
|
|
295
|
-
if (Object.prototype.hasOwnProperty.call(opts, 'nonceInfo')) {
|
|
296
|
-
const {minContextSlot, nonceInfo} = opts as TransactionNonceCtor;
|
|
297
|
-
this.minNonceContextSlot = minContextSlot;
|
|
298
|
-
this.nonceInfo = nonceInfo;
|
|
299
|
-
} else if (
|
|
300
|
-
Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')
|
|
301
|
-
) {
|
|
302
|
-
const {blockhash, lastValidBlockHeight} =
|
|
303
|
-
opts as TransactionBlockhashCtor;
|
|
304
|
-
this.recentBlockhash = blockhash;
|
|
305
|
-
this.lastValidBlockHeight = lastValidBlockHeight;
|
|
306
|
-
} else {
|
|
307
|
-
const {recentBlockhash, nonceInfo} =
|
|
308
|
-
opts as TransactionCtorFields_DEPRECATED;
|
|
309
|
-
if (nonceInfo) {
|
|
310
|
-
this.nonceInfo = nonceInfo;
|
|
311
|
-
}
|
|
312
|
-
this.recentBlockhash = recentBlockhash;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* @internal
|
|
318
|
-
*/
|
|
319
|
-
toJSON(): TransactionJSON {
|
|
320
|
-
return {
|
|
321
|
-
recentBlockhash: this.recentBlockhash || null,
|
|
322
|
-
feePayer: this.feePayer ? this.feePayer.toJSON() : null,
|
|
323
|
-
nonceInfo: this.nonceInfo
|
|
324
|
-
? {
|
|
325
|
-
nonce: this.nonceInfo.nonce,
|
|
326
|
-
nonceInstruction: this.nonceInfo.nonceInstruction.toJSON(),
|
|
327
|
-
}
|
|
328
|
-
: null,
|
|
329
|
-
instructions: this.instructions.map(instruction => instruction.toJSON()),
|
|
330
|
-
signers: this.signatures.map(({publicKey}) => {
|
|
331
|
-
return publicKey.toJSON();
|
|
332
|
-
}),
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Add one or more instructions to this Transaction
|
|
338
|
-
*/
|
|
339
|
-
add(
|
|
340
|
-
...items: Array<
|
|
341
|
-
Transaction | TransactionInstruction | TransactionInstructionCtorFields
|
|
342
|
-
>
|
|
343
|
-
): Transaction {
|
|
344
|
-
if (items.length === 0) {
|
|
345
|
-
throw new Error('No instructions');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
items.forEach((item: any) => {
|
|
349
|
-
if ('instructions' in item) {
|
|
350
|
-
this.instructions = this.instructions.concat(item.instructions);
|
|
351
|
-
} else if ('data' in item && 'programId' in item && 'keys' in item) {
|
|
352
|
-
this.instructions.push(item);
|
|
353
|
-
} else {
|
|
354
|
-
this.instructions.push(new TransactionInstruction(item));
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
return this;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Compile transaction data
|
|
362
|
-
*/
|
|
363
|
-
compileMessage(): Message {
|
|
364
|
-
if (
|
|
365
|
-
this._message &&
|
|
366
|
-
JSON.stringify(this.toJSON()) === JSON.stringify(this._json)
|
|
367
|
-
) {
|
|
368
|
-
return this._message;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
let recentBlockhash;
|
|
372
|
-
let instructions: TransactionInstruction[];
|
|
373
|
-
if (this.nonceInfo) {
|
|
374
|
-
recentBlockhash = this.nonceInfo.nonce;
|
|
375
|
-
if (this.instructions[0] != this.nonceInfo.nonceInstruction) {
|
|
376
|
-
instructions = [this.nonceInfo.nonceInstruction, ...this.instructions];
|
|
377
|
-
} else {
|
|
378
|
-
instructions = this.instructions;
|
|
379
|
-
}
|
|
380
|
-
} else {
|
|
381
|
-
recentBlockhash = this.recentBlockhash;
|
|
382
|
-
instructions = this.instructions;
|
|
383
|
-
}
|
|
384
|
-
if (!recentBlockhash) {
|
|
385
|
-
throw new Error('Transaction recentBlockhash required');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (instructions.length < 1) {
|
|
389
|
-
console.warn('No instructions provided');
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
let feePayer: PublicKey;
|
|
393
|
-
if (this.feePayer) {
|
|
394
|
-
feePayer = this.feePayer;
|
|
395
|
-
} else if (this.signatures.length > 0 && this.signatures[0].publicKey) {
|
|
396
|
-
// Use implicit fee payer
|
|
397
|
-
feePayer = this.signatures[0].publicKey;
|
|
398
|
-
} else {
|
|
399
|
-
throw new Error('Transaction fee payer required');
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
for (let i = 0; i < instructions.length; i++) {
|
|
403
|
-
if (instructions[i].programId === undefined) {
|
|
404
|
-
throw new Error(
|
|
405
|
-
`Transaction instruction index ${i} has undefined program id`,
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const programIds: string[] = [];
|
|
411
|
-
const accountMetas: AccountMeta[] = [];
|
|
412
|
-
instructions.forEach(instruction => {
|
|
413
|
-
instruction.keys.forEach(accountMeta => {
|
|
414
|
-
accountMetas.push({...accountMeta});
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
const programId = instruction.programId.toString();
|
|
418
|
-
if (!programIds.includes(programId)) {
|
|
419
|
-
programIds.push(programId);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// Append programID account metas
|
|
424
|
-
programIds.forEach(programId => {
|
|
425
|
-
accountMetas.push({
|
|
426
|
-
pubkey: new PublicKey(programId),
|
|
427
|
-
isSigner: false,
|
|
428
|
-
isWritable: false,
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
// Cull duplicate account metas
|
|
433
|
-
const uniqueMetas: AccountMeta[] = [];
|
|
434
|
-
accountMetas.forEach(accountMeta => {
|
|
435
|
-
const pubkeyString = accountMeta.pubkey.toString();
|
|
436
|
-
const uniqueIndex = uniqueMetas.findIndex(x => {
|
|
437
|
-
return x.pubkey.toString() === pubkeyString;
|
|
438
|
-
});
|
|
439
|
-
if (uniqueIndex > -1) {
|
|
440
|
-
uniqueMetas[uniqueIndex].isWritable =
|
|
441
|
-
uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable;
|
|
442
|
-
uniqueMetas[uniqueIndex].isSigner =
|
|
443
|
-
uniqueMetas[uniqueIndex].isSigner || accountMeta.isSigner;
|
|
444
|
-
} else {
|
|
445
|
-
uniqueMetas.push(accountMeta);
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
// Sort. Prioritizing first by signer, then by writable
|
|
450
|
-
uniqueMetas.sort(function (x, y) {
|
|
451
|
-
if (x.isSigner !== y.isSigner) {
|
|
452
|
-
// Signers always come before non-signers
|
|
453
|
-
return x.isSigner ? -1 : 1;
|
|
454
|
-
}
|
|
455
|
-
if (x.isWritable !== y.isWritable) {
|
|
456
|
-
// Writable accounts always come before read-only accounts
|
|
457
|
-
return x.isWritable ? -1 : 1;
|
|
458
|
-
}
|
|
459
|
-
// Otherwise, sort by pubkey, stringwise.
|
|
460
|
-
const options = {
|
|
461
|
-
localeMatcher: 'best fit',
|
|
462
|
-
usage: 'sort',
|
|
463
|
-
sensitivity: 'variant',
|
|
464
|
-
ignorePunctuation: false,
|
|
465
|
-
numeric: false,
|
|
466
|
-
caseFirst: 'lower',
|
|
467
|
-
};
|
|
468
|
-
return x.pubkey
|
|
469
|
-
.toBase58()
|
|
470
|
-
.localeCompare(y.pubkey.toBase58(), 'en', options);
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
// Move fee payer to the front
|
|
474
|
-
const feePayerIndex = uniqueMetas.findIndex(x => {
|
|
475
|
-
return x.pubkey.equals(feePayer);
|
|
476
|
-
});
|
|
477
|
-
if (feePayerIndex > -1) {
|
|
478
|
-
const [payerMeta] = uniqueMetas.splice(feePayerIndex, 1);
|
|
479
|
-
payerMeta.isSigner = true;
|
|
480
|
-
payerMeta.isWritable = true;
|
|
481
|
-
uniqueMetas.unshift(payerMeta);
|
|
482
|
-
} else {
|
|
483
|
-
uniqueMetas.unshift({
|
|
484
|
-
pubkey: feePayer,
|
|
485
|
-
isSigner: true,
|
|
486
|
-
isWritable: true,
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// Disallow unknown signers
|
|
491
|
-
for (const signature of this.signatures) {
|
|
492
|
-
const uniqueIndex = uniqueMetas.findIndex(x => {
|
|
493
|
-
return x.pubkey.equals(signature.publicKey);
|
|
494
|
-
});
|
|
495
|
-
if (uniqueIndex > -1) {
|
|
496
|
-
if (!uniqueMetas[uniqueIndex].isSigner) {
|
|
497
|
-
uniqueMetas[uniqueIndex].isSigner = true;
|
|
498
|
-
console.warn(
|
|
499
|
-
'Transaction references a signature that is unnecessary, ' +
|
|
500
|
-
'only the fee payer and instruction signer accounts should sign a transaction. ' +
|
|
501
|
-
'This behavior is deprecated and will throw an error in the next major version release.',
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
} else {
|
|
505
|
-
throw new Error(`unknown signer: ${signature.publicKey.toString()}`);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
let numRequiredSignatures = 0;
|
|
510
|
-
let numReadonlySignedAccounts = 0;
|
|
511
|
-
let numReadonlyUnsignedAccounts = 0;
|
|
512
|
-
|
|
513
|
-
// Split out signing from non-signing keys and count header values
|
|
514
|
-
const signedKeys: string[] = [];
|
|
515
|
-
const unsignedKeys: string[] = [];
|
|
516
|
-
uniqueMetas.forEach(({pubkey, isSigner, isWritable}) => {
|
|
517
|
-
if (isSigner) {
|
|
518
|
-
signedKeys.push(pubkey.toString());
|
|
519
|
-
numRequiredSignatures += 1;
|
|
520
|
-
if (!isWritable) {
|
|
521
|
-
numReadonlySignedAccounts += 1;
|
|
522
|
-
}
|
|
523
|
-
} else {
|
|
524
|
-
unsignedKeys.push(pubkey.toString());
|
|
525
|
-
if (!isWritable) {
|
|
526
|
-
numReadonlyUnsignedAccounts += 1;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
const accountKeys = signedKeys.concat(unsignedKeys);
|
|
532
|
-
const compiledInstructions: CompiledInstruction[] = instructions.map(
|
|
533
|
-
instruction => {
|
|
534
|
-
const {data, programId} = instruction;
|
|
535
|
-
return {
|
|
536
|
-
programIdIndex: accountKeys.indexOf(programId.toString()),
|
|
537
|
-
accounts: instruction.keys.map(meta =>
|
|
538
|
-
accountKeys.indexOf(meta.pubkey.toString()),
|
|
539
|
-
),
|
|
540
|
-
data: bs58.encode(data),
|
|
541
|
-
};
|
|
542
|
-
},
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
compiledInstructions.forEach(instruction => {
|
|
546
|
-
invariant(instruction.programIdIndex >= 0);
|
|
547
|
-
instruction.accounts.forEach(keyIndex => invariant(keyIndex >= 0));
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
return new Message({
|
|
551
|
-
header: {
|
|
552
|
-
numRequiredSignatures,
|
|
553
|
-
numReadonlySignedAccounts,
|
|
554
|
-
numReadonlyUnsignedAccounts,
|
|
555
|
-
},
|
|
556
|
-
accountKeys,
|
|
557
|
-
recentBlockhash,
|
|
558
|
-
instructions: compiledInstructions,
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* @internal
|
|
564
|
-
*/
|
|
565
|
-
_compile(): Message {
|
|
566
|
-
const message = this.compileMessage();
|
|
567
|
-
const signedKeys = message.accountKeys.slice(
|
|
568
|
-
0,
|
|
569
|
-
message.header.numRequiredSignatures,
|
|
570
|
-
);
|
|
571
|
-
|
|
572
|
-
if (this.signatures.length === signedKeys.length) {
|
|
573
|
-
const valid = this.signatures.every((pair, index) => {
|
|
574
|
-
return signedKeys[index].equals(pair.publicKey);
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
if (valid) return message;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
this.signatures = signedKeys.map(publicKey => ({
|
|
581
|
-
signature: null,
|
|
582
|
-
publicKey,
|
|
583
|
-
}));
|
|
584
|
-
|
|
585
|
-
return message;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Get a buffer of the Transaction data that need to be covered by signatures
|
|
590
|
-
*/
|
|
591
|
-
serializeMessage(): Buffer {
|
|
592
|
-
return this._compile().serialize();
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/**
|
|
596
|
-
* Get the estimated fee associated with a transaction
|
|
597
|
-
*/
|
|
598
|
-
async getEstimatedFee(connection: Connection): Promise<number | null> {
|
|
599
|
-
return (await connection.getFeeForMessage(this.compileMessage())).value;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Specify the public keys which will be used to sign the Transaction.
|
|
604
|
-
* The first signer will be used as the transaction fee payer account.
|
|
605
|
-
*
|
|
606
|
-
* Signatures can be added with either `partialSign` or `addSignature`
|
|
607
|
-
*
|
|
608
|
-
* @deprecated Deprecated since v0.84.0. Only the fee payer needs to be
|
|
609
|
-
* specified and it can be set in the Transaction constructor or with the
|
|
610
|
-
* `feePayer` property.
|
|
611
|
-
*/
|
|
612
|
-
setSigners(...signers: Array<PublicKey>) {
|
|
613
|
-
if (signers.length === 0) {
|
|
614
|
-
throw new Error('No signers');
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
const seen = new Set();
|
|
618
|
-
this.signatures = signers
|
|
619
|
-
.filter(publicKey => {
|
|
620
|
-
const key = publicKey.toString();
|
|
621
|
-
if (seen.has(key)) {
|
|
622
|
-
return false;
|
|
623
|
-
} else {
|
|
624
|
-
seen.add(key);
|
|
625
|
-
return true;
|
|
626
|
-
}
|
|
627
|
-
})
|
|
628
|
-
.map(publicKey => ({signature: null, publicKey}));
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/**
|
|
632
|
-
* Sign the Transaction with the specified signers. Multiple signatures may
|
|
633
|
-
* be applied to a Transaction. The first signature is considered "primary"
|
|
634
|
-
* and is used identify and confirm transactions.
|
|
635
|
-
*
|
|
636
|
-
* If the Transaction `feePayer` is not set, the first signer will be used
|
|
637
|
-
* as the transaction fee payer account.
|
|
638
|
-
*
|
|
639
|
-
* Transaction fields should not be modified after the first call to `sign`,
|
|
640
|
-
* as doing so may invalidate the signature and cause the Transaction to be
|
|
641
|
-
* rejected.
|
|
642
|
-
*
|
|
643
|
-
* The Transaction must be assigned a valid `recentBlockhash` before invoking this method
|
|
644
|
-
*/
|
|
645
|
-
sign(...signers: Array<Signer>) {
|
|
646
|
-
if (signers.length === 0) {
|
|
647
|
-
throw new Error('No signers');
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Dedupe signers
|
|
651
|
-
const seen = new Set();
|
|
652
|
-
const uniqueSigners = [];
|
|
653
|
-
for (const signer of signers) {
|
|
654
|
-
const key = signer.publicKey.toString();
|
|
655
|
-
if (seen.has(key)) {
|
|
656
|
-
continue;
|
|
657
|
-
} else {
|
|
658
|
-
seen.add(key);
|
|
659
|
-
uniqueSigners.push(signer);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
this.signatures = uniqueSigners.map(signer => ({
|
|
664
|
-
signature: null,
|
|
665
|
-
publicKey: signer.publicKey,
|
|
666
|
-
}));
|
|
667
|
-
|
|
668
|
-
const message = this._compile();
|
|
669
|
-
this._partialSign(message, ...uniqueSigners);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* Partially sign a transaction with the specified accounts. All accounts must
|
|
674
|
-
* correspond to either the fee payer or a signer account in the transaction
|
|
675
|
-
* instructions.
|
|
676
|
-
*
|
|
677
|
-
* All the caveats from the `sign` method apply to `partialSign`
|
|
678
|
-
*/
|
|
679
|
-
partialSign(...signers: Array<Signer>) {
|
|
680
|
-
if (signers.length === 0) {
|
|
681
|
-
throw new Error('No signers');
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// Dedupe signers
|
|
685
|
-
const seen = new Set();
|
|
686
|
-
const uniqueSigners = [];
|
|
687
|
-
for (const signer of signers) {
|
|
688
|
-
const key = signer.publicKey.toString();
|
|
689
|
-
if (seen.has(key)) {
|
|
690
|
-
continue;
|
|
691
|
-
} else {
|
|
692
|
-
seen.add(key);
|
|
693
|
-
uniqueSigners.push(signer);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
const message = this._compile();
|
|
698
|
-
this._partialSign(message, ...uniqueSigners);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* @internal
|
|
703
|
-
*/
|
|
704
|
-
_partialSign(message: Message, ...signers: Array<Signer>) {
|
|
705
|
-
const signData = message.serialize();
|
|
706
|
-
signers.forEach(signer => {
|
|
707
|
-
const signature = sign(signData, signer.secretKey);
|
|
708
|
-
this._addSignature(signer.publicKey, toBuffer(signature));
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Add an externally created signature to a transaction. The public key
|
|
714
|
-
* must correspond to either the fee payer or a signer account in the transaction
|
|
715
|
-
* instructions.
|
|
716
|
-
*/
|
|
717
|
-
addSignature(pubkey: PublicKey, signature: Buffer) {
|
|
718
|
-
this._compile(); // Ensure signatures array is populated
|
|
719
|
-
this._addSignature(pubkey, signature);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* @internal
|
|
724
|
-
*/
|
|
725
|
-
_addSignature(pubkey: PublicKey, signature: Buffer) {
|
|
726
|
-
invariant(signature.length === 64);
|
|
727
|
-
|
|
728
|
-
const index = this.signatures.findIndex(sigpair =>
|
|
729
|
-
pubkey.equals(sigpair.publicKey),
|
|
730
|
-
);
|
|
731
|
-
if (index < 0) {
|
|
732
|
-
throw new Error(`unknown signer: ${pubkey.toString()}`);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
this.signatures[index].signature = Buffer.from(signature);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Verify signatures of a Transaction
|
|
740
|
-
* Optional parameter specifies if we're expecting a fully signed Transaction or a partially signed one.
|
|
741
|
-
* If no boolean is provided, we expect a fully signed Transaction by default.
|
|
742
|
-
*/
|
|
743
|
-
verifySignatures(requireAllSignatures?: boolean): boolean {
|
|
744
|
-
return this._verifySignatures(
|
|
745
|
-
this.serializeMessage(),
|
|
746
|
-
requireAllSignatures === undefined ? true : requireAllSignatures,
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* @internal
|
|
752
|
-
*/
|
|
753
|
-
_verifySignatures(
|
|
754
|
-
signData: Uint8Array,
|
|
755
|
-
requireAllSignatures: boolean,
|
|
756
|
-
): boolean {
|
|
757
|
-
for (const {signature, publicKey} of this.signatures) {
|
|
758
|
-
if (signature === null) {
|
|
759
|
-
if (requireAllSignatures) {
|
|
760
|
-
return false;
|
|
761
|
-
}
|
|
762
|
-
} else {
|
|
763
|
-
if (!verify(signature, signData, publicKey.toBytes())) {
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
return true;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
/**
|
|
772
|
-
* Serialize the Transaction in the wire format.
|
|
773
|
-
*/
|
|
774
|
-
serialize(config?: SerializeConfig): Buffer {
|
|
775
|
-
const {requireAllSignatures, verifySignatures} = Object.assign(
|
|
776
|
-
{requireAllSignatures: true, verifySignatures: true},
|
|
777
|
-
config,
|
|
778
|
-
);
|
|
779
|
-
|
|
780
|
-
const signData = this.serializeMessage();
|
|
781
|
-
if (
|
|
782
|
-
verifySignatures &&
|
|
783
|
-
!this._verifySignatures(signData, requireAllSignatures)
|
|
784
|
-
) {
|
|
785
|
-
throw new Error('Signature verification failed');
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
return this._serialize(signData);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/**
|
|
792
|
-
* @internal
|
|
793
|
-
*/
|
|
794
|
-
_serialize(signData: Buffer): Buffer {
|
|
795
|
-
const {signatures} = this;
|
|
796
|
-
const signatureCount: number[] = [];
|
|
797
|
-
shortvec.encodeLength(signatureCount, signatures.length);
|
|
798
|
-
const transactionLength =
|
|
799
|
-
signatureCount.length + signatures.length * 64 + signData.length;
|
|
800
|
-
const wireTransaction = Buffer.alloc(transactionLength);
|
|
801
|
-
invariant(signatures.length < 256);
|
|
802
|
-
Buffer.from(signatureCount).copy(wireTransaction, 0);
|
|
803
|
-
signatures.forEach(({signature}, index) => {
|
|
804
|
-
if (signature !== null) {
|
|
805
|
-
invariant(signature.length === 64, `signature has invalid length`);
|
|
806
|
-
Buffer.from(signature).copy(
|
|
807
|
-
wireTransaction,
|
|
808
|
-
signatureCount.length + index * 64,
|
|
809
|
-
);
|
|
810
|
-
}
|
|
811
|
-
});
|
|
812
|
-
signData.copy(
|
|
813
|
-
wireTransaction,
|
|
814
|
-
signatureCount.length + signatures.length * 64,
|
|
815
|
-
);
|
|
816
|
-
invariant(
|
|
817
|
-
wireTransaction.length <= PACKET_DATA_SIZE,
|
|
818
|
-
`Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`,
|
|
819
|
-
);
|
|
820
|
-
return wireTransaction;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
/**
|
|
824
|
-
* Deprecated method
|
|
825
|
-
* @internal
|
|
826
|
-
*/
|
|
827
|
-
get keys(): Array<PublicKey> {
|
|
828
|
-
invariant(this.instructions.length === 1);
|
|
829
|
-
return this.instructions[0].keys.map(keyObj => keyObj.pubkey);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
/**
|
|
833
|
-
* Deprecated method
|
|
834
|
-
* @internal
|
|
835
|
-
*/
|
|
836
|
-
get programId(): PublicKey {
|
|
837
|
-
invariant(this.instructions.length === 1);
|
|
838
|
-
return this.instructions[0].programId;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* Deprecated method
|
|
843
|
-
* @internal
|
|
844
|
-
*/
|
|
845
|
-
get data(): Buffer {
|
|
846
|
-
invariant(this.instructions.length === 1);
|
|
847
|
-
return this.instructions[0].data;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
/**
|
|
851
|
-
* Parse a wire transaction into a Transaction object.
|
|
852
|
-
*/
|
|
853
|
-
static from(buffer: Buffer | Uint8Array | Array<number>): Transaction {
|
|
854
|
-
// Slice up wire data
|
|
855
|
-
let byteArray = [...buffer];
|
|
856
|
-
|
|
857
|
-
const signatureCount = shortvec.decodeLength(byteArray);
|
|
858
|
-
let signatures = [];
|
|
859
|
-
for (let i = 0; i < signatureCount; i++) {
|
|
860
|
-
const signature = byteArray.slice(0, SIGNATURE_LENGTH_IN_BYTES);
|
|
861
|
-
byteArray = byteArray.slice(SIGNATURE_LENGTH_IN_BYTES);
|
|
862
|
-
signatures.push(bs58.encode(Buffer.from(signature)));
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
return Transaction.populate(Message.from(byteArray), signatures);
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
/**
|
|
869
|
-
* Populate Transaction object from message and signatures
|
|
870
|
-
*/
|
|
871
|
-
static populate(
|
|
872
|
-
message: Message,
|
|
873
|
-
signatures: Array<string> = [],
|
|
874
|
-
): Transaction {
|
|
875
|
-
const transaction = new Transaction();
|
|
876
|
-
transaction.recentBlockhash = message.recentBlockhash;
|
|
877
|
-
if (message.header.numRequiredSignatures > 0) {
|
|
878
|
-
transaction.feePayer = message.accountKeys[0];
|
|
879
|
-
}
|
|
880
|
-
signatures.forEach((signature, index) => {
|
|
881
|
-
const sigPubkeyPair = {
|
|
882
|
-
signature:
|
|
883
|
-
signature == bs58.encode(DEFAULT_SIGNATURE)
|
|
884
|
-
? null
|
|
885
|
-
: bs58.decode(signature),
|
|
886
|
-
publicKey: message.accountKeys[index],
|
|
887
|
-
};
|
|
888
|
-
transaction.signatures.push(sigPubkeyPair);
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
message.instructions.forEach(instruction => {
|
|
892
|
-
const keys = instruction.accounts.map(account => {
|
|
893
|
-
const pubkey = message.accountKeys[account];
|
|
894
|
-
return {
|
|
895
|
-
pubkey,
|
|
896
|
-
isSigner:
|
|
897
|
-
transaction.signatures.some(
|
|
898
|
-
keyObj => keyObj.publicKey.toString() === pubkey.toString(),
|
|
899
|
-
) || message.isAccountSigner(account),
|
|
900
|
-
isWritable: message.isAccountWritable(account),
|
|
901
|
-
};
|
|
902
|
-
});
|
|
903
|
-
|
|
904
|
-
transaction.instructions.push(
|
|
905
|
-
new TransactionInstruction({
|
|
906
|
-
keys,
|
|
907
|
-
programId: message.accountKeys[instruction.programIdIndex],
|
|
908
|
-
data: bs58.decode(instruction.data),
|
|
909
|
-
}),
|
|
910
|
-
);
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
transaction._message = message;
|
|
914
|
-
transaction._json = transaction.toJSON();
|
|
915
|
-
|
|
916
|
-
return transaction;
|
|
917
|
-
}
|
|
918
|
-
}
|