@exodus/solana-api 3.11.8 → 3.11.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.
- package/CHANGELOG.md +12 -0
- package/package.json +3 -3
- package/src/account-state.js +1 -0
- package/src/api.js +7 -4
- package/src/get-balances.js +20 -1
- package/src/tx-log/solana-monitor.js +21 -6
- package/src/tx-send.js +4 -16
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.11.9](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.11.8...@exodus/solana-api@3.11.9) (2024-12-31)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: include rentExemptAmount in balance calculation (#4738)
|
|
13
|
+
|
|
14
|
+
* fix: integration tests (#4720)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
## [3.11.8](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.11.6...@exodus/solana-api@3.11.8) (2024-12-10)
|
|
7
19
|
|
|
8
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.11.
|
|
3
|
+
"version": "3.11.9",
|
|
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",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@exodus/fetch": "^1.2.0",
|
|
31
31
|
"@exodus/models": "^12.0.1",
|
|
32
32
|
"@exodus/simple-retry": "^0.0.6",
|
|
33
|
-
"@exodus/solana-lib": "^3.9.
|
|
33
|
+
"@exodus/solana-lib": "^3.9.3",
|
|
34
34
|
"@exodus/solana-meta": "^2.0.2",
|
|
35
35
|
"@exodus/timer": "^1.1.1",
|
|
36
36
|
"bn.js": "^4.11.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@exodus/assets-testing": "^1.0.0",
|
|
48
48
|
"@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "44b274a6a6f0228014aa0eaac5af850dcaf76fed",
|
|
51
51
|
"bugs": {
|
|
52
52
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
53
53
|
},
|
package/src/account-state.js
CHANGED
package/src/api.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import BN from 'bn.js'
|
|
18
18
|
import lodash from 'lodash'
|
|
19
19
|
import assert from 'minimalistic-assert'
|
|
20
|
+
import ms from 'ms'
|
|
20
21
|
import urljoin from 'url-join'
|
|
21
22
|
import wretch from 'wretch'
|
|
22
23
|
|
|
@@ -46,6 +47,12 @@ export class Api {
|
|
|
46
47
|
const result = await this.rpcCall('getTokenSupply', [mintAddress])
|
|
47
48
|
return result?.value?.amount
|
|
48
49
|
})
|
|
50
|
+
|
|
51
|
+
this.getMinimumBalanceForRentExemption = memoize(
|
|
52
|
+
(accountSize) => this.rpcCall('getMinimumBalanceForRentExemption', [accountSize]),
|
|
53
|
+
(accountSize) => accountSize,
|
|
54
|
+
ms('15m')
|
|
55
|
+
)
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
setServer(rpcUrl) {
|
|
@@ -876,10 +883,6 @@ export class Api {
|
|
|
876
883
|
}, 0)
|
|
877
884
|
}
|
|
878
885
|
|
|
879
|
-
async getMinimumBalanceForRentExemption(size) {
|
|
880
|
-
return this.rpcCall('getMinimumBalanceForRentExemption', [size])
|
|
881
|
-
}
|
|
882
|
-
|
|
883
886
|
async getProgramAccounts(programId, config) {
|
|
884
887
|
return this.rpcCall('getProgramAccounts', [programId, config])
|
|
885
888
|
}
|
package/src/get-balances.js
CHANGED
|
@@ -33,7 +33,18 @@ export const getBalancesFactory =
|
|
|
33
33
|
.clampLowerZero()
|
|
34
34
|
|
|
35
35
|
const total = stakingFeatureAvailable ? balance : balanceWithoutStaking
|
|
36
|
-
|
|
36
|
+
|
|
37
|
+
const networkReserve = accountState.rentExemptAmount || zero
|
|
38
|
+
|
|
39
|
+
const accountReserve = asset.accountReserve || zero
|
|
40
|
+
|
|
41
|
+
// there is no wallet reserve when there are no tokens nor staking actions. Just network reserve for the rent exempt amount.
|
|
42
|
+
const walletReserve =
|
|
43
|
+
hasStakedFunds({ locked, withdrawable, pending }) || hasTokensBalance({ accountState })
|
|
44
|
+
? accountReserve.sub(networkReserve).clampLowerZero()
|
|
45
|
+
: zero
|
|
46
|
+
|
|
47
|
+
const spendable = balanceWithoutStaking.sub(walletReserve).sub(networkReserve).clampLowerZero()
|
|
37
48
|
|
|
38
49
|
const staked = locked
|
|
39
50
|
const unstaking = pending
|
|
@@ -47,6 +58,8 @@ export const getBalancesFactory =
|
|
|
47
58
|
spendable,
|
|
48
59
|
staked,
|
|
49
60
|
unstaking,
|
|
61
|
+
networkReserve,
|
|
62
|
+
walletReserve,
|
|
50
63
|
}
|
|
51
64
|
}
|
|
52
65
|
|
|
@@ -93,3 +106,9 @@ const getBalanceFromAccountState = ({ asset, accountState }) => {
|
|
|
93
106
|
asset.currency.ZERO
|
|
94
107
|
)
|
|
95
108
|
}
|
|
109
|
+
|
|
110
|
+
const hasStakedFunds = ({ locked, withdrawable, pending }) =>
|
|
111
|
+
[locked, withdrawable, pending].some((amount) => amount.isPositive)
|
|
112
|
+
|
|
113
|
+
const hasTokensBalance = ({ accountState }) =>
|
|
114
|
+
Object.values(accountState?.tokenBalances || {}).some((balance) => balance.isPositive)
|
|
@@ -294,10 +294,18 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
294
294
|
|
|
295
295
|
async getAccount({ refresh, address, tokenAccounts, accountState, walletAccount }) {
|
|
296
296
|
const tokens = Object.keys(this.assets).filter((name) => name !== this.asset.name)
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
const accountInfo = await this.api.getAccountInfo(address).catch(() => {})
|
|
298
|
+
const accountSize = accountInfo?.space || 0
|
|
299
|
+
const solBalance = accountInfo?.lamports || 0
|
|
300
|
+
|
|
301
|
+
const rentExemptValue = await this.api.getMinimumBalanceForRentExemption(accountSize)
|
|
302
|
+
const rentExemptAmount = this.asset.currency.baseUnit(rentExemptValue)
|
|
303
|
+
|
|
304
|
+
const splBalances = await this.api.getTokensBalance({
|
|
305
|
+
address,
|
|
306
|
+
filterByTokens: tokens,
|
|
307
|
+
tokenAccounts,
|
|
308
|
+
})
|
|
301
309
|
|
|
302
310
|
const tokenBalances = _.mapValues(splBalances, (balance, name) =>
|
|
303
311
|
this.assets[name].currency.baseUnit(balance).toDefault()
|
|
@@ -334,14 +342,21 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
334
342
|
account: {
|
|
335
343
|
balance,
|
|
336
344
|
tokenBalances,
|
|
345
|
+
rentExemptAmount,
|
|
337
346
|
},
|
|
338
347
|
staking,
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
350
|
|
|
342
351
|
async updateState({ account, cursorState, walletAccount, staking }) {
|
|
343
|
-
const { balance, tokenBalances } = account
|
|
344
|
-
const newData = {
|
|
352
|
+
const { balance, tokenBalances, rentExemptAmount } = account
|
|
353
|
+
const newData = {
|
|
354
|
+
balance,
|
|
355
|
+
rentExemptAmount,
|
|
356
|
+
tokenBalances,
|
|
357
|
+
stakingInfo: staking,
|
|
358
|
+
...cursorState,
|
|
359
|
+
}
|
|
345
360
|
return this.updateAccountState({ newData, walletAccount })
|
|
346
361
|
}
|
|
347
362
|
|
package/src/tx-send.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
TOKEN_2022_PROGRAM_ID,
|
|
6
6
|
TOKEN_PROGRAM_ID,
|
|
7
7
|
} from '@exodus/solana-lib'
|
|
8
|
-
import { transactionToBase58 } from '@exodus/solana-lib/src/tx/common.js'
|
|
9
8
|
import assert from 'minimalistic-assert'
|
|
10
9
|
|
|
11
10
|
export const createAndBroadcastTXFactory =
|
|
@@ -34,6 +33,7 @@ export const createAndBroadcastTXFactory =
|
|
|
34
33
|
expectedMintAddress,
|
|
35
34
|
metadataAddress,
|
|
36
35
|
creators,
|
|
36
|
+
priorityFee,
|
|
37
37
|
// </MagicEden>
|
|
38
38
|
reference,
|
|
39
39
|
memo,
|
|
@@ -129,7 +129,7 @@ export const createAndBroadcastTXFactory =
|
|
|
129
129
|
from,
|
|
130
130
|
to: address,
|
|
131
131
|
amount,
|
|
132
|
-
fee: feeAmount
|
|
132
|
+
fee: feeData.fee, // feeAmount includes the priortyFee
|
|
133
133
|
recentBlockhash,
|
|
134
134
|
feeData,
|
|
135
135
|
reference,
|
|
@@ -139,26 +139,14 @@ export const createAndBroadcastTXFactory =
|
|
|
139
139
|
...magicEdenParams,
|
|
140
140
|
})
|
|
141
141
|
|
|
142
|
-
let { priorityFee } = feeData
|
|
143
|
-
|
|
144
142
|
const transactionForFeeEstimation = prepareForSigning(unsignedTransaction)
|
|
145
143
|
|
|
146
|
-
if (!priorityFee) {
|
|
147
|
-
try {
|
|
148
|
-
priorityFee = await api.getPriorityFee(transactionToBase58(transactionForFeeEstimation))
|
|
149
|
-
} catch (e) {
|
|
150
|
-
console.warn(`Failed to fetch priority fee: ${e.message}`)
|
|
151
|
-
priorityFee = feeData.fallbackPriorityFee
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
144
|
const { unitsConsumed: computeUnits, err } = await api.simulateUnsignedTransaction({
|
|
156
145
|
message: transactionForFeeEstimation.message,
|
|
157
146
|
})
|
|
147
|
+
if (err) throw new Error(JSON.stringify(err))
|
|
158
148
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
unsignedTransaction.txData.priorityFee = priorityFee
|
|
149
|
+
unsignedTransaction.txData.priorityFee = priorityFee ?? 0
|
|
162
150
|
unsignedTransaction.txData.computeUnits = computeUnits * feeData.computeUnitsMultiplier
|
|
163
151
|
|
|
164
152
|
const { txId, rawTx } = await assetClientInterface.signTransaction({
|