@exodus/solana-lib 1.3.14 → 1.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-lib",
3
- "version": "1.3.14",
3
+ "version": "1.4.0",
4
4
  "description": "Exodus internal Solana low-level library",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -13,7 +13,7 @@
13
13
  "access": "restricted"
14
14
  },
15
15
  "dependencies": {
16
- "@exodus/asset-lib": "^3.6.0",
16
+ "@exodus/asset-lib": "^3.6.2",
17
17
  "@exodus/assets": "^8.0.68",
18
18
  "@exodus/assets-base": "^8.0.139",
19
19
  "@exodus/buffer-layout": "^1.2.0-exodus1",
@@ -29,5 +29,5 @@
29
29
  "lodash": "^4.17.11",
30
30
  "tweetnacl": "^1.0.3"
31
31
  },
32
- "gitHead": "f8668de32398cd2f583d9bc90ddbd4b5a7425e26"
32
+ "gitHead": "6ffded97383f994c21ccaebb2703c32d48aa70c5"
33
33
  }
package/src/constants.js CHANGED
@@ -9,6 +9,8 @@ export const STAKE_PROGRAM_ID = StakeProgram.programId
9
9
 
10
10
  export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')
11
11
 
12
+ export const MEMO_PROGRAM_ID = new PublicKey('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr')
13
+
12
14
  export const MAGIC_EDEN_ESCROW_PROGRAM_ID = new PublicKey(
13
15
  'MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'
14
16
  )
@@ -1,4 +1,4 @@
1
- import { Token } from './spl-token'
1
+ import { Token } from '@exodus/solana-spl-token'
2
2
  import { PublicKey, TransactionInstruction, SystemProgram, SYSVAR_RENT_PUBKEY } from '../vendor'
3
3
  import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'
4
4
  import { findAssociatedTokenAddress } from '../encode'
@@ -70,3 +70,17 @@ export const createTokenTransferInstruction = (owner, fromTokenAddress, to, amou
70
70
 
71
71
  return transferIx
72
72
  }
73
+
74
+ export const createCloseAccountInstruction = ({
75
+ programId = TOKEN_PROGRAM_ID,
76
+ tokenPublicKey,
77
+ walletPublicKey,
78
+ }) => {
79
+ return Token.createCloseAccountInstruction(
80
+ programId,
81
+ tokenPublicKey,
82
+ walletPublicKey,
83
+ walletPublicKey,
84
+ []
85
+ )
86
+ }
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ export * from './encode'
6
6
  export * from './keypair'
7
7
  export * from './tx'
8
8
  export {
9
+ TransactionInstruction,
9
10
  StakeInstruction,
10
11
  PublicKey,
11
12
  Transaction as SolanaWeb3Transaction,
@@ -9,6 +9,7 @@ import { findAssociatedTokenAddress, createStakeAddress } from './encode'
9
9
  import {
10
10
  createAssociatedTokenAccount,
11
11
  createTokenTransferInstruction,
12
+ createCloseAccountInstruction,
12
13
  } from './helpers/tokenTransfer'
13
14
  import {
14
15
  PublicKey,
@@ -19,9 +20,10 @@ import {
19
20
  StakeInstruction,
20
21
  Authorized,
21
22
  Lockup,
23
+ TransactionInstruction,
22
24
  } from './vendor'
23
25
  import { MagicEdenEscrowProgram } from './magiceden/escrow-program'
24
- import { SEED, STAKE_PROGRAM_ID } from './constants'
26
+ import { MEMO_PROGRAM_ID, SEED, STAKE_PROGRAM_ID } from './constants'
25
27
 
26
28
  class Tx {
27
29
  constructor({
@@ -38,6 +40,8 @@ class Tx {
38
40
  fromTokenAddresses, // sender token addresses
39
41
  instructions,
40
42
  feePayer,
43
+ memo,
44
+ reference,
41
45
  } = {}) {
42
46
  if (!instructions) {
43
47
  assert(from, 'from is required')
@@ -69,6 +73,7 @@ class Tx {
69
73
  fromTokenAddresses,
70
74
  instructions,
71
75
  feePayer,
76
+ reference,
72
77
  }
73
78
 
74
79
  if (tokenMintAddress) {
@@ -80,18 +85,41 @@ class Tx {
80
85
  // SOL tx
81
86
  this.buildSOLtransaction(this.txObj)
82
87
  }
88
+
89
+ // If a memo is provided, add it to the transaction before adding the transfer instruction
90
+ if (memo) {
91
+ this.transaction.add(
92
+ new TransactionInstruction({
93
+ programId: MEMO_PROGRAM_ID,
94
+ keys: [],
95
+ data: Buffer.from(memo, 'utf8'),
96
+ })
97
+ )
98
+ }
83
99
  }
84
100
 
85
- buildSOLtransaction({ from, to, amount, recentBlockhash }) {
101
+ buildSOLtransaction({ from, to, amount, recentBlockhash, feePayer, reference }) {
86
102
  const txInstruction = SystemProgram.transfer({
87
103
  fromPubkey: new PublicKey(from),
88
104
  toPubkey: new PublicKey(to),
89
105
  lamports: amount,
90
106
  })
91
107
 
108
+ // If reference accounts are provided, add them to the transfer instruction
109
+ if (reference) {
110
+ if (!Array.isArray(reference)) {
111
+ reference = [reference]
112
+ }
113
+
114
+ for (const pubkey of reference) {
115
+ txInstruction.keys.push({ pubkey, isWritable: false, isSigner: false })
116
+ }
117
+ }
118
+
92
119
  this.transaction = new Transaction({
93
120
  instructions: [txInstruction],
94
121
  recentBlockhash,
122
+ feePayer: feePayer ? new PublicKey(feePayer) : undefined,
95
123
  })
96
124
  }
97
125
 
@@ -119,9 +147,12 @@ class Tx {
119
147
  destinationAddressType,
120
148
  isAssociatedTokenAccountActive,
121
149
  fromTokenAddresses,
150
+ feePayer,
151
+ reference,
122
152
  }) {
123
153
  this.transaction = new Transaction({
124
154
  recentBlockhash,
155
+ feePayer: feePayer ? new PublicKey(feePayer) : undefined,
125
156
  })
126
157
  // const isUnknown = destinationAddressType === null
127
158
  // if (isUnknown) throw new Error('Destination SOL balance cannot be zero (address not active)') // cannot initialize without knowing the owner
@@ -147,10 +178,26 @@ class Tx {
147
178
  }
148
179
 
149
180
  const dest = isSOLaddress ? findAssociatedTokenAddress(to, tokenMintAddress) : to
150
- // add transfer token instruction
151
- this.transaction.add(
152
- createTokenTransferInstruction(from, tokenAccountAddress, dest, amountToSend)
181
+ const tokenTransferInstruction = createTokenTransferInstruction(
182
+ from,
183
+ tokenAccountAddress,
184
+ dest,
185
+ amountToSend
153
186
  )
187
+
188
+ // If reference accounts are provided, add them to the transfer instruction
189
+ if (reference) {
190
+ if (!Array.isArray(reference)) {
191
+ reference = [reference]
192
+ }
193
+
194
+ for (const pubkey of reference) {
195
+ tokenTransferInstruction.keys.push({ pubkey, isWritable: false, isSigner: false })
196
+ }
197
+ }
198
+
199
+ // add transfer token instruction
200
+ this.transaction.add(tokenTransferInstruction)
154
201
  }
155
202
 
156
203
  assert(amountLeft === 0, `Not enough balance to send ${amount} ${tokenMintAddress}`)
@@ -397,6 +444,15 @@ class Tx {
397
444
  }
398
445
  return bs58.encode(transaction.signature)
399
446
  }
447
+
448
+ static createCloseAccount({ programId, tokenPublicKey, walletPublicKey, recentBlockhash }) {
449
+ const tx = new Transaction()
450
+ tx.add(createCloseAccountInstruction({ programId, tokenPublicKey, walletPublicKey }))
451
+ tx.feePayer = walletPublicKey
452
+ tx.recentBlockhash = recentBlockhash
453
+
454
+ return tx
455
+ }
400
456
  }
401
457
 
402
458
  export default Tx
@@ -1,130 +1,189 @@
1
+ import { merge } from 'lodash'
1
2
  import assets from '@exodus/assets'
2
3
  import type { UnsignedTransaction, SignedTransaction } from '@exodus/models/lib/types'
4
+
3
5
  import { Transaction } from '../'
4
6
 
5
7
  export function signUnsignedTx(
6
8
  unsignedTx: UnsignedTransaction,
7
9
  privateKey: Buffer
8
10
  ): SignedTransaction {
9
- const {
10
- from,
11
- to,
12
- amount: unitAmount,
13
- recentBlockhash,
14
- // tokens related
15
- tokenMintAddress,
16
- destinationAddressType,
17
- isAssociatedTokenAccountActive,
18
- fromTokenAddresses,
19
- // staking related
20
- stakeAddresses,
21
- method,
22
- seed,
23
- pool,
24
- // MagicEden escrow/related:
25
- initializerAddress,
26
- initializerDepositTokenAddress,
27
- takerAmount,
28
- escrowAddress,
29
- escrowBump,
30
- pdaAddress,
31
- takerAddress,
32
- expectedTakerAmount,
33
- expectedMintAddress,
34
- metadataAddress,
35
- creators,
36
- // Wallet Connect
37
- instructions,
38
- feePayer,
39
- } = unsignedTx.txData
11
+ const { amount: unitAmount, from, method, transaction } = unsignedTx.txData
40
12
 
41
- const asset = assets.solana
13
+ if (transaction) {
14
+ return _signTx({ tx: transaction, privateKey })
15
+ }
42
16
 
17
+ const asset = assets.solana
43
18
  const address = from
44
19
  const amount = unitAmount ? asset.currency.baseUnit(unitAmount).toNumber() : unitAmount
45
20
 
21
+ const args = merge(unsignedTx.txData, {
22
+ asset,
23
+ address,
24
+ amount,
25
+ })
26
+
27
+ const tx = createTx({ txData: args, method })
28
+ return _signTx({ tx, privateKey })
29
+ }
30
+
31
+ // Signs plain tx.
32
+ const _signTx = ({ tx, privateKey }) => {
33
+ Transaction.sign(tx, privateKey)
34
+ const rawTx = Transaction.serialize(tx)
35
+ const txId = Transaction.getTxId(tx)
36
+
37
+ return { txId, rawTx }
38
+ }
39
+
40
+ const createTx = ({ txData, method }) => {
46
41
  let tx
47
42
  switch (method) {
48
43
  case 'delegate':
49
- tx = Transaction.createStakeAccountTransaction({
50
- address,
51
- amount,
52
- recentBlockhash,
53
- seed,
54
- pool,
55
- })
44
+ tx = createDelegateTransaction(txData)
56
45
  break
57
46
  case 'undelegate':
58
- tx = Transaction.undelegate({
59
- address,
60
- stakeAddresses,
61
- recentBlockhash,
62
- })
47
+ tx = createUndelegateTransaction(txData)
63
48
  break
64
49
  case 'withdraw':
65
- tx = Transaction.withdraw({
66
- address,
67
- stakeAddresses,
68
- amount,
69
- recentBlockhash,
70
- })
50
+ tx = createWithdrawTransaction(txData)
51
+ break
52
+ case 'closeAccount':
53
+ tx = createCloseAccountTransaction(txData)
71
54
  break
72
55
  case 'initializeEscrow': {
73
- tx = Transaction.magicEdenInitializeEscrow({
74
- initializerAddress,
75
- initializerDepositTokenAddress,
76
- escrowBump,
77
- escrowAddress,
78
- takerAmount,
79
- recentBlockhash,
80
- })
81
-
56
+ tx = createMagicEdenInitializeEscrowTransaction(txData)
82
57
  break
83
58
  }
84
59
  case 'cancelEscrow':
85
- tx = Transaction.magicEdenCancelEscrow({
86
- initializerAddress,
87
- initializerDepositTokenAddress,
88
- escrowAddress,
89
- pdaAddress,
90
- recentBlockhash,
91
- })
60
+ tx = createMagicEdenCancelEscrowTransaction(txData)
92
61
  break
93
62
  case 'exchange':
94
- tx = Transaction.magicEdenExchange({
95
- expectedTakerAmount,
96
- expectedMintAddress,
97
- takerAddress,
98
- initializerAddress,
99
- initializerDepositTokenAddress,
100
- escrowAddress,
101
- pdaAddress,
102
- metadataAddress,
103
- creators,
104
- recentBlockhash,
105
- })
63
+ tx = createMagicEdenExchangeTransaction(txData)
106
64
  break
107
65
  default:
108
66
  // SOL and Token tx
109
- tx = new Transaction({
110
- from,
111
- to,
112
- amount,
113
- recentBlockhash,
114
- tokenMintAddress,
115
- destinationAddressType,
116
- isAssociatedTokenAccountActive,
117
- fromTokenAddresses,
118
- instructions,
119
- feePayer,
120
- })
67
+ tx = createTokenTransaction(txData)
121
68
  break
122
69
  }
70
+ return tx
71
+ }
123
72
 
124
- // sign plain tx
125
- Transaction.sign(tx, privateKey)
126
- const rawTx = Transaction.serialize(tx)
127
- const txId = Transaction.getTxId(tx)
73
+ const createDelegateTransaction = ({ address, amount, pool, recentBlockhash, seed }) =>
74
+ Transaction.createStakeAccountTransaction({
75
+ address,
76
+ amount,
77
+ recentBlockhash,
78
+ seed,
79
+ pool,
80
+ })
128
81
 
129
- return { txId, rawTx }
130
- }
82
+ const createUndelegateTransaction = ({ address, recentBlockhash, stakeAddresses }) =>
83
+ Transaction.undelegate({
84
+ address,
85
+ recentBlockhash,
86
+ stakeAddresses,
87
+ })
88
+
89
+ const createWithdrawTransaction = ({ address, amount, recentBlockhash, stakeAddresses }) =>
90
+ Transaction.withdraw({
91
+ address,
92
+ amount,
93
+ recentBlockhash,
94
+ stakeAddresses,
95
+ })
96
+
97
+ const createMagicEdenInitializeEscrowTransaction = ({
98
+ escrowAddress,
99
+ escrowBump,
100
+ initializerDepositTokenAddress,
101
+ recentBlockhash,
102
+ takerAmount,
103
+ initializerAddress,
104
+ }) =>
105
+ Transaction.magicEdenInitializeEscrow({
106
+ escrowAddress,
107
+ escrowBump,
108
+ initializerAddress,
109
+ initializerDepositTokenAddress,
110
+ recentBlockhash,
111
+ takerAmount,
112
+ })
113
+
114
+ const createMagicEdenCancelEscrowTransaction = ({
115
+ escrowAddress,
116
+ initializerAddress,
117
+ initializerDepositTokenAddress,
118
+ pdaAddress,
119
+ recentBlockhash,
120
+ }) =>
121
+ Transaction.magicEdenCancelEscrow({
122
+ escrowAddress,
123
+ initializerAddress,
124
+ initializerDepositTokenAddress,
125
+ pdaAddress,
126
+ recentBlockhash,
127
+ })
128
+
129
+ const createMagicEdenExchangeTransaction = ({
130
+ creators,
131
+ escrowAddress,
132
+ expectedMintAddress,
133
+ expectedTakerAmount,
134
+ initializerAddress,
135
+ initializerDepositTokenAddress,
136
+ metadataAddress,
137
+ pdaAddress,
138
+ recentBlockhash,
139
+ takerAddress,
140
+ }) =>
141
+ Transaction.magicEdenExchange({
142
+ creators,
143
+ escrowAddress,
144
+ expectedMintAddress,
145
+ expectedTakerAmount,
146
+ initializerAddress,
147
+ initializerDepositTokenAddress,
148
+ metadataAddress,
149
+ pdaAddress,
150
+ recentBlockhash,
151
+ takerAddress,
152
+ })
153
+
154
+ const createTokenTransaction = ({
155
+ amount,
156
+ destinationAddressType,
157
+ feePayer,
158
+ from,
159
+ fromTokenAddresses,
160
+ instructions,
161
+ isAssociatedTokenAccountActive,
162
+ recentBlockhash,
163
+ to,
164
+ tokenMintAddress,
165
+ memo,
166
+ reference,
167
+ }) =>
168
+ new Transaction({
169
+ amount,
170
+ destinationAddressType,
171
+ feePayer,
172
+ from,
173
+ fromTokenAddresses,
174
+ instructions,
175
+ isAssociatedTokenAccountActive,
176
+ recentBlockhash,
177
+ to,
178
+ tokenMintAddress,
179
+ memo,
180
+ reference,
181
+ })
182
+
183
+ const createCloseAccountTransaction = ({ account, programId, recentBlockhash, walletPublicKey }) =>
184
+ Transaction.createCloseAccount({
185
+ account,
186
+ programId,
187
+ recentBlockhash,
188
+ walletPublicKey,
189
+ })