@exodus/solana-lib 3.11.1 → 3.12.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/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.12.0](https://github.com/ExodusMovement/assets/compare/@exodus/solana-lib@3.11.2...@exodus/solana-lib@3.12.0) (2025-09-25)
7
+
8
+
9
+ ### Features
10
+
11
+
12
+ * feat: use trezor compatibility mode for solana (#6564)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+
18
+ * fix: don't use Sync methods in async (#5682)
19
+
20
+
21
+
22
+ ## [3.11.2](https://github.com/ExodusMovement/assets/compare/@exodus/solana-lib@3.11.1...@exodus/solana-lib@3.11.2) (2025-05-05)
23
+
24
+ **Note:** Version bump only for package @exodus/solana-lib
25
+
26
+
27
+
28
+
29
+
6
30
  ## [3.11.1](https://github.com/ExodusMovement/assets/compare/@exodus/solana-lib@3.11.0...@exodus/solana-lib@3.11.1) (2025-04-21)
7
31
 
8
32
  **Note:** Version bump only for package @exodus/solana-lib
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-lib",
3
- "version": "3.11.1",
3
+ "version": "3.12.0",
4
4
  "description": "Solana utils, such as for cryptography, address encoding/decoding, transaction building, etc.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -33,10 +33,10 @@
33
33
  "minimalistic-assert": "^1.0.1"
34
34
  },
35
35
  "devDependencies": {
36
+ "@exodus/bip39": "^1.0.1",
36
37
  "@exodus/key-identifier": "^1.3.0",
37
38
  "@exodus/keychain": "^7.3.0",
38
- "@exodus/solana-meta": "^2.0.0",
39
- "bip39": "^2.6.0"
39
+ "@exodus/solana-meta": "^2.0.0"
40
40
  },
41
41
  "bugs": {
42
42
  "url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-lib"
@@ -46,5 +46,5 @@
46
46
  "type": "git",
47
47
  "url": "git+https://github.com/ExodusMovement/assets.git"
48
48
  },
49
- "gitHead": "2e550990ef9db4209f8fe4e6e0485579d1afeedf"
49
+ "gitHead": "50814bd63872e287b650e161010e77be15b7994e"
50
50
  }
@@ -118,10 +118,13 @@ export function decodeTransferCheckedWithFeeInstruction(
118
118
  instruction, // TransactionInstruction
119
119
  programId // PublicKey
120
120
  ) {
121
- if (!instruction.programId.equals(programId))
121
+ if (!instruction.programId.equals(programId)) {
122
122
  throw new Error('TokenInvalidInstructionProgramError')
123
- if (instruction.data.length !== transferCheckedWithFeeInstructionData.span)
123
+ }
124
+
125
+ if (instruction.data.length !== transferCheckedWithFeeInstructionData.span) {
124
126
  throw new Error('TokenInvalidInstructionDataError')
127
+ }
125
128
 
126
129
  const {
127
130
  keys: { source, mint, destination, authority, signers },
@@ -130,8 +133,10 @@ export function decodeTransferCheckedWithFeeInstruction(
130
133
  if (
131
134
  data.instruction !== TokenInstruction.TransferFeeExtension ||
132
135
  data.transferFeeInstruction !== TransferFeeInstruction.TransferCheckedWithFee
133
- )
136
+ ) {
134
137
  throw new Error('TokenInvalidInstructionTypeError')
138
+ }
139
+
135
140
  if (!mint) throw new Error('TokenInvalidInstructionKeysError')
136
141
 
137
142
  return {
@@ -37,6 +37,7 @@ export const createGetKeyIdentifier =
37
37
  keyType: 'nacl',
38
38
  }
39
39
  case 'ledger':
40
+ case 'trezor':
40
41
  case 'trust':
41
42
  return {
42
43
  assetName,
@@ -1,4 +1,4 @@
1
- import { signDetachedSync } from '@exodus/crypto/curve25519'
1
+ import { signDetached } from '@exodus/crypto/curve25519'
2
2
  import assert from 'minimalistic-assert'
3
3
 
4
4
  import { assertValidMessage } from './validation.js'
@@ -11,5 +11,5 @@ export const signMessageNew = async ({ privateKey, message }) => {
11
11
  `privateKey is not a Buffer or Uint8Array`
12
12
  )
13
13
 
14
- return signDetachedSync({ message: rawMessage, privateKey, format: 'buffer' })
14
+ return signDetached({ message: rawMessage, privateKey, format: 'buffer' })
15
15
  }
@@ -167,8 +167,9 @@ class Tx {
167
167
  if (!rawTokenProgram) throw new Error('Cannot detect token program')
168
168
  const tokenProgram = new PublicKey(rawTokenProgram).toBase58()
169
169
  // crete account instruction
170
- if (isSOLaddress && !isAssociatedTokenAccountActive)
170
+ if (isSOLaddress && !isAssociatedTokenAccountActive) {
171
171
  this.transaction.add(createAssociatedTokenAccount(from, tokenMintAddress, to, tokenProgram))
172
+ }
172
173
 
173
174
  let amountLeft = amount
174
175
  let amountToSend
@@ -277,7 +278,7 @@ class Tx {
277
278
  }
278
279
 
279
280
  static undelegate({ address, stakeAddresses, recentBlockhash }) {
280
- // undelegate all stake addresses
281
+ // undelegate all stake addresses, in a single tx
281
282
  assert(Array.isArray(stakeAddresses), 'stakeAddresses Array is required')
282
283
 
283
284
  const fromPubkey = new PublicKey(address)
@@ -295,19 +296,29 @@ class Tx {
295
296
  return transaction
296
297
  }
297
298
 
298
- static withdraw({ address, stakeAddresses, amount, recentBlockhash }) {
299
+ static withdraw({ address, accounts, recentBlockhash }) {
300
+ // withdraw all inactive unstaked addresses, in a single tx
301
+ assert(typeof accounts === 'object', 'accounts object is required')
299
302
  const fromPubkey = new PublicKey(address)
300
- const stakeAddress = Array.isArray(stakeAddresses) ? stakeAddresses[0] : stakeAddresses
301
- const stakePublicKey = new PublicKey(stakeAddress)
302
303
 
303
- // TODO: why don't we put all withdraw in a single tx??
304
- const transaction = StakeProgram.withdraw({
305
- stakePubkey: stakePublicKey,
306
- authorizedPubkey: fromPubkey,
307
- toPubkey: fromPubkey,
308
- lamports: amount,
309
- })
310
- transaction.recentBlockhash = recentBlockhash
304
+ const transaction = new Transaction({ recentBlockhash })
305
+
306
+ // putting all withdraw instructions in a single tx
307
+ for (const [stakeAddress, account] of Object.entries(accounts)) {
308
+ if (!account.canWithdraw) continue // skip non-withdrawable accounts
309
+ if (!account.lamports) continue // skip empty accounts
310
+
311
+ const stakePublicKey = new PublicKey(stakeAddress)
312
+
313
+ const instruction = StakeProgram.withdraw({
314
+ stakePubkey: stakePublicKey,
315
+ authorizedPubkey: fromPubkey,
316
+ toPubkey: fromPubkey,
317
+ lamports: account.lamports,
318
+ })
319
+ transaction.add(instruction)
320
+ }
321
+
311
322
  return transaction
312
323
  }
313
324
 
@@ -18,6 +18,7 @@ export function createUnsignedTx({
18
18
  method,
19
19
  // Staking related:
20
20
  stakeAddresses,
21
+ accounts,
21
22
  seed,
22
23
  pool,
23
24
  // MagicEden escrow/related:
@@ -54,6 +55,7 @@ export function createUnsignedTx({
54
55
  // Staking related:
55
56
  method,
56
57
  stakeAddresses,
58
+ accounts,
57
59
  seed,
58
60
  pool,
59
61
  // MagicEden escrow/related:
@@ -9,6 +9,7 @@ export function parseUnsignedTx({ asset, unsignedTx }) {
9
9
  fromTokenAddresses,
10
10
  method,
11
11
  stakeAddresses,
12
+ accounts,
12
13
  seed,
13
14
  pool,
14
15
  initializerAddress,
@@ -41,6 +42,7 @@ export function parseUnsignedTx({ asset, unsignedTx }) {
41
42
  // staking related
42
43
  method,
43
44
  stakeAddresses,
45
+ accounts,
44
46
  seed,
45
47
  pool,
46
48
  // MagicEden escrow/related:
@@ -141,12 +141,12 @@ const createUndelegateTransaction = ({ address, recentBlockhash, stakeAddresses
141
141
  stakeAddresses,
142
142
  })
143
143
 
144
- const createWithdrawTransaction = ({ address, amount, recentBlockhash, stakeAddresses }) =>
144
+ const createWithdrawTransaction = ({ address, amount, recentBlockhash, accounts }) =>
145
145
  Transaction.withdraw({
146
146
  address,
147
147
  amount,
148
148
  recentBlockhash,
149
- stakeAddresses,
149
+ accounts,
150
150
  })
151
151
 
152
152
  const createMagicEdenInitializeEscrowTransaction = ({