@exodus/bitcoin-api 2.3.5 → 2.3.7
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.7",
|
|
4
4
|
"description": "Exodus bitcoin-api",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -20,12 +20,14 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@exodus/asset-lib": "^3.7.2",
|
|
22
22
|
"@exodus/basic-utils": "^2.0.1",
|
|
23
|
+
"@exodus/bip-schnorr": "0.6.6-fork-1",
|
|
23
24
|
"@exodus/bip44-constants": "^195.0.0",
|
|
24
25
|
"@exodus/bitcoinjs-lib": "6.0.2-beta.5",
|
|
25
26
|
"@exodus/models": "^8.10.4",
|
|
26
27
|
"@exodus/secp256k1": "4.0.2-exodus.0",
|
|
27
28
|
"@exodus/simple-retry": "0.0.6",
|
|
28
29
|
"@exodus/timer": "^1.0.0",
|
|
30
|
+
"@noble/secp256k1": "~1.5.3",
|
|
29
31
|
"bech32": "^1.1.3",
|
|
30
32
|
"coininfo": "5.1.0",
|
|
31
33
|
"delay": "4.0.1",
|
|
@@ -36,11 +38,8 @@
|
|
|
36
38
|
"url-join": "4.0.0"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
|
-
"@exodus/asset-lib": "^3.7.1",
|
|
40
|
-
"@exodus/bcash-meta": "^1.0.0",
|
|
41
|
-
"@exodus/bip-schnorr": "0.6.6-fork-1",
|
|
42
41
|
"@exodus/bitcoin-meta": "^1.0.1",
|
|
43
|
-
"
|
|
42
|
+
"jest-when": "^3.5.1"
|
|
44
43
|
},
|
|
45
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "7a83d2ff5d672615938fba868779293df74ff51d"
|
|
46
45
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
import { orderTxs } from '../insight-api-client/util'
|
|
3
3
|
import { Address, UtxoCollection } from '@exodus/models'
|
|
4
|
-
import { isEqual, compact } from 'lodash'
|
|
4
|
+
import { isEqual, compact, uniq } from 'lodash'
|
|
5
5
|
import ms from 'ms'
|
|
6
6
|
|
|
7
7
|
import assert from 'minimalistic-assert'
|
|
@@ -505,4 +505,56 @@ export class BitcoinMonitorScanner {
|
|
|
505
505
|
changedUnusedAddressIndexes,
|
|
506
506
|
}
|
|
507
507
|
}
|
|
508
|
+
|
|
509
|
+
async rescanOnNewBlock({ walletAccount }) {
|
|
510
|
+
const aci = this.#assetClientInterface
|
|
511
|
+
const asset = this.#asset
|
|
512
|
+
const assetName = this.#asset.name
|
|
513
|
+
|
|
514
|
+
const accountState = await aci.getAccountState({ assetName, walletAccount })
|
|
515
|
+
|
|
516
|
+
const allStoredUtxos = getUtxos({ accountState, asset })
|
|
517
|
+
|
|
518
|
+
const currentTxs = Array.from(await aci.getTxLog({ assetName, walletAccount }))
|
|
519
|
+
|
|
520
|
+
const unconfirmedTxIds = uniq([
|
|
521
|
+
...allStoredUtxos
|
|
522
|
+
.toArray()
|
|
523
|
+
.filter((utxos) => !utxos.confirmations)
|
|
524
|
+
.map((utxos) => utxos.txId),
|
|
525
|
+
...currentTxs.filter((tx) => !tx.dropped && !tx.confirmations).map((tx) => tx.txId),
|
|
526
|
+
])
|
|
527
|
+
|
|
528
|
+
const confirmationsList = (
|
|
529
|
+
await Promise.all(
|
|
530
|
+
unconfirmedTxIds.map(async (txId) => {
|
|
531
|
+
const txStatus = await this.#insightClient.fetchTx(txId)
|
|
532
|
+
if (!txStatus?.confirmations) {
|
|
533
|
+
return undefined
|
|
534
|
+
}
|
|
535
|
+
return { txId, confirmations: txStatus.confirmations }
|
|
536
|
+
})
|
|
537
|
+
)
|
|
538
|
+
).filter(Boolean)
|
|
539
|
+
|
|
540
|
+
const updatedPropertiesTxs = currentTxs
|
|
541
|
+
.map((tx) => {
|
|
542
|
+
const updatedProperties = {}
|
|
543
|
+
const confirmations = confirmationsList.find(({ txId }) => tx.txId === txId)?.confirmations
|
|
544
|
+
if (!tx.dropped && !tx.confirmations && confirmations > 0) {
|
|
545
|
+
updatedProperties.confirmations = confirmations
|
|
546
|
+
}
|
|
547
|
+
return { txId: tx.txId, ...updatedProperties }
|
|
548
|
+
})
|
|
549
|
+
.filter((tx) => Object.keys(tx).length > 1)
|
|
550
|
+
|
|
551
|
+
const txConfirmedUtxos = confirmationsList.length
|
|
552
|
+
? allStoredUtxos.updateConfirmations(confirmationsList)
|
|
553
|
+
: null
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
utxos: txConfirmedUtxos,
|
|
557
|
+
txsToUpdate: updatedPropertiesTxs,
|
|
558
|
+
}
|
|
559
|
+
}
|
|
508
560
|
}
|
|
@@ -94,7 +94,6 @@ export class Monitor extends BaseMonitor {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
#connectWS = async (wsUrl) => {
|
|
97
|
-
const aci = this.aci
|
|
98
97
|
if (this.#ws) {
|
|
99
98
|
this.#ws.close()
|
|
100
99
|
this.#ws = null
|
|
@@ -125,46 +124,7 @@ export class Monitor extends BaseMonitor {
|
|
|
125
124
|
)
|
|
126
125
|
this.tickWalletAccounts({ walletAccount })
|
|
127
126
|
})
|
|
128
|
-
this.#ws.on('block',
|
|
129
|
-
await this.#yieldToUI(100)
|
|
130
|
-
const assetName = this.asset.name
|
|
131
|
-
|
|
132
|
-
const walletAccounts = await aci.getWalletAccounts({ assetName })
|
|
133
|
-
for (const walletAccount of walletAccounts) {
|
|
134
|
-
const currentTxs = Array.from(await aci.getTxLog({ assetName, walletAccount }))
|
|
135
|
-
const updatedPropertiesTxs = await Promise.all(
|
|
136
|
-
currentTxs.map(async (tx) => {
|
|
137
|
-
if (tx.dropped || (tx.confirmations && tx.confirmations > 0)) return null
|
|
138
|
-
const txStatus = await this.#insightClient.fetchTx(tx.txId)
|
|
139
|
-
if (!txStatus) return null
|
|
140
|
-
if (txStatus.confirmations <= 0) return null
|
|
141
|
-
return { txId: tx.txId, confirmations: txStatus.confirmations }
|
|
142
|
-
})
|
|
143
|
-
).then((res) => res.filter((status) => !!status))
|
|
144
|
-
if (updatedPropertiesTxs.length) {
|
|
145
|
-
await this.updateTxLog({ assetName, walletAccount, logItems: updatedPropertiesTxs })
|
|
146
|
-
|
|
147
|
-
const accountState = await aci.getAccountState({ assetName, walletAccount })
|
|
148
|
-
|
|
149
|
-
const utxos = accountState.utxos.updateConfirmations(updatedPropertiesTxs)
|
|
150
|
-
await aci.updateAccountState({
|
|
151
|
-
accountState,
|
|
152
|
-
assetName,
|
|
153
|
-
walletAccount,
|
|
154
|
-
newData: { utxos },
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
if (['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
|
|
158
|
-
updateUnconfirmedAncestorData({
|
|
159
|
-
asset: this.asset,
|
|
160
|
-
walletAccount,
|
|
161
|
-
accountState,
|
|
162
|
-
insightClient: this.#insightClient,
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
})
|
|
127
|
+
this.#ws.on('block', () => this.onNewBlock())
|
|
168
128
|
this.#ws.on('disconnect', () => {
|
|
169
129
|
this.#logWsStatus('disconnect')
|
|
170
130
|
this.timer.setNewInterval(this.interval)
|
|
@@ -175,6 +135,42 @@ export class Monitor extends BaseMonitor {
|
|
|
175
135
|
})
|
|
176
136
|
}
|
|
177
137
|
|
|
138
|
+
async onNewBlock() {
|
|
139
|
+
await this.#yieldToUI(100)
|
|
140
|
+
const aci = this.aci
|
|
141
|
+
const asset = this.asset
|
|
142
|
+
const assetName = asset.name
|
|
143
|
+
const walletAccounts = await aci.getWalletAccounts({ assetName })
|
|
144
|
+
for (const walletAccount of walletAccounts) {
|
|
145
|
+
const { txsToUpdate, utxos } = await this.#scanner.rescanOnNewBlock({
|
|
146
|
+
walletAccount,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
if (utxos) {
|
|
150
|
+
await aci.updateAccountState({
|
|
151
|
+
assetName,
|
|
152
|
+
walletAccount,
|
|
153
|
+
newData: {
|
|
154
|
+
utxos,
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (txsToUpdate.length) {
|
|
160
|
+
const accountState = await aci.getAccountState({ assetName, walletAccount })
|
|
161
|
+
await this.updateTxLog({ assetName, walletAccount, logItems: txsToUpdate })
|
|
162
|
+
if (['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
|
|
163
|
+
updateUnconfirmedAncestorData({
|
|
164
|
+
asset,
|
|
165
|
+
walletAccount,
|
|
166
|
+
accountState,
|
|
167
|
+
insightClient: this.#insightClient,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
178
174
|
#subscribeToNewAddresses = async () => {
|
|
179
175
|
const newAddressesByWalletAccount = await this.#getReceiveAddressesByWalletAccount()
|
|
180
176
|
if (!isEqual(newAddressesByWalletAccount, this.#addressesByWalletAccount)) {
|
package/src/tx-send/index.js
CHANGED
|
@@ -92,21 +92,10 @@ export const getSizeAndChangeScriptFactory = ({ bitcoinJsLib = defaultBitcoinjsL
|
|
|
92
92
|
assert(rawTx, 'rawTx is required')
|
|
93
93
|
assert(typeof changeUtxoIndex === 'number', 'changeUtxoIndex must be a number')
|
|
94
94
|
|
|
95
|
-
const getSize = (tx) => {
|
|
96
|
-
if (typeof tx.size === 'number') return tx.size
|
|
97
|
-
if (typeof tx.virtualSize === 'function') {
|
|
98
|
-
return tx.virtualSize()
|
|
99
|
-
}
|
|
100
|
-
if (typeof tx.virtualSize === 'number') {
|
|
101
|
-
return tx.virtualSize
|
|
102
|
-
}
|
|
103
|
-
return undefined
|
|
104
|
-
}
|
|
105
|
-
|
|
106
95
|
if (tx) {
|
|
107
96
|
return {
|
|
108
|
-
script: tx.outs?.[changeUtxoIndex]?.script
|
|
109
|
-
size:
|
|
97
|
+
script: tx.outs?.[changeUtxoIndex]?.script,
|
|
98
|
+
size: tx.virtualSize,
|
|
110
99
|
}
|
|
111
100
|
}
|
|
112
101
|
// Trezor doesn't return tx!! we need to reparse it!
|
|
@@ -114,7 +103,7 @@ export const getSizeAndChangeScriptFactory = ({ bitcoinJsLib = defaultBitcoinjsL
|
|
|
114
103
|
try {
|
|
115
104
|
return {
|
|
116
105
|
script: parsedTx.outs?.[changeUtxoIndex]?.script.toString('hex'),
|
|
117
|
-
size:
|
|
106
|
+
size: tx.virtualSize?.(),
|
|
118
107
|
}
|
|
119
108
|
} catch (e) {
|
|
120
109
|
console.warn(
|
|
@@ -24,6 +24,16 @@ const canParseTx = (rawTxBuffer) => {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export const serializeTx = ({ tx }) => {
|
|
28
|
+
// for desktop compatibility
|
|
29
|
+
return {
|
|
30
|
+
virtualSize: tx.virtualSize?.(),
|
|
31
|
+
outs: tx.outs?.map((out) => ({
|
|
32
|
+
script: out.script.toString('hex'),
|
|
33
|
+
})),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, network, ecc }) => {
|
|
28
38
|
assert(assetName, 'assetName is required')
|
|
29
39
|
assert(resolvePurpose, 'resolvePurpose is required')
|
|
@@ -134,6 +144,6 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
|
|
|
134
144
|
const txId = tx.getId()
|
|
135
145
|
|
|
136
146
|
// tx needs to be serializable for desktop RPC send => sign communication
|
|
137
|
-
return { rawTx, txId, tx: {
|
|
147
|
+
return { rawTx, txId, tx: serializeTx({ tx }) }
|
|
138
148
|
}
|
|
139
149
|
}
|
package/src/tx-sign/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { signTxFactory } from './default-create-tx'
|
|
1
|
+
export { signTxFactory, serializeTx } from './default-create-tx'
|
package/src/utxos-utils.js
CHANGED
|
@@ -12,18 +12,12 @@ export function getUtxos({ accountState, asset }) {
|
|
|
12
12
|
)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function getConfirmedUtxos({
|
|
16
|
-
assert(asset, 'asset is required')
|
|
15
|
+
export function getConfirmedUtxos({ utxos }) {
|
|
17
16
|
assert(utxos, 'utxos is required')
|
|
18
|
-
|
|
19
|
-
return UtxoCollection.fromArray(
|
|
20
|
-
utxos.toArray().filter(({ confirmations }) => confirmations > 0),
|
|
21
|
-
{ currency }
|
|
22
|
-
)
|
|
17
|
+
return utxos.filter(({ confirmations }) => confirmations > 0)
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
export function getConfirmedOrRfbDisabledUtxos({
|
|
26
|
-
assert(asset, 'asset is required')
|
|
20
|
+
export function getConfirmedOrRfbDisabledUtxos({ utxos, allowUnconfirmedRbfEnabledUtxos }) {
|
|
27
21
|
assert(utxos, 'utxos is required')
|
|
28
22
|
assert(
|
|
29
23
|
allowUnconfirmedRbfEnabledUtxos !== undefined,
|
|
@@ -32,11 +26,7 @@ export function getConfirmedOrRfbDisabledUtxos({ asset, utxos, allowUnconfirmedR
|
|
|
32
26
|
if (allowUnconfirmedRbfEnabledUtxos) {
|
|
33
27
|
return utxos
|
|
34
28
|
}
|
|
35
|
-
|
|
36
|
-
return UtxoCollection.fromArray(
|
|
37
|
-
utxos.toArray().filter((utxo) => utxo.confirmations > 0 || !utxo.rbfEnabled),
|
|
38
|
-
{ currency }
|
|
39
|
-
)
|
|
29
|
+
return utxos.filter((utxo) => utxo.confirmations > 0 || !utxo.rbfEnabled)
|
|
40
30
|
}
|
|
41
31
|
|
|
42
32
|
export function getUsableUtxos({ asset, utxos, feeData, txSet }) {
|
|
@@ -58,8 +48,5 @@ export function getUsableUtxos({ asset, utxos, feeData, txSet }) {
|
|
|
58
48
|
})
|
|
59
49
|
return largeUnconfirmedTxs.size === 0
|
|
60
50
|
? utxos
|
|
61
|
-
:
|
|
62
|
-
utxos.toArray().filter((utxo) => !largeUnconfirmedTxs.has(utxo.txId)),
|
|
63
|
-
{ currency: asset.currency }
|
|
64
|
-
)
|
|
51
|
+
: utxos.filter((utxo) => !largeUnconfirmedTxs.has(utxo.txId))
|
|
65
52
|
}
|