@exodus/solana-api 2.5.31 → 2.5.33
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/package.json +3 -3
- package/src/api.js +3 -1
- package/src/tx-log/solana-monitor.js +77 -16
- package/src/tx-send.js +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.33",
|
|
4
4
|
"description": "Exodus internal Solana asset API wrapper",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@exodus/asset-json-rpc": "^1.0.0",
|
|
24
|
-
"@exodus/asset-lib": "^4.
|
|
24
|
+
"@exodus/asset-lib": "^4.1.0",
|
|
25
25
|
"@exodus/assets": "^9.0.1",
|
|
26
26
|
"@exodus/basic-utils": "^2.1.0",
|
|
27
27
|
"@exodus/currency": "^2.3.2",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@exodus/assets-testing": "^1.0.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "a35477168e62cc23a0d047983278b64ef1081a97"
|
|
48
48
|
}
|
package/src/api.js
CHANGED
|
@@ -28,11 +28,12 @@ const FORCE_HTTP = true // use https over ws
|
|
|
28
28
|
|
|
29
29
|
// Tokens + SOL api support
|
|
30
30
|
export class Api {
|
|
31
|
-
constructor({ rpcUrl, wsUrl, assets }) {
|
|
31
|
+
constructor({ rpcUrl, wsUrl, assets, txsLimit }) {
|
|
32
32
|
this.setServer(rpcUrl)
|
|
33
33
|
this.setWsEndpoint(wsUrl)
|
|
34
34
|
this.setTokens(assets)
|
|
35
35
|
this.tokensToSkip = {}
|
|
36
|
+
this.txsLimit = txsLimit
|
|
36
37
|
this.connections = {}
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -167,6 +168,7 @@ export class Api {
|
|
|
167
168
|
* Get transactions from an address
|
|
168
169
|
*/
|
|
169
170
|
async getTransactions(address, { cursor, before, limit, includeUnparsed = false } = {}) {
|
|
171
|
+
limit = limit || this.txsLimit
|
|
170
172
|
let transactions = []
|
|
171
173
|
// cursor is a txHash
|
|
172
174
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseMonitor } from '@exodus/asset-lib'
|
|
2
2
|
import _ from 'lodash'
|
|
3
3
|
import assert from 'minimalistic-assert'
|
|
4
|
+
import ms from 'ms'
|
|
4
5
|
|
|
5
6
|
const DEFAULT_POOL_ADDRESS = '9QU2QSxhb24FUX3Tu2FpczXjpK3VYrvRudywSZaM29mF' // Everstake
|
|
6
7
|
|
|
@@ -10,14 +11,26 @@ const DEFAULT_REMOTE_CONFIG = {
|
|
|
10
11
|
staking: { enabled: true, pool: DEFAULT_POOL_ADDRESS },
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
const TICKS_BETWEEN_HISTORY_FETCHES = 10
|
|
15
|
+
const TICKS_BETWEEN_STAKE_FETCHES = 5
|
|
16
|
+
const TX_STALE_AFTER = ms('2m') // mark txs as dropped after N minutes
|
|
17
|
+
|
|
13
18
|
export class SolanaMonitor extends BaseMonitor {
|
|
14
|
-
constructor({
|
|
19
|
+
constructor({
|
|
20
|
+
api,
|
|
21
|
+
includeUnparsed = false,
|
|
22
|
+
ticksBetweenHistoryFetches = TICKS_BETWEEN_HISTORY_FETCHES,
|
|
23
|
+
ticksBetweenStakeFetches = TICKS_BETWEEN_STAKE_FETCHES,
|
|
24
|
+
...args
|
|
25
|
+
}) {
|
|
15
26
|
super(args)
|
|
16
27
|
assert(api, 'api is required')
|
|
17
28
|
this.api = api
|
|
18
29
|
this.cursors = {}
|
|
19
30
|
this.assets = {}
|
|
20
31
|
this.staking = DEFAULT_REMOTE_CONFIG.staking
|
|
32
|
+
this.ticksBetweenStakeFetches = ticksBetweenStakeFetches
|
|
33
|
+
this.ticksBetweenHistoryFetches = ticksBetweenHistoryFetches
|
|
21
34
|
this.includeUnparsed = includeUnparsed
|
|
22
35
|
this.addHook('before-stop', (...args) => this.beforeStop(...args))
|
|
23
36
|
}
|
|
@@ -87,6 +100,37 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
87
100
|
return _.uniq(stakingAddresses.flat())
|
|
88
101
|
}
|
|
89
102
|
|
|
103
|
+
#balanceChanged({ account, newAccount }) {
|
|
104
|
+
const solBalanceChanged = !account.balance || !account.balance.equals(newAccount.balance)
|
|
105
|
+
if (solBalanceChanged) return true
|
|
106
|
+
|
|
107
|
+
// token balance changed
|
|
108
|
+
return (
|
|
109
|
+
!account.tokenBalances ||
|
|
110
|
+
Object.entries(newAccount.tokenBalances).some(
|
|
111
|
+
([token, balance]) =>
|
|
112
|
+
!account.tokenBalances[token] || !account.tokenBalances[token].equals(balance)
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async markStaleTransactions({ walletAccount, logItemsByAsset = {} }) {
|
|
118
|
+
// mark stale txs as dropped in logItemsByAsset
|
|
119
|
+
const clearedLogItems = logItemsByAsset
|
|
120
|
+
const tokenNames = [...this.api.tokens.values()].map(({ name }) => name)
|
|
121
|
+
const assets = [this.asset.name, ...tokenNames]
|
|
122
|
+
|
|
123
|
+
for (const assetName of assets) {
|
|
124
|
+
const txSet = await this.aci.getTxLog({ assetName, walletAccount })
|
|
125
|
+
const { stale } = this.getUnconfirmed({ txSet, staleTxAge: TX_STALE_AFTER })
|
|
126
|
+
if (stale.length > 0) {
|
|
127
|
+
clearedLogItems[assetName] = _.unionBy(logItemsByAsset[assetName], stale, 'txId')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return clearedLogItems
|
|
132
|
+
}
|
|
133
|
+
|
|
90
134
|
async tick({ walletAccount, refresh }) {
|
|
91
135
|
// Check for new wallet account
|
|
92
136
|
await this.initWalletAccount({ walletAccount })
|
|
@@ -99,28 +143,45 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
99
143
|
const address = await this.aci.getReceiveAddress({ assetName, walletAccount, useCache: true })
|
|
100
144
|
const stakingAddresses = await this.getStakingAddressesFromTxLog({ assetName, walletAccount })
|
|
101
145
|
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
146
|
+
const fetchStakingInfo = this.tickCount[walletAccount] % this.ticksBetweenStakeFetches === 0
|
|
147
|
+
const staking = fetchStakingInfo
|
|
148
|
+
? await this.getStakingInfo({ address, stakingAddresses })
|
|
149
|
+
: accountState.mem
|
|
150
|
+
|
|
151
|
+
const tokenAccounts = await this.api.getTokenAccountsByOwner(address)
|
|
152
|
+
const account = await this.getAccount({ address, staking, tokenAccounts })
|
|
108
153
|
|
|
109
|
-
const
|
|
154
|
+
const balanceChanged = this.#balanceChanged({ account: accountState, newAccount: account })
|
|
110
155
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
refresh || cursorChanged
|
|
114
|
-
? await this.getStakingInfo({ address, stakingAddresses })
|
|
115
|
-
: accountState.mem
|
|
156
|
+
const isHistoryUpdateTick =
|
|
157
|
+
this.tickCount[walletAccount] % this.ticksBetweenHistoryFetches === 0
|
|
116
158
|
|
|
117
|
-
|
|
118
|
-
|
|
159
|
+
const shouldUpdateHistory = refresh || isHistoryUpdateTick || balanceChanged
|
|
160
|
+
const shouldUpdateOnlyBalance = balanceChanged && !shouldUpdateHistory
|
|
161
|
+
const shouldUpdateBalanceBeforeHistory = true
|
|
119
162
|
|
|
163
|
+
// getHistory is more likely to fail/be rate limited, so we want to update users balance only on a lot of ticks
|
|
164
|
+
if (shouldUpdateBalanceBeforeHistory || shouldUpdateOnlyBalance) {
|
|
120
165
|
// update all state at once
|
|
166
|
+
await this.updateState({ account, walletAccount, staking })
|
|
121
167
|
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
122
|
-
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (shouldUpdateHistory) {
|
|
171
|
+
const { logItemsByAsset, cursorState } = await this.getHistory({
|
|
172
|
+
address,
|
|
173
|
+
accountState,
|
|
174
|
+
walletAccount,
|
|
175
|
+
refresh,
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
const cursorChanged = this.hasNewCursor({ walletAccount, cursorState })
|
|
179
|
+
|
|
180
|
+
// update all state at once
|
|
181
|
+
const clearedLogItems = await this.markStaleTransactions({ walletAccount, logItemsByAsset })
|
|
182
|
+
await this.updateTxLogByAsset({ walletAccount, logItemsByAsset: clearedLogItems, refresh })
|
|
123
183
|
await this.updateState({ account, cursorState, walletAccount, staking })
|
|
184
|
+
await this.emitUnknownTokensEvent({ tokenAccounts })
|
|
124
185
|
if (refresh || cursorChanged) {
|
|
125
186
|
this.cursors[walletAccount] = cursorState.cursor
|
|
126
187
|
}
|
package/src/tx-send.js
CHANGED
|
@@ -136,7 +136,9 @@ export const createAndBroadcastTXFactory =
|
|
|
136
136
|
? asset.currency.ZERO
|
|
137
137
|
: amount.abs().negate()
|
|
138
138
|
|
|
139
|
-
const data = isStakingTx
|
|
139
|
+
const data = isStakingTx
|
|
140
|
+
? { staking: { ...stakingParams, stake: coinAmount.toBaseNumber() } }
|
|
141
|
+
: Object.create(null)
|
|
140
142
|
const tx = {
|
|
141
143
|
txId,
|
|
142
144
|
confirmations: 0,
|