@exodus/solana-lib 1.2.14 → 1.2.20

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.
Files changed (60) hide show
  1. package/package.json +6 -5
  2. package/src/constants.js +12 -0
  3. package/src/encode.js +62 -0
  4. package/src/fee-data/index.js +1 -0
  5. package/src/fee-data/solana.js +9 -0
  6. package/src/helpers/spl-token.js +108 -0
  7. package/src/helpers/tokenTransfer.js +72 -0
  8. package/src/index.js +9 -0
  9. package/src/keypair.js +32 -0
  10. package/src/tokens.js +12 -0
  11. package/src/transaction.js +292 -0
  12. package/src/tx/create-and-sign-tx.js +8 -0
  13. package/{lib → src}/tx/create-unsigned-tx.js +11 -18
  14. package/src/tx/index.js +4 -0
  15. package/src/tx/parse-unsigned-tx.js +41 -0
  16. package/src/tx/sign-unsigned-tx.js +78 -0
  17. package/src/vendor/account.js +38 -0
  18. package/src/vendor/index.js +9 -0
  19. package/src/vendor/instruction.js +46 -0
  20. package/src/vendor/message.js +216 -0
  21. package/src/vendor/nonce-account.js +46 -0
  22. package/src/vendor/publickey.js +212 -0
  23. package/src/vendor/stake-program.js +527 -0
  24. package/src/vendor/system-program.js +782 -0
  25. package/src/vendor/sysvar.js +16 -0
  26. package/src/vendor/transaction.js +594 -0
  27. package/src/vendor/utils/blockhash.js +6 -0
  28. package/src/vendor/utils/fee-calculator.js +17 -0
  29. package/src/vendor/utils/layout.js +80 -0
  30. package/src/vendor/utils/shortvec-encoding.js +30 -0
  31. package/src/vendor/utils/to-buffer.js +9 -0
  32. package/lib/constants.js +0 -19
  33. package/lib/encode.js +0 -67
  34. package/lib/fee-data/index.js +0 -15
  35. package/lib/fee-data/solana.js +0 -14
  36. package/lib/helpers/spl-token.js +0 -122
  37. package/lib/helpers/tokenTransfer.js +0 -78
  38. package/lib/index.js +0 -88
  39. package/lib/keypair.js +0 -38
  40. package/lib/tokens.js +0 -21
  41. package/lib/transaction.js +0 -338
  42. package/lib/tx/create-and-sign-tx.js +0 -15
  43. package/lib/tx/index.js +0 -53
  44. package/lib/tx/parse-unsigned-tx.js +0 -55
  45. package/lib/tx/sign-unsigned-tx.js +0 -90
  46. package/lib/vendor/account.js +0 -48
  47. package/lib/vendor/index.js +0 -113
  48. package/lib/vendor/instruction.js +0 -48
  49. package/lib/vendor/message.js +0 -167
  50. package/lib/vendor/nonce-account.js +0 -56
  51. package/lib/vendor/publickey.js +0 -211
  52. package/lib/vendor/stake-program.js +0 -476
  53. package/lib/vendor/system-program.js +0 -640
  54. package/lib/vendor/sysvar.js +0 -19
  55. package/lib/vendor/transaction.js +0 -594
  56. package/lib/vendor/utils/blockhash.js +0 -1
  57. package/lib/vendor/utils/fee-calculator.js +0 -25
  58. package/lib/vendor/utils/layout.js +0 -97
  59. package/lib/vendor/utils/shortvec-encoding.js +0 -41
  60. package/lib/vendor/utils/to-buffer.js +0 -18
@@ -0,0 +1,16 @@
1
+ // @flow
2
+ import { PublicKey } from './publickey'
3
+
4
+ export const SYSVAR_CLOCK_PUBKEY = new PublicKey('SysvarC1ock11111111111111111111111111111111')
5
+
6
+ export const SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey(
7
+ 'SysvarRecentB1ockHashes11111111111111111111'
8
+ )
9
+
10
+ export const SYSVAR_RENT_PUBKEY = new PublicKey('SysvarRent111111111111111111111111111111111')
11
+
12
+ export const SYSVAR_REWARDS_PUBKEY = new PublicKey('SysvarRewards111111111111111111111111111111')
13
+
14
+ export const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey(
15
+ 'SysvarStakeHistory1111111111111111111111111'
16
+ )
@@ -0,0 +1,594 @@
1
+ // @flow
2
+ // https://github.com/solana-labs/solana-web3.js/blob/master/src/transaction.js
3
+
4
+ import invariant from 'assert'
5
+ import nacl from 'tweetnacl'
6
+ import bs58 from 'bs58'
7
+
8
+ import type { Blockhash } from './utils/blockhash'
9
+ import type { CompiledInstruction } from './message'
10
+ import { Message } from './message'
11
+ import { PublicKey, Account } from './index'
12
+ import * as shortvec from './utils/shortvec-encoding'
13
+
14
+ /**
15
+ * @typedef {string} TransactionSignature
16
+ */
17
+ export type TransactionSignature = string
18
+
19
+ /**
20
+ * Default (empty) signature
21
+ *
22
+ * Signatures are 64 bytes in length
23
+ */
24
+ const DEFAULT_SIGNATURE = Buffer.alloc(64).fill(0)
25
+
26
+ /**
27
+ * Maximum over-the-wire size of a Transaction
28
+ *
29
+ * 1280 is IPv6 minimum MTU
30
+ * 40 bytes is the size of the IPv6 header
31
+ * 8 bytes is the size of the fragment header
32
+ */
33
+ export const PACKET_DATA_SIZE = 1280 - 40 - 8
34
+
35
+ const SIGNATURE_LENGTH = 64
36
+
37
+ /**
38
+ * Account metadata used to define instructions
39
+ *
40
+ * @typedef {Object} AccountMeta
41
+ * @property {PublicKey} pubkey An account's public key
42
+ * @property {boolean} isSigner True if an instruction requires a transaction signature matching `pubkey`
43
+ * @property {boolean} isWritable True if the `pubkey` can be loaded as a read-write account.
44
+ */
45
+ export type AccountMeta = {
46
+ pubkey: PublicKey,
47
+ isSigner: boolean,
48
+ isWritable: boolean,
49
+ }
50
+
51
+ /**
52
+ * List of TransactionInstruction object fields that may be initialized at construction
53
+ *
54
+ * @typedef {Object} TransactionInstructionCtorFields
55
+ * @property {?Array<PublicKey>} keys
56
+ * @property {?PublicKey} programId
57
+ * @property {?Buffer} data
58
+ */
59
+ export type TransactionInstructionCtorFields = {|
60
+ keys?: Array<AccountMeta>,
61
+ programId?: PublicKey,
62
+ data?: Buffer,
63
+ |}
64
+
65
+ /**
66
+ * Configuration object for Transaction.serialize()
67
+ *
68
+ * @typedef {Object} SerializeConfig
69
+ * @property {boolean|undefined} requireAllSignatures Require all transaction signatures be present (default: true)
70
+ * @property {boolean|undefined} verifySignatures Verify provided signatures (default: true)
71
+ */
72
+ export type SerializeConfig = {
73
+ requireAllSignatures?: boolean,
74
+ verifySignatures?: boolean,
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
+ opts && Object.assign(this, opts)
99
+ }
100
+ }
101
+
102
+ /**
103
+ * @private
104
+ */
105
+ type SignaturePubkeyPair = {|
106
+ signature: Buffer | null,
107
+ publicKey: PublicKey,
108
+ |}
109
+
110
+ /**
111
+ * NonceInformation to be used to build a Transaction.
112
+ *
113
+ * @typedef {Object} NonceInformation
114
+ * @property {Blockhash} nonce The current Nonce blockhash
115
+ * @property {TransactionInstruction} nonceInstruction AdvanceNonceAccount Instruction
116
+ */
117
+ type NonceInformation = {|
118
+ nonce: Blockhash,
119
+ nonceInstruction: TransactionInstruction,
120
+ |}
121
+
122
+ /**
123
+ * List of Transaction object fields that may be initialized at construction
124
+ *
125
+ * @typedef {Object} TransactionCtorFields
126
+ * @property {?Blockhash} recentBlockhash A recent blockhash
127
+ * @property {?Array<SignaturePubkeyPair>} signatures One or more signatures
128
+ *
129
+ */
130
+ type TransactionCtorFields = {|
131
+ recentBlockhash?: Blockhash | null,
132
+ nonceInfo?: NonceInformation | null,
133
+ signatures?: Array<SignaturePubkeyPair>,
134
+ |}
135
+
136
+ /**
137
+ * Transaction class
138
+ */
139
+ export class Transaction {
140
+ /**
141
+ * Signatures for the transaction. Typically created by invoking the
142
+ * `sign()` method
143
+ */
144
+ signatures: Array<SignaturePubkeyPair> = []
145
+
146
+ /**
147
+ * The first (payer) Transaction signature
148
+ */
149
+ get signature(): Buffer | null {
150
+ if (this.signatures.length > 0) {
151
+ return this.signatures[0].signature
152
+ }
153
+ return null
154
+ }
155
+ /**
156
+ * The transaction fee payer (first signer)
157
+ */
158
+ get feePayer(): PublicKey | null {
159
+ if (this.signatures.length > 0) {
160
+ return this.signatures[0].publicKey
161
+ }
162
+ return null
163
+ }
164
+ /**
165
+ * The instructions to atomically execute
166
+ */
167
+ instructions: Array<TransactionInstruction> = []
168
+
169
+ /**
170
+ * A recent transaction id. Must be populated by the caller
171
+ */
172
+ recentBlockhash: Blockhash | null
173
+
174
+ /**
175
+ * Optional Nonce information. If populated, transaction will use a durable
176
+ * Nonce hash instead of a recentBlockhash. Must be populated by the caller
177
+ */
178
+ nonceInfo: NonceInformation | null
179
+
180
+ /**
181
+ * Construct an empty Transaction
182
+ */
183
+ constructor(opts?: TransactionCtorFields) {
184
+ opts && Object.assign(this, opts)
185
+ }
186
+ /**
187
+ * Add one or more instructions to this Transaction
188
+ */
189
+ add(
190
+ ...items: Array<Transaction | TransactionInstruction | TransactionInstructionCtorFields>
191
+ ): Transaction {
192
+ if (items.length === 0) {
193
+ throw new Error('No instructions')
194
+ }
195
+
196
+ items.forEach((item: any) => {
197
+ if ('instructions' in item) {
198
+ this.instructions = this.instructions.concat(item.instructions)
199
+ } else if ('data' in item && 'programId' in item && 'keys' in item) {
200
+ this.instructions.push(item)
201
+ } else {
202
+ this.instructions.push(new TransactionInstruction(item))
203
+ }
204
+ })
205
+ return this
206
+ }
207
+ /**
208
+ * Compile transaction data
209
+ */
210
+ compileMessage(): Message {
211
+ const { nonceInfo } = this
212
+ if (nonceInfo && this.instructions[0] !== nonceInfo.nonceInstruction) {
213
+ this.recentBlockhash = nonceInfo.nonce
214
+ this.instructions.unshift(nonceInfo.nonceInstruction)
215
+ }
216
+ const { recentBlockhash } = this
217
+ if (!recentBlockhash) {
218
+ throw new Error('Transaction recentBlockhash required')
219
+ }
220
+
221
+ if (this.instructions.length < 1) {
222
+ throw new Error('No instructions provided')
223
+ }
224
+
225
+ if (this.feePayer === null) {
226
+ throw new Error('Transaction feePayer required')
227
+ }
228
+
229
+ const programIds: string[] = []
230
+ const accountMetas: AccountMeta[] = []
231
+ this.instructions.forEach((instruction) => {
232
+ instruction.keys.forEach((accountMeta) => {
233
+ accountMetas.push({ ...accountMeta })
234
+ })
235
+
236
+ const programId = instruction.programId.toString()
237
+ if (!programIds.includes(programId)) {
238
+ programIds.push(programId)
239
+ }
240
+ })
241
+ // Append programID account metas
242
+ programIds.forEach((programId) => {
243
+ accountMetas.push({
244
+ pubkey: new PublicKey(programId),
245
+ isSigner: false,
246
+ isWritable: false,
247
+ })
248
+ })
249
+
250
+ // Sort. Prioritizing first by signer, then by writable
251
+ accountMetas.sort(function(x, y) {
252
+ const checkSigner = x.isSigner === y.isSigner ? 0 : x.isSigner ? -1 : 1
253
+ const checkWritable = x.isWritable === y.isWritable ? 0 : x.isWritable ? -1 : 1
254
+ return checkSigner || checkWritable
255
+ })
256
+
257
+ // Cull duplicate account metas
258
+ const uniqueMetas: AccountMeta[] = []
259
+ accountMetas.forEach((accountMeta) => {
260
+ const pubkeyString = accountMeta.pubkey.toString()
261
+ const uniqueIndex = uniqueMetas.findIndex((x) => {
262
+ return x.pubkey.toString() === pubkeyString
263
+ })
264
+ if (uniqueIndex > -1) {
265
+ uniqueMetas[uniqueIndex].isWritable =
266
+ uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable
267
+ } else {
268
+ uniqueMetas.push(accountMeta)
269
+ }
270
+ })
271
+ // Move payer to the front and disallow unknown signers
272
+ this.signatures.forEach((signature, signatureIndex) => {
273
+ const isPayer = signatureIndex === 0
274
+ const uniqueIndex = uniqueMetas.findIndex((x) => {
275
+ return x.pubkey.equals(signature.publicKey)
276
+ })
277
+ if (uniqueIndex > -1) {
278
+ if (isPayer) {
279
+ const [payerMeta] = uniqueMetas.splice(uniqueIndex, 1)
280
+ payerMeta.isSigner = true
281
+ payerMeta.isWritable = true
282
+ uniqueMetas.unshift(payerMeta)
283
+ } else {
284
+ uniqueMetas[uniqueIndex].isSigner = true
285
+ }
286
+ } else if (isPayer) {
287
+ uniqueMetas.unshift({
288
+ pubkey: signature.publicKey,
289
+ isSigner: true,
290
+ isWritable: true,
291
+ })
292
+ } else {
293
+ throw new Error(`unknown signer: ${signature.publicKey.toString()}`)
294
+ }
295
+ })
296
+
297
+ let numRequiredSignatures = 0
298
+ let numReadonlySignedAccounts = 0
299
+ let numReadonlyUnsignedAccounts = 0
300
+ // Split out signing from non-signing keys and count header values
301
+ const signedKeys: string[] = []
302
+ const unsignedKeys: string[] = []
303
+ uniqueMetas.forEach(({ pubkey, isSigner, isWritable }) => {
304
+ if (isSigner) {
305
+ signedKeys.push(pubkey.toString())
306
+ numRequiredSignatures += 1
307
+ if (!isWritable) {
308
+ numReadonlySignedAccounts += 1
309
+ }
310
+ } else {
311
+ unsignedKeys.push(pubkey.toString())
312
+ if (!isWritable) {
313
+ numReadonlyUnsignedAccounts += 1
314
+ }
315
+ }
316
+ })
317
+
318
+ if (numRequiredSignatures !== this.signatures.length) {
319
+ throw new Error(
320
+ `missing signer(s) - required signatures: ${numRequiredSignatures}, got ${this.signatures.length}`
321
+ )
322
+ }
323
+
324
+ const accountKeys = signedKeys.concat(unsignedKeys)
325
+ const instructions: CompiledInstruction[] = this.instructions.map((instruction) => {
326
+ const { data, programId } = instruction
327
+ return {
328
+ programIdIndex: accountKeys.indexOf(programId.toString()),
329
+ accounts: instruction.keys.map((keyObj) => accountKeys.indexOf(keyObj.pubkey.toString())),
330
+ data: bs58.encode(data),
331
+ }
332
+ })
333
+
334
+ instructions.forEach((instruction) => {
335
+ invariant(instruction.programIdIndex >= 0)
336
+ instruction.accounts.forEach((keyIndex) => invariant(keyIndex >= 0))
337
+ })
338
+
339
+ return new Message({
340
+ header: {
341
+ numRequiredSignatures,
342
+ numReadonlySignedAccounts,
343
+ numReadonlyUnsignedAccounts,
344
+ },
345
+ accountKeys,
346
+ recentBlockhash,
347
+ instructions,
348
+ })
349
+ }
350
+ /**
351
+ * Get a buffer of the Transaction data that need to be covered by signatures
352
+ */
353
+ serializeMessage(): Buffer {
354
+ return this.compileMessage().serialize()
355
+ }
356
+ /**
357
+ * Specify the public keys which will be used to sign the Transaction.
358
+ * The first signer will be used as the transaction fee payer account.
359
+ *
360
+ * Signatures can be added with either `partialSign` or `addSignature`
361
+ */
362
+ setSigners(...signers: Array<PublicKey>) {
363
+ if (signers.length === 0) {
364
+ throw new Error('No signers')
365
+ }
366
+
367
+ const seen = new Set()
368
+ this.signatures = signers
369
+ .filter((publicKey) => {
370
+ const key = publicKey.toString()
371
+ if (seen.has(key)) {
372
+ return false
373
+ } else {
374
+ seen.add(key)
375
+ return true
376
+ }
377
+ })
378
+ .map((publicKey) => ({ signature: null, publicKey }))
379
+ }
380
+ /**
381
+ * Sign the Transaction with the specified accounts. Multiple signatures may
382
+ * be applied to a Transaction. The first signature is considered "primary"
383
+ * and is used when testing for Transaction confirmation. The first signer
384
+ * will be used as the transaction fee payer account.
385
+ *
386
+ * Transaction fields should not be modified after the first call to `sign`,
387
+ * as doing so may invalidate the signature and cause the Transaction to be
388
+ * rejected.
389
+ *
390
+ * The Transaction must be assigned a valid `recentBlockhash` before invoking this method
391
+ */
392
+ sign(...signers: Array<Account>) {
393
+ if (signers.length === 0) {
394
+ throw new Error('No signers')
395
+ }
396
+
397
+ const seen = new Set()
398
+ this.signatures = signers
399
+ .filter((signer) => {
400
+ const key = signer.publicKey.toString()
401
+ if (seen.has(key)) {
402
+ return false
403
+ } else {
404
+ seen.add(key)
405
+ return true
406
+ }
407
+ })
408
+ .map((signer) => ({
409
+ signature: null,
410
+ publicKey: signer.publicKey,
411
+ }))
412
+
413
+ this.partialSign(...signers)
414
+ }
415
+ /**
416
+ * Partially sign a transaction with the specified accounts. All accounts must
417
+ * correspond to a public key that was previously provided to `setSigners`.
418
+ *
419
+ * All the caveats from the `sign` method apply to `partialSign`
420
+ */
421
+ partialSign(...signers: Array<Account>) {
422
+ if (signers.length === 0) {
423
+ throw new Error('No signers')
424
+ }
425
+
426
+ const message = this.compileMessage()
427
+ this.signatures.sort(function(x, y) {
428
+ const xIndex = message.findSignerIndex(x.publicKey)
429
+ const yIndex = message.findSignerIndex(y.publicKey)
430
+ return xIndex < yIndex ? -1 : 1
431
+ })
432
+
433
+ const signData = message.serialize()
434
+ signers.forEach((signer) => {
435
+ const signature = nacl.sign.detached(signData, signer.secretKey)
436
+ this.addSignature(signer.publicKey, signature)
437
+ })
438
+ }
439
+ /**
440
+ * Add an externally created signature to a transaction. The public key
441
+ * must correspond to a public key that was previously provided to `setSigners`.
442
+ */
443
+ addSignature(pubkey: PublicKey, signature: Buffer) {
444
+ invariant(signature.length === 64)
445
+
446
+ const index = this.signatures.findIndex((sigpair) => pubkey.equals(sigpair.publicKey))
447
+ if (index < 0) {
448
+ throw new Error(`unknown signer: ${pubkey.toString()}`)
449
+ }
450
+
451
+ this.signatures[index].signature = Buffer.from(signature)
452
+ }
453
+ /**
454
+ * Verify signatures of a complete, signed Transaction
455
+ */
456
+ verifySignatures(): boolean {
457
+ return this._verifySignatures(this.serializeMessage(), true)
458
+ }
459
+ /**
460
+ * @private
461
+ */
462
+ _verifySignatures(signData: Buffer, requireAllSignatures: boolean): boolean {
463
+ for (const { signature, publicKey } of this.signatures) {
464
+ if (signature === null) {
465
+ if (requireAllSignatures) {
466
+ return false
467
+ }
468
+ } else {
469
+ if (!nacl.sign.detached.verify(signData, signature, publicKey.toBuffer())) {
470
+ return false
471
+ }
472
+ }
473
+ }
474
+ return true
475
+ }
476
+ /**
477
+ * Serialize the Transaction in the wire format.
478
+ */
479
+ serialize(config?: SerializeConfig): Buffer {
480
+ const { requireAllSignatures, verifySignatures } = Object.assign(
481
+ { requireAllSignatures: true, verifySignatures: true },
482
+ config
483
+ )
484
+
485
+ const signData = this.serializeMessage()
486
+ if (verifySignatures && !this._verifySignatures(signData, requireAllSignatures)) {
487
+ throw new Error('Signature verification failed')
488
+ }
489
+
490
+ return this._serialize(signData)
491
+ }
492
+ /**
493
+ * @private
494
+ */
495
+ _serialize(signData: Buffer): Buffer {
496
+ const { signatures } = this
497
+ const signatureCount = []
498
+ shortvec.encodeLength(signatureCount, signatures.length)
499
+ const transactionLength = signatureCount.length + signatures.length * 64 + signData.length
500
+ const wireTransaction = Buffer.alloc(transactionLength)
501
+ invariant(signatures.length < 256)
502
+ Buffer.from(signatureCount).copy(wireTransaction, 0)
503
+ signatures.forEach(({ signature }, index) => {
504
+ if (signature !== null) {
505
+ invariant(signature.length === 64, `signature has invalid length`)
506
+ Buffer.from(signature).copy(wireTransaction, signatureCount.length + index * 64)
507
+ }
508
+ })
509
+ signData.copy(wireTransaction, signatureCount.length + signatures.length * 64)
510
+ invariant(
511
+ wireTransaction.length <= PACKET_DATA_SIZE,
512
+ `Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`
513
+ )
514
+ return wireTransaction
515
+ }
516
+ /**
517
+ * Deprecated method
518
+ * @private
519
+ */
520
+ get keys(): Array<PublicKey> {
521
+ invariant(this.instructions.length === 1)
522
+ return this.instructions[0].keys.map((keyObj) => keyObj.pubkey)
523
+ }
524
+ /**
525
+ * Deprecated method
526
+ * @private
527
+ */
528
+ get programId(): PublicKey {
529
+ invariant(this.instructions.length === 1)
530
+ return this.instructions[0].programId
531
+ }
532
+ /**
533
+ * Deprecated method
534
+ * @private
535
+ */
536
+ get data(): Buffer {
537
+ invariant(this.instructions.length === 1)
538
+ return this.instructions[0].data
539
+ }
540
+ /**
541
+ * Parse a wire transaction into a Transaction object.
542
+ */
543
+ static from(buffer: Buffer | Uint8Array | Array<number>): Transaction {
544
+ // Slice up wire data
545
+ let byteArray = [...buffer]
546
+
547
+ const signatureCount = shortvec.decodeLength(byteArray)
548
+ let signatures = []
549
+ for (let i = 0; i < signatureCount; i++) {
550
+ const signature = byteArray.slice(0, SIGNATURE_LENGTH)
551
+ byteArray = byteArray.slice(SIGNATURE_LENGTH)
552
+ signatures.push(bs58.encode(Buffer.from(signature)))
553
+ }
554
+
555
+ return Transaction.populate(Message.from(byteArray), signatures)
556
+ }
557
+ /**
558
+ * Populate Transaction object from message and signatures
559
+ */
560
+ static populate(message: Message, signatures: Array<string>): Transaction {
561
+ const transaction = new Transaction()
562
+ transaction.recentBlockhash = message.recentBlockhash
563
+ signatures.forEach((signature, index) => {
564
+ const sigPubkeyPair = {
565
+ signature: signature === bs58.encode(DEFAULT_SIGNATURE) ? null : bs58.decode(signature),
566
+ publicKey: message.accountKeys[index],
567
+ }
568
+ transaction.signatures.push(sigPubkeyPair)
569
+ })
570
+
571
+ message.instructions.forEach((instruction) => {
572
+ const keys = instruction.accounts.map((account) => {
573
+ const pubkey = message.accountKeys[account]
574
+ return {
575
+ pubkey,
576
+ isSigner: transaction.signatures.some(
577
+ (keyObj) => keyObj.publicKey.toString() === pubkey.toString()
578
+ ),
579
+ isWritable: message.isAccountWritable(account),
580
+ }
581
+ })
582
+
583
+ transaction.instructions.push(
584
+ new TransactionInstruction({
585
+ keys,
586
+ programId: message.accountKeys[instruction.programIdIndex],
587
+ data: bs58.decode(instruction.data),
588
+ })
589
+ )
590
+ })
591
+
592
+ return transaction
593
+ }
594
+ }
@@ -0,0 +1,6 @@
1
+ // @flow
2
+
3
+ /**
4
+ * @typedef {string} Blockhash
5
+ */
6
+ export type Blockhash = string
@@ -0,0 +1,17 @@
1
+ // @flow
2
+ import * as BufferLayout from '@exodus/buffer-layout'
3
+
4
+ /**
5
+ * https://github.com/solana-labs/solana/blob/90bedd7e067b5b8f3ddbb45da00a4e9cabb22c62/sdk/src/fee_calculator.rs#L7-L11
6
+ *
7
+ * @private
8
+ */
9
+ export const FeeCalculatorLayout = BufferLayout.nu64('lamportsPerSignature')
10
+
11
+ /**
12
+ * @typedef {Object} FeeCalculator
13
+ * @property {number} lamportsPerSignature lamports Cost in lamports to validate a signature
14
+ */
15
+ export type FeeCalculator = {
16
+ lamportsPerSignature: number,
17
+ }
@@ -0,0 +1,80 @@
1
+ // @flow
2
+
3
+ import * as BufferLayout from '@exodus/buffer-layout'
4
+
5
+ /**
6
+ * Layout for a public key
7
+ */
8
+ export const publicKey = (property: string = 'publicKey'): Object => {
9
+ return BufferLayout.blob(32, property)
10
+ }
11
+
12
+ /**
13
+ * Layout for a 64bit unsigned value
14
+ */
15
+ export const uint64 = (property: string = 'uint64'): Object => {
16
+ return BufferLayout.blob(8, property)
17
+ }
18
+
19
+ /**
20
+ * Layout for a Rust String type
21
+ */
22
+ export const rustString = (property: string = 'string') => {
23
+ const rsl = BufferLayout.struct(
24
+ [
25
+ BufferLayout.u32('length'),
26
+ BufferLayout.u32('lengthPadding'),
27
+ BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'),
28
+ ],
29
+ property
30
+ )
31
+ const _decode = rsl.decode.bind(rsl)
32
+ const _encode = rsl.encode.bind(rsl)
33
+
34
+ rsl.decode = (buffer, offset) => {
35
+ const data = _decode(buffer, offset)
36
+ return data.chars.toString('utf8')
37
+ }
38
+
39
+ rsl.encode = (str, buffer, offset) => {
40
+ const data = {
41
+ chars: Buffer.from(str, 'utf8'),
42
+ }
43
+ return _encode(data, buffer, offset)
44
+ }
45
+
46
+ rsl.alloc = (str) => {
47
+ return BufferLayout.u32().span + BufferLayout.u32().span + Buffer.from(str, 'utf8').length
48
+ }
49
+
50
+ return rsl
51
+ }
52
+
53
+ /**
54
+ * Layout for an Authorized object
55
+ */
56
+ export const authorized = (property: string = 'authorized') => {
57
+ return BufferLayout.struct([publicKey('staker'), publicKey('withdrawer')], property)
58
+ }
59
+
60
+ /**
61
+ * Layout for a Lockup object
62
+ */
63
+ export const lockup = (property: string = 'lockup') => {
64
+ return BufferLayout.struct(
65
+ [BufferLayout.ns64('unixTimestamp'), BufferLayout.ns64('epoch'), publicKey('custodian')],
66
+ property
67
+ )
68
+ }
69
+
70
+ export function getAlloc(type: Object, fields: Object): number {
71
+ let alloc = 0
72
+ type.layout.fields.forEach((item) => {
73
+ if (item.span >= 0) {
74
+ alloc += item.span
75
+ } else if (typeof item.alloc === 'function') {
76
+ alloc += item.alloc(fields[item.property])
77
+ }
78
+ })
79
+ return alloc
80
+ }