@exodus/solana-lib 1.2.9-build → 1.2.9

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/package.json +3 -3
  2. package/src/constants.js +12 -0
  3. package/src/encode.js +57 -0
  4. package/src/fee-data/index.js +1 -0
  5. package/src/fee-data/solana.js +9 -0
  6. package/src/helpers/spl-token.js +108 -0
  7. package/src/helpers/tokenTransfer.js +72 -0
  8. package/src/index.js +8 -0
  9. package/src/keypair.js +32 -0
  10. package/src/tokens.js +19 -0
  11. package/src/transaction.js +240 -0
  12. package/src/tx/create-and-sign-tx.js +8 -0
  13. package/{lib → src}/tx/create-unsigned-tx.js +11 -18
  14. package/src/tx/index.js +4 -0
  15. package/src/tx/parse-unsigned-tx.js +41 -0
  16. package/src/tx/sign-unsigned-tx.js +78 -0
  17. package/src/vendor/account.js +38 -0
  18. package/src/vendor/index.js +9 -0
  19. package/src/vendor/instruction.js +46 -0
  20. package/src/vendor/message.js +216 -0
  21. package/src/vendor/nonce-account.js +46 -0
  22. package/src/vendor/publickey.js +212 -0
  23. package/src/vendor/stake-program.js +527 -0
  24. package/src/vendor/system-program.js +782 -0
  25. package/src/vendor/sysvar.js +16 -0
  26. package/src/vendor/transaction.js +594 -0
  27. package/src/vendor/utils/blockhash.js +6 -0
  28. package/src/vendor/utils/fee-calculator.js +17 -0
  29. package/src/vendor/utils/layout.js +80 -0
  30. package/src/vendor/utils/shortvec-encoding.js +30 -0
  31. package/src/vendor/utils/to-buffer.js +9 -0
  32. package/lib/constants.js +0 -19
  33. package/lib/encode.js +0 -67
  34. package/lib/fee-data/index.js +0 -15
  35. package/lib/fee-data/solana.js +0 -14
  36. package/lib/helpers/spl-token.js +0 -122
  37. package/lib/helpers/tokenTransfer.js +0 -78
  38. package/lib/index.js +0 -79
  39. package/lib/keypair.js +0 -38
  40. package/lib/tokens.js +0 -21
  41. package/lib/transaction.js +0 -279
  42. package/lib/tx/create-and-sign-tx.js +0 -15
  43. package/lib/tx/index.js +0 -53
  44. package/lib/tx/parse-unsigned-tx.js +0 -55
  45. package/lib/tx/sign-unsigned-tx.js +0 -90
  46. package/lib/vendor/account.js +0 -48
  47. package/lib/vendor/index.js +0 -113
  48. package/lib/vendor/instruction.js +0 -48
  49. package/lib/vendor/message.js +0 -167
  50. package/lib/vendor/nonce-account.js +0 -56
  51. package/lib/vendor/publickey.js +0 -211
  52. package/lib/vendor/stake-program.js +0 -476
  53. package/lib/vendor/system-program.js +0 -640
  54. package/lib/vendor/sysvar.js +0 -19
  55. package/lib/vendor/transaction.js +0 -594
  56. package/lib/vendor/utils/blockhash.js +0 -1
  57. package/lib/vendor/utils/fee-calculator.js +0 -25
  58. package/lib/vendor/utils/layout.js +0 -97
  59. package/lib/vendor/utils/shortvec-encoding.js +0 -41
  60. package/lib/vendor/utils/to-buffer.js +0 -18
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@exodus/solana-lib",
3
- "version": "1.2.9-build",
3
+ "version": "1.2.9",
4
4
  "description": "Exodus internal Solana low-level library",
5
- "main": "lib/index.js",
5
+ "main": "src/index.js",
6
6
  "files": [
7
- "lib/",
7
+ "src/",
8
8
  "!src/__tests__"
9
9
  ],
10
10
  "author": "Exodus",
@@ -0,0 +1,12 @@
1
+ import { PublicKey, SystemProgram, StakeProgram } from './vendor'
2
+
3
+ export const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey(
4
+ 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
5
+ )
6
+ export const SYSTEM_PROGRAM_ID = SystemProgram.programId
7
+
8
+ export const STAKE_PROGRAM_ID = StakeProgram.programId
9
+
10
+ export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')
11
+
12
+ export const SEED = 'stake:0'
package/src/encode.js ADDED
@@ -0,0 +1,57 @@
1
+ // @flow
2
+ import { PublicKey, StakeProgram } from './vendor'
3
+ import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, TOKEN_PROGRAM_ID, SEED } from './constants'
4
+ import { getPublicKey } from './keypair'
5
+ import bs58 from 'bs58'
6
+ import BN from 'bn.js'
7
+
8
+ export function getAddressFromPublicKey(publicKey: string | Buffer): string {
9
+ return bs58.encode(Buffer.from(publicKey, 'hex'))
10
+ }
11
+
12
+ export function getAddressFromPrivateKey(privateKey: string | Buffer): string {
13
+ return getAddressFromPublicKey(getPublicKey(privateKey))
14
+ }
15
+
16
+ export function isValidAddress(address: string): boolean {
17
+ try {
18
+ // assume base 58 encoding by default
19
+ const decoded = bs58.decode(address)
20
+ if (decoded.length !== 32) {
21
+ return false
22
+ }
23
+ const _bn = new BN(decoded)
24
+ if (_bn.byteLength() > 32) {
25
+ return false
26
+ }
27
+ return true
28
+ } catch (e) {
29
+ return false
30
+ }
31
+ }
32
+
33
+ // doc: https://spl.solana.com/associated-token-account (HACK: refactored to sync)
34
+ export function findAssociatedTokenAddress(
35
+ walletAddress: string,
36
+ tokenMintAddress: string
37
+ ): string {
38
+ walletAddress = new PublicKey(walletAddress)
39
+ tokenMintAddress = new PublicKey(tokenMintAddress)
40
+ return PublicKey.findProgramAddress(
41
+ [walletAddress.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), tokenMintAddress.toBuffer()],
42
+ SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
43
+ )[0].toBase58() // returns encoded PublicKey
44
+ }
45
+
46
+ export function createStakeAddress(walletAddress: string, seed = SEED): string {
47
+ const fromPubkey = new PublicKey(walletAddress)
48
+
49
+ const newAccountPubkey = PublicKey.createWithSeed(
50
+ // HACK: refactored to sync
51
+ fromPubkey,
52
+ seed,
53
+ StakeProgram.programId
54
+ )
55
+
56
+ return newAccountPubkey.toBase58()
57
+ }
@@ -0,0 +1 @@
1
+ export { default as solana } from './solana'
@@ -0,0 +1,9 @@
1
+ import { FeeData } from '@exodus/asset-lib'
2
+
3
+ export default new FeeData(
4
+ {
5
+ fee: '0.000005 SOL',
6
+ },
7
+ 'fee',
8
+ 'solana'
9
+ )
@@ -0,0 +1,108 @@
1
+ import assert from 'assert'
2
+ import BN from 'bn.js'
3
+ import * as BufferLayout from '@exodus/buffer-layout'
4
+ import { Account, PublicKey, TransactionInstruction } from '../vendor'
5
+ import * as Layout from '../vendor/utils/layout'
6
+
7
+ // Extracted from https://github.com/ExodusMovement/solana-spl-token/blob/master/src/index.js#L263
8
+
9
+ /**
10
+ * 64-bit value
11
+ */
12
+ export class U64 extends BN {
13
+ /**
14
+ * Convert to Buffer representation
15
+ */
16
+ toBuffer(): typeof Buffer {
17
+ const a = super.toArray().reverse()
18
+ const b = Buffer.from(a)
19
+ if (b.length === 8) {
20
+ return b
21
+ }
22
+ assert(b.length < 8, 'u64 too large')
23
+
24
+ const zeroPad = Buffer.alloc(8)
25
+ b.copy(zeroPad)
26
+ return zeroPad
27
+ }
28
+
29
+ /**
30
+ * Construct a u64 from Buffer representation
31
+ */
32
+ static fromBuffer(buffer: typeof Buffer): U64 {
33
+ assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`)
34
+ return new U64(
35
+ [...buffer]
36
+ .reverse()
37
+ .map((i) => `00${i.toString(16)}`.slice(-2))
38
+ .join(''),
39
+ 16
40
+ )
41
+ }
42
+ }
43
+
44
+ const u64 = U64 // alias
45
+
46
+ /**
47
+ * An ERC20-like Token
48
+ */
49
+ export class Token {
50
+ /**
51
+ * Construct a Transfer instruction
52
+ *
53
+ * @param programId SPL Token program account
54
+ * @param source Source account
55
+ * @param destination Destination account
56
+ * @param owner Owner of the source account
57
+ * @param multiSigners Signing accounts if `authority` is a multiSig
58
+ * @param amount Number of tokens to transfer
59
+ */
60
+ static createTransferInstruction(
61
+ programId: PublicKey,
62
+ source: PublicKey,
63
+ destination: PublicKey,
64
+ owner: PublicKey,
65
+ multiSigners: Array<Account>,
66
+ amount: number | u64
67
+ ): TransactionInstruction {
68
+ const dataLayout = BufferLayout.struct([
69
+ BufferLayout.u8('instruction'),
70
+ Layout.uint64('amount'),
71
+ ])
72
+
73
+ const data = Buffer.alloc(dataLayout.span)
74
+ dataLayout.encode(
75
+ {
76
+ instruction: 3, // Transfer instruction
77
+ amount: new U64(amount).toBuffer(),
78
+ },
79
+ data
80
+ )
81
+
82
+ let keys = [
83
+ { pubkey: source, isSigner: false, isWritable: true },
84
+ { pubkey: destination, isSigner: false, isWritable: true },
85
+ ]
86
+ if (multiSigners.length === 0) {
87
+ keys.push({
88
+ pubkey: owner,
89
+ isSigner: true,
90
+ isWritable: false,
91
+ })
92
+ } else {
93
+ keys.push({ pubkey: owner, isSigner: false, isWritable: false })
94
+ multiSigners.forEach((signer) =>
95
+ keys.push({
96
+ pubkey: signer.publicKey,
97
+ isSigner: true,
98
+ isWritable: false,
99
+ })
100
+ )
101
+ }
102
+ return new TransactionInstruction({
103
+ keys,
104
+ programId: programId,
105
+ data,
106
+ })
107
+ }
108
+ }
@@ -0,0 +1,72 @@
1
+ import { Token } from './spl-token'
2
+ import { PublicKey, TransactionInstruction, SystemProgram, SYSVAR_RENT_PUBKEY } from '../vendor'
3
+ import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'
4
+ import { findAssociatedTokenAddress } from '../encode'
5
+
6
+ // https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/associatedToken.ts#L59
7
+ export const createAssociatedTokenAccount = (
8
+ senderAddress: string,
9
+ tokenMintAddress: string,
10
+ ownerAddress: string // destination SOL address
11
+ ) => {
12
+ const associatedTokenAccountPublicKey = new PublicKey(
13
+ findAssociatedTokenAddress(ownerAddress, tokenMintAddress)
14
+ )
15
+
16
+ const feePayerPublicKey = new PublicKey(senderAddress)
17
+ const ownerPublicKey = new PublicKey(ownerAddress)
18
+ const tokenMintPublicKey = new PublicKey(tokenMintAddress)
19
+
20
+ const ix = createIx(
21
+ feePayerPublicKey, // feePayer
22
+ associatedTokenAccountPublicKey,
23
+ ownerPublicKey,
24
+ tokenMintPublicKey
25
+ )
26
+
27
+ return ix // returns the instruction
28
+ }
29
+
30
+ function createIx(
31
+ funderPubkey: PublicKey,
32
+ associatedTokenAccountPublicKey: PublicKey,
33
+ ownerPublicKey: PublicKey,
34
+ tokenMintPublicKey: PublicKey
35
+ ) {
36
+ return new TransactionInstruction({
37
+ programId: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
38
+ data: Buffer.from([]),
39
+ keys: [
40
+ { pubkey: funderPubkey, isSigner: true, isWritable: true },
41
+ {
42
+ pubkey: associatedTokenAccountPublicKey,
43
+ isSigner: false,
44
+ isWritable: true,
45
+ },
46
+ { pubkey: ownerPublicKey, isSigner: false, isWritable: false },
47
+ { pubkey: tokenMintPublicKey, isSigner: false, isWritable: false },
48
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
49
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
50
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
51
+ ],
52
+ })
53
+ }
54
+
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) => {
57
+ const sourcePubkey = new PublicKey(fromTokenAddress) // the token ADDRESS needed!
58
+ const destinationPubkey = new PublicKey(to)
59
+ console.log(`destination token address: ${destinationPubkey.toBase58()}`)
60
+ const ownerAccountOrWalletPublicKey = new PublicKey(owner) // the only native SOL address
61
+
62
+ const transferIx = Token.createTransferInstruction(
63
+ TOKEN_PROGRAM_ID,
64
+ sourcePubkey,
65
+ destinationPubkey,
66
+ ownerAccountOrWalletPublicKey,
67
+ [],
68
+ amount
69
+ )
70
+
71
+ return transferIx
72
+ }
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // @flow
2
+
3
+ export * from './constants'
4
+ export * from './encode'
5
+ export * from './keypair'
6
+ export * from './tx'
7
+ export { default as tokens } from './tokens'
8
+ export { default as Transaction } from './transaction'
package/src/keypair.js ADDED
@@ -0,0 +1,32 @@
1
+ // @flow
2
+ import nacl from 'tweetnacl'
3
+
4
+ export function getKeyPairFromPrivateKey(privateKey: string | Buffer): Object {
5
+ const { publicKey, secretKey } = nacl.sign.keyPair.fromSeed(
6
+ Buffer.from(privateKey, 'hex').slice(0, 32)
7
+ )
8
+
9
+ return {
10
+ secretKey: Buffer.from(secretKey, 'hex'), // secretKey
11
+ publicKey: Buffer.from(publicKey, 'hex'),
12
+ }
13
+ }
14
+
15
+ export function getPublicKey(privateKey: string | Buffer): Buffer {
16
+ return getKeyPairFromPrivateKey(privateKey).publicKey
17
+ }
18
+
19
+ export function sign(data: Buffer, privateKey: string | Buffer): Buffer {
20
+ return Buffer.from(
21
+ nacl.sign.detached(data, getKeyPairFromPrivateKey(Buffer.from(privateKey, 'hex')).secretKey),
22
+ 'hex'
23
+ )
24
+ }
25
+
26
+ export function verifySignature(
27
+ data: Buffer,
28
+ signature: Buffer,
29
+ publicKey: string | Buffer
30
+ ): boolean {
31
+ return nacl.sign.detached.verify(data, signature, Buffer.from(publicKey, 'hex'))
32
+ }
package/src/tokens.js ADDED
@@ -0,0 +1,19 @@
1
+ // adapted from https://github.com/project-serum/spl-token-wallet/blob/master/src/utils/tokens/names.js
2
+
3
+ const TOKENS = [
4
+ {
5
+ mintAddress: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt',
6
+ tokenName: 'serum',
7
+ tokenProperName: 'Serum',
8
+ tokenSymbol: 'SRM',
9
+ },
10
+ {
11
+ mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
12
+ tokenName: 'usdcoin_solana',
13
+ tokenProperName: 'USD Coin Solana',
14
+ tokenSymbol: 'USDCSOL',
15
+ },
16
+ // ....
17
+ ]
18
+
19
+ export default TOKENS
@@ -0,0 +1,240 @@
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
@@ -0,0 +1,8 @@
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
+ }
@@ -1,11 +1,6 @@
1
- "use strict";
1
+ import type { UnsignedTransaction, ParsedTransaction } from '@exodus/models/lib/types'
2
2
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.createUnsignedTx = createUnsignedTx;
7
-
8
- function createUnsignedTx({
3
+ export function createUnsignedTx({
9
4
  asset,
10
5
  from,
11
6
  to,
@@ -15,16 +10,14 @@ function createUnsignedTx({
15
10
  // Tokens related:
16
11
  tokenName,
17
12
  destinationAddressType,
18
- isAssociatedTokenAccountActive,
19
- // true when recipient balance !== 0
20
- fromTokenAddresses,
21
- // sender token addresses
13
+ isAssociatedTokenAccountActive, // true when recipient balance !== 0
14
+ fromTokenAddresses, // sender token addresses
22
15
  // Staking related:
23
16
  method,
24
17
  stakeAddresses,
25
18
  seed,
26
- pool
27
- }) {
19
+ pool,
20
+ }: ParsedTransaction): UnsignedTransaction {
28
21
  return {
29
22
  txData: {
30
23
  from,
@@ -41,10 +34,10 @@ function createUnsignedTx({
41
34
  method,
42
35
  stakeAddresses,
43
36
  seed,
44
- pool
37
+ pool,
45
38
  },
46
39
  txMeta: {
47
- assetName: asset.name
48
- }
49
- };
50
- }
40
+ assetName: asset.name,
41
+ },
42
+ }
43
+ }
@@ -0,0 +1,4 @@
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'
@@ -0,0 +1,41 @@
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
+ const fee = asset.currency.baseUnit(txData.fee)
23
+ return {
24
+ asset,
25
+ from: [from],
26
+ to,
27
+ amount,
28
+ fee,
29
+ recentBlockhash,
30
+ // token related
31
+ tokenName,
32
+ destinationAddressType,
33
+ isAssociatedTokenAccountActive,
34
+ fromTokenAddresses,
35
+ // staking related
36
+ method,
37
+ stakeAddresses,
38
+ seed,
39
+ pool,
40
+ }
41
+ }