@exodus/bitcoin-api 2.7.8 → 2.8.1
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/account-state.js +1 -0
- package/src/fee/can-bump-tx.js +1 -1
- package/src/insight-api-client/index.js +1 -2
- package/src/tx-log/bitcoin-monitor-scanner.js +19 -3
- package/src/tx-send/index.js +1 -1
- package/src/tx-sign/create-sign-with-wallet.js +7 -3
- package/src/utxos-utils.js +51 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Exodus bitcoin-api",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"coininfo": "5.1.0",
|
|
33
33
|
"delay": "4.0.1",
|
|
34
34
|
"ecpair": "2.0.1",
|
|
35
|
-
"querystring": "0.2.0",
|
|
36
35
|
"socket.io-client": "2.1.1",
|
|
37
36
|
"tiny-secp256k1": "1.1.3",
|
|
38
37
|
"url-join": "4.0.0"
|
|
@@ -43,5 +42,5 @@
|
|
|
43
42
|
"@scure/btc-signer": "^1.1.0",
|
|
44
43
|
"jest-when": "^3.5.1"
|
|
45
44
|
},
|
|
46
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "652eb821c1fe5b2bd561710d05fcb569d9f4a137"
|
|
47
46
|
}
|
package/src/account-state.js
CHANGED
package/src/fee/can-bump-tx.js
CHANGED
|
@@ -3,7 +3,7 @@ import assert from 'minimalistic-assert'
|
|
|
3
3
|
import { findUnconfirmedSentRbfTxs } from '../tx-utils'
|
|
4
4
|
import { getUsableUtxos, getUtxos } from '../utxos-utils'
|
|
5
5
|
|
|
6
|
-
import { BumpType } from '@exodus/bitcoin-lib
|
|
6
|
+
import { BumpType } from '@exodus/bitcoin-lib'
|
|
7
7
|
|
|
8
8
|
export const ASSET_NAMES = ['bitcoin', 'bitcoinregtest', 'bitcointestnet']
|
|
9
9
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* global fetch */
|
|
2
2
|
import urlJoin from 'url-join'
|
|
3
|
-
import qs from 'querystring'
|
|
4
3
|
import delay from 'delay'
|
|
5
4
|
import { isEmpty } from 'lodash'
|
|
6
5
|
|
|
@@ -133,7 +132,7 @@ export default class InsightAPIClient {
|
|
|
133
132
|
if (!Array.isArray(addrs) || addrs.length === 0) return { items: [], totalItems: 0 }
|
|
134
133
|
|
|
135
134
|
options = { noScriptSig: 1, noAsm: 1, noSpent: 0, from: 0, to: 10, ...options }
|
|
136
|
-
const url = `${urlJoin(this._baseURL, `/addrs/txs`)}?${
|
|
135
|
+
const url = `${urlJoin(this._baseURL, `/addrs/txs`)}?${new URLSearchParams(options)}`
|
|
137
136
|
|
|
138
137
|
const fetchOptions = {
|
|
139
138
|
method: 'post',
|
|
@@ -590,12 +590,19 @@ export class BitcoinMonitorScanner {
|
|
|
590
590
|
})
|
|
591
591
|
|
|
592
592
|
const ordinalAddress = await this.getOrdinalAddress({ walletAccount })
|
|
593
|
+
|
|
594
|
+
// latest account state, in case knownBalanceUtxoIds or mustAvoidUtxoIds gets updated in on another promise
|
|
595
|
+
const latestAccountState = await assetClientInterface.getAccountState({
|
|
596
|
+
assetName,
|
|
597
|
+
walletAccount,
|
|
598
|
+
})
|
|
593
599
|
const utxosData = utxoCol
|
|
594
600
|
? partitionUtxos({
|
|
595
601
|
allUtxos: utxoCol,
|
|
596
602
|
ordinalsEnabled: this.#ordinalsEnabled,
|
|
597
603
|
ordinalAddress,
|
|
598
|
-
knownBalanceUtxoIds:
|
|
604
|
+
knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
|
|
605
|
+
mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
|
|
599
606
|
})
|
|
600
607
|
: {}
|
|
601
608
|
|
|
@@ -653,11 +660,20 @@ export class BitcoinMonitorScanner {
|
|
|
653
660
|
|
|
654
661
|
const txConfirmedUtxos = allStoredUtxos.updateConfirmations(confirmationsList)
|
|
655
662
|
|
|
663
|
+
const ordinalAddress = await this.getOrdinalAddress({ walletAccount })
|
|
664
|
+
|
|
665
|
+
// latest account state, in case knownBalanceUtxoIds or mustAvoidUtxoIds gets updated in on another promise
|
|
666
|
+
const latestAccountState = await aci.getAccountState({
|
|
667
|
+
assetName,
|
|
668
|
+
walletAccount,
|
|
669
|
+
})
|
|
670
|
+
|
|
656
671
|
const { utxos, ordinalsUtxos } = partitionUtxos({
|
|
657
672
|
allUtxos: txConfirmedUtxos,
|
|
658
673
|
ordinalsEnabled: this.#ordinalsEnabled,
|
|
659
|
-
ordinalAddress:
|
|
660
|
-
knownBalanceUtxoIds:
|
|
674
|
+
ordinalAddress: ordinalAddress,
|
|
675
|
+
knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
|
|
676
|
+
mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
|
|
661
677
|
})
|
|
662
678
|
|
|
663
679
|
return {
|
package/src/tx-send/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import doShuffle from 'lodash/shuffle'
|
|
|
5
5
|
import { UtxoCollection, Address } from '@exodus/models'
|
|
6
6
|
import { retry } from '@exodus/simple-retry'
|
|
7
7
|
import { selectUtxos } from '../fee/utxo-selector'
|
|
8
|
-
import getTxSequence from '@exodus/bitcoin-lib
|
|
8
|
+
import { getTxSequence } from '@exodus/bitcoin-lib'
|
|
9
9
|
|
|
10
10
|
import { parseCurrency } from '../fee/fee-utils'
|
|
11
11
|
|
|
@@ -33,8 +33,12 @@ export function createSignWithWallet({
|
|
|
33
33
|
// dApps request to sign only specific transaction inputs.
|
|
34
34
|
if (!inputInfo) continue
|
|
35
35
|
const { address, sigHash } = inputInfo
|
|
36
|
-
//
|
|
37
|
-
|
|
36
|
+
// The sighash value from the PSBT input itself will be used.
|
|
37
|
+
// This list just represents possible sighash values the inputs can have.
|
|
38
|
+
const allowedSigHashTypes =
|
|
39
|
+
sigHash !== undefined
|
|
40
|
+
? [sigHash, Transaction.SIGHASH_ALL] // `SIGHASH_DEFAULT` is a default safe sig hash, always allow it.
|
|
41
|
+
: undefined
|
|
38
42
|
const { key, purpose, publicKey } = getKeyAndPurpose(address)
|
|
39
43
|
|
|
40
44
|
const isP2SH = purpose === 49
|
|
@@ -67,7 +71,7 @@ export function createSignWithWallet({
|
|
|
67
71
|
|
|
68
72
|
// desktop / BE / mobile with bip-schnorr signing
|
|
69
73
|
const signingKey = isTaprootAddress ? tweakSigner({ signer: key, ECPair, network }) : key
|
|
70
|
-
await psbt.signInputAsync(index, toAsyncSigner({ keyPair: signingKey }),
|
|
74
|
+
await psbt.signInputAsync(index, toAsyncSigner({ keyPair: signingKey }), allowedSigHashTypes)
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
}
|
package/src/utxos-utils.js
CHANGED
|
@@ -5,18 +5,32 @@ import assert from 'minimalistic-assert'
|
|
|
5
5
|
|
|
6
6
|
const MAX_ORDINAL_VALUE_POSTAGE = 10000
|
|
7
7
|
|
|
8
|
+
export const getInscriptionTxId = (inscriptionId) => {
|
|
9
|
+
return inscriptionId.split('i')[0]
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
export function getTransferOrdinalsUtxos({ inscriptionIds, ordinalsUtxos }) {
|
|
9
13
|
const transferOrdinalsUtxos = ordinalsUtxos.filter((utxo) =>
|
|
10
14
|
utxo.inscriptions?.some((i) => inscriptionIds.includes(i.inscriptionId))
|
|
11
15
|
)
|
|
16
|
+
|
|
17
|
+
// this is for the micky mouse case. It has 2 inscriptions from the same tx but different output
|
|
18
|
+
const inscriptionTxs = inscriptionIds.map(getInscriptionTxId)
|
|
19
|
+
|
|
20
|
+
// https://ordinals.hiro.so/inscription/862ecd0fe343da32d19ff9277639ff71e10d894f55b6dee82dbfb9c158d5d30ci0
|
|
21
|
+
// https://ordinals.hiro.so/inscription/862ecd0fe343da32d19ff9277639ff71e10d894f55b6dee82dbfb9c158d5d30ci1
|
|
22
|
+
|
|
12
23
|
const unsafeInscriptions = transferOrdinalsUtxos.toArray().flatMap(
|
|
13
24
|
(utxo) =>
|
|
14
|
-
utxo.inscriptions?.filter((
|
|
25
|
+
utxo.inscriptions?.filter((inscription) => {
|
|
15
26
|
const validInscription = isValidInscription({
|
|
16
27
|
value: utxo.value.toBaseNumber(),
|
|
17
|
-
offset:
|
|
28
|
+
offset: inscription.offset,
|
|
18
29
|
})
|
|
19
|
-
return
|
|
30
|
+
return (
|
|
31
|
+
validInscription &&
|
|
32
|
+
!inscriptionTxs.includes(getInscriptionTxId(inscription.inscriptionId))
|
|
33
|
+
)
|
|
20
34
|
}) || []
|
|
21
35
|
)
|
|
22
36
|
assert(
|
|
@@ -69,13 +83,23 @@ export function getValidInscriptions({ utxo }) {
|
|
|
69
83
|
)
|
|
70
84
|
}
|
|
71
85
|
|
|
72
|
-
function isOrdinalUtxo({
|
|
86
|
+
function isOrdinalUtxo({
|
|
87
|
+
utxo,
|
|
88
|
+
ordinalsEnabled,
|
|
89
|
+
knownBalanceUtxoIds,
|
|
90
|
+
ordinalAddress,
|
|
91
|
+
mustAvoidUtxoIds,
|
|
92
|
+
}) {
|
|
73
93
|
if (!ordinalsEnabled) {
|
|
74
94
|
return false
|
|
75
95
|
}
|
|
76
96
|
|
|
77
97
|
const utxoId = `${utxo.txId}:${utxo.vout}`.toLowerCase()
|
|
78
98
|
|
|
99
|
+
if (mustAvoidUtxoIds && mustAvoidUtxoIds.includes(utxoId)) {
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
|
|
79
103
|
if (knownBalanceUtxoIds?.includes(utxoId) && !utxo.inscriptionsIndexed) {
|
|
80
104
|
return false // this allows users see and spend change balance after sending before hiro confirmation
|
|
81
105
|
}
|
|
@@ -98,15 +122,34 @@ function isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds, ordinalAddr
|
|
|
98
122
|
return hasOrdinals
|
|
99
123
|
}
|
|
100
124
|
|
|
101
|
-
export function partitionUtxos({
|
|
125
|
+
export function partitionUtxos({
|
|
126
|
+
allUtxos,
|
|
127
|
+
ordinalsEnabled,
|
|
128
|
+
knownBalanceUtxoIds,
|
|
129
|
+
ordinalAddress,
|
|
130
|
+
mustAvoidUtxoIds,
|
|
131
|
+
}) {
|
|
102
132
|
assert(allUtxos, 'allUtxos is required')
|
|
103
|
-
if (ordinalsEnabled) assert(ordinalAddress, 'ordinalAddress is required')
|
|
133
|
+
if (ordinalsEnabled) assert(ordinalAddress, 'ordinalAddress is required')
|
|
104
134
|
return {
|
|
105
135
|
utxos: allUtxos.filter(
|
|
106
|
-
(utxo) =>
|
|
136
|
+
(utxo) =>
|
|
137
|
+
!isOrdinalUtxo({
|
|
138
|
+
utxo,
|
|
139
|
+
ordinalsEnabled,
|
|
140
|
+
knownBalanceUtxoIds,
|
|
141
|
+
ordinalAddress,
|
|
142
|
+
mustAvoidUtxoIds,
|
|
143
|
+
})
|
|
107
144
|
),
|
|
108
145
|
ordinalsUtxos: allUtxos.filter((utxo) =>
|
|
109
|
-
isOrdinalUtxo({
|
|
146
|
+
isOrdinalUtxo({
|
|
147
|
+
utxo,
|
|
148
|
+
ordinalsEnabled,
|
|
149
|
+
knownBalanceUtxoIds,
|
|
150
|
+
ordinalAddress,
|
|
151
|
+
mustAvoidUtxoIds,
|
|
152
|
+
})
|
|
110
153
|
),
|
|
111
154
|
}
|
|
112
155
|
}
|