@exodus/solana-api 3.26.0 → 3.26.2
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 +22 -0
- package/package.json +2 -2
- package/src/api.js +0 -8
- package/src/create-unsigned-tx-for-send.js +3 -0
- package/src/rpc-api.js +0 -8
- package/src/tx-log/clarity-monitor.js +24 -6
- package/src/tx-log/solana-monitor.js +16 -5
- package/src/tx-send.js +4 -17
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
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.26.2](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.26.1...@exodus/solana-api@3.26.2) (2025-12-15)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @exodus/solana-api
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [3.26.1](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.26.0...@exodus/solana-api@3.26.1) (2025-12-12)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
* fix: remove unused SOL RPC call (#7107)
|
|
21
|
+
|
|
22
|
+
* fix: SOL pending sent txs (#7105)
|
|
23
|
+
|
|
24
|
+
* fix: use batch operations for Solana monitors (#7085)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [3.26.0](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.25.4...@exodus/solana-api@3.26.0) (2025-12-08)
|
|
7
29
|
|
|
8
30
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.26.
|
|
3
|
+
"version": "3.26.2",
|
|
4
4
|
"description": "Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Solana",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@exodus/assets-testing": "^1.0.0",
|
|
50
50
|
"@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "937ac1707d279c2dda93b162586b5a596236ce08",
|
|
53
53
|
"bugs": {
|
|
54
54
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
55
55
|
},
|
package/src/api.js
CHANGED
|
@@ -127,14 +127,6 @@ export class Api {
|
|
|
127
127
|
])
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
async getPriorityFee(transaction) {
|
|
131
|
-
// https://docs.helius.dev/solana-rpc-nodes/alpha-priority-fee-api
|
|
132
|
-
const result = await this.rpcCall('getPriorityFeeEstimate', [
|
|
133
|
-
{ transaction, options: { recommended: true } },
|
|
134
|
-
])
|
|
135
|
-
return result.priorityFeeEstimate
|
|
136
|
-
}
|
|
137
|
-
|
|
138
130
|
async getBalance(address) {
|
|
139
131
|
const result = await this.rpcCall('getBalance', [address, { encoding: 'jsonParsed' }])
|
|
140
132
|
return lodash.get(result, 'value', 0)
|
|
@@ -24,6 +24,7 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
24
24
|
feeData: providedFeeData,
|
|
25
25
|
fromAddress: providedFromAddress,
|
|
26
26
|
toAddress,
|
|
27
|
+
address,
|
|
27
28
|
amount,
|
|
28
29
|
reference,
|
|
29
30
|
memo,
|
|
@@ -56,6 +57,8 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
56
57
|
assert(asset, 'asset is required')
|
|
57
58
|
assert(walletAccount, 'walletAccount is required')
|
|
58
59
|
|
|
60
|
+
toAddress = toAddress ?? address
|
|
61
|
+
|
|
59
62
|
let tokenParams = Object.create(null)
|
|
60
63
|
|
|
61
64
|
const baseAsset = asset.baseAsset
|
package/src/rpc-api.js
CHANGED
|
@@ -112,14 +112,6 @@ export class RpcApi {
|
|
|
112
112
|
return result?.value?.blockhash
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
async getPriorityFee(transaction) {
|
|
116
|
-
// https://docs.helius.dev/solana-rpc-nodes/alpha-priority-fee-api
|
|
117
|
-
const result = await this.rpcCall('getPriorityFeeEstimate', [
|
|
118
|
-
{ transaction, options: { recommended: true } },
|
|
119
|
-
])
|
|
120
|
-
return result.priorityFeeEstimate
|
|
121
|
-
}
|
|
122
|
-
|
|
123
115
|
async getBlockTime(slot) {
|
|
124
116
|
// might result in error if executed on a validator with partial ledger (https://github.com/solana-labs/solana/issues/12413)
|
|
125
117
|
return this.rpcCall('getBlockTime', [slot])
|
|
@@ -128,13 +128,22 @@ export class SolanaClarityMonitor extends BaseMonitor {
|
|
|
128
128
|
const isHistoryUpdateTick =
|
|
129
129
|
this.tickCount[walletAccount] % this.ticksBetweenHistoryFetches === 0
|
|
130
130
|
|
|
131
|
-
const
|
|
131
|
+
const baseAssetTxLog = await this.aci.getTxLog({
|
|
132
|
+
assetName,
|
|
133
|
+
walletAccount,
|
|
134
|
+
})
|
|
135
|
+
const hasUnconfirmedSentTx = [...baseAssetTxLog].some((tx) => tx.pending && tx.sent)
|
|
136
|
+
|
|
137
|
+
const shouldUpdateHistory =
|
|
138
|
+
refresh || isHistoryUpdateTick || balanceChanged || hasUnconfirmedSentTx
|
|
132
139
|
const shouldUpdateOnlyBalance = balanceChanged && !shouldUpdateHistory
|
|
133
140
|
|
|
141
|
+
// start a batch
|
|
142
|
+
const batch = this.aci.createOperationsBatch()
|
|
134
143
|
// getHistory is more likely to fail/be rate limited, so we want to update users balance only on a lot of ticks
|
|
135
144
|
if (this.shouldUpdateBalanceBeforeHistory || shouldUpdateOnlyBalance) {
|
|
136
145
|
// update all state at once
|
|
137
|
-
|
|
146
|
+
this.updateState({ account, walletAccount, staking, batch })
|
|
138
147
|
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
139
148
|
}
|
|
140
149
|
|
|
@@ -151,13 +160,21 @@ export class SolanaClarityMonitor extends BaseMonitor {
|
|
|
151
160
|
|
|
152
161
|
// update all state at once
|
|
153
162
|
const clearedLogItems = await this.markStaleTransactions({ walletAccount, logItemsByAsset })
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
this.updateTxLogByAssetBatch({
|
|
164
|
+
logItemsByAsset: clearedLogItems,
|
|
165
|
+
walletAccount,
|
|
166
|
+
refresh,
|
|
167
|
+
batch,
|
|
168
|
+
})
|
|
169
|
+
this.updateState({ account, cursorState, walletAccount, staking, batch })
|
|
156
170
|
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
157
171
|
if (refresh || cursorChanged) {
|
|
158
172
|
this.cursors[walletAccount] = cursorState.cursor
|
|
159
173
|
}
|
|
160
174
|
}
|
|
175
|
+
|
|
176
|
+
// close batch
|
|
177
|
+
await this.aci.executeOperationsBatch(batch)
|
|
161
178
|
}
|
|
162
179
|
|
|
163
180
|
async getHistory({ address, accountState, refresh, tokenAccounts } = Object.create(null)) {
|
|
@@ -319,7 +336,8 @@ export class SolanaClarityMonitor extends BaseMonitor {
|
|
|
319
336
|
}
|
|
320
337
|
}
|
|
321
338
|
|
|
322
|
-
|
|
339
|
+
updateState({ account, cursorState = {}, walletAccount, staking, batch }) {
|
|
340
|
+
const assetName = this.asset.name
|
|
323
341
|
const { balance, tokenBalances, rentExemptAmount, accountSize, ownerChanged } = account
|
|
324
342
|
const newData = {
|
|
325
343
|
balance,
|
|
@@ -330,7 +348,7 @@ export class SolanaClarityMonitor extends BaseMonitor {
|
|
|
330
348
|
stakingInfo: staking,
|
|
331
349
|
...cursorState,
|
|
332
350
|
}
|
|
333
|
-
return this.
|
|
351
|
+
return this.updateAccountStateBatch({ assetName, walletAccount, newData, batch })
|
|
334
352
|
}
|
|
335
353
|
|
|
336
354
|
async getStakingInfo({ address, accountState, walletAccount }) {
|
|
@@ -170,10 +170,12 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
170
170
|
const shouldUpdateHistory = refresh || isHistoryUpdateTick || balanceChanged
|
|
171
171
|
const shouldUpdateOnlyBalance = balanceChanged && !shouldUpdateHistory
|
|
172
172
|
|
|
173
|
+
// start a batch
|
|
174
|
+
const batch = this.aci.createOperationsBatch()
|
|
173
175
|
// getHistory is more likely to fail/be rate limited, so we want to update users balance only on a lot of ticks
|
|
174
176
|
if (this.shouldUpdateBalanceBeforeHistory || shouldUpdateOnlyBalance) {
|
|
175
177
|
// update all state at once
|
|
176
|
-
|
|
178
|
+
this.updateState({ account, walletAccount, staking, batch })
|
|
177
179
|
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -190,13 +192,21 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
190
192
|
|
|
191
193
|
// update all state at once
|
|
192
194
|
const clearedLogItems = await this.markStaleTransactions({ walletAccount, logItemsByAsset })
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
this.updateTxLogByAssetBatch({
|
|
196
|
+
logItemsByAsset: clearedLogItems,
|
|
197
|
+
walletAccount,
|
|
198
|
+
refresh,
|
|
199
|
+
batch,
|
|
200
|
+
})
|
|
201
|
+
this.updateState({ account, cursorState, walletAccount, staking, batch })
|
|
195
202
|
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
196
203
|
if (refresh || cursorChanged) {
|
|
197
204
|
this.cursors[walletAccount] = cursorState.cursor
|
|
198
205
|
}
|
|
199
206
|
}
|
|
207
|
+
|
|
208
|
+
// close batch
|
|
209
|
+
await this.aci.executeOperationsBatch(batch)
|
|
200
210
|
}
|
|
201
211
|
|
|
202
212
|
async getHistory({ address, accountState, refresh, tokenAccounts } = Object.create(null)) {
|
|
@@ -352,7 +362,8 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
352
362
|
}
|
|
353
363
|
}
|
|
354
364
|
|
|
355
|
-
|
|
365
|
+
updateState({ account, cursorState = {}, walletAccount, staking, batch }) {
|
|
366
|
+
const assetName = this.asset.name
|
|
356
367
|
const { balance, tokenBalances, rentExemptAmount, accountSize, ownerChanged } = account
|
|
357
368
|
const newData = {
|
|
358
369
|
balance,
|
|
@@ -363,7 +374,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
363
374
|
stakingInfo: staking,
|
|
364
375
|
...cursorState,
|
|
365
376
|
}
|
|
366
|
-
return this.
|
|
377
|
+
return this.updateAccountStateBatch({ assetName, walletAccount, newData, batch })
|
|
367
378
|
}
|
|
368
379
|
|
|
369
380
|
async getStakingInfo({ address, accountState, walletAccount }) {
|
package/src/tx-send.js
CHANGED
|
@@ -6,26 +6,13 @@ export const createAndBroadcastTXFactory = ({ api, assetClientInterface }) => {
|
|
|
6
6
|
assert(assetClientInterface, 'assetClientInterface is required')
|
|
7
7
|
assert(api, 'api is required')
|
|
8
8
|
|
|
9
|
-
return async ({ asset, walletAccount, unsignedTx:
|
|
9
|
+
return async ({ asset, walletAccount, unsignedTx: providedUnsignedTx, ...legacyParams }) => {
|
|
10
10
|
const assetName = asset.name
|
|
11
11
|
const baseAsset = asset.baseAsset
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return baseAsset.api.createTx({
|
|
19
|
-
asset,
|
|
20
|
-
walletAccount,
|
|
21
|
-
amount: legacyParams.amount,
|
|
22
|
-
toAddress: legacyParams.address,
|
|
23
|
-
...legacyParams,
|
|
24
|
-
...legacyParams.options,
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const unsignedTx = await resolveTxs()
|
|
13
|
+
const { unsignedTx } = providedUnsignedTx
|
|
14
|
+
? { unsignedTx: providedUnsignedTx }
|
|
15
|
+
: await baseAsset.api.createTx({ asset, walletAccount, ...legacyParams })
|
|
29
16
|
|
|
30
17
|
const signedTx = await assetClientInterface.signTransaction({
|
|
31
18
|
assetName: baseAsset.name,
|