@exodus/solana-api 3.30.5 → 3.30.7
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 +18 -0
- package/package.json +3 -3
- package/src/api.js +9 -13
- package/src/clarity-api.js +2 -6
- package/src/rpc-api.js +36 -11
- package/src/ws-api.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
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.30.7](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.30.6...@exodus/solana-api@3.30.7) (2026-04-01)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: addressIsActive users tx history (#7708)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [3.30.6](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.30.5...@exodus/solana-api@3.30.6) (2026-03-30)
|
|
17
|
+
|
|
18
|
+
**Note:** Version bump only for package @exodus/solana-api
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [3.30.5](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.30.4...@exodus/solana-api@3.30.5) (2026-03-27)
|
|
7
25
|
|
|
8
26
|
**Note:** Version bump only for package @exodus/solana-api
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.30.
|
|
3
|
+
"version": "3.30.7",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@exodus/fetch": "^1.7.3",
|
|
34
34
|
"@exodus/models": "^13.0.0",
|
|
35
35
|
"@exodus/simple-retry": "^0.0.6",
|
|
36
|
-
"@exodus/solana-lib": "^3.22.
|
|
36
|
+
"@exodus/solana-lib": "^3.22.3",
|
|
37
37
|
"@exodus/solana-meta": "^2.0.2",
|
|
38
38
|
"@exodus/timer": "^1.1.1",
|
|
39
39
|
"debug": "^4.1.1",
|
|
@@ -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": "3a8c58c8457a1d096ee5d3ecb2eea9e82b69ecb7",
|
|
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
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
findAssociatedTokenAddress,
|
|
13
13
|
getMetadataAccount,
|
|
14
14
|
getTransactionSimulationParams,
|
|
15
|
+
isSystemProgram,
|
|
16
|
+
isTokenProgram,
|
|
15
17
|
SOL_DECIMAL,
|
|
16
18
|
STAKE_PROGRAM_ID,
|
|
17
|
-
SYSTEM_PROGRAM_ID,
|
|
18
19
|
TOKEN_2022_PROGRAM_ID,
|
|
19
20
|
TOKEN_PROGRAM_ID,
|
|
20
21
|
} from '@exodus/solana-lib'
|
|
@@ -455,11 +456,7 @@ export class Api {
|
|
|
455
456
|
const value = accountInfo || (await this.getAccountInfo(address))
|
|
456
457
|
const owner = value?.owner // program owner
|
|
457
458
|
if (!owner) return false // not initialized account (or purged)
|
|
458
|
-
return !
|
|
459
|
-
SYSTEM_PROGRAM_ID.toBase58(),
|
|
460
|
-
TOKEN_PROGRAM_ID.toBase58(),
|
|
461
|
-
TOKEN_2022_PROGRAM_ID.toBase58(),
|
|
462
|
-
].includes(owner)
|
|
459
|
+
return !(isSystemProgram(owner) || isTokenProgram(owner))
|
|
463
460
|
}
|
|
464
461
|
|
|
465
462
|
async fetchValidatedDelegation({ delegatedAddress, expectedDelegate }) {
|
|
@@ -500,14 +497,13 @@ export class Api {
|
|
|
500
497
|
}
|
|
501
498
|
|
|
502
499
|
/**
|
|
503
|
-
* Returns true if the
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
* runtime deleted the account, RPC returns null.
|
|
500
|
+
* Returns true if the address has any transaction history.
|
|
501
|
+
* Solana system accounts can be reclaimed after staying below rent exemption, so
|
|
502
|
+
* current account info is not a reliable signal for whether an address was ever used.
|
|
507
503
|
*/
|
|
508
504
|
async addressIsActive(address) {
|
|
509
|
-
const
|
|
510
|
-
return
|
|
505
|
+
const signatures = await this.getSignaturesForAddress(address, { limit: 1 })
|
|
506
|
+
return signatures.length > 0
|
|
511
507
|
}
|
|
512
508
|
|
|
513
509
|
async isSpl(address) {
|
|
@@ -552,7 +548,7 @@ export class Api {
|
|
|
552
548
|
lamports: value.lamports,
|
|
553
549
|
}
|
|
554
550
|
|
|
555
|
-
if (account.owner
|
|
551
|
+
if (isSystemProgram(account.owner)) return 'solana'
|
|
556
552
|
if (account.owner === TOKEN_PROGRAM_ID.toBase58()) return 'token'
|
|
557
553
|
if (account.owner === TOKEN_2022_PROGRAM_ID.toBase58()) return 'token-2022'
|
|
558
554
|
return null
|
package/src/clarity-api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memoizeLruCache } from '@exodus/asset-lib'
|
|
2
2
|
import { isNil, memoize, omitBy } from '@exodus/basic-utils'
|
|
3
3
|
import wretch from '@exodus/fetch/wretch'
|
|
4
|
-
import {
|
|
4
|
+
import { isSystemProgram, isTokenProgram, TOKEN_PROGRAM_ID } from '@exodus/solana-lib'
|
|
5
5
|
import ms from 'ms'
|
|
6
6
|
import urljoin from 'url-join'
|
|
7
7
|
|
|
@@ -205,11 +205,7 @@ export class ClarityApi extends RpcApi {
|
|
|
205
205
|
const value = accountInfo || (await this.getAccountInfo(address))
|
|
206
206
|
const owner = value?.owner // program owner
|
|
207
207
|
if (!owner) return false // not initialized account (or purged)
|
|
208
|
-
return !
|
|
209
|
-
SYSTEM_PROGRAM_ID.toBase58(),
|
|
210
|
-
TOKEN_PROGRAM_ID.toBase58(),
|
|
211
|
-
TOKEN_2022_PROGRAM_ID.toBase58(),
|
|
212
|
-
].includes(owner)
|
|
208
|
+
return !(isSystemProgram(owner) || isTokenProgram(owner))
|
|
213
209
|
}
|
|
214
210
|
|
|
215
211
|
ataOwnershipChangedCached = memoizeLruCache(
|
package/src/rpc-api.js
CHANGED
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
findAssociatedTokenAddress,
|
|
11
11
|
getMetadataAccount,
|
|
12
12
|
getTransactionSimulationParams,
|
|
13
|
+
isSystemProgram,
|
|
14
|
+
isTokenProgram,
|
|
13
15
|
SOL_DECIMAL,
|
|
14
|
-
SYSTEM_PROGRAM_ID as SYSTEM_PROGRAM_ID_KEY,
|
|
15
16
|
TOKEN_2022_PROGRAM_ID as TOKEN_2022_PROGRAM_ID_KEY,
|
|
16
17
|
TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID_KEY,
|
|
17
18
|
} from '@exodus/solana-lib'
|
|
@@ -24,8 +25,7 @@ import {
|
|
|
24
25
|
fetchValidatedDelegation as _fetchValidatedDelegation,
|
|
25
26
|
} from './tx-log/delegation-utils.js'
|
|
26
27
|
|
|
27
|
-
const [
|
|
28
|
-
SYSTEM_PROGRAM_ID_KEY.toBase58(),
|
|
28
|
+
const [TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID] = [
|
|
29
29
|
TOKEN_PROGRAM_ID_KEY.toBase58(),
|
|
30
30
|
TOKEN_2022_PROGRAM_ID_KEY.toBase58(),
|
|
31
31
|
]
|
|
@@ -190,6 +190,32 @@ export class RpcApi {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
async getSignaturesForAddress(address, { until, before, limit } = {}) {
|
|
194
|
+
until = until || undefined
|
|
195
|
+
|
|
196
|
+
const fetchRetry = retry(
|
|
197
|
+
async () => {
|
|
198
|
+
try {
|
|
199
|
+
return await this.rpcCall('getSignaturesForAddress', [address, { until, before, limit }])
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (
|
|
202
|
+
error.message &&
|
|
203
|
+
!errorMessagesToRetry.some((errorMessage) => error.message.includes(errorMessage))
|
|
204
|
+
) {
|
|
205
|
+
error.finalError = true
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.warn(`Error getting signatures. Retrying...`, error)
|
|
209
|
+
|
|
210
|
+
throw error
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{ delayTimesMs: ['8s', '10s', '15s'] }
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return fetchRetry()
|
|
217
|
+
}
|
|
218
|
+
|
|
193
219
|
async getWalletTokensList({ tokenAccounts }) {
|
|
194
220
|
const tokensMint = []
|
|
195
221
|
for (const account of tokenAccounts) {
|
|
@@ -217,7 +243,7 @@ export class RpcApi {
|
|
|
217
243
|
|
|
218
244
|
async isSpl(address) {
|
|
219
245
|
const { owner } = await this.getAccountInfo(address)
|
|
220
|
-
return
|
|
246
|
+
return isTokenProgram(owner)
|
|
221
247
|
}
|
|
222
248
|
|
|
223
249
|
async getRawAccountInfo({ address, encoding = 'jsonParsed' }) {
|
|
@@ -244,14 +270,13 @@ export class RpcApi {
|
|
|
244
270
|
}
|
|
245
271
|
|
|
246
272
|
/**
|
|
247
|
-
* Returns true if the
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
* runtime deleted the account, RPC returns null.
|
|
273
|
+
* Returns true if the address has any transaction history.
|
|
274
|
+
* Solana system accounts can be reclaimed after staying below rent exemption, so
|
|
275
|
+
* current account info is not a reliable signal for whether an address was ever used.
|
|
251
276
|
*/
|
|
252
277
|
async addressIsActive(address) {
|
|
253
|
-
const
|
|
254
|
-
return
|
|
278
|
+
const signatures = await this.getSignaturesForAddress(address, { limit: 1 })
|
|
279
|
+
return signatures.length > 0
|
|
255
280
|
}
|
|
256
281
|
|
|
257
282
|
async getTokenFeeBasisPoints(address) {
|
|
@@ -292,7 +317,7 @@ export class RpcApi {
|
|
|
292
317
|
lamports: value.lamports,
|
|
293
318
|
}
|
|
294
319
|
|
|
295
|
-
if (account.owner
|
|
320
|
+
if (isSystemProgram(account.owner)) return 'solana'
|
|
296
321
|
if (account.owner === TOKEN_PROGRAM_ID) return 'token'
|
|
297
322
|
if (account.owner === TOKEN_2022_PROGRAM_ID) return 'token-2022'
|
|
298
323
|
return null
|
package/src/ws-api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isSystemProgram,
|
|
2
3
|
isTokenProgram,
|
|
3
4
|
PublicKey,
|
|
4
5
|
Token,
|
|
@@ -392,8 +393,7 @@ export class WsApi {
|
|
|
392
393
|
*/
|
|
393
394
|
parseAccountNotification({ address, walletAccount, tokenAccountsByOwner, result }) {
|
|
394
395
|
const value = result?.value ?? result // support both { context, value } and flat result
|
|
395
|
-
|
|
396
|
-
if (isSolAccount) {
|
|
396
|
+
if (isSystemProgram(value.owner)) {
|
|
397
397
|
// SOL balance changed
|
|
398
398
|
const amount = value.lamports
|
|
399
399
|
return { solAddress: address, amount }
|