@exodus/bitcoin-api 4.15.4 → 4.15.6
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 +20 -0
- package/package.json +2 -2
- package/src/move-funds.js +1 -0
- package/src/psbt-utils.js +2 -3
- package/src/tx-create/create-tx.js +1 -0
- package/src/tx-log/bitcoin-monitor-scanner.js +28 -0
- package/src/tx-sign/create-sign-with-wallet.js +2 -0
- package/src/tx-sign/default-create-tx.js +4 -0
- package/src/tx-sign/default-prepare-for-signing.js +1 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.15.6](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.15.5...@exodus/bitcoin-api@4.15.6) (2026-06-03)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: remove stale stored UTXOs during refresh (#8184)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [4.15.5](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.15.4...@exodus/bitcoin-api@4.15.5) (2026-06-02)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* fix: restrict unsafe non-segwit signing to internal LTC PSBTs (#8172)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [4.15.4](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.15.3...@exodus/bitcoin-api@4.15.4) (2026-05-28)
|
|
7
27
|
|
|
8
28
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "4.15.
|
|
3
|
+
"version": "4.15.6",
|
|
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",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"type": "git",
|
|
64
64
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "c19821f0073cd61c5e2a6b07c962165e8ee77416"
|
|
67
67
|
}
|
package/src/move-funds.js
CHANGED
package/src/psbt-utils.js
CHANGED
|
@@ -118,10 +118,9 @@ export const createPsbtToUnsignedTx =
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
-
* Temporarily
|
|
122
|
-
* whose legacy inputs are missing nonWitnessUtxo.
|
|
121
|
+
* Temporarily sets __UNSAFE_SIGN_NONSEGWIT for explicitly allowed internal fallbacks.
|
|
123
122
|
*/
|
|
124
|
-
export async function withUnsafeNonSegwit({ psbt, fn, unsafe =
|
|
123
|
+
export async function withUnsafeNonSegwit({ psbt, fn, unsafe = false }) {
|
|
125
124
|
const cache = psbt.__CACHE
|
|
126
125
|
const prevValue = cache.__UNSAFE_SIGN_NONSEGWIT
|
|
127
126
|
cache.__UNSAFE_SIGN_NONSEGWIT = unsafe
|
|
@@ -258,6 +258,14 @@ export class BitcoinMonitorScanner {
|
|
|
258
258
|
// newChains moves receive to 7. The second loop then scans receive 8..12
|
|
259
259
|
// and change 7..7. This keeps expanding until the fetched address batch has no txs.
|
|
260
260
|
let allTxs = []
|
|
261
|
+
const scannedAddressSet = new Set()
|
|
262
|
+
const fetchStoredUtxoAddressTxs = async ({ storedUtxoAddresses }) => {
|
|
263
|
+
const storedOnlyAddresses = [...storedUtxoAddresses].filter(
|
|
264
|
+
(storedUtxoAddress) => !scannedAddressSet.has(storedUtxoAddress)
|
|
265
|
+
)
|
|
266
|
+
return fetchAllTxs(storedOnlyAddresses)
|
|
267
|
+
}
|
|
268
|
+
|
|
261
269
|
for (let fetchCount = 0; ; fetchCount++) {
|
|
262
270
|
const chainObjects = gapSearchParameters.flatMap(
|
|
263
271
|
({ purpose, chain, startAddressIndexes, endAddressIndexes }) => {
|
|
@@ -289,6 +297,7 @@ export class BitcoinMonitorScanner {
|
|
|
289
297
|
}
|
|
290
298
|
|
|
291
299
|
const addresses = await aggregateAddresses(chainObjects)
|
|
300
|
+
addresses.forEach((address) => scannedAddressSet.add(address))
|
|
292
301
|
|
|
293
302
|
if (fetchCount === 0) {
|
|
294
303
|
// in compatibility mode, the receive address could be different
|
|
@@ -299,6 +308,7 @@ export class BitcoinMonitorScanner {
|
|
|
299
308
|
})
|
|
300
309
|
if (!addresses.includes(receiveAddress.toString())) {
|
|
301
310
|
addresses.push(receiveAddress.toString())
|
|
311
|
+
scannedAddressSet.add(receiveAddress.toString())
|
|
302
312
|
addrMap[receiveAddress.toString()] = receiveAddress
|
|
303
313
|
}
|
|
304
314
|
}
|
|
@@ -370,6 +380,16 @@ export class BitcoinMonitorScanner {
|
|
|
370
380
|
}
|
|
371
381
|
|
|
372
382
|
allTxs = orderTxs(allTxs)
|
|
383
|
+
let storedUtxoAddressTxs = []
|
|
384
|
+
if (refresh) {
|
|
385
|
+
const storedUtxoAddresses = new Set(
|
|
386
|
+
storedUtxos
|
|
387
|
+
.toArray()
|
|
388
|
+
.map((utxo) => utxo.address?.toString())
|
|
389
|
+
.filter(Boolean)
|
|
390
|
+
)
|
|
391
|
+
storedUtxoAddressTxs = await fetchStoredUtxoAddressTxs({ storedUtxoAddresses })
|
|
392
|
+
}
|
|
373
393
|
|
|
374
394
|
// post process TX data
|
|
375
395
|
// NOTE: this can be optimized
|
|
@@ -379,6 +399,14 @@ export class BitcoinMonitorScanner {
|
|
|
379
399
|
const newTxs = []
|
|
380
400
|
const existingTxs = []
|
|
381
401
|
|
|
402
|
+
storedUtxoAddressTxs.forEach((txItem) => {
|
|
403
|
+
txItem.vin.forEach((vin) => {
|
|
404
|
+
if (Object.keys(vin).length === 0) return
|
|
405
|
+
|
|
406
|
+
vinTxids[`${vin.txid}-${vin.vout}`] = true
|
|
407
|
+
})
|
|
408
|
+
})
|
|
409
|
+
|
|
382
410
|
allTxs.forEach((txItem) => {
|
|
383
411
|
const isCoinbase = txItem.vin.length === 0
|
|
384
412
|
|
|
@@ -14,6 +14,7 @@ export function createSignWithWallet({
|
|
|
14
14
|
coinInfo,
|
|
15
15
|
getKeyIdentifier,
|
|
16
16
|
getPrivateKeyFromMap,
|
|
17
|
+
allowUnsafeNonSegwit = false,
|
|
17
18
|
}) {
|
|
18
19
|
const getKeyWithMetadata = createGetKeyWithMetadata({
|
|
19
20
|
signer,
|
|
@@ -90,6 +91,7 @@ export function createSignWithWallet({
|
|
|
90
91
|
await withUnsafeNonSegwit({
|
|
91
92
|
psbt,
|
|
92
93
|
fn: () => Promise.all(signingPromises.map((sign) => sign())),
|
|
94
|
+
unsafe: allowUnsafeNonSegwit,
|
|
93
95
|
})
|
|
94
96
|
}
|
|
95
97
|
}
|
|
@@ -12,6 +12,7 @@ export const signTxFactory = ({
|
|
|
12
12
|
network,
|
|
13
13
|
getKeyIdentifier,
|
|
14
14
|
getPrivateKeyFromMap,
|
|
15
|
+
allowUnsafeNonSegwitSigning = false,
|
|
15
16
|
Psbt = DefaultPsbt,
|
|
16
17
|
Transaction = DefaultTransaction,
|
|
17
18
|
}) => {
|
|
@@ -39,6 +40,8 @@ export const signTxFactory = ({
|
|
|
39
40
|
const psbt = prepareForSigning({ unsignedTx })
|
|
40
41
|
|
|
41
42
|
const inputsToSign = unsignedTx.txMeta.inputsToSign || unsignedTx.txData.inputs
|
|
43
|
+
const allowUnsafeNonSegwit =
|
|
44
|
+
allowUnsafeNonSegwitSigning && unsignedTx.txMeta.psbtOrigin === 'internal'
|
|
42
45
|
const signWithWallet = createSignWithWallet({
|
|
43
46
|
signer,
|
|
44
47
|
hdkeys,
|
|
@@ -48,6 +51,7 @@ export const signTxFactory = ({
|
|
|
48
51
|
addressPathsMap,
|
|
49
52
|
coinInfo,
|
|
50
53
|
network,
|
|
54
|
+
allowUnsafeNonSegwit,
|
|
51
55
|
getKeyIdentifier: (args) => {
|
|
52
56
|
assert(
|
|
53
57
|
!('accountIndex' in args) || args.accountIndex === accountIndex,
|
|
@@ -130,9 +130,7 @@ function createPsbtFromTxData({
|
|
|
130
130
|
if (canParseTx(Transaction, rawTxBuffer)) {
|
|
131
131
|
txIn.nonWitnessUtxo = rawTxBuffer
|
|
132
132
|
} else {
|
|
133
|
-
|
|
134
|
-
console.warn(`Setting psbt.__CACHE.__UNSAFE_SIGN_NONSEGWIT = true for asset ${assetName}`)
|
|
135
|
-
psbt.__CACHE.__UNSAFE_SIGN_NONSEGWIT = true
|
|
133
|
+
console.warn(`Falling back to witnessUtxo for unparseable previous tx on ${assetName}`)
|
|
136
134
|
txIn.witnessUtxo = {
|
|
137
135
|
value: normalizeWitnessUtxoValue(value),
|
|
138
136
|
script: Buffer.from(script, 'hex'),
|