@exodus/bitcoin-api 4.9.4 → 4.9.5
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 +10 -0
- package/package.json +2 -2
- package/src/tx-log/bitcoin-monitor-scanner.js +14 -137
- package/src/tx-log/bitcoin-monitor.js +2 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
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
|
+
## [4.9.5](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.9.4...@exodus/bitcoin-api@4.9.5) (2026-02-14)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: Remove ordinals paths from bitcoin monitor scanner (#7430)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## [4.9.4](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.9.3...@exodus/bitcoin-api@4.9.4) (2026-02-10)
|
|
7
17
|
|
|
8
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.5",
|
|
4
4
|
"description": "Bitcoin transaction and fee monitors, RPC with the blockchain node, other networking code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"type": "git",
|
|
62
62
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "8c4fcde522beb978df6a5099e0fa9e34bb4a7e04"
|
|
65
65
|
}
|
|
@@ -5,9 +5,7 @@ import ms from 'ms'
|
|
|
5
5
|
|
|
6
6
|
import { isChangeAddress, isReceiveAddress } from '../address-utils.js'
|
|
7
7
|
import { orderTxs } from '../insight-api-client/util.js'
|
|
8
|
-
import {
|
|
9
|
-
import { getOrdinalsUtxos, getUtxos, partitionUtxos } from '../utxos-utils.js'
|
|
10
|
-
import { indexOrdinalUnconfirmedTx } from './ordinals-indexer-utils.js'
|
|
8
|
+
import { getUtxos } from '../utxos-utils.js'
|
|
11
9
|
|
|
12
10
|
const { compact, isEqual, uniq } = lodash
|
|
13
11
|
|
|
@@ -23,8 +21,6 @@ export class BitcoinMonitorScanner {
|
|
|
23
21
|
#txFetchLimitResolver
|
|
24
22
|
#shouldExcludeVoutUtxo
|
|
25
23
|
#yieldToUI
|
|
26
|
-
#ordinalsEnabled
|
|
27
|
-
#ordinalChainIndex
|
|
28
24
|
#extraChainIndexEnabled
|
|
29
25
|
#extraChainIndex
|
|
30
26
|
#gapLimit
|
|
@@ -36,8 +32,6 @@ export class BitcoinMonitorScanner {
|
|
|
36
32
|
yieldToUI = () => {},
|
|
37
33
|
shouldExcludeVoutUtxo = () => false,
|
|
38
34
|
txFetchLimitResolver = ({ refresh }) => (refresh ? 50 : 10),
|
|
39
|
-
ordinalsEnabled,
|
|
40
|
-
ordinalChainIndex,
|
|
41
35
|
extraChainIndexEnabled,
|
|
42
36
|
extraChainIndex,
|
|
43
37
|
gapLimit = 10,
|
|
@@ -57,8 +51,6 @@ export class BitcoinMonitorScanner {
|
|
|
57
51
|
this.#assetClientInterface = assetClientInterface
|
|
58
52
|
this.#txFetchLimitResolver = txFetchLimitResolver
|
|
59
53
|
this.#shouldExcludeVoutUtxo = shouldExcludeVoutUtxo
|
|
60
|
-
this.#ordinalsEnabled = ordinalsEnabled
|
|
61
|
-
this.#ordinalChainIndex = ordinalChainIndex
|
|
62
54
|
this.#extraChainIndexEnabled = extraChainIndexEnabled
|
|
63
55
|
this.#extraChainIndex = extraChainIndex
|
|
64
56
|
this.#gapLimit = gapLimit
|
|
@@ -92,9 +84,6 @@ export class BitcoinMonitorScanner {
|
|
|
92
84
|
const multiAddressMode = assetConfig.multiAddressMode ?? true
|
|
93
85
|
|
|
94
86
|
const storedUtxos = getUtxos({ asset, accountState })
|
|
95
|
-
const storedOrdinalUtxos = getOrdinalsUtxos({ asset, accountState })
|
|
96
|
-
|
|
97
|
-
const currentStoredUtxos = storedUtxos.union(storedOrdinalUtxos)
|
|
98
87
|
|
|
99
88
|
const currentTime = Date.now()
|
|
100
89
|
const unconfirmedTxsToCheck = [...currentTxs].reduce((txs, tx) => {
|
|
@@ -116,9 +105,7 @@ export class BitcoinMonitorScanner {
|
|
|
116
105
|
: (txs) =>
|
|
117
106
|
txs.filter((tx) => {
|
|
118
107
|
const txItem = currentTxs.get(tx.txid)
|
|
119
|
-
|
|
120
|
-
const inscriptionsIndexed = txItem?.data?.inscriptionsIndexed
|
|
121
|
-
return confirmed && (!this.#ordinalsEnabled || inscriptionsIndexed)
|
|
108
|
+
return txItem && txItem.confirmed
|
|
122
109
|
}).length >= txs.length
|
|
123
110
|
|
|
124
111
|
const unusedAddressIndexes = await assetClientInterface.getUnusedAddressIndexes({
|
|
@@ -254,28 +241,7 @@ export class BitcoinMonitorScanner {
|
|
|
254
241
|
}
|
|
255
242
|
|
|
256
243
|
const listOfTxs = await Promise.all(promises)
|
|
257
|
-
|
|
258
|
-
if (!this.#ordinalsEnabled) {
|
|
259
|
-
return insightTxs
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return Promise.all(
|
|
263
|
-
insightTxs.map((tx) => {
|
|
264
|
-
try {
|
|
265
|
-
return indexOrdinalUnconfirmedTx({
|
|
266
|
-
tx,
|
|
267
|
-
currency: this.#asset.currency,
|
|
268
|
-
insightClient,
|
|
269
|
-
})
|
|
270
|
-
} catch (e) {
|
|
271
|
-
console.warn(
|
|
272
|
-
`Could not index ${asset.name} ordinal tx ${tx.txid} for wallet account ${walletAccount}. message: ${e.message}`,
|
|
273
|
-
e
|
|
274
|
-
)
|
|
275
|
-
return tx
|
|
276
|
-
}
|
|
277
|
-
})
|
|
278
|
-
)
|
|
244
|
+
return listOfTxs.flat()
|
|
279
245
|
}
|
|
280
246
|
|
|
281
247
|
const gapSearchParameters = newChains.map(({ purpose, chain }) => {
|
|
@@ -305,21 +271,6 @@ export class BitcoinMonitorScanner {
|
|
|
305
271
|
}
|
|
306
272
|
)
|
|
307
273
|
|
|
308
|
-
if (
|
|
309
|
-
fetchCount === 0 &&
|
|
310
|
-
this.#ordinalsEnabled &&
|
|
311
|
-
this.#ordinalChainIndex > 1 &&
|
|
312
|
-
purposes.includes(86)
|
|
313
|
-
) {
|
|
314
|
-
// this is the ordinal address
|
|
315
|
-
chainObjects.push({
|
|
316
|
-
purpose: 86,
|
|
317
|
-
chainIndex: this.#ordinalChainIndex,
|
|
318
|
-
startAddressIndex: 0,
|
|
319
|
-
endAddressIndex: 1,
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
|
|
323
274
|
if (
|
|
324
275
|
fetchCount === 0 &&
|
|
325
276
|
this.#extraChainIndexEnabled &&
|
|
@@ -373,10 +324,7 @@ export class BitcoinMonitorScanner {
|
|
|
373
324
|
const addressString = String(address)
|
|
374
325
|
const purposeToUpdate = purposeMap[addressString]
|
|
375
326
|
|
|
376
|
-
if (
|
|
377
|
-
metaAddressIndex === undefined ||
|
|
378
|
-
(metaChainIndex === this.#ordinalChainIndex && this.#ordinalChainIndex > 1)
|
|
379
|
-
) {
|
|
327
|
+
if (metaAddressIndex === undefined) {
|
|
380
328
|
return
|
|
381
329
|
}
|
|
382
330
|
|
|
@@ -461,15 +409,6 @@ export class BitcoinMonitorScanner {
|
|
|
461
409
|
currencies: { [assetName]: currency },
|
|
462
410
|
}
|
|
463
411
|
|
|
464
|
-
if (this.#ordinalsEnabled) {
|
|
465
|
-
txLogItem.data = {
|
|
466
|
-
...txLogItem.data,
|
|
467
|
-
inscriptionsIndexed: txItem.inscriptionsIndexed,
|
|
468
|
-
sentInscriptions: [],
|
|
469
|
-
receivedInscriptions: [],
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
412
|
let from = []
|
|
474
413
|
|
|
475
414
|
// if txItem.vin has an address that matches ours, means we've spent this tx
|
|
@@ -495,14 +434,6 @@ export class BitcoinMonitorScanner {
|
|
|
495
434
|
txLogItem.coinAmount = txLogItem.coinAmount.sub(currency.defaultUnit(vin.value))
|
|
496
435
|
isSent = true
|
|
497
436
|
txLogItem.data.sent = []
|
|
498
|
-
if (this.#ordinalsEnabled && vin.inscriptions) {
|
|
499
|
-
txLogItem.data.sentInscriptions.push(
|
|
500
|
-
...vin.inscriptions.map((i) => ({
|
|
501
|
-
...i,
|
|
502
|
-
value: currency.defaultUnit(vin.value).toBaseNumber(),
|
|
503
|
-
}))
|
|
504
|
-
)
|
|
505
|
-
}
|
|
506
437
|
|
|
507
438
|
// this is only used to exclude the utxos in the reducer which is why we don't care about the other fields
|
|
508
439
|
utxosToRemove.push({
|
|
@@ -584,15 +515,6 @@ export class BitcoinMonitorScanner {
|
|
|
584
515
|
amount: currency.defaultUnit(vout.value).toBaseString(),
|
|
585
516
|
})
|
|
586
517
|
|
|
587
|
-
if (this.#ordinalsEnabled && vout.inscriptions) {
|
|
588
|
-
txLogItem.data.receivedInscriptions.push(
|
|
589
|
-
...vout.inscriptions.map((i) => ({
|
|
590
|
-
...i,
|
|
591
|
-
value: currency.defaultUnit(vout.value).toBaseNumber(),
|
|
592
|
-
}))
|
|
593
|
-
)
|
|
594
|
-
}
|
|
595
|
-
|
|
596
518
|
// it was sent to us...
|
|
597
519
|
const val = currency.defaultUnit(vout.value)
|
|
598
520
|
txLogItem.coinAmount = txLogItem.coinAmount.add(val)
|
|
@@ -609,11 +531,6 @@ export class BitcoinMonitorScanner {
|
|
|
609
531
|
...(isCoinbase ? { isCoinbase: true } : undefined),
|
|
610
532
|
}
|
|
611
533
|
|
|
612
|
-
if (this.#ordinalsEnabled) {
|
|
613
|
-
output.inscriptionsIndexed = txItem.inscriptionsIndexed
|
|
614
|
-
output.inscriptions = vout.inscriptions || []
|
|
615
|
-
}
|
|
616
|
-
|
|
617
534
|
if (this.#shouldExcludeVoutUtxo({ asset, output, txItem, vout })) {
|
|
618
535
|
utxosToRemove.push({
|
|
619
536
|
address,
|
|
@@ -682,7 +599,7 @@ export class BitcoinMonitorScanner {
|
|
|
682
599
|
|
|
683
600
|
const utxosToRemoveCol = UtxoCollection.fromArray(utxosToRemove, { currency })
|
|
684
601
|
// Keep new utxos when they intersect with the stored utxos.
|
|
685
|
-
utxoCol = utxoCol.union(
|
|
602
|
+
utxoCol = utxoCol.union(storedUtxos).difference(utxosToRemoveCol)
|
|
686
603
|
|
|
687
604
|
const pendingDropCandidates = Object.values(unconfirmedTxsToCheck)
|
|
688
605
|
const verificationResults = await Promise.all(
|
|
@@ -727,7 +644,7 @@ export class BitcoinMonitorScanner {
|
|
|
727
644
|
}
|
|
728
645
|
|
|
729
646
|
// no changes, ignore
|
|
730
|
-
if (utxoCol.equals(
|
|
647
|
+
if (utxoCol.equals(storedUtxos)) {
|
|
731
648
|
utxoCol = null
|
|
732
649
|
}
|
|
733
650
|
|
|
@@ -737,28 +654,10 @@ export class BitcoinMonitorScanner {
|
|
|
737
654
|
return !isEqual(chain, originalChain.chain)
|
|
738
655
|
})
|
|
739
656
|
|
|
740
|
-
const ordinalAddress = await this.getOrdinalAddress({ walletAccount })
|
|
741
|
-
|
|
742
|
-
// latest account state, in case knownBalanceUtxoIds or mustAvoidUtxoIds gets updated in on another promise
|
|
743
|
-
const latestAccountState = await assetClientInterface.getAccountState({
|
|
744
|
-
assetName,
|
|
745
|
-
walletAccount,
|
|
746
|
-
})
|
|
747
|
-
const utxosData = utxoCol
|
|
748
|
-
? partitionUtxos({
|
|
749
|
-
allUtxos: utxoCol,
|
|
750
|
-
ordinalsEnabled: this.#ordinalsEnabled,
|
|
751
|
-
ordinalAddress,
|
|
752
|
-
knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
|
|
753
|
-
mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
|
|
754
|
-
additionalInscriptions: latestAccountState.additionalInscriptions,
|
|
755
|
-
})
|
|
756
|
-
: {}
|
|
757
|
-
|
|
758
657
|
return {
|
|
759
658
|
txsToUpdate: existingTxs,
|
|
760
659
|
txsToAdd: newTxs,
|
|
761
|
-
...
|
|
660
|
+
...(utxoCol ? { utxos: utxoCol } : {}),
|
|
762
661
|
changedUnusedAddressIndexes,
|
|
763
662
|
}
|
|
764
663
|
}
|
|
@@ -771,8 +670,6 @@ export class BitcoinMonitorScanner {
|
|
|
771
670
|
const accountState = await aci.getAccountState({ assetName, walletAccount })
|
|
772
671
|
|
|
773
672
|
const storedUtxos = getUtxos({ accountState, asset })
|
|
774
|
-
const storedOrdinalsUtxos = getOrdinalsUtxos({ accountState, asset })
|
|
775
|
-
const allStoredUtxos = storedUtxos.union(storedOrdinalsUtxos)
|
|
776
673
|
|
|
777
674
|
const currentTxs = [...(await aci.getTxLog({ assetName, walletAccount }))]
|
|
778
675
|
|
|
@@ -819,38 +716,18 @@ export class BitcoinMonitorScanner {
|
|
|
819
716
|
})
|
|
820
717
|
.filter((tx) => Object.keys(tx).length > 1)
|
|
821
718
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const latestAccountState = await aci.getAccountState({
|
|
828
|
-
assetName,
|
|
829
|
-
walletAccount,
|
|
719
|
+
// Check before updateConfirmations since it mutates the shared utxo object references,
|
|
720
|
+
// which would cause storedUtxos.toJSON() to also reflect the updated confirmations.
|
|
721
|
+
const utxosChanged = storedUtxos.toArray().some((utxo) => {
|
|
722
|
+
const update = confirmationsList.find(({ txId }) => utxo.txId === txId)
|
|
723
|
+
return update && utxo.confirmations !== update.confirmations
|
|
830
724
|
})
|
|
831
725
|
|
|
832
|
-
const
|
|
833
|
-
allUtxos: txConfirmedUtxos,
|
|
834
|
-
ordinalsEnabled: this.#ordinalsEnabled,
|
|
835
|
-
ordinalAddress,
|
|
836
|
-
knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
|
|
837
|
-
mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
|
|
838
|
-
additionalInscriptions: latestAccountState.additionalInscriptions,
|
|
839
|
-
})
|
|
726
|
+
const txConfirmedUtxos = storedUtxos.updateConfirmations(confirmationsList)
|
|
840
727
|
|
|
841
728
|
return {
|
|
842
|
-
utxos:
|
|
843
|
-
ordinalsUtxos: ordinalsUtxos.equals(storedOrdinalsUtxos) ? null : ordinalsUtxos,
|
|
729
|
+
utxos: utxosChanged ? txConfirmedUtxos : null,
|
|
844
730
|
txsToUpdate: updatedPropertiesTxs,
|
|
845
731
|
}
|
|
846
732
|
}
|
|
847
|
-
|
|
848
|
-
getOrdinalAddress({ walletAccount }) {
|
|
849
|
-
return getOrdinalAddress({
|
|
850
|
-
asset: this.#asset,
|
|
851
|
-
assetClientInterface: this.#assetClientInterface,
|
|
852
|
-
walletAccount,
|
|
853
|
-
ordinalChainIndex: this.#ordinalChainIndex,
|
|
854
|
-
})
|
|
855
|
-
}
|
|
856
733
|
}
|
|
@@ -166,13 +166,12 @@ export class Monitor extends BaseMonitor {
|
|
|
166
166
|
const assetName = asset.name
|
|
167
167
|
const walletAccounts = await aci.getWalletAccounts({ assetName })
|
|
168
168
|
for (const walletAccount of walletAccounts) {
|
|
169
|
-
const { txsToUpdate, utxos
|
|
169
|
+
const { txsToUpdate, utxos } = await this.#scanner.rescanOnNewBlock({
|
|
170
170
|
walletAccount,
|
|
171
171
|
})
|
|
172
172
|
|
|
173
173
|
const newData = {}
|
|
174
174
|
if (utxos) newData.utxos = utxos
|
|
175
|
-
if (ordinalsUtxos) newData.ordinalsUtxos = ordinalsUtxos
|
|
176
175
|
|
|
177
176
|
if (txsToUpdate.length > 0) {
|
|
178
177
|
await this.updateTxLog({ assetName, walletAccount, logItems: txsToUpdate })
|
|
@@ -237,7 +236,7 @@ export class Monitor extends BaseMonitor {
|
|
|
237
236
|
// wait for all wallet accounts to load
|
|
238
237
|
await aci.getWalletAccounts({ assetName })
|
|
239
238
|
|
|
240
|
-
const { txsToAdd, txsToUpdate, utxos,
|
|
239
|
+
const { txsToAdd, txsToUpdate, utxos, changedUnusedAddressIndexes } =
|
|
241
240
|
await this.#scanner.rescanBlockchainInsight({
|
|
242
241
|
walletAccount,
|
|
243
242
|
refresh,
|
|
@@ -245,7 +244,6 @@ export class Monitor extends BaseMonitor {
|
|
|
245
244
|
|
|
246
245
|
const newData = {}
|
|
247
246
|
if (utxos) newData.utxos = utxos
|
|
248
|
-
if (ordinalsUtxos) newData.ordinalsUtxos = ordinalsUtxos
|
|
249
247
|
|
|
250
248
|
if (!isEmpty(changedUnusedAddressIndexes)) {
|
|
251
249
|
// Only for mobile atm, browser and hydra calculates from the latest txLogs
|