@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/tx-sign/common.js
CHANGED
|
@@ -6,16 +6,16 @@ export function extractTransaction({ psbt, skipFinalize }) {
|
|
|
6
6
|
const rawPSBT = psbt.toBuffer()
|
|
7
7
|
|
|
8
8
|
return { plainTx: { rawPSBT } }
|
|
9
|
-
} else {
|
|
10
|
-
// Serialize tx
|
|
11
|
-
psbt.finalizeAllInputs()
|
|
12
|
-
const tx = psbt.extractTransaction()
|
|
13
|
-
const rawTx = tx.toBuffer()
|
|
14
|
-
const txId = tx.getId()
|
|
15
|
-
|
|
16
|
-
// tx needs to be serializable for desktop RPC send => sign communication
|
|
17
|
-
return { rawTx, txId, tx: serializeTx({ tx }) }
|
|
18
9
|
}
|
|
10
|
+
|
|
11
|
+
// Serialize tx
|
|
12
|
+
psbt.finalizeAllInputs()
|
|
13
|
+
const tx = psbt.extractTransaction()
|
|
14
|
+
const rawTx = tx.toBuffer()
|
|
15
|
+
const txId = tx.getId()
|
|
16
|
+
|
|
17
|
+
// tx needs to be serializable for desktop RPC send => sign communication
|
|
18
|
+
return { rawTx, txId, tx: serializeTx({ tx }) }
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export const serializeTx = ({ tx }) => {
|
|
@@ -20,9 +20,9 @@ export const createGetKeyAndPurpose = ({
|
|
|
20
20
|
const networkInfo = coinInfo.toBitcoinJS()
|
|
21
21
|
if (privateKeysAddressMap) {
|
|
22
22
|
return getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address)
|
|
23
|
-
} else {
|
|
24
|
-
return getPrivateKeyFromHDKeys(hdkeys, addressPathsMap, keys, networkInfo, purpose, address)
|
|
25
23
|
}
|
|
24
|
+
|
|
25
|
+
return getPrivateKeyFromHDKeys(hdkeys, addressPathsMap, keys, networkInfo, purpose, address)
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
function getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address) {
|
|
@@ -36,9 +36,9 @@ export function createSignWithWallet({
|
|
|
36
36
|
// The sighash value from the PSBT input itself will be used.
|
|
37
37
|
// This list just represents possible sighash values the inputs can have.
|
|
38
38
|
const allowedSigHashTypes =
|
|
39
|
-
sigHash
|
|
40
|
-
?
|
|
41
|
-
:
|
|
39
|
+
sigHash === undefined
|
|
40
|
+
? undefined // `SIGHASH_DEFAULT` is a default safe sig hash, always allow it.
|
|
41
|
+
: [sigHash, Transaction.SIGHASH_ALL]
|
|
42
42
|
const { key, purpose, publicKey } = getKeyAndPurpose(address)
|
|
43
43
|
|
|
44
44
|
const isP2SH = purpose === 49
|
|
@@ -2,8 +2,8 @@ import assert from 'minimalistic-assert'
|
|
|
2
2
|
import { Psbt, Transaction } from '@exodus/bitcoinjs-lib'
|
|
3
3
|
|
|
4
4
|
const _MAXIMUM_FEE_RATES = {
|
|
5
|
-
qtumignition:
|
|
6
|
-
ravencoin:
|
|
5
|
+
qtumignition: 25_000,
|
|
6
|
+
ravencoin: 1_000_000,
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -24,27 +24,25 @@ export function createPrepareForSigning({ assetName, resolvePurpose, coinInfo })
|
|
|
24
24
|
if (isPsbtBufferPassed) {
|
|
25
25
|
// PSBT created externally (Web3, etc..)
|
|
26
26
|
return createPsbtFromBuffer({ psbtBuffer: unsignedTx.txData.psbtBuffer })
|
|
27
|
-
} else {
|
|
28
|
-
// Create PSBT based on internal Exodus data structure
|
|
29
|
-
const networkInfo = coinInfo.toBitcoinJS()
|
|
30
|
-
const psbt = createPsbtFromTxData({
|
|
31
|
-
...unsignedTx.txData,
|
|
32
|
-
...unsignedTx.txMeta,
|
|
33
|
-
resolvePurpose,
|
|
34
|
-
networkInfo,
|
|
35
|
-
})
|
|
36
|
-
if (!['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) psbt.setVersion(1)
|
|
37
|
-
|
|
38
|
-
return psbt
|
|
39
27
|
}
|
|
28
|
+
|
|
29
|
+
// Create PSBT based on internal Exodus data structure
|
|
30
|
+
const networkInfo = coinInfo.toBitcoinJS()
|
|
31
|
+
const psbt = createPsbtFromTxData({
|
|
32
|
+
...unsignedTx.txData,
|
|
33
|
+
...unsignedTx.txMeta,
|
|
34
|
+
resolvePurpose,
|
|
35
|
+
networkInfo,
|
|
36
|
+
})
|
|
37
|
+
if (!['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) psbt.setVersion(1)
|
|
38
|
+
|
|
39
|
+
return psbt
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// Creates a PSBT instance from the passed transaction buffer provided by 3rd parties (e.g. dApps).
|
|
44
44
|
function createPsbtFromBuffer({ psbtBuffer, ecc }) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return psbt
|
|
45
|
+
return Psbt.fromBuffer(psbtBuffer, { eccLib: ecc })
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
// Creates a PSBT instance from the passed inputs, outputs etc. The wallet itself provides this data.
|
|
@@ -97,7 +95,7 @@ const canParseTx = (rawTxBuffer) => {
|
|
|
97
95
|
try {
|
|
98
96
|
Transaction.fromBuffer(rawTxBuffer)
|
|
99
97
|
return true
|
|
100
|
-
} catch
|
|
98
|
+
} catch {
|
|
101
99
|
return false
|
|
102
100
|
}
|
|
103
101
|
}
|
|
@@ -58,12 +58,13 @@ function createSignWithHardwareWallet({ assetName, resolvePurpose }) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function getDerivationPaths({ resolvePurpose, accountIndex, addressPathsMap }) {
|
|
61
|
-
|
|
61
|
+
const derivationPaths = []
|
|
62
62
|
for (const [address, path] of Object.entries(addressPathsMap)) {
|
|
63
63
|
const purpose = resolvePurpose(address)
|
|
64
64
|
const derivationPath = `m/${purpose}'/0'/${accountIndex}'/${path.slice(2)}` // TODO: coinindex
|
|
65
65
|
derivationPaths.push(derivationPath)
|
|
66
66
|
}
|
|
67
|
+
|
|
67
68
|
return derivationPaths
|
|
68
69
|
}
|
|
69
70
|
|
package/src/tx-sign/taproot.js
CHANGED
|
@@ -15,6 +15,7 @@ export function tweakSigner({ signer, tweakHash, network }) {
|
|
|
15
15
|
if (!privateKey) {
|
|
16
16
|
throw new Error('Private key is required for tweaking signer!')
|
|
17
17
|
}
|
|
18
|
+
|
|
18
19
|
if (signer.publicKey[0] === 3) {
|
|
19
20
|
privateKey = ecc.privateNegate(privateKey)
|
|
20
21
|
}
|
|
@@ -41,14 +42,17 @@ function tapTweakHash(pubKey, h) {
|
|
|
41
42
|
*/
|
|
42
43
|
export function toAsyncSigner({ keyPair }) {
|
|
43
44
|
assert(keyPair, 'keyPair is required')
|
|
45
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
44
46
|
keyPair.sign = async (h) => {
|
|
45
47
|
const sig = await ecc.signAsync(h, keyPair.privateKey)
|
|
46
48
|
return Buffer.from(sig)
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
49
52
|
keyPair.signSchnorr = async (h) => {
|
|
50
53
|
const sig = await ecc.signSchnorrAsync(h, keyPair.privateKey, getSchnorrEntropy())
|
|
51
54
|
return Buffer.from(sig)
|
|
52
55
|
}
|
|
56
|
+
|
|
53
57
|
return keyPair
|
|
54
58
|
}
|
package/src/tx-utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveExtraFeeOfTx } from './unconfirmed-ancestor-data'
|
|
2
2
|
|
|
3
3
|
export const findUnconfirmedSentRbfTxs = (txSet) =>
|
|
4
|
-
|
|
4
|
+
[...txSet].filter(
|
|
5
5
|
(tx) =>
|
|
6
6
|
tx.sent &&
|
|
7
7
|
tx.pending &&
|
|
@@ -12,10 +12,9 @@ export const findUnconfirmedSentRbfTxs = (txSet) =>
|
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
export const findLargeUnconfirmedTxs = ({ txSet, feeRate, maxFee, unconfirmedTxAncestor }) =>
|
|
15
|
-
|
|
16
|
-
? new Set(
|
|
17
|
-
|
|
18
|
-
Array.from(txSet)
|
|
15
|
+
txSet
|
|
16
|
+
? new Set(
|
|
17
|
+
[...txSet]
|
|
19
18
|
.filter((tx) => {
|
|
20
19
|
if (!tx.pending) return false
|
|
21
20
|
const extraFee = resolveExtraFeeOfTx({
|
|
@@ -27,3 +26,4 @@ export const findLargeUnconfirmedTxs = ({ txSet, feeRate, maxFee, unconfirmedTxA
|
|
|
27
26
|
})
|
|
28
27
|
.map((tx) => tx.txId)
|
|
29
28
|
)
|
|
29
|
+
: new Set()
|
package/src/utxos-utils.js
CHANGED
|
@@ -3,7 +3,7 @@ import { UtxoCollection } from '@exodus/models'
|
|
|
3
3
|
import { findLargeUnconfirmedTxs } from './tx-utils'
|
|
4
4
|
import assert from 'minimalistic-assert'
|
|
5
5
|
|
|
6
|
-
const MAX_ORDINAL_VALUE_POSTAGE =
|
|
6
|
+
const MAX_ORDINAL_VALUE_POSTAGE = 10_000
|
|
7
7
|
|
|
8
8
|
export const getInscriptionTxId = (inscriptionId) => {
|
|
9
9
|
return inscriptionId.split('i')[0]
|
|
@@ -15,7 +15,7 @@ export function getTransferOrdinalsUtxos({ inscriptionIds, ordinalsUtxos }) {
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
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)
|
|
18
|
+
const inscriptionTxs = new Set(inscriptionIds.map(getInscriptionTxId))
|
|
19
19
|
|
|
20
20
|
// https://ordinals.hiro.so/inscription/862ecd0fe343da32d19ff9277639ff71e10d894f55b6dee82dbfb9c158d5d30ci0
|
|
21
21
|
// https://ordinals.hiro.so/inscription/862ecd0fe343da32d19ff9277639ff71e10d894f55b6dee82dbfb9c158d5d30ci1
|
|
@@ -28,13 +28,12 @@ export function getTransferOrdinalsUtxos({ inscriptionIds, ordinalsUtxos }) {
|
|
|
28
28
|
offset: inscription.offset,
|
|
29
29
|
})
|
|
30
30
|
return (
|
|
31
|
-
validInscription &&
|
|
32
|
-
!inscriptionTxs.includes(getInscriptionTxId(inscription.inscriptionId))
|
|
31
|
+
validInscription && !inscriptionTxs.has(getInscriptionTxId(inscription.inscriptionId))
|
|
33
32
|
)
|
|
34
33
|
}) || []
|
|
35
34
|
)
|
|
36
35
|
assert(
|
|
37
|
-
|
|
36
|
+
unsafeInscriptions.length === 0,
|
|
38
37
|
`The following inscriptions are unsafe ${unsafeInscriptions.map(
|
|
39
38
|
(i) => i.inscriptionId
|
|
40
39
|
)} when ${inscriptionIds} should be spent`
|
|
@@ -117,8 +116,10 @@ function isOrdinalUtxo({
|
|
|
117
116
|
if (!hasOrdinals) {
|
|
118
117
|
console.log('Excluding utxo from btc spending:', utxo.address.toString(), utxo)
|
|
119
118
|
}
|
|
119
|
+
|
|
120
120
|
return true // assume is ordinal just in case
|
|
121
121
|
}
|
|
122
|
+
|
|
122
123
|
return hasOrdinals
|
|
123
124
|
}
|
|
124
125
|
|
|
@@ -136,15 +137,18 @@ export function mergeAdditionalInscriptions({ allUtxos, additionalInscriptions }
|
|
|
136
137
|
existingInscription.inscriptionId === additionalInscription.inscriptionId
|
|
137
138
|
)
|
|
138
139
|
}
|
|
140
|
+
|
|
139
141
|
return forUtxo
|
|
140
142
|
})
|
|
141
143
|
.map((additionalInscription) => ({
|
|
142
144
|
inscriptionId: additionalInscription.inscriptionId,
|
|
143
145
|
offset: additionalInscription.offset || 0,
|
|
144
146
|
}))
|
|
145
|
-
if (inscriptions.length) {
|
|
147
|
+
if (inscriptions.length > 0) {
|
|
148
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
146
149
|
utxo.inscriptions = [...(utxo.inscriptions || []), ...inscriptions]
|
|
147
150
|
}
|
|
151
|
+
|
|
148
152
|
return utxo
|
|
149
153
|
}),
|
|
150
154
|
{
|
|
@@ -205,6 +209,7 @@ export function getConfirmedOrRfbDisabledUtxos({ utxos, allowUnconfirmedRbfEnabl
|
|
|
205
209
|
if (allowUnconfirmedRbfEnabledUtxos) {
|
|
206
210
|
return utxos
|
|
207
211
|
}
|
|
212
|
+
|
|
208
213
|
return utxos.filter((utxo) => utxo.confirmations > 0 || !utxo.rbfEnabled)
|
|
209
214
|
}
|
|
210
215
|
|
|
@@ -212,6 +217,7 @@ function filterDustUtxos({ utxos, feeData }) {
|
|
|
212
217
|
if (feeData.utxoDustValue) {
|
|
213
218
|
return utxos.filter((utxo) => utxo.value.toBaseNumber() > feeData.utxoDustValue)
|
|
214
219
|
}
|
|
220
|
+
|
|
215
221
|
return utxos
|
|
216
222
|
}
|
|
217
223
|
|