@exodus/solana-lib 3.4.2 → 3.5.1

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.
@@ -1,10 +1,10 @@
1
1
  import { isNumberUnit } from '@exodus/currency'
2
- import BN from 'bn.js'
3
2
  import { VersionedTransaction } from '@exodus/solana-web3.js'
3
+ import BN from 'bn.js'
4
4
 
5
- import { ComputeBudgetProgram, PublicKey } from '../vendor'
6
- import Transaction from '../transaction'
7
5
  import { createMetaplexTransferTransaction } from '../helpers/metaplex-transfer'
6
+ import Transaction from '../transaction'
7
+ import { ComputeBudgetProgram, PublicKey } from '../vendor'
8
8
 
9
9
  const addPriorityFeeToTransaction = ({ transaction, priorityFee }) => {
10
10
  const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
@@ -20,10 +20,14 @@ const addComputeBudgetToTransaction = ({ transaction, computeUnits }) => {
20
20
  transaction.add(computeBudgetInstruction)
21
21
  }
22
22
 
23
+ const deserializeTransactionBytes = (wireTransactionBuffer) => {
24
+ return VersionedTransaction.deserialize(Uint8Array.from(wireTransactionBuffer))
25
+ }
26
+
23
27
  /**
24
28
  * Prepares the transaction to be signed (exodus & ledger).
25
29
  * @param {UnsignedTx} unsignedTx
26
- * @returns a Solana Web3.js Transaction object
30
+ * @returns a Solana Web3.js VersionedTransaction object (supports both Legacy & Versioned transactions)
27
31
  */
28
32
  export function prepareForSigning(unsignedTx) {
29
33
  const {
@@ -37,7 +41,7 @@ export function prepareForSigning(unsignedTx) {
37
41
 
38
42
  // Recreate a Web3.js Transaction instance if the buffer provided.
39
43
  if (transactionBuffer) {
40
- return VersionedTransaction.deserialize(transactionBuffer)
44
+ return deserializeTransactionBytes(transactionBuffer)
41
45
  }
42
46
 
43
47
  if (!transaction) {
@@ -54,31 +58,19 @@ export function prepareForSigning(unsignedTx) {
54
58
 
55
59
  const txData = { ...unsignedTx.txData, address, amount, fee }
56
60
 
57
- const transaction = createTx({ txData, method })
58
-
59
- if (txData.priorityFee) {
60
- addPriorityFeeToTransaction({
61
- transaction,
62
- priorityFee: txData.priorityFee,
63
- })
64
- }
65
-
66
- if (txData.computeUnits) {
67
- addComputeBudgetToTransaction({ transaction, computeUnits: txData.computeUnits })
68
- }
69
-
70
- if (!transaction.feePayer) {
71
- transaction.feePayer = new PublicKey(from)
72
- }
73
-
74
- return transaction
61
+ const legacyTransaction = createTx({ txData, method, from })
62
+ return VersionedTransaction.deserialize(
63
+ legacyTransaction.serialize({ requireAllSignatures: false, verifySignatures: false })
64
+ )
75
65
  }
76
66
 
77
67
  // unsignedTx contained a transaction in web3.js format
78
- return transaction
68
+ return VersionedTransaction.deserialize(
69
+ transaction.serialize({ requireAllSignatures: false, verifySignatures: false })
70
+ )
79
71
  }
80
72
 
81
- const createTx = ({ txData, method }) => {
73
+ const createTx = ({ txData, method, from }) => {
82
74
  let tx
83
75
  switch (method) {
84
76
  case 'delegate':
@@ -113,6 +105,31 @@ const createTx = ({ txData, method }) => {
113
105
  break
114
106
  }
115
107
 
108
+ if (txData.priorityFee) {
109
+ addPriorityFeeToTransaction({
110
+ transaction: tx,
111
+ priorityFee: txData.priorityFee,
112
+ })
113
+ }
114
+
115
+ if (txData.computeUnits) {
116
+ addComputeBudgetToTransaction({ transaction: tx, computeUnits: txData.computeUnits })
117
+ }
118
+
119
+ const publicKey = new PublicKey(from)
120
+ if (!tx.feePayer) {
121
+ tx.feePayer = publicKey
122
+ }
123
+
124
+ if (tx.signatures.length !== tx.compileMessage().header.numRequiredSignatures) {
125
+ // Some transactions that we construct internally are technically not complete.
126
+ // They don't contain the empty signature slot for the public key.
127
+ tx.signatures.push({
128
+ publicKey,
129
+ signature: null,
130
+ })
131
+ }
132
+
116
133
  return tx
117
134
  }
118
135
 
@@ -1,8 +1,8 @@
1
1
  import assert from 'minimalistic-assert'
2
2
 
3
- import { prepareForSigning } from './prepare-for-signing'
4
3
  import { PublicKey } from '../vendor'
5
- import { isVersionedTransaction, isLegacyTransaction, extractTransaction } from './common'
4
+ import { extractTransaction } from './common'
5
+ import { prepareForSigning } from './prepare-for-signing'
6
6
 
7
7
  export async function signHardware({ unsignedTx, hardwareDevice, accountIndex }) {
8
8
  assert(hardwareDevice, 'expected hardwareDevice to be defined')
@@ -19,9 +19,7 @@ const signWithHardwareWallet = async ({ tx, hardwareDevice, accountIndex }) => {
19
19
  assert(hardwareDevice, `hardwareDevice required`)
20
20
  assert(Number.isInteger(accountIndex), `accountIndex required`)
21
21
 
22
- const messageToSign = isVersionedTransaction(tx)
23
- ? tx.message.serialize()
24
- : tx.compileMessage().serialize()
22
+ const messageToSign = tx.message.serialize()
25
23
 
26
24
  return hardwareDevice.signTransaction({
27
25
  assetName: 'solana',
@@ -31,24 +29,6 @@ const signWithHardwareWallet = async ({ tx, hardwareDevice, accountIndex }) => {
31
29
  }
32
30
 
33
31
  const applySignatures = ({ tx, signatures }) => {
34
- if (isLegacyTransaction(tx)) {
35
- signatures.forEach(({ publicKey: publicKeyBuffer }) => {
36
- const publicKey = new PublicKey(publicKeyBuffer)
37
- // Some transactions that we construct internally are technically not complete.
38
- // They don't contain the empty signature slot for the public key.
39
- const foundEmptySignatureSlot = tx.signatures.find(({ publicKey: pubKey }) =>
40
- pubKey.equals(publicKey)
41
- )
42
- if (!foundEmptySignatureSlot) {
43
- // We could use `setSigners` but maybe this is more robust?
44
- tx.signatures.push({
45
- publicKey,
46
- signature: null,
47
- })
48
- }
49
- })
50
- }
51
-
52
32
  signatures.forEach(({ publicKey, signature }) => {
53
33
  tx.addSignature(new PublicKey(publicKey), signature)
54
34
  })
@@ -1,11 +1,11 @@
1
+ import bs58 from 'bs58'
1
2
  import assert from 'minimalistic-assert'
2
3
  import * as nacl from 'tweetnacl'
3
- import bs58 from 'bs58'
4
4
 
5
- import { prepareForSigning } from './prepare-for-signing'
6
5
  import { getKeyPairFromPrivateKey } from '../keypair'
7
6
  import { PublicKey } from '../vendor'
8
- import { extractTransaction, isVersionedTransaction } from './common'
7
+ import { extractTransaction } from './common'
8
+ import { prepareForSigning } from './prepare-for-signing'
9
9
 
10
10
  /**
11
11
  *
@@ -38,44 +38,10 @@ export async function signUnsignedTx(unsignedTx, privateKey) {
38
38
  return extractTransaction({ tx })
39
39
  }
40
40
 
41
- // Some transactions that we construct internally are technically not complete.
42
- // They don't contain the empty signature slot for the public key.
43
- export const fillTransactionWithEmptySignatureSlot = ({ transaction, publicKey }) => {
44
- const foundEmptySignatureSlot = transaction.signatures.find(({ publicKey: _publicKey }) =>
45
- _publicKey.equals(publicKey)
46
- )
47
- if (!foundEmptySignatureSlot) {
48
- // We could use `setSigners` but maybe this is more robust?
49
- transaction.signatures.push({
50
- publicKey,
51
- signature: null,
52
- })
53
- }
54
- }
55
-
56
41
  // Signs plain tx.
57
42
  const _signTx = async ({ tx, signer }) => {
58
43
  const publicKey = new PublicKey(bs58.encode(Buffer.from(await signer.getPublicKey())))
59
-
60
- if (isVersionedTransaction(tx)) {
61
- // VersionedTransaction
62
- return _signVersionedTransaction({ tx, signer, publicKey })
63
- }
64
-
65
- // Legacy Transactions
66
- fillTransactionWithEmptySignatureSlot({ transaction: tx, publicKey })
67
-
68
- return _signLegacyTransaction({ tx, signer, publicKey })
69
- }
70
-
71
- const _signVersionedTransaction = async ({ tx, signer, publicKey }) => {
72
44
  const messageData = tx.message.serialize()
73
45
  const signature = await signer.sign({ data: messageData, signatureType: 'ed25519' })
74
46
  tx.addSignature(publicKey, signature)
75
47
  }
76
-
77
- const _signLegacyTransaction = async ({ tx, signer, publicKey }) => {
78
- const messageData = tx.compileMessage().serialize()
79
- const signature = await signer.sign({ data: messageData, signatureType: 'ed25519' })
80
- tx.addSignature(publicKey, signature)
81
- }
@@ -0,0 +1,197 @@
1
+ // internalized from https://github.com/ExodusMovement/serum-ts/blob/0bb5a69176266cbf2c0c06847d01eb4f9d5de4a4/packages/serum/src/token-instructions.js
2
+ import * as BufferLayout from '@exodus/buffer-layout'
3
+ import { PublicKey, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@exodus/solana-web3.js'
4
+
5
+ import { publicKeyLayout } from './layout'
6
+
7
+ // NOTE: Update these if the position of arguments for the initializeAccount instruction changes
8
+ export const INITIALIZE_ACCOUNT_ACCOUNT_INDEX = 0
9
+ export const INITIALIZE_ACCOUNT_MINT_INDEX = 1
10
+ export const INITIALIZE_ACCOUNT_OWNER_INDEX = 2
11
+
12
+ // NOTE: Update these if the position of arguments for the transfer instruction changes
13
+ export const TRANSFER_SOURCE_INDEX = 0
14
+ export const TRANSFER_DESTINATION_INDEX = 1
15
+ export const TRANSFER_OWNER_INDEX = 2
16
+
17
+ // NOTE: Update these if the position of arguments for the closeAccount instruction changes
18
+ export const CLOSE_ACCOUNT_SOURCE_INDEX = 0
19
+ export const CLOSE_ACCOUNT_DESTINATION_INDEX = 1
20
+ export const CLOSE_ACCOUNT_OWNER_INDEX = 2
21
+
22
+ export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')
23
+
24
+ export const WRAPPED_SOL_MINT = new PublicKey('So11111111111111111111111111111111111111112')
25
+
26
+ export const MSRM_MINT = new PublicKey('MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L')
27
+ export const MSRM_DECIMALS = 0
28
+
29
+ export const SRM_MINT = new PublicKey('SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt')
30
+ export const SRM_DECIMALS = 6
31
+
32
+ const LAYOUT = BufferLayout.union(BufferLayout.u8('instruction'))
33
+ LAYOUT.addVariant(
34
+ 0,
35
+ BufferLayout.struct([
36
+ BufferLayout.u8('decimals'),
37
+ publicKeyLayout('mintAuthority'),
38
+ BufferLayout.u8('freezeAuthorityOption'),
39
+ publicKeyLayout('freezeAuthority'),
40
+ ]),
41
+ 'initializeMint'
42
+ )
43
+ LAYOUT.addVariant(1, BufferLayout.struct([]), 'initializeAccount')
44
+ LAYOUT.addVariant(3, BufferLayout.struct([BufferLayout.nu64('amount')]), 'transfer')
45
+ LAYOUT.addVariant(4, BufferLayout.struct([BufferLayout.nu64('amount')]), 'approve')
46
+ LAYOUT.addVariant(5, BufferLayout.struct([]), 'revoke')
47
+ LAYOUT.addVariant(
48
+ 6,
49
+ BufferLayout.struct([
50
+ BufferLayout.u8('authorityType'),
51
+ BufferLayout.u8('newAuthorityOption'),
52
+ publicKeyLayout('newAuthority'),
53
+ ]),
54
+ 'setAuthority'
55
+ )
56
+ LAYOUT.addVariant(7, BufferLayout.struct([BufferLayout.nu64('amount')]), 'mintTo')
57
+ LAYOUT.addVariant(8, BufferLayout.struct([BufferLayout.nu64('amount')]), 'burn')
58
+ LAYOUT.addVariant(9, BufferLayout.struct([]), 'closeAccount')
59
+
60
+ const instructionMaxSpan = Math.max(...Object.values(LAYOUT.registry).map((r) => r.span))
61
+
62
+ function encodeTokenInstructionData(instruction) {
63
+ const b = Buffer.alloc(instructionMaxSpan)
64
+ const span = LAYOUT.encode(instruction, b)
65
+ return b.slice(0, span)
66
+ }
67
+
68
+ export function decodeTokenInstructionData(instruction) {
69
+ return LAYOUT.decode(instruction)
70
+ }
71
+
72
+ export function initializeMint({ mint, decimals, mintAuthority, freezeAuthority = null }) {
73
+ const keys = [
74
+ { pubkey: mint, isSigner: false, isWritable: true },
75
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
76
+ ]
77
+ return new TransactionInstruction({
78
+ keys,
79
+ data: encodeTokenInstructionData({
80
+ initializeMint: {
81
+ decimals,
82
+ mintAuthority,
83
+ freezeAuthorityOption: !!freezeAuthority,
84
+ freezeAuthority: freezeAuthority || new PublicKey(0),
85
+ },
86
+ }),
87
+ programId: TOKEN_PROGRAM_ID,
88
+ })
89
+ }
90
+
91
+ export function initializeAccount({ account, mint, owner }) {
92
+ const keys = [
93
+ { pubkey: account, isSigner: false, isWritable: true },
94
+ { pubkey: mint, isSigner: false, isWritable: false },
95
+ { pubkey: owner, isSigner: false, isWritable: false },
96
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
97
+ ]
98
+ return new TransactionInstruction({
99
+ keys,
100
+ data: encodeTokenInstructionData({
101
+ initializeAccount: {},
102
+ }),
103
+ programId: TOKEN_PROGRAM_ID,
104
+ })
105
+ }
106
+
107
+ export function transfer({ source, destination, amount, owner }) {
108
+ const keys = [
109
+ { pubkey: source, isSigner: false, isWritable: true },
110
+ { pubkey: destination, isSigner: false, isWritable: true },
111
+ { pubkey: owner, isSigner: true, isWritable: false },
112
+ ]
113
+ return new TransactionInstruction({
114
+ keys,
115
+ data: encodeTokenInstructionData({
116
+ transfer: { amount },
117
+ }),
118
+ programId: TOKEN_PROGRAM_ID,
119
+ })
120
+ }
121
+
122
+ export function approve({ source, delegate, amount, owner }) {
123
+ const keys = [
124
+ { pubkey: source, isSigner: false, isWritable: true },
125
+ { pubkey: delegate, isSigner: false, isWritable: false },
126
+ { pubkey: owner, isSigner: true, isWritable: false },
127
+ ]
128
+ return new TransactionInstruction({
129
+ keys,
130
+ data: encodeTokenInstructionData({
131
+ approve: { amount },
132
+ }),
133
+ programId: TOKEN_PROGRAM_ID,
134
+ })
135
+ }
136
+
137
+ export function revoke({ source, owner }) {
138
+ const keys = [
139
+ { pubkey: source, isSigner: false, isWritable: true },
140
+ { pubkey: owner, isSigner: true, isWritable: false },
141
+ ]
142
+ return new TransactionInstruction({
143
+ keys,
144
+ data: encodeTokenInstructionData({
145
+ revoke: {},
146
+ }),
147
+ programId: TOKEN_PROGRAM_ID,
148
+ })
149
+ }
150
+
151
+ export function setAuthority({ target, currentAuthority, newAuthority, authorityType }) {
152
+ const keys = [
153
+ { pubkey: target, isSigner: false, isWritable: true },
154
+ { pubkey: currentAuthority, isSigner: true, isWritable: false },
155
+ ]
156
+ return new TransactionInstruction({
157
+ keys,
158
+ data: encodeTokenInstructionData({
159
+ setAuthority: {
160
+ authorityType,
161
+ newAuthorityOption: !!newAuthority,
162
+ newAuthority,
163
+ },
164
+ }),
165
+ programId: TOKEN_PROGRAM_ID,
166
+ })
167
+ }
168
+
169
+ export function mintTo({ mint, destination, amount, mintAuthority }) {
170
+ const keys = [
171
+ { pubkey: mint, isSigner: false, isWritable: true },
172
+ { pubkey: destination, isSigner: false, isWritable: true },
173
+ { pubkey: mintAuthority, isSigner: true, isWritable: false },
174
+ ]
175
+ return new TransactionInstruction({
176
+ keys,
177
+ data: encodeTokenInstructionData({
178
+ mintTo: { amount },
179
+ }),
180
+ programId: TOKEN_PROGRAM_ID,
181
+ })
182
+ }
183
+
184
+ export function closeAccount({ source, destination, owner }) {
185
+ const keys = [
186
+ { pubkey: source, isSigner: false, isWritable: true },
187
+ { pubkey: destination, isSigner: false, isWritable: true },
188
+ { pubkey: owner, isSigner: true, isWritable: false },
189
+ ]
190
+ return new TransactionInstruction({
191
+ keys,
192
+ data: encodeTokenInstructionData({
193
+ closeAccount: {},
194
+ }),
195
+ programId: TOKEN_PROGRAM_ID,
196
+ })
197
+ }
@@ -0,0 +1,12 @@
1
+ import { PublicKey } from '@exodus/solana-web3.js'
2
+
3
+ import Markets from './markets.json'
4
+
5
+ export const MARKETS = Markets.map((market) => {
6
+ return {
7
+ address: new PublicKey(market.address),
8
+ name: market.name,
9
+ programId: new PublicKey(market.programId),
10
+ deprecated: market.deprecated,
11
+ }
12
+ })
@@ -1,5 +1,5 @@
1
- import { PublicKey } from './publickey'
2
1
  import { getKeyPairFromPrivateKey } from '../keypair'
2
+ import { PublicKey } from './publickey'
3
3
 
4
4
  /**
5
5
  * An account key pair (public and secret keys).
@@ -1,6 +1,6 @@
1
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
2
 
3
- import { encodeData, decodeData } from './instruction'
3
+ import { decodeData, encodeData } from './instruction'
4
4
  import { PublicKey } from './publickey'
5
5
  import { TransactionInstruction } from './transaction'
6
6
 
@@ -1,12 +1,11 @@
1
- import bs58 from 'bs58'
2
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
+ import bs58 from 'bs58'
3
3
 
4
+ import { PACKET_DATA_SIZE } from './constants'
4
5
  import { PublicKey } from './publickey'
5
-
6
+ import { guardedShift, guardedSplice } from './utils/guarded-array-utils.js'
6
7
  import * as Layout from './utils/layout'
7
- import { PACKET_DATA_SIZE } from './constants'
8
8
  import * as shortvec from './utils/shortvec-encoding'
9
- import { guardedShift, guardedSplice } from './utils/guarded-array-utils.js'
10
9
 
11
10
  /**
12
11
  * The message header, identifying signed and read-only account
@@ -1,10 +1,8 @@
1
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
2
 
3
3
  import { PublicKey } from './publickey'
4
-
5
- import * as Layout from './utils/layout'
6
-
7
4
  import { FeeCalculatorLayout } from './utils/fee-calculator'
5
+ import * as Layout from './utils/layout'
8
6
  import { toBuffer } from './utils/to-buffer'
9
7
 
10
8
  /**
@@ -34,7 +32,7 @@ export class NonceAccount {
34
32
  * Deserialize NonceAccount from the account data.
35
33
  *
36
34
  * @param buffer account data
37
- * @return NonceAccount
35
+ * @returns NonceAccount
38
36
  */
39
37
  static fromAccountData(buffer) {
40
38
  const nonceAccount = NonceAccountLayout.decode(toBuffer(buffer), 0)
@@ -1,7 +1,7 @@
1
1
  import BN from 'bn.js'
2
2
  import bs58 from 'bs58'
3
- import nacl from 'tweetnacl'
4
3
  import createHash from 'create-hash'
4
+ import nacl from 'tweetnacl'
5
5
 
6
6
  // $FlowFixMe
7
7
  const naclLowLevel = nacl.lowlevel
@@ -1,11 +1,11 @@
1
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
2
 
3
- import { encodeData, decodeData } from './instruction'
4
- import * as Layout from './utils/layout'
3
+ import { decodeData, encodeData } from './instruction'
5
4
  import { PublicKey } from './publickey'
6
5
  import { SystemProgram } from './system-program'
7
6
  import { SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY } from './sysvar'
8
7
  import { Transaction, TransactionInstruction } from './transaction'
8
+ import * as Layout from './utils/layout'
9
9
 
10
10
  export const STAKE_CONFIG_ID = new PublicKey('StakeConfig11111111111111111111111111111111')
11
11
 
@@ -1,11 +1,11 @@
1
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
2
 
3
- import { encodeData, decodeData } from './instruction'
4
- import * as Layout from './utils/layout'
3
+ import { decodeData, encodeData } from './instruction'
5
4
  import { NONCE_ACCOUNT_LENGTH } from './nonce-account'
6
5
  import { PublicKey } from './publickey'
7
6
  import { SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY } from './sysvar'
8
7
  import { Transaction, TransactionInstruction } from './transaction'
8
+ import * as Layout from './utils/layout'
9
9
 
10
10
  /**
11
11
  * Create account system transaction params
@@ -1,14 +1,14 @@
1
1
  // https://github.com/solana-labs/solana-web3.js/blob/master/src/transaction.js
2
2
 
3
3
  import invariant from 'assert'
4
- import nacl from 'tweetnacl'
5
4
  import bs58 from 'bs58'
5
+ import nacl from 'tweetnacl'
6
6
 
7
+ import { PACKET_DATA_SIZE } from './constants'
7
8
  import { Message } from './message'
8
9
  import { PublicKey } from './publickey'
9
- import { PACKET_DATA_SIZE } from './constants'
10
- import * as shortvec from './utils/shortvec-encoding'
11
10
  import { guardedSplice } from './utils/guarded-array-utils.js'
11
+ import * as shortvec from './utils/shortvec-encoding'
12
12
 
13
13
  /**
14
14
  * @typedef {string} TransactionSignature
@@ -1,5 +1,5 @@
1
- import BN from 'bn.js'
2
1
  import * as BufferLayout from '@exodus/buffer-layout'
2
+ import BN from 'bn.js'
3
3
 
4
4
  /**
5
5
  * Layout for a public key