@exodus/solana-lib 1.3.15 → 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 +2 -2
- package/src/constants.js +2 -0
- package/src/helpers/tokenTransfer.js +15 -1
- package/src/index.js +1 -0
- package/src/transaction.js +61 -5
- package/src/tx/sign-unsigned-tx.js +44 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Exodus internal Solana low-level library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"lodash": "^4.17.11",
|
|
30
30
|
"tweetnacl": "^1.0.3"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
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 '
|
|
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
package/src/transaction.js
CHANGED
|
@@ -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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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,16 +1,20 @@
|
|
|
1
1
|
import { merge } from 'lodash'
|
|
2
2
|
import assets from '@exodus/assets'
|
|
3
3
|
import type { UnsignedTransaction, SignedTransaction } from '@exodus/models/lib/types'
|
|
4
|
+
|
|
4
5
|
import { Transaction } from '../'
|
|
5
6
|
|
|
6
7
|
export function signUnsignedTx(
|
|
7
8
|
unsignedTx: UnsignedTransaction,
|
|
8
9
|
privateKey: Buffer
|
|
9
10
|
): SignedTransaction {
|
|
10
|
-
const { amount: unitAmount, from, method } = unsignedTx.txData
|
|
11
|
+
const { amount: unitAmount, from, method, transaction } = unsignedTx.txData
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
if (transaction) {
|
|
14
|
+
return _signTx({ tx: transaction, privateKey })
|
|
15
|
+
}
|
|
13
16
|
|
|
17
|
+
const asset = assets.solana
|
|
14
18
|
const address = from
|
|
15
19
|
const amount = unitAmount ? asset.currency.baseUnit(unitAmount).toNumber() : unitAmount
|
|
16
20
|
|
|
@@ -19,39 +23,51 @@ export function signUnsignedTx(
|
|
|
19
23
|
address,
|
|
20
24
|
amount,
|
|
21
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 }) => {
|
|
22
41
|
let tx
|
|
23
42
|
switch (method) {
|
|
24
43
|
case 'delegate':
|
|
25
|
-
tx = createDelegateTransaction(
|
|
44
|
+
tx = createDelegateTransaction(txData)
|
|
26
45
|
break
|
|
27
46
|
case 'undelegate':
|
|
28
|
-
tx = createUndelegateTransaction(
|
|
47
|
+
tx = createUndelegateTransaction(txData)
|
|
29
48
|
break
|
|
30
49
|
case 'withdraw':
|
|
31
|
-
tx = createWithdrawTransaction(
|
|
50
|
+
tx = createWithdrawTransaction(txData)
|
|
51
|
+
break
|
|
52
|
+
case 'closeAccount':
|
|
53
|
+
tx = createCloseAccountTransaction(txData)
|
|
32
54
|
break
|
|
33
55
|
case 'initializeEscrow': {
|
|
34
|
-
tx = createMagicEdenInitializeEscrowTransaction(
|
|
56
|
+
tx = createMagicEdenInitializeEscrowTransaction(txData)
|
|
35
57
|
break
|
|
36
58
|
}
|
|
37
59
|
case 'cancelEscrow':
|
|
38
|
-
tx = createMagicEdenCancelEscrowTransaction(
|
|
60
|
+
tx = createMagicEdenCancelEscrowTransaction(txData)
|
|
39
61
|
break
|
|
40
62
|
case 'exchange':
|
|
41
|
-
tx = createMagicEdenExchangeTransaction(
|
|
63
|
+
tx = createMagicEdenExchangeTransaction(txData)
|
|
42
64
|
break
|
|
43
65
|
default:
|
|
44
66
|
// SOL and Token tx
|
|
45
|
-
tx = createTokenTransaction(
|
|
67
|
+
tx = createTokenTransaction(txData)
|
|
46
68
|
break
|
|
47
69
|
}
|
|
48
|
-
|
|
49
|
-
// sign plain tx
|
|
50
|
-
Transaction.sign(tx, privateKey)
|
|
51
|
-
const rawTx = Transaction.serialize(tx)
|
|
52
|
-
const txId = Transaction.getTxId(tx)
|
|
53
|
-
|
|
54
|
-
return { txId, rawTx }
|
|
70
|
+
return tx
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
const createDelegateTransaction = ({ address, amount, pool, recentBlockhash, seed }) =>
|
|
@@ -146,6 +162,8 @@ const createTokenTransaction = ({
|
|
|
146
162
|
recentBlockhash,
|
|
147
163
|
to,
|
|
148
164
|
tokenMintAddress,
|
|
165
|
+
memo,
|
|
166
|
+
reference,
|
|
149
167
|
}) =>
|
|
150
168
|
new Transaction({
|
|
151
169
|
amount,
|
|
@@ -158,4 +176,14 @@ const createTokenTransaction = ({
|
|
|
158
176
|
recentBlockhash,
|
|
159
177
|
to,
|
|
160
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,
|
|
161
189
|
})
|