@exodus/solana-api 3.19.0 → 3.20.1
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 +20 -0
- package/package.json +2 -2
- package/src/account-state.js +1 -0
- package/src/api.js +13 -0
- package/src/get-balances.js +49 -22
- package/src/tx-log/solana-monitor.js +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.20.1](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.20.0...@exodus/solana-api@3.20.1) (2025-06-11)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: SOL owner changed check (#5805)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [3.20.0](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.19.0...@exodus/solana-api@3.20.0) (2025-06-11)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* feat(solana): implement unconfirmedSent/unconfirmedReceived in solana balances (#5802)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [3.19.0](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.18.2...@exodus/solana-api@3.19.0) (2025-06-10)
|
|
7
27
|
|
|
8
28
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.1",
|
|
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",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@exodus/assets-testing": "^1.0.0",
|
|
47
47
|
"@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "8302af88cf085350c4c0149ab5e581e8297c548b",
|
|
50
50
|
"bugs": {
|
|
51
51
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
52
52
|
},
|
package/src/account-state.js
CHANGED
package/src/api.js
CHANGED
|
@@ -953,6 +953,19 @@ export class Api {
|
|
|
953
953
|
return owner && owner !== address
|
|
954
954
|
}
|
|
955
955
|
|
|
956
|
+
async ownerChanged(address, accountInfo) {
|
|
957
|
+
// method to check if the owner of the account has changed, compared to standard programs.
|
|
958
|
+
// as there could be malicious dapps that reassign the ownership of the account (see https://github.com/coinspect/solana-assign-test)
|
|
959
|
+
const value = accountInfo || (await this.getAccountInfo(address))
|
|
960
|
+
const owner = value?.owner // program owner
|
|
961
|
+
if (!owner) return false // not initialized account (or purged)
|
|
962
|
+
return ![
|
|
963
|
+
SYSTEM_PROGRAM_ID.toBase58(),
|
|
964
|
+
TOKEN_PROGRAM_ID.toBase58(),
|
|
965
|
+
TOKEN_2022_PROGRAM_ID.toBase58(),
|
|
966
|
+
].includes(owner)
|
|
967
|
+
}
|
|
968
|
+
|
|
956
969
|
ataOwnershipChangedCached = memoizeLruCache(
|
|
957
970
|
(...args) => this.ataOwnershipChanged(...args),
|
|
958
971
|
(address, tokenAddress) => `${address}:${tokenAddress}`,
|
package/src/get-balances.js
CHANGED
|
@@ -8,7 +8,15 @@ export const getBalancesFactory =
|
|
|
8
8
|
({ asset, accountState, txLog }) => {
|
|
9
9
|
const zero = asset.currency.ZERO
|
|
10
10
|
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
balance,
|
|
13
|
+
locked,
|
|
14
|
+
activating,
|
|
15
|
+
withdrawable,
|
|
16
|
+
pending,
|
|
17
|
+
unconfirmedSent,
|
|
18
|
+
unconfirmedReceived,
|
|
19
|
+
} = fixBalances({
|
|
12
20
|
txLog,
|
|
13
21
|
balance: getBalanceFromAccountState({ asset, accountState }),
|
|
14
22
|
locked: accountState.stakingInfo?.locked || zero,
|
|
@@ -16,6 +24,8 @@ export const getBalancesFactory =
|
|
|
16
24
|
activating: accountState.stakingInfo?.activating || zero,
|
|
17
25
|
pending: accountState.stakingInfo?.pending || zero,
|
|
18
26
|
asset,
|
|
27
|
+
unconfirmedSent: zero,
|
|
28
|
+
unconfirmedReceived: zero,
|
|
19
29
|
})
|
|
20
30
|
if (asset.baseAsset.name !== asset.name) {
|
|
21
31
|
return {
|
|
@@ -70,6 +80,8 @@ export const getBalancesFactory =
|
|
|
70
80
|
unstaking,
|
|
71
81
|
networkReserve,
|
|
72
82
|
walletReserve: zero,
|
|
83
|
+
unconfirmedSent,
|
|
84
|
+
unconfirmedReceived,
|
|
73
85
|
}
|
|
74
86
|
}
|
|
75
87
|
|
|
@@ -81,41 +93,56 @@ const fixBalances = ({
|
|
|
81
93
|
activating,
|
|
82
94
|
pending,
|
|
83
95
|
asset,
|
|
96
|
+
unconfirmedSent,
|
|
97
|
+
unconfirmedReceived,
|
|
84
98
|
}) => {
|
|
85
99
|
for (const tx of txLog) {
|
|
86
|
-
if (
|
|
100
|
+
if (!tx.pending || tx.error) {
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (tx.data.staking) {
|
|
105
|
+
if (tx.coinAmount.unitType.equals(tx.feeAmount.unitType)) {
|
|
106
|
+
unconfirmedSent = unconfirmedSent.add(tx.feeAmount)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// staking tx
|
|
110
|
+
switch (tx.data.staking?.method) {
|
|
111
|
+
case 'delegate':
|
|
112
|
+
activating = activating.add(tx.coinAmount.abs())
|
|
113
|
+
break
|
|
114
|
+
case 'withdraw':
|
|
115
|
+
withdrawable = asset.currency.ZERO
|
|
116
|
+
break
|
|
117
|
+
case 'undelegate':
|
|
118
|
+
pending = pending.add(locked).add(activating)
|
|
119
|
+
locked = asset.currency.ZERO
|
|
120
|
+
activating = asset.currency.ZERO
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
} else if (tx.sent) {
|
|
87
124
|
if (tx.coinAmount.unitType.equals(tx.feeAmount.unitType)) {
|
|
88
|
-
|
|
125
|
+
unconfirmedSent = unconfirmedSent.add(tx.feeAmount)
|
|
89
126
|
}
|
|
90
127
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
activating = activating.add(tx.coinAmount.abs())
|
|
96
|
-
break
|
|
97
|
-
case 'withdraw':
|
|
98
|
-
withdrawable = asset.currency.ZERO
|
|
99
|
-
break
|
|
100
|
-
case 'undelegate':
|
|
101
|
-
pending = pending.add(locked).add(activating)
|
|
102
|
-
locked = asset.currency.ZERO
|
|
103
|
-
activating = asset.currency.ZERO
|
|
104
|
-
break
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
// coinAmount is negative for sent tx
|
|
108
|
-
balance = balance.sub(tx.coinAmount.abs())
|
|
128
|
+
unconfirmedSent = unconfirmedSent.add(tx.coinAmount.abs())
|
|
129
|
+
} else if (tx.received) {
|
|
130
|
+
if (tx.coinAmount.unitType.equals(tx.feeAmount.unitType)) {
|
|
131
|
+
unconfirmedReceived = unconfirmedReceived.sub(tx.feeAmount)
|
|
109
132
|
}
|
|
133
|
+
|
|
134
|
+
unconfirmedReceived = unconfirmedReceived.add(tx.coinAmount.abs())
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
|
|
113
138
|
return {
|
|
114
|
-
balance: balance.clampLowerZero(),
|
|
139
|
+
balance: balance.sub(unconfirmedSent).clampLowerZero(),
|
|
115
140
|
locked: locked.clampLowerZero(),
|
|
116
141
|
withdrawable: withdrawable.clampLowerZero(),
|
|
117
142
|
activating: activating.clampLowerZero(),
|
|
118
143
|
pending: pending.clampLowerZero(),
|
|
144
|
+
unconfirmedSent,
|
|
145
|
+
unconfirmedReceived,
|
|
119
146
|
}
|
|
120
147
|
}
|
|
121
148
|
|
|
@@ -305,6 +305,8 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
305
305
|
await this.api.getMinimumBalanceForRentExemption(accountSize)
|
|
306
306
|
)
|
|
307
307
|
|
|
308
|
+
const ownerChanged = await this.api.ownerChanged(address, accountInfo)
|
|
309
|
+
|
|
308
310
|
const tokenBalances = _.mapValues(splBalances, (balance, name) =>
|
|
309
311
|
this.assets[name].currency.baseUnit(balance)
|
|
310
312
|
)
|
|
@@ -343,6 +345,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
343
345
|
tokenBalances,
|
|
344
346
|
rentExemptAmount,
|
|
345
347
|
accountSize,
|
|
348
|
+
ownerChanged,
|
|
346
349
|
},
|
|
347
350
|
staking,
|
|
348
351
|
tokenAccounts,
|
|
@@ -350,11 +353,12 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
350
353
|
}
|
|
351
354
|
|
|
352
355
|
async updateState({ account, cursorState, walletAccount, staking }) {
|
|
353
|
-
const { balance, tokenBalances, rentExemptAmount, accountSize } = account
|
|
356
|
+
const { balance, tokenBalances, rentExemptAmount, accountSize, ownerChanged } = account
|
|
354
357
|
const newData = {
|
|
355
358
|
balance,
|
|
356
359
|
rentExemptAmount,
|
|
357
360
|
accountSize,
|
|
361
|
+
ownerChanged,
|
|
358
362
|
tokenBalances,
|
|
359
363
|
stakingInfo: staking,
|
|
360
364
|
...cursorState,
|