@exodus/solana-lib 1.2.4 → 1.2.5
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 +3 -3
- package/src/helpers/tokenTransfer.js +4 -10
- package/src/tokens.js +4 -17
- package/src/transaction.js +17 -11
- package/src/tx/create-unsigned-tx.js +10 -0
- package/src/tx/parse-unsigned-tx.js +15 -1
- package/src/tx/sign-unsigned-tx.js +14 -1
- package/src/vendor/transaction.js +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Exodus internal Solana low-level library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@exodus/asset-lib": "^3.4.3",
|
|
17
|
-
"@exodus/assets": "^8.0.
|
|
17
|
+
"@exodus/assets": "^8.0.2",
|
|
18
18
|
"@exodus/buffer-layout": "^1.2.0-exodus1",
|
|
19
19
|
"@exodus/models": "^8.4.0",
|
|
20
20
|
"bn.js": "~4.11.0",
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"create-hash": "~1.1.3",
|
|
23
23
|
"tweetnacl": "^1.0.3"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "791e305a718246460d5ac93ed2eb7808955c0f5d"
|
|
26
26
|
}
|
|
@@ -52,17 +52,11 @@ function createIx(
|
|
|
52
52
|
})
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/editing.ts#
|
|
56
|
-
export const createTokenTransferInstruction = (
|
|
57
|
-
owner,
|
|
58
|
-
fromTokenAddress,
|
|
59
|
-
tokenMintAddress,
|
|
60
|
-
to,
|
|
61
|
-
amount
|
|
62
|
-
) => {
|
|
55
|
+
// https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/editing.ts#L211
|
|
56
|
+
export const createTokenTransferInstruction = (owner, fromTokenAddress, to, amount) => {
|
|
63
57
|
const sourcePubkey = new PublicKey(fromTokenAddress) // the token ADDRESS needed!
|
|
64
|
-
const destinationPubkey = new PublicKey(
|
|
65
|
-
console.log(`destination
|
|
58
|
+
const destinationPubkey = new PublicKey(to)
|
|
59
|
+
console.log(`destination token address: ${destinationPubkey.toBase58()}`)
|
|
66
60
|
const ownerAccountOrWalletPublicKey = new PublicKey(owner) // the only native SOL address
|
|
67
61
|
|
|
68
62
|
const transferIx = Token.createTransferInstruction(
|
package/src/tokens.js
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
//
|
|
1
|
+
// adapted from https://github.com/project-serum/spl-token-wallet/blob/master/src/utils/tokens/names.js
|
|
2
2
|
|
|
3
3
|
const TOKENS = [
|
|
4
4
|
{
|
|
5
5
|
mintAddress: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt',
|
|
6
|
-
tokenName: '
|
|
6
|
+
tokenName: 'serum',
|
|
7
|
+
tokenProperName: 'Serum',
|
|
7
8
|
tokenSymbol: 'SRM',
|
|
8
9
|
},
|
|
9
|
-
|
|
10
|
-
tokenSymbol: 'BTC',
|
|
11
|
-
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
|
12
|
-
tokenName: 'Wrapped Bitcoin',
|
|
13
|
-
icon:
|
|
14
|
-
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/bitcoin/info/logo.png',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
tokenSymbol: 'USDC',
|
|
18
|
-
mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
19
|
-
tokenName: 'USD Coin',
|
|
20
|
-
icon:
|
|
21
|
-
'https://raw.githubusercontent.com/trustwallet/assets/f3ffd0b9ae2165336279ce2f8db1981a55ce30f8/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
|
|
22
|
-
},
|
|
23
|
-
// ... TODO: do we want to add decimals for every token? (Serum SRM is 6)
|
|
10
|
+
// ....
|
|
24
11
|
]
|
|
25
12
|
|
|
26
13
|
export default TOKENS
|
package/src/transaction.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import assert from 'assert'
|
|
3
3
|
|
|
4
4
|
import { getKeyPairFromPrivateKey } from './keypair'
|
|
5
|
+
import { findAssociatedTokenAddress } from './encode'
|
|
5
6
|
import {
|
|
6
7
|
createAssociatedTokenAccount,
|
|
7
8
|
createTokenTransferInstruction,
|
|
@@ -18,7 +19,8 @@ class Tx {
|
|
|
18
19
|
recentBlockhash,
|
|
19
20
|
// fee, // (Fee per Signature: 5000 lamports)
|
|
20
21
|
// Tokens related:
|
|
21
|
-
|
|
22
|
+
tokenName,
|
|
23
|
+
destinationAddressType,
|
|
22
24
|
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
23
25
|
fromTokenAddresses, // sender token addresses
|
|
24
26
|
} = {}) {
|
|
@@ -27,7 +29,11 @@ class Tx {
|
|
|
27
29
|
assert(amount, 'amount is required')
|
|
28
30
|
assert(typeof amount === 'number', 'amount must be a number')
|
|
29
31
|
assert(recentBlockhash, 'recentBlockhash is required')
|
|
30
|
-
if (
|
|
32
|
+
if (tokenName) {
|
|
33
|
+
assert(
|
|
34
|
+
typeof destinationAddressType !== 'undefined',
|
|
35
|
+
'destinationAddressType is required when sending tokens'
|
|
36
|
+
)
|
|
31
37
|
assert(
|
|
32
38
|
typeof isAssociatedTokenAccountActive !== 'undefined',
|
|
33
39
|
'isAssociatedTokenAccountActive is required when sending tokens'
|
|
@@ -35,13 +41,14 @@ class Tx {
|
|
|
35
41
|
assert(Array.isArray(fromTokenAddresses), 'fromTokenAddresses Array is required')
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
const token = TOKENS.find(({
|
|
44
|
+
const token = TOKENS.find(({ tokenName: name }) => name === tokenName)
|
|
39
45
|
this.txObj = {
|
|
40
46
|
from,
|
|
41
47
|
to,
|
|
42
48
|
amount,
|
|
43
49
|
recentBlockhash,
|
|
44
50
|
token,
|
|
51
|
+
destinationAddressType,
|
|
45
52
|
isAssociatedTokenAccountActive,
|
|
46
53
|
fromTokenAddresses,
|
|
47
54
|
}
|
|
@@ -74,14 +81,18 @@ class Tx {
|
|
|
74
81
|
amount,
|
|
75
82
|
recentBlockhash,
|
|
76
83
|
token,
|
|
84
|
+
destinationAddressType,
|
|
77
85
|
isAssociatedTokenAccountActive,
|
|
78
86
|
fromTokenAddresses,
|
|
79
87
|
}) {
|
|
80
88
|
this.transaction = new Transaction({
|
|
81
89
|
recentBlockhash,
|
|
82
90
|
})
|
|
91
|
+
const isUnknown = destinationAddressType === null
|
|
92
|
+
const isSOLaddress = destinationAddressType === 'solana'
|
|
83
93
|
// crete account instruction
|
|
84
|
-
if (
|
|
94
|
+
if (isUnknown) throw new Error('Destination SOL balance cannot be zero (address not active)') // cannot initialize without knowing the owner
|
|
95
|
+
if (isSOLaddress && !isAssociatedTokenAccountActive)
|
|
85
96
|
this.transaction.add(createAssociatedTokenAccount(from, token.mintAddress, to))
|
|
86
97
|
|
|
87
98
|
let amountLeft = amount
|
|
@@ -100,15 +111,10 @@ class Tx {
|
|
|
100
111
|
amountLeft -= amountToSend
|
|
101
112
|
}
|
|
102
113
|
|
|
114
|
+
const dest = isSOLaddress ? findAssociatedTokenAddress(to, token.mintAddress) : to
|
|
103
115
|
// add transfer token instruction
|
|
104
116
|
this.transaction.add(
|
|
105
|
-
createTokenTransferInstruction(
|
|
106
|
-
from,
|
|
107
|
-
tokenAccountAddress,
|
|
108
|
-
token.mintAddress,
|
|
109
|
-
to,
|
|
110
|
-
amountToSend
|
|
111
|
-
)
|
|
117
|
+
createTokenTransferInstruction(from, tokenAccountAddress, dest, amountToSend)
|
|
112
118
|
)
|
|
113
119
|
}
|
|
114
120
|
|
|
@@ -6,6 +6,11 @@ export function createUnsignedTx({
|
|
|
6
6
|
to,
|
|
7
7
|
amount,
|
|
8
8
|
recentBlockhash,
|
|
9
|
+
// Tokens related:
|
|
10
|
+
tokenName,
|
|
11
|
+
destinationAddressType,
|
|
12
|
+
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
13
|
+
fromTokenAddresses, // sender token addresses
|
|
9
14
|
}: ParsedTransaction): UnsignedTransaction {
|
|
10
15
|
return {
|
|
11
16
|
txData: {
|
|
@@ -13,6 +18,11 @@ export function createUnsignedTx({
|
|
|
13
18
|
to,
|
|
14
19
|
amount: amount.toBase().toNumber(),
|
|
15
20
|
recentBlockhash,
|
|
21
|
+
// Tokens related:
|
|
22
|
+
tokenName,
|
|
23
|
+
destinationAddressType,
|
|
24
|
+
isAssociatedTokenAccountActive,
|
|
25
|
+
fromTokenAddresses,
|
|
16
26
|
},
|
|
17
27
|
txMeta: {
|
|
18
28
|
assetName: asset.name,
|
|
@@ -3,7 +3,16 @@ import type { UnsignedTransaction, ParsedTransaction } from '@exodus/models/lib/
|
|
|
3
3
|
|
|
4
4
|
export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransaction {
|
|
5
5
|
const asset = assets.solana
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
from,
|
|
8
|
+
to,
|
|
9
|
+
recentBlockhash,
|
|
10
|
+
tokenName,
|
|
11
|
+
destinationAddressType,
|
|
12
|
+
isAssociatedTokenAccountActive,
|
|
13
|
+
fromTokenAddresses,
|
|
14
|
+
...txData
|
|
15
|
+
} = unsignedTx.txData
|
|
7
16
|
|
|
8
17
|
const amount = asset.currency.baseUnit(txData.amount)
|
|
9
18
|
return {
|
|
@@ -12,5 +21,10 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
12
21
|
to,
|
|
13
22
|
amount,
|
|
14
23
|
recentBlockhash,
|
|
24
|
+
// token related
|
|
25
|
+
tokenName,
|
|
26
|
+
destinationAddressType,
|
|
27
|
+
isAssociatedTokenAccountActive,
|
|
28
|
+
fromTokenAddresses,
|
|
15
29
|
}
|
|
16
30
|
}
|
|
@@ -6,7 +6,16 @@ export function signUnsignedTx(
|
|
|
6
6
|
unsignedTx: UnsignedTransaction,
|
|
7
7
|
privateKey: Buffer
|
|
8
8
|
): SignedTransaction {
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
from,
|
|
11
|
+
to,
|
|
12
|
+
amount,
|
|
13
|
+
recentBlockhash,
|
|
14
|
+
tokenName,
|
|
15
|
+
destinationAddressType,
|
|
16
|
+
isAssociatedTokenAccountActive,
|
|
17
|
+
fromTokenAddresses,
|
|
18
|
+
} = unsignedTx.txData
|
|
10
19
|
|
|
11
20
|
const asset = assets.solana
|
|
12
21
|
const tx = new Transaction({
|
|
@@ -14,6 +23,10 @@ export function signUnsignedTx(
|
|
|
14
23
|
to,
|
|
15
24
|
amount: asset.currency.baseUnit(amount).toNumber(),
|
|
16
25
|
recentBlockhash,
|
|
26
|
+
tokenName,
|
|
27
|
+
destinationAddressType,
|
|
28
|
+
isAssociatedTokenAccountActive,
|
|
29
|
+
fromTokenAddresses,
|
|
17
30
|
})
|
|
18
31
|
|
|
19
32
|
// sign plain tx
|
|
@@ -316,7 +316,9 @@ export class Transaction {
|
|
|
316
316
|
})
|
|
317
317
|
|
|
318
318
|
if (numRequiredSignatures !== this.signatures.length) {
|
|
319
|
-
throw new Error(
|
|
319
|
+
throw new Error(
|
|
320
|
+
`missing signer(s) - required signatures: ${numRequiredSignatures}, got ${this.signatures.length}`
|
|
321
|
+
)
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
const accountKeys = signedKeys.concat(unsignedKeys)
|