@exodus/bitcoin-api 2.9.2 → 2.9.3-hotfix
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 +2 -3
- package/src/bitcoinjs-lib/ecc/common.js +1 -1
- package/src/bitcoinjs-lib/ecc/mobile.js +3 -3
- package/src/bitcoinjs-lib/script-classify/index.js +1 -1
- package/src/btc-like-address.js +3 -4
- package/src/btc-like-keys.js +4 -0
- package/src/constants/bip44.js +2 -2
- package/src/fee/can-bump-tx.js +3 -1
- package/src/fee/fee-estimator.js +5 -1
- package/src/fee/fee-utils.js +6 -5
- package/src/fee/get-fee-resolver.js +2 -1
- package/src/fee/script-classifier.js +5 -10
- package/src/fee/utxo-selector.js +10 -3
- package/src/hash-utils.js +4 -9
- package/src/insight-api-client/index.js +14 -12
- package/src/insight-api-client/util.js +16 -15
- package/src/insight-api-client/ws.js +1 -1
- package/src/move-funds.js +17 -17
- package/src/ordinals-utils.js +2 -2
- package/src/parse-unsigned-tx.js +80 -81
- package/src/tx-log/bitcoin-monitor-scanner.js +50 -38
- package/src/tx-log/bitcoin-monitor.js +14 -13
- package/src/tx-log/ordinals-indexer-utils.js +6 -0
- package/src/tx-send/dogecoin.js +2 -2
- package/src/tx-send/index.js +426 -418
- package/src/tx-sign/common.js +9 -9
- package/src/tx-sign/create-get-key-and-purpose.js +2 -2
- package/src/tx-sign/create-sign-with-wallet.js +3 -3
- package/src/tx-sign/default-entropy.js +1 -3
- package/src/tx-sign/default-prepare-for-signing.js +16 -18
- package/src/tx-sign/default-sign-hardware.js +2 -1
- package/src/tx-sign/taproot.js +4 -0
- package/src/tx-utils.js +5 -5
- package/src/unconfirmed-ancestor-data.js +1 -0
- package/src/utxos-utils.js +12 -6
package/src/parse-unsigned-tx.js
CHANGED
|
@@ -4,95 +4,94 @@ import BN from 'bn.js'
|
|
|
4
4
|
import lodash from 'lodash'
|
|
5
5
|
import { Transaction as BitcoinTransactionClass } from '@exodus/bitcoinjs-lib'
|
|
6
6
|
|
|
7
|
-
export const parseUnsignedTxFactory =
|
|
8
|
-
|
|
9
|
-
unsignedTx,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return asset.currency.baseUnit(parsedValue).toDefault()
|
|
17
|
-
}
|
|
7
|
+
export const parseUnsignedTxFactory =
|
|
8
|
+
({ Transaction = BitcoinTransactionClass } = {}) =>
|
|
9
|
+
async ({ asset, unsignedTx, getAddress }) => {
|
|
10
|
+
const assetName = asset.name
|
|
11
|
+
|
|
12
|
+
const toNumberUnit = (value) => {
|
|
13
|
+
const parsedValue = Buffer.isBuffer(value) ? new BN(value, 10, 'le') : value // handle Dogecoin buffer values
|
|
14
|
+
return asset.currency.baseUnit(parsedValue).toDefault()
|
|
15
|
+
}
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
const parseAddress = assetName === 'bcash' ? asset.address.toCashAddress : (address) => address
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
const { inputs, outputs } = unsignedTx.txData
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
const from = lodash.uniq(inputs.map(({ address }) => parseAddress(address)))
|
|
22
|
+
const outputAddresses = lodash.uniq(outputs.map(([address]) => address))
|
|
23
|
+
const inputTxIds = lodash.uniq(inputs.map(({ txId }) => txId))
|
|
24
|
+
const insightClient = asset.baseAsset.insightClient
|
|
25
|
+
const inputTxsRaw = await Promise.all(inputTxIds.map((txId) => insightClient.fetchRawTx(txId)))
|
|
26
|
+
const inputTxsById = new Map(
|
|
27
|
+
inputTxsRaw.map((hex) => {
|
|
28
|
+
const tx = Transaction.fromHex(hex)
|
|
29
|
+
return [tx.getId(), tx]
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
inputs.forEach(({ txId, vout, value }) => {
|
|
34
|
+
const tx = inputTxsById.get(txId)
|
|
35
|
+
const output = tx.outs[vout]
|
|
36
|
+
const expected = assetName === 'dogecoin' ? output.valueBuffer : output.value
|
|
37
|
+
assert(
|
|
38
|
+
lodash.isEqual(expected, value),
|
|
39
|
+
`${txId} tx input has invalid value. Expected: ${expected} , Actual: ${value}`
|
|
40
|
+
)
|
|
32
41
|
})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
|
|
43
|
+
const { addressPathsMap } = unsignedTx.txMeta
|
|
44
|
+
const [changeOutputAddresses, toOutputAddresses] = lodash.partition(
|
|
45
|
+
outputAddresses,
|
|
46
|
+
(address) => {
|
|
47
|
+
const path = addressPathsMap[address]
|
|
48
|
+
if (!path) return false
|
|
49
|
+
|
|
50
|
+
const [chain, index] = BIPPath.fromString(path).path
|
|
51
|
+
const isOurs = getAddress({ chain, index }).toString() === address
|
|
52
|
+
return isOurs && chain === 1
|
|
53
|
+
}
|
|
42
54
|
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
outputAddresses,
|
|
48
|
-
(address) => {
|
|
49
|
-
const path = addressPathsMap[address]
|
|
50
|
-
if (!path) return false
|
|
51
|
-
|
|
52
|
-
const [chain, index] = BIPPath.fromString(path).path
|
|
53
|
-
const isOurs = getAddress({ chain, index }).toString() === address
|
|
54
|
-
return isOurs && chain === 1
|
|
55
|
+
|
|
56
|
+
// the user is explicitly sending to a change address, so take a wild guess
|
|
57
|
+
if (toOutputAddresses.length === 0) {
|
|
58
|
+
toOutputAddresses.push(changeOutputAddresses.pop())
|
|
55
59
|
}
|
|
56
|
-
)
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
61
|
+
const [changeOutputs, sendOutputs] = lodash.partition(outputs, ([address]) =>
|
|
62
|
+
changeOutputAddresses.includes(address)
|
|
63
|
+
)
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
changeAmount,
|
|
94
|
-
fee,
|
|
65
|
+
const sum = (arr) => arr.reduce((a, b) => a.add(b), asset.currency.ZERO)
|
|
66
|
+
const sumOutputs = (outputs) => sum(outputs.map(([_, value]) => toNumberUnit(value)))
|
|
67
|
+
|
|
68
|
+
// sum(inputs) = intendedSendAmount + fee + change
|
|
69
|
+
// sum(outputs) = intendedSendAmount + change
|
|
70
|
+
|
|
71
|
+
const inputsNF = inputs.map(({ value }) => toNumberUnit(value))
|
|
72
|
+
const outputsNF = outputs.map(([_, value]) => toNumberUnit(value))
|
|
73
|
+
const changeAmount = sumOutputs(changeOutputs)
|
|
74
|
+
const amount = sumOutputs(sendOutputs)
|
|
75
|
+
|
|
76
|
+
const inputsTotal = sum(inputsNF)
|
|
77
|
+
const outputsTotal = sum(outputsNF)
|
|
78
|
+
const fee = inputsTotal.sub(outputsTotal)
|
|
79
|
+
|
|
80
|
+
const changeAddress =
|
|
81
|
+
changeOutputAddresses.length > 0 ? parseAddress(changeOutputAddresses[0]) : null
|
|
82
|
+
// TODO: return entire toOutputAddresses array
|
|
83
|
+
assert(toOutputAddresses.length === 1, 'multiple outputs not supported yet in 2fa mode')
|
|
84
|
+
|
|
85
|
+
const to = parseAddress(toOutputAddresses[0])
|
|
86
|
+
return {
|
|
87
|
+
asset,
|
|
88
|
+
from,
|
|
89
|
+
to,
|
|
90
|
+
amount,
|
|
91
|
+
changeAddress,
|
|
92
|
+
changeAmount,
|
|
93
|
+
fee,
|
|
94
|
+
}
|
|
95
95
|
}
|
|
96
|
-
}
|
|
97
96
|
|
|
98
97
|
export const parseUnsignedTx = parseUnsignedTxFactory()
|
|
@@ -71,14 +71,15 @@ export class BitcoinMonitorScanner {
|
|
|
71
71
|
|
|
72
72
|
const currentStoredUtxos = storedUtxos.union(storedOrdinalUtxos)
|
|
73
73
|
|
|
74
|
-
const currentTime =
|
|
75
|
-
const unconfirmedTxsToCheck =
|
|
76
|
-
if (
|
|
77
|
-
// Don't check sent tx that is younger than 2 minutes, because server might not have indexed it yet
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
const currentTime = Date.now()
|
|
75
|
+
const unconfirmedTxsToCheck = [...currentTxs].reduce((txs, tx) => {
|
|
76
|
+
if (
|
|
77
|
+
tx.pending && // Don't check sent tx that is younger than 2 minutes, because server might not have indexed it yet
|
|
78
|
+
(!tx.sent || !tx.date || currentTime - tx.date.getTime() > SENT_TIME_TO_DROP)
|
|
79
|
+
) {
|
|
80
|
+
txs[tx.txId] = tx
|
|
81
81
|
}
|
|
82
|
+
|
|
82
83
|
return txs
|
|
83
84
|
}, Object.create(null))
|
|
84
85
|
|
|
@@ -139,7 +140,7 @@ export class BitcoinMonitorScanner {
|
|
|
139
140
|
|
|
140
141
|
const aggregateAddresses = async (chainObjects) => {
|
|
141
142
|
const promises = []
|
|
142
|
-
for (
|
|
143
|
+
for (const chainObject of chainObjects) {
|
|
143
144
|
const { purpose, chainIndex, startAddressIndex, endAddressIndex } = chainObject
|
|
144
145
|
for (let addressIndex = startAddressIndex; addressIndex < endAddressIndex; addressIndex++) {
|
|
145
146
|
promises.push(
|
|
@@ -165,6 +166,7 @@ export class BitcoinMonitorScanner {
|
|
|
165
166
|
)
|
|
166
167
|
}
|
|
167
168
|
}
|
|
169
|
+
|
|
168
170
|
const addresses = []
|
|
169
171
|
const result = await Promise.all(promises)
|
|
170
172
|
result.forEach(({ address, purpose }) => {
|
|
@@ -192,13 +194,12 @@ export class BitcoinMonitorScanner {
|
|
|
192
194
|
promises.push(promise)
|
|
193
195
|
}
|
|
194
196
|
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
[]
|
|
198
|
-
)
|
|
197
|
+
const listOfTxs = await Promise.all(promises)
|
|
198
|
+
const insightTxs = listOfTxs.flat()
|
|
199
199
|
if (!this.#ordinalsEnabled) {
|
|
200
200
|
return insightTxs
|
|
201
201
|
}
|
|
202
|
+
|
|
202
203
|
return Promise.all(
|
|
203
204
|
insightTxs.map((tx) => {
|
|
204
205
|
try {
|
|
@@ -232,8 +233,8 @@ export class BitcoinMonitorScanner {
|
|
|
232
233
|
let allTxs = []
|
|
233
234
|
|
|
234
235
|
for (let fetchCount = 0; ; fetchCount++) {
|
|
235
|
-
const chainObjects = gapSearchParameters
|
|
236
|
-
|
|
236
|
+
const chainObjects = gapSearchParameters.flatMap(
|
|
237
|
+
({ purpose, chain, startAddressIndexes, endAddressIndexes }) => {
|
|
237
238
|
return chain.map((_, chainIndex) => {
|
|
238
239
|
return {
|
|
239
240
|
purpose,
|
|
@@ -242,8 +243,8 @@ export class BitcoinMonitorScanner {
|
|
|
242
243
|
endAddressIndex: endAddressIndexes[chainIndex],
|
|
243
244
|
}
|
|
244
245
|
})
|
|
245
|
-
}
|
|
246
|
-
|
|
246
|
+
}
|
|
247
|
+
)
|
|
247
248
|
|
|
248
249
|
if (
|
|
249
250
|
fetchCount === 0 &&
|
|
@@ -277,7 +278,7 @@ export class BitcoinMonitorScanner {
|
|
|
277
278
|
|
|
278
279
|
const txs = await fetchAllTxs(addresses)
|
|
279
280
|
if (txs.length === 0) break
|
|
280
|
-
allTxs = allTxs
|
|
281
|
+
allTxs = [...allTxs, ...txs]
|
|
281
282
|
|
|
282
283
|
// Update chains to see if we need to fetch more
|
|
283
284
|
txs.forEach((tx) =>
|
|
@@ -307,6 +308,7 @@ export class BitcoinMonitorScanner {
|
|
|
307
308
|
console.warn(`${assetName}: Cannot resolve purpose from address ${addressString}`)
|
|
308
309
|
return
|
|
309
310
|
}
|
|
311
|
+
|
|
310
312
|
const chainToUpgrade = newChains.find((newChain) => newChain.purpose === purposeToUpdate)
|
|
311
313
|
if (!chainToUpgrade) {
|
|
312
314
|
console.log(
|
|
@@ -314,12 +316,14 @@ export class BitcoinMonitorScanner {
|
|
|
314
316
|
)
|
|
315
317
|
return
|
|
316
318
|
}
|
|
319
|
+
|
|
317
320
|
if (chainToUpgrade.chain[metaChainIndex] === undefined) {
|
|
318
321
|
console.log(
|
|
319
322
|
`${assetName}: There is no chain info for purpose ${purposeToUpdate}, address ${addressString} and chain index ${metaChainIndex}`
|
|
320
323
|
)
|
|
321
324
|
return
|
|
322
325
|
}
|
|
326
|
+
|
|
323
327
|
chainToUpgrade.chain[metaChainIndex] = Math.max(
|
|
324
328
|
metaAddressIndex + 1,
|
|
325
329
|
chainToUpgrade.chain[metaChainIndex]
|
|
@@ -328,7 +332,9 @@ export class BitcoinMonitorScanner {
|
|
|
328
332
|
)
|
|
329
333
|
|
|
330
334
|
gapSearchParameters.forEach((indexData) => {
|
|
335
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
331
336
|
indexData.startAddressIndexes = [...indexData.endAddressIndexes]
|
|
337
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
332
338
|
indexData.endAddressIndexes = indexData.chain.map((addressIndex) => {
|
|
333
339
|
const resolvedGapLimit = refresh ? this.#refreshGapLimit : this.#gapLimit
|
|
334
340
|
return addressIndex + resolvedGapLimit
|
|
@@ -343,14 +349,14 @@ export class BitcoinMonitorScanner {
|
|
|
343
349
|
|
|
344
350
|
// post process TX data
|
|
345
351
|
// NOTE: this can be optimized
|
|
346
|
-
|
|
352
|
+
const vinTxids = Object.create(null)
|
|
347
353
|
let utxos = []
|
|
348
354
|
const utxosToRemove = []
|
|
349
|
-
|
|
350
|
-
|
|
355
|
+
const newTxs = []
|
|
356
|
+
const existingTxs = []
|
|
351
357
|
|
|
352
358
|
allTxs.forEach((txItem) => {
|
|
353
|
-
|
|
359
|
+
const txLogItem = {
|
|
354
360
|
txId: txItem.txid,
|
|
355
361
|
coinAmount: currency.ZERO,
|
|
356
362
|
date: txItem.time ? new Date(txItem.time * 1000) : new Date(),
|
|
@@ -406,7 +412,7 @@ export class BitcoinMonitorScanner {
|
|
|
406
412
|
|
|
407
413
|
// this is only used to exclude the utxos in the reducer which is why we don't care about the other fields
|
|
408
414
|
utxosToRemove.push({
|
|
409
|
-
address
|
|
415
|
+
address,
|
|
410
416
|
txId: vin.txid,
|
|
411
417
|
vout: vin.vout,
|
|
412
418
|
value: currency.defaultUnit(vin.value || 0),
|
|
@@ -459,6 +465,7 @@ export class BitcoinMonitorScanner {
|
|
|
459
465
|
const sentDisplayAddress = asset.address.displayAddress?.(sentAddress) || sentAddress
|
|
460
466
|
txLogItem.data.sent.push({ address: sentDisplayAddress, amount: val })
|
|
461
467
|
}
|
|
468
|
+
|
|
462
469
|
return
|
|
463
470
|
}
|
|
464
471
|
|
|
@@ -481,7 +488,7 @@ export class BitcoinMonitorScanner {
|
|
|
481
488
|
}
|
|
482
489
|
|
|
483
490
|
// it was sent to us...
|
|
484
|
-
|
|
491
|
+
const val = currency.defaultUnit(vout.value)
|
|
485
492
|
txLogItem.coinAmount = txLogItem.coinAmount.add(val)
|
|
486
493
|
|
|
487
494
|
const output = {
|
|
@@ -502,6 +509,7 @@ export class BitcoinMonitorScanner {
|
|
|
502
509
|
if (this.#shouldExcludeVoutUtxo({ asset, output, txItem, vout })) {
|
|
503
510
|
return
|
|
504
511
|
}
|
|
512
|
+
|
|
505
513
|
if (vout.spentTxId) return
|
|
506
514
|
utxos.push(output) // but save the unspent ones for state.utxos
|
|
507
515
|
})
|
|
@@ -510,6 +518,7 @@ export class BitcoinMonitorScanner {
|
|
|
510
518
|
if (txLogItem.to) {
|
|
511
519
|
txLogItem.to = asset.address.displayAddress(txLogItem.to)
|
|
512
520
|
}
|
|
521
|
+
|
|
513
522
|
from = from.map(asset.address.displayAddress)
|
|
514
523
|
}
|
|
515
524
|
|
|
@@ -557,17 +566,18 @@ export class BitcoinMonitorScanner {
|
|
|
557
566
|
// Keep new utxos when they intersect with the stored utxos.
|
|
558
567
|
utxoCol = utxoCol.union(currentStoredUtxos).difference(utxosToRemoveCol)
|
|
559
568
|
|
|
560
|
-
for (
|
|
569
|
+
for (const tx of Object.values(unconfirmedTxsToCheck)) {
|
|
561
570
|
existingTxs.push({ ...tx, dropped: true }) // TODO: this will decrease the chain index, it shouldn't be an issue considering the gap limit
|
|
562
571
|
utxoCol = utxoCol.difference(utxoCol.getTxIdUtxos(tx.txId))
|
|
563
572
|
const utxosToAdd = []
|
|
564
573
|
if (tx.data.inputs) {
|
|
565
574
|
const prevUtxos = UtxoCollection.fromJSON(tx.data.inputs, { currency })
|
|
566
|
-
for (
|
|
575
|
+
for (const utxo of prevUtxos.toArray()) {
|
|
567
576
|
if (vinTxids[`${utxo.txId}-${utxo.vout}`]) {
|
|
568
577
|
// This utxo was already spent in another tx
|
|
569
578
|
continue
|
|
570
579
|
}
|
|
580
|
+
|
|
571
581
|
const tx = await insightClient.fetchTx(utxo.txId)
|
|
572
582
|
if (tx) {
|
|
573
583
|
// previously spent tx still exists, readd utxo
|
|
@@ -575,6 +585,7 @@ export class BitcoinMonitorScanner {
|
|
|
575
585
|
}
|
|
576
586
|
}
|
|
577
587
|
}
|
|
588
|
+
|
|
578
589
|
utxoCol = utxoCol.union(UtxoCollection.fromArray(utxosToAdd, { currency }))
|
|
579
590
|
}
|
|
580
591
|
|
|
@@ -626,7 +637,7 @@ export class BitcoinMonitorScanner {
|
|
|
626
637
|
const storedOrdinalsUtxos = getOrdinalsUtxos({ accountState, asset })
|
|
627
638
|
const allStoredUtxos = storedUtxos.union(storedOrdinalsUtxos)
|
|
628
639
|
|
|
629
|
-
const currentTxs =
|
|
640
|
+
const currentTxs = [...(await aci.getTxLog({ assetName, walletAccount }))]
|
|
630
641
|
|
|
631
642
|
const unconfirmedTxIds = uniq([
|
|
632
643
|
...storedUtxos
|
|
@@ -636,17 +647,17 @@ export class BitcoinMonitorScanner {
|
|
|
636
647
|
...currentTxs.filter((tx) => !tx.dropped && !tx.confirmations).map((tx) => tx.txId),
|
|
637
648
|
])
|
|
638
649
|
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
+
const maybeConfirmationList = await Promise.all(
|
|
651
|
+
unconfirmedTxIds.map(async (txId) => {
|
|
652
|
+
const txStatus = await this.#insightClient.fetchTx(txId)
|
|
653
|
+
if (!txStatus?.confirmations) {
|
|
654
|
+
return
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return { txId, confirmations: txStatus.confirmations }
|
|
658
|
+
})
|
|
659
|
+
)
|
|
660
|
+
const confirmationsList = maybeConfirmationList.filter(Boolean)
|
|
650
661
|
|
|
651
662
|
const updatedPropertiesTxs = currentTxs
|
|
652
663
|
.map((tx) => {
|
|
@@ -655,6 +666,7 @@ export class BitcoinMonitorScanner {
|
|
|
655
666
|
if (!tx.dropped && !tx.confirmations && confirmations > 0) {
|
|
656
667
|
updatedProperties.confirmations = confirmations
|
|
657
668
|
}
|
|
669
|
+
|
|
658
670
|
return { txId: tx.txId, ...updatedProperties }
|
|
659
671
|
})
|
|
660
672
|
.filter((tx) => Object.keys(tx).length > 1)
|
|
@@ -672,7 +684,7 @@ export class BitcoinMonitorScanner {
|
|
|
672
684
|
const { utxos, ordinalsUtxos } = partitionUtxos({
|
|
673
685
|
allUtxos: txConfirmedUtxos,
|
|
674
686
|
ordinalsEnabled: this.#ordinalsEnabled,
|
|
675
|
-
ordinalAddress
|
|
687
|
+
ordinalAddress,
|
|
676
688
|
knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
|
|
677
689
|
mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
|
|
678
690
|
additionalInscriptions: latestAccountState.additionalInscriptions,
|
|
@@ -72,6 +72,7 @@ export class Monitor extends BaseMonitor {
|
|
|
72
72
|
if (apiUrl) {
|
|
73
73
|
this.#insightClient.setBaseUrl(apiUrl)
|
|
74
74
|
}
|
|
75
|
+
|
|
75
76
|
if (!this.#wsUrl || this.#wsUrl !== wsUrl) {
|
|
76
77
|
this.#connectWS(wsUrl || this.#wsUrl || toWSUrl(this.#apiUrl))
|
|
77
78
|
}
|
|
@@ -101,10 +102,12 @@ export class Monitor extends BaseMonitor {
|
|
|
101
102
|
if (!this.#webSocketEnabled) {
|
|
102
103
|
return
|
|
103
104
|
}
|
|
105
|
+
|
|
104
106
|
if (this.#ws) {
|
|
105
107
|
this.#ws.close()
|
|
106
108
|
this.#ws = null
|
|
107
109
|
}
|
|
110
|
+
|
|
108
111
|
this.#wsUrl = wsUrl
|
|
109
112
|
if (!wsUrl) {
|
|
110
113
|
return
|
|
@@ -114,7 +117,7 @@ export class Monitor extends BaseMonitor {
|
|
|
114
117
|
|
|
115
118
|
const addressesArr = Object.values(this.#addressesByWalletAccount).flat()
|
|
116
119
|
|
|
117
|
-
if (
|
|
120
|
+
if (addressesArr.length === 0) {
|
|
118
121
|
this.#logWsStatus('no addressesArr to subscribe')
|
|
119
122
|
return
|
|
120
123
|
}
|
|
@@ -167,7 +170,7 @@ export class Monitor extends BaseMonitor {
|
|
|
167
170
|
)
|
|
168
171
|
}
|
|
169
172
|
|
|
170
|
-
if (txsToUpdate.length) {
|
|
173
|
+
if (txsToUpdate.length > 0) {
|
|
171
174
|
await this.updateTxLog({ assetName, walletAccount, logItems: txsToUpdate })
|
|
172
175
|
if (utxos && ['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
|
|
173
176
|
const unconfirmedTxAncestor = await resolveUnconfirmedAncestorData({
|
|
@@ -177,6 +180,7 @@ export class Monitor extends BaseMonitor {
|
|
|
177
180
|
newData.mem = { unconfirmedTxAncestor }
|
|
178
181
|
}
|
|
179
182
|
}
|
|
183
|
+
|
|
180
184
|
await aci.updateAccountState({
|
|
181
185
|
assetName,
|
|
182
186
|
walletAccount,
|
|
@@ -202,10 +206,12 @@ export class Monitor extends BaseMonitor {
|
|
|
202
206
|
if (refresh && this.#runningByWalletAccount[walletAccount]?.refresh !== refresh) {
|
|
203
207
|
await this.#waitForWalletToFinish(walletAccount)
|
|
204
208
|
}
|
|
209
|
+
|
|
205
210
|
if (this.#runningByWalletAccount[walletAccount]) {
|
|
206
211
|
this.logger.debug(`Skipping ${walletAccount} tick as previous tick is still running`)
|
|
207
212
|
return
|
|
208
213
|
}
|
|
214
|
+
|
|
209
215
|
const promise = this.#syncWalletAccount({ walletAccount, refresh })
|
|
210
216
|
this.#runningByWalletAccount[walletAccount] = { refresh, promise }
|
|
211
217
|
try {
|
|
@@ -221,16 +227,11 @@ export class Monitor extends BaseMonitor {
|
|
|
221
227
|
// wait for all wallet accounts to load
|
|
222
228
|
await aci.getWalletAccounts({ assetName })
|
|
223
229
|
|
|
224
|
-
const {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
changedUnusedAddressIndexes,
|
|
230
|
-
} = await this.#scanner.rescanBlockchainInsight({
|
|
231
|
-
walletAccount,
|
|
232
|
-
refresh,
|
|
233
|
-
})
|
|
230
|
+
const { txsToAdd, txsToUpdate, utxos, ordinalsUtxos, changedUnusedAddressIndexes } =
|
|
231
|
+
await this.#scanner.rescanBlockchainInsight({
|
|
232
|
+
walletAccount,
|
|
233
|
+
refresh,
|
|
234
|
+
})
|
|
234
235
|
|
|
235
236
|
const newData = {}
|
|
236
237
|
if (utxos || ordinalsUtxos)
|
|
@@ -256,7 +257,7 @@ export class Monitor extends BaseMonitor {
|
|
|
256
257
|
|
|
257
258
|
const txs = [...txsToUpdate, ...txsToAdd]
|
|
258
259
|
|
|
259
|
-
if (txs.length) {
|
|
260
|
+
if (txs.length > 0) {
|
|
260
261
|
await this.updateTxLog({
|
|
261
262
|
assetName,
|
|
262
263
|
logItems: txs,
|
|
@@ -26,6 +26,8 @@ export const indexOutputs = ({ tx, currency }) => {
|
|
|
26
26
|
.map((i) => ({ ...i, offset: i.offset.sub(outputOffset).toBaseNumber() }))
|
|
27
27
|
outputOffset = outputOffset.add(value)
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
29
31
|
tx.inscriptionsMemoryIndexed = true // avoids btc being spent even when the mempool index was done in memory
|
|
30
32
|
return tx
|
|
31
33
|
}
|
|
@@ -35,6 +37,7 @@ export const cachedIndexOrdinalUnconfirmedTx = memoizeLruCache(
|
|
|
35
37
|
if (tx.inscriptionsIndexed || tx.inscriptionsMemoryIndexed) {
|
|
36
38
|
return tx
|
|
37
39
|
}
|
|
40
|
+
|
|
38
41
|
const copyTx = cloneDeep(tx)
|
|
39
42
|
await Promise.all(
|
|
40
43
|
copyTx.vin.map(async (vin) => {
|
|
@@ -46,6 +49,8 @@ export const cachedIndexOrdinalUnconfirmedTx = memoizeLruCache(
|
|
|
46
49
|
if (!outputTx.inscriptionsIndexed && !outputTx.inscriptionsMemoryIndexed) {
|
|
47
50
|
throw new Error(`Cannot index ${tx.txid}. Input tx ${outputTx.txid} is not indexed. `)
|
|
48
51
|
}
|
|
52
|
+
|
|
53
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
49
54
|
vin.inscriptions = outputTx.vout[vin.vout].inscriptions
|
|
50
55
|
})
|
|
51
56
|
)
|
|
@@ -59,6 +64,7 @@ export const indexOrdinalUnconfirmedTx = ({ insightClient, currency, tx }) => {
|
|
|
59
64
|
if (tx.inscriptionsIndexed) {
|
|
60
65
|
return tx
|
|
61
66
|
}
|
|
67
|
+
|
|
62
68
|
return cachedIndexOrdinalUnconfirmedTx({
|
|
63
69
|
insightClient,
|
|
64
70
|
currency,
|
package/src/tx-send/dogecoin.js
CHANGED
|
@@ -3,10 +3,10 @@ export function createInputs(utxos) {
|
|
|
3
3
|
txId: utxo.txId,
|
|
4
4
|
vout: utxo.vout,
|
|
5
5
|
address: utxo.address.toString(),
|
|
6
|
-
value: utxo.value.
|
|
6
|
+
value: utxo.value.toBaseBufferLE(8),
|
|
7
7
|
}))
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function createOutput(address, sendAmount) {
|
|
11
|
-
return [address, sendAmount.
|
|
11
|
+
return [address, sendAmount.toBaseBufferLE(8)]
|
|
12
12
|
}
|