@exodus/solana-lib 1.2.8 → 1.2.9-build

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/lib/constants.js +19 -0
  2. package/lib/encode.js +67 -0
  3. package/lib/fee-data/index.js +15 -0
  4. package/lib/fee-data/solana.js +14 -0
  5. package/lib/helpers/spl-token.js +122 -0
  6. package/lib/helpers/tokenTransfer.js +78 -0
  7. package/lib/index.js +79 -0
  8. package/lib/keypair.js +38 -0
  9. package/lib/tokens.js +21 -0
  10. package/lib/transaction.js +279 -0
  11. package/lib/tx/create-and-sign-tx.js +15 -0
  12. package/{src → lib}/tx/create-unsigned-tx.js +20 -11
  13. package/lib/tx/index.js +53 -0
  14. package/lib/tx/parse-unsigned-tx.js +55 -0
  15. package/lib/tx/sign-unsigned-tx.js +90 -0
  16. package/lib/vendor/account.js +48 -0
  17. package/lib/vendor/index.js +113 -0
  18. package/lib/vendor/instruction.js +48 -0
  19. package/lib/vendor/message.js +167 -0
  20. package/lib/vendor/nonce-account.js +56 -0
  21. package/lib/vendor/publickey.js +211 -0
  22. package/lib/vendor/stake-program.js +476 -0
  23. package/lib/vendor/system-program.js +640 -0
  24. package/lib/vendor/sysvar.js +19 -0
  25. package/lib/vendor/transaction.js +594 -0
  26. package/lib/vendor/utils/blockhash.js +1 -0
  27. package/lib/vendor/utils/fee-calculator.js +25 -0
  28. package/lib/vendor/utils/layout.js +97 -0
  29. package/lib/vendor/utils/shortvec-encoding.js +41 -0
  30. package/lib/vendor/utils/to-buffer.js +18 -0
  31. package/package.json +4 -5
  32. package/src/constants.js +0 -12
  33. package/src/encode.js +0 -57
  34. package/src/fee-data/index.js +0 -1
  35. package/src/fee-data/solana.js +0 -9
  36. package/src/helpers/spl-token.js +0 -108
  37. package/src/helpers/tokenTransfer.js +0 -72
  38. package/src/index.js +0 -8
  39. package/src/keypair.js +0 -32
  40. package/src/tokens.js +0 -19
  41. package/src/transaction.js +0 -240
  42. package/src/tx/create-and-sign-tx.js +0 -8
  43. package/src/tx/index.js +0 -4
  44. package/src/tx/parse-unsigned-tx.js +0 -39
  45. package/src/tx/sign-unsigned-tx.js +0 -78
  46. package/src/vendor/account.js +0 -38
  47. package/src/vendor/index.js +0 -9
  48. package/src/vendor/instruction.js +0 -46
  49. package/src/vendor/message.js +0 -216
  50. package/src/vendor/nonce-account.js +0 -46
  51. package/src/vendor/publickey.js +0 -212
  52. package/src/vendor/stake-program.js +0 -527
  53. package/src/vendor/system-program.js +0 -782
  54. package/src/vendor/sysvar.js +0 -16
  55. package/src/vendor/transaction.js +0 -594
  56. package/src/vendor/utils/blockhash.js +0 -6
  57. package/src/vendor/utils/fee-calculator.js +0 -17
  58. package/src/vendor/utils/layout.js +0 -80
  59. package/src/vendor/utils/shortvec-encoding.js +0 -30
  60. package/src/vendor/utils/to-buffer.js +0 -9
@@ -1,240 +0,0 @@
1
- // @flow
2
- import assert from 'assert'
3
-
4
- import { getKeyPairFromPrivateKey } from './keypair'
5
- import { findAssociatedTokenAddress, createStakeAddress } from './encode'
6
- import {
7
- createAssociatedTokenAccount,
8
- createTokenTransferInstruction,
9
- } from './helpers/tokenTransfer'
10
- import {
11
- PublicKey,
12
- Account,
13
- Transaction,
14
- SystemProgram,
15
- StakeProgram,
16
- Authorized,
17
- Lockup,
18
- } from './vendor'
19
- import { SEED } from './constants'
20
- import TOKENS from './tokens'
21
- import bs58 from 'bs58'
22
-
23
- class Tx {
24
- constructor({
25
- from,
26
- to,
27
- amount,
28
- recentBlockhash,
29
- // fee, // (Fee per Signature: 5000 lamports)
30
- // Tokens related:
31
- tokenName,
32
- destinationAddressType,
33
- isAssociatedTokenAccountActive, // true when recipient balance !== 0
34
- fromTokenAddresses, // sender token addresses
35
- } = {}) {
36
- assert(from, 'from is required')
37
- assert(to, 'to is required')
38
- assert(amount, 'amount is required')
39
- assert(typeof amount === 'number', 'amount must be a number')
40
- assert(recentBlockhash, 'recentBlockhash is required')
41
- if (tokenName) {
42
- assert(
43
- typeof destinationAddressType !== 'undefined',
44
- 'destinationAddressType is required when sending tokens'
45
- )
46
- assert(
47
- typeof isAssociatedTokenAccountActive !== 'undefined',
48
- 'isAssociatedTokenAccountActive is required when sending tokens'
49
- ) // needed to create the recipient account
50
- assert(Array.isArray(fromTokenAddresses), 'fromTokenAddresses Array is required')
51
- }
52
-
53
- const token = TOKENS.find(({ tokenName: name }) => name === tokenName)
54
- this.txObj = {
55
- from,
56
- to,
57
- amount,
58
- recentBlockhash,
59
- token,
60
- destinationAddressType,
61
- isAssociatedTokenAccountActive,
62
- fromTokenAddresses,
63
- }
64
-
65
- if (token) {
66
- // TOKEN transfer tx
67
- this.buildTokenTransaction(this.txObj)
68
- } else {
69
- // SOL tx
70
- this.buildSOLtransaction(this.txObj)
71
- }
72
- }
73
-
74
- buildSOLtransaction({ from, to, amount, recentBlockhash }) {
75
- const txInstruction = SystemProgram.transfer({
76
- fromPubkey: new PublicKey(from),
77
- toPubkey: new PublicKey(to),
78
- lamports: amount,
79
- })
80
-
81
- this.transaction = new Transaction({
82
- instructions: [txInstruction],
83
- recentBlockhash,
84
- })
85
- }
86
-
87
- buildTokenTransaction({
88
- from,
89
- to,
90
- amount,
91
- recentBlockhash,
92
- token,
93
- destinationAddressType,
94
- isAssociatedTokenAccountActive,
95
- fromTokenAddresses,
96
- }) {
97
- this.transaction = new Transaction({
98
- recentBlockhash,
99
- })
100
- const isUnknown = destinationAddressType === null
101
- const isSOLaddress = destinationAddressType === 'solana'
102
- // crete account instruction
103
- if (isUnknown) throw new Error('Destination SOL balance cannot be zero (address not active)') // cannot initialize without knowing the owner
104
- if (isSOLaddress && !isAssociatedTokenAccountActive)
105
- this.transaction.add(createAssociatedTokenAccount(from, token.mintAddress, to))
106
-
107
- let amountLeft = amount
108
- let amountToSend
109
- for (let { ticker, tokenAccountAddress, balance } of fromTokenAddresses) {
110
- // need to add more of this instruction until we reach the desired balance (amount) to send
111
- assert(ticker === token.tokenSymbol, `Got unexpected ticker ${ticker}`)
112
- if (amountLeft === 0) break
113
-
114
- balance = Number(balance)
115
- if (balance >= amountLeft) {
116
- amountToSend = amountLeft
117
- amountLeft = 0
118
- } else {
119
- amountToSend = balance // not enough balance
120
- amountLeft -= amountToSend
121
- }
122
-
123
- const dest = isSOLaddress ? findAssociatedTokenAddress(to, token.mintAddress) : to
124
- // add transfer token instruction
125
- this.transaction.add(
126
- createTokenTransferInstruction(from, tokenAccountAddress, dest, amountToSend)
127
- )
128
- }
129
-
130
- assert(amountLeft === 0, `Not enough balance to send ${amount} ${token.tokenSymbol}`)
131
- }
132
-
133
- static createStakeAccountTransaction({ address, amount, seed = SEED, pool, recentBlockhash }) {
134
- const fromPubkey = new PublicKey(address)
135
- const stakeAddress = createStakeAddress(address, seed)
136
- const stakePublicKey = new PublicKey(stakeAddress)
137
- const poolKey = new PublicKey(pool)
138
-
139
- const authorized = new Authorized(fromPubkey, fromPubkey) // staker, withdrawer
140
- const lockup = new Lockup(0, 0, fromPubkey) // no lockup
141
-
142
- // create account instruction
143
- const programTx = StakeProgram.createAccountWithSeed({
144
- fromPubkey,
145
- stakePubkey: stakePublicKey,
146
- basePubkey: fromPubkey,
147
- seed,
148
- authorized,
149
- lockup,
150
- lamports: amount, // number
151
- })
152
-
153
- // delegate funds instruction
154
- const delegateTx = StakeProgram.delegate({
155
- stakePubkey: stakePublicKey,
156
- authorizedPubkey: fromPubkey,
157
- votePubkey: poolKey, // pool vote key
158
- })
159
-
160
- const transaction = new Transaction({ recentBlockhash }).add(programTx).add(delegateTx)
161
- return transaction
162
- }
163
-
164
- static undelegate({ address, stakeAddresses, recentBlockhash }) {
165
- // undelegate all stake addresses
166
- assert(Array.isArray(stakeAddresses), 'stakeAddresses Array is required')
167
-
168
- const fromPubkey = new PublicKey(address)
169
- const transaction = new Transaction({ recentBlockhash })
170
-
171
- stakeAddresses.forEach((stakeAddress) => {
172
- const stakePublicKey = new PublicKey(stakeAddress)
173
- const programTx = StakeProgram.deactivate({
174
- stakePubkey: stakePublicKey,
175
- authorizedPubkey: fromPubkey,
176
- })
177
- transaction.add(programTx)
178
- })
179
-
180
- return transaction
181
- }
182
-
183
- static withdraw({ address, stakeAddresses, amount, recentBlockhash }) {
184
- const fromPubkey = new PublicKey(address)
185
- const stakeAddress = Array.isArray(stakeAddresses) ? stakeAddresses[0] : stakeAddresses
186
- const stakePublicKey = new PublicKey(stakeAddress)
187
-
188
- const transaction = StakeProgram.withdraw({
189
- stakePubkey: stakePublicKey,
190
- authorizedPubkey: fromPubkey,
191
- toPubkey: fromPubkey,
192
- lamports: amount,
193
- })
194
- transaction.recentBlockhash = recentBlockhash
195
- return transaction
196
- }
197
-
198
- static sign(tx, privateKey: Buffer | string) {
199
- if (!privateKey) throw new Error('Please provide a secretKey')
200
- const { secretKey } = getKeyPairFromPrivateKey(privateKey)
201
- const signers = [new Account(secretKey)]
202
-
203
- let transaction = tx
204
- if (tx instanceof Tx) transaction = tx.transaction
205
-
206
- transaction.sign(...signers)
207
- if (!transaction.signature) {
208
- throw new Error('!signature') // should never happen
209
- }
210
- }
211
-
212
- serialize() {
213
- const wireTransaction = this.transaction.serialize()
214
- return wireTransaction.toString('base64')
215
- }
216
-
217
- static serialize(tx) {
218
- let transaction = tx
219
- if (tx instanceof Tx) transaction = tx.transaction
220
- return transaction.serialize().toString('base64')
221
- }
222
-
223
- getTxId() {
224
- if (!this.transaction.signature) {
225
- throw new Error('Cannot get txId, tx is not signed')
226
- }
227
- return bs58.encode(this.transaction.signature)
228
- }
229
-
230
- static getTxId(tx) {
231
- let transaction = tx
232
- if (tx instanceof Tx) transaction = tx.transaction
233
- if (!transaction.signature) {
234
- throw new Error('Cannot get txId, tx is not signed')
235
- }
236
- return bs58.encode(transaction.signature)
237
- }
238
- }
239
-
240
- export default Tx
@@ -1,8 +0,0 @@
1
- import { createUnsignedTx } from './create-unsigned-tx'
2
- import { signUnsignedTx } from './sign-unsigned-tx'
3
- import type { ParsedTransaction, SignedTransaction } from '@exodus/models/lib/types'
4
-
5
- export function createAndSignTx(input: ParsedTransaction, privateKey: Buffer): SignedTransaction {
6
- const unsignedTx = createUnsignedTx(input)
7
- return signUnsignedTx(unsignedTx, privateKey)
8
- }
package/src/tx/index.js DELETED
@@ -1,4 +0,0 @@
1
- export * from './sign-unsigned-tx'
2
- export * from './parse-unsigned-tx'
3
- export * from './create-unsigned-tx'
4
- export * from './create-and-sign-tx'
@@ -1,39 +0,0 @@
1
- import assets from '@exodus/assets'
2
- import type { UnsignedTransaction, ParsedTransaction } from '@exodus/models/lib/types'
3
-
4
- export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransaction {
5
- const asset = assets.solana
6
- const {
7
- from,
8
- to,
9
- recentBlockhash,
10
- tokenName,
11
- destinationAddressType,
12
- isAssociatedTokenAccountActive,
13
- fromTokenAddresses,
14
- method,
15
- stakeAddresses,
16
- seed,
17
- pool,
18
- ...txData
19
- } = unsignedTx.txData
20
-
21
- const amount = asset.currency.baseUnit(txData.amount)
22
- return {
23
- asset,
24
- from: [from],
25
- to,
26
- amount,
27
- recentBlockhash,
28
- // token related
29
- tokenName,
30
- destinationAddressType,
31
- isAssociatedTokenAccountActive,
32
- fromTokenAddresses,
33
- // staking related
34
- method,
35
- stakeAddresses,
36
- seed,
37
- pool,
38
- }
39
- }
@@ -1,78 +0,0 @@
1
- import assets from '@exodus/assets'
2
- import type { UnsignedTransaction, SignedTransaction } from '@exodus/models/lib/types'
3
- import { Transaction } from '../'
4
-
5
- export function signUnsignedTx(
6
- unsignedTx: UnsignedTransaction,
7
- privateKey: Buffer
8
- ): SignedTransaction {
9
- const {
10
- from,
11
- to,
12
- amount: unitAmount,
13
- recentBlockhash,
14
- // tokens related
15
- tokenName,
16
- destinationAddressType,
17
- isAssociatedTokenAccountActive,
18
- fromTokenAddresses,
19
- // staking related
20
- stakeAddresses,
21
- method,
22
- seed,
23
- pool,
24
- } = unsignedTx.txData
25
-
26
- const asset = assets.solana
27
-
28
- const address = from
29
- const amount = unitAmount ? asset.currency.baseUnit(unitAmount).toNumber() : unitAmount
30
-
31
- let tx
32
- switch (method) {
33
- case 'delegate':
34
- tx = Transaction.createStakeAccountTransaction({
35
- address,
36
- amount,
37
- recentBlockhash,
38
- seed,
39
- pool,
40
- })
41
- break
42
- case 'undelegate':
43
- tx = Transaction.undelegate({
44
- address,
45
- stakeAddresses,
46
- recentBlockhash,
47
- })
48
- break
49
- case 'withdraw':
50
- tx = Transaction.withdraw({
51
- address,
52
- stakeAddresses,
53
- amount,
54
- recentBlockhash,
55
- })
56
- break
57
- default:
58
- // SOL and Token tx
59
- tx = new Transaction({
60
- from,
61
- to,
62
- amount,
63
- recentBlockhash,
64
- tokenName,
65
- destinationAddressType,
66
- isAssociatedTokenAccountActive,
67
- fromTokenAddresses,
68
- })
69
- break
70
- }
71
-
72
- // sign plain tx
73
- Transaction.sign(tx, privateKey)
74
- const rawTx = Transaction.serialize(tx)
75
- const txId = Transaction.getTxId(tx)
76
-
77
- return { txId, rawTx }
78
- }
@@ -1,38 +0,0 @@
1
- // @flow
2
- import type { KeyPair } from 'tweetnacl'
3
- import { PublicKey } from './publickey'
4
- import { getKeyPairFromPrivateKey } from '../keypair'
5
-
6
- /**
7
- * An account key pair (public and secret keys).
8
- */
9
- export class Account {
10
- _keypair: KeyPair
11
-
12
- /**
13
- * Create a new Account object
14
- *
15
- * @param secretKey Secret key for the account
16
- */
17
- constructor(secretKey: Buffer | Uint8Array | Array<number>) {
18
- if (secretKey) {
19
- this._keypair = getKeyPairFromPrivateKey(Buffer.from(secretKey, 'hex'))
20
- } else {
21
- throw new Error('Please provide a secretKey')
22
- }
23
- }
24
-
25
- /**
26
- * The public key for this account
27
- */
28
- get publicKey(): PublicKey {
29
- return new PublicKey(this._keypair.publicKey)
30
- }
31
-
32
- /**
33
- * The **unencrypted** secret key for this account
34
- */
35
- get secretKey(): Buffer {
36
- return this._keypair.secretKey
37
- }
38
- }
@@ -1,9 +0,0 @@
1
- export * from './account'
2
- export * from './instruction'
3
- export * from './message'
4
- export * from './nonce-account'
5
- export * from './publickey'
6
- export * from './system-program'
7
- export * from './stake-program'
8
- export * from './sysvar'
9
- export * from './transaction'
@@ -1,46 +0,0 @@
1
- // @flow
2
-
3
- import * as BufferLayout from '@exodus/buffer-layout'
4
-
5
- import * as Layout from './utils/layout'
6
-
7
- /**
8
- * @typedef {Object} InstructionType
9
- * @property (index} The Instruction index (from solana upstream program)
10
- * @property (BufferLayout} The BufferLayout to use to build data
11
- */
12
- export type InstructionType = {|
13
- index: number,
14
- layout: typeof BufferLayout,
15
- |}
16
-
17
- /**
18
- * Populate a buffer of instruction data using an InstructionType
19
- */
20
- export function encodeData(type: InstructionType, fields: Object): Buffer {
21
- const allocLength = type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields)
22
- const data = Buffer.alloc(allocLength)
23
- const layoutFields = Object.assign({ instruction: type.index }, fields)
24
- type.layout.encode(layoutFields, data)
25
- return data
26
- }
27
-
28
- /**
29
- * Decode instruction data buffer using an InstructionType
30
- */
31
- export function decodeData(type: InstructionType, buffer: Buffer): Object {
32
- let data
33
- try {
34
- data = type.layout.decode(buffer)
35
- } catch (err) {
36
- throw new Error('invalid instruction; ' + err)
37
- }
38
-
39
- if (data.instruction !== type.index) {
40
- throw new Error(
41
- `invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`
42
- )
43
- }
44
-
45
- return data
46
- }
@@ -1,216 +0,0 @@
1
- // @flow
2
-
3
- import bs58 from 'bs58'
4
- import * as BufferLayout from '@exodus/buffer-layout'
5
-
6
- import { PublicKey } from './publickey'
7
- import type { Blockhash } from './utils/blockhash'
8
- import * as Layout from './utils/layout'
9
- import { PACKET_DATA_SIZE } from './transaction'
10
- import * as shortvec from './utils/shortvec-encoding'
11
-
12
- /**
13
- * The message header, identifying signed and read-only account
14
- *
15
- * @typedef {Object} MessageHeader
16
- * @property {number} numRequiredSignatures The number of signatures required for this message to be considered valid. The
17
- * signatures must match the first `numRequiredSignatures` of `accountKeys`.
18
- * @property {number} numReadonlySignedAccounts: The last `numReadonlySignedAccounts` of the signed keys are read-only accounts
19
- * @property {number} numReadonlyUnsignedAccounts The last `numReadonlySignedAccounts` of the unsigned keys are read-only accounts
20
- */
21
- export type MessageHeader = {
22
- numRequiredSignatures: number,
23
- numReadonlySignedAccounts: number,
24
- numReadonlyUnsignedAccounts: number,
25
- }
26
-
27
- /**
28
- * An instruction to execute by a program
29
- *
30
- * @typedef {Object} CompiledInstruction
31
- * @property {number} programIdIndex Index into the transaction keys array indicating the program account that executes this instruction
32
- * @property {number[]} accounts Ordered indices into the transaction keys array indicating which accounts to pass to the program
33
- * @property {string} data The program input data encoded as base 58
34
- */
35
- export type CompiledInstruction = {
36
- programIdIndex: number,
37
- accounts: number[],
38
- data: string,
39
- }
40
-
41
- /**
42
- * Message constructor arguments
43
- *
44
- * @typedef {Object} MessageArgs
45
- * @property {MessageHeader} header The message header, identifying signed and read-only `accountKeys`
46
- * @property {string[]} accounts All the account keys used by this transaction
47
- * @property {Blockhash} recentBlockhash The hash of a recent ledger block
48
- * @property {CompiledInstruction[]} instructions Instructions that will be executed in sequence and committed in one atomic transaction if all succeed.
49
- */
50
- type MessageArgs = {
51
- header: MessageHeader,
52
- accountKeys: string[],
53
- recentBlockhash: Blockhash,
54
- instructions: CompiledInstruction[],
55
- }
56
-
57
- const PUBKEY_LENGTH = 32
58
-
59
- /**
60
- * List of instructions to be processed atomically
61
- */
62
- export class Message {
63
- header: MessageHeader
64
- accountKeys: PublicKey[]
65
- recentBlockhash: Blockhash
66
- instructions: CompiledInstruction[]
67
-
68
- constructor(args: MessageArgs) {
69
- this.header = args.header
70
- this.accountKeys = args.accountKeys.map((account) => new PublicKey(account))
71
- this.recentBlockhash = args.recentBlockhash
72
- this.instructions = args.instructions
73
- }
74
-
75
- isAccountWritable(index: number): boolean {
76
- return (
77
- index < this.header.numRequiredSignatures - this.header.numReadonlySignedAccounts ||
78
- (index >= this.header.numRequiredSignatures &&
79
- index < this.accountKeys.length - this.header.numReadonlyUnsignedAccounts)
80
- )
81
- }
82
-
83
- findSignerIndex(signer: PublicKey): number {
84
- const index = this.accountKeys.findIndex((accountKey) => {
85
- return accountKey.equals(signer)
86
- })
87
- if (index < 0) {
88
- throw new Error(`unknown signer: ${signer.toString()}`)
89
- }
90
- return index
91
- }
92
-
93
- serialize(): Buffer {
94
- const numKeys = this.accountKeys.length
95
-
96
- let keyCount = []
97
- shortvec.encodeLength(keyCount, numKeys)
98
-
99
- const instructions = this.instructions.map((instruction) => {
100
- const { accounts, programIdIndex } = instruction
101
- const data = bs58.decode(instruction.data)
102
-
103
- let keyIndicesCount = []
104
- shortvec.encodeLength(keyIndicesCount, accounts.length)
105
-
106
- let dataCount = []
107
- shortvec.encodeLength(dataCount, data.length)
108
-
109
- return {
110
- programIdIndex,
111
- keyIndicesCount: Buffer.from(keyIndicesCount),
112
- keyIndices: Buffer.from(accounts),
113
- dataLength: Buffer.from(dataCount),
114
- data,
115
- }
116
- })
117
-
118
- let instructionCount = []
119
- shortvec.encodeLength(instructionCount, instructions.length)
120
- let instructionBuffer = Buffer.alloc(PACKET_DATA_SIZE)
121
- Buffer.from(instructionCount).copy(instructionBuffer)
122
- let instructionBufferLength = instructionCount.length
123
-
124
- instructions.forEach((instruction) => {
125
- const instructionLayout = BufferLayout.struct([
126
- BufferLayout.u8('programIdIndex'),
127
-
128
- BufferLayout.blob(instruction.keyIndicesCount.length, 'keyIndicesCount'),
129
- BufferLayout.seq(BufferLayout.u8('keyIndex'), instruction.keyIndices.length, 'keyIndices'),
130
- BufferLayout.blob(instruction.dataLength.length, 'dataLength'),
131
- BufferLayout.seq(BufferLayout.u8('userdatum'), instruction.data.length, 'data'),
132
- ])
133
- const length = instructionLayout.encode(
134
- instruction,
135
- instructionBuffer,
136
- instructionBufferLength
137
- )
138
- instructionBufferLength += length
139
- })
140
- instructionBuffer = instructionBuffer.slice(0, instructionBufferLength)
141
-
142
- const signDataLayout = BufferLayout.struct([
143
- BufferLayout.blob(1, 'numRequiredSignatures'),
144
- BufferLayout.blob(1, 'numReadonlySignedAccounts'),
145
- BufferLayout.blob(1, 'numReadonlyUnsignedAccounts'),
146
- BufferLayout.blob(keyCount.length, 'keyCount'),
147
- BufferLayout.seq(Layout.publicKey('key'), numKeys, 'keys'),
148
- Layout.publicKey('recentBlockhash'),
149
- ])
150
-
151
- const transaction = {
152
- numRequiredSignatures: Buffer.from([this.header.numRequiredSignatures]),
153
- numReadonlySignedAccounts: Buffer.from([this.header.numReadonlySignedAccounts]),
154
- numReadonlyUnsignedAccounts: Buffer.from([this.header.numReadonlyUnsignedAccounts]),
155
- keyCount: Buffer.from(keyCount),
156
- keys: this.accountKeys.map((key) => key.toBuffer()),
157
- recentBlockhash: bs58.decode(this.recentBlockhash),
158
- }
159
-
160
- let signData = Buffer.alloc(2048)
161
- const length = signDataLayout.encode(transaction, signData)
162
- instructionBuffer.copy(signData, length)
163
- return signData.slice(0, length + instructionBuffer.length)
164
- }
165
-
166
- /**
167
- * Decode a compiled message into a Message object.
168
- */
169
- static from(buffer: Buffer | Uint8Array | Array<number>): Message {
170
- // Slice up wire data
171
- let byteArray = [...buffer]
172
-
173
- const numRequiredSignatures = byteArray.shift()
174
- const numReadonlySignedAccounts = byteArray.shift()
175
- const numReadonlyUnsignedAccounts = byteArray.shift()
176
-
177
- const accountCount = shortvec.decodeLength(byteArray)
178
- let accountKeys = []
179
- for (let i = 0; i < accountCount; i++) {
180
- const account = byteArray.slice(0, PUBKEY_LENGTH)
181
- byteArray = byteArray.slice(PUBKEY_LENGTH)
182
- accountKeys.push(bs58.encode(Buffer.from(account)))
183
- }
184
-
185
- const recentBlockhash = byteArray.slice(0, PUBKEY_LENGTH)
186
- byteArray = byteArray.slice(PUBKEY_LENGTH)
187
-
188
- const instructionCount = shortvec.decodeLength(byteArray)
189
- let instructions = []
190
- for (let i = 0; i < instructionCount; i++) {
191
- let instruction = {}
192
- instruction.programIdIndex = byteArray.shift()
193
- const accountCount = shortvec.decodeLength(byteArray)
194
- instruction.accounts = byteArray.slice(0, accountCount)
195
- byteArray = byteArray.slice(accountCount)
196
- const dataLength = shortvec.decodeLength(byteArray)
197
- const data = byteArray.slice(0, dataLength)
198
- instruction.data = bs58.encode(Buffer.from(data))
199
- byteArray = byteArray.slice(dataLength)
200
- instructions.push(instruction)
201
- }
202
-
203
- const messageArgs = {
204
- header: {
205
- numRequiredSignatures,
206
- numReadonlySignedAccounts,
207
- numReadonlyUnsignedAccounts,
208
- },
209
- recentBlockhash: bs58.encode(Buffer.from(recentBlockhash)),
210
- accountKeys,
211
- instructions,
212
- }
213
-
214
- return new Message(messageArgs)
215
- }
216
- }