@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.
Files changed (35) hide show
  1. package/package.json +2 -3
  2. package/src/bitcoinjs-lib/ecc/common.js +1 -1
  3. package/src/bitcoinjs-lib/ecc/mobile.js +3 -3
  4. package/src/bitcoinjs-lib/script-classify/index.js +1 -1
  5. package/src/btc-like-address.js +3 -4
  6. package/src/btc-like-keys.js +4 -0
  7. package/src/constants/bip44.js +2 -2
  8. package/src/fee/can-bump-tx.js +3 -1
  9. package/src/fee/fee-estimator.js +5 -1
  10. package/src/fee/fee-utils.js +6 -5
  11. package/src/fee/get-fee-resolver.js +2 -1
  12. package/src/fee/script-classifier.js +5 -10
  13. package/src/fee/utxo-selector.js +10 -3
  14. package/src/hash-utils.js +4 -9
  15. package/src/insight-api-client/index.js +14 -12
  16. package/src/insight-api-client/util.js +16 -15
  17. package/src/insight-api-client/ws.js +1 -1
  18. package/src/move-funds.js +17 -17
  19. package/src/ordinals-utils.js +2 -2
  20. package/src/parse-unsigned-tx.js +80 -81
  21. package/src/tx-log/bitcoin-monitor-scanner.js +50 -38
  22. package/src/tx-log/bitcoin-monitor.js +14 -13
  23. package/src/tx-log/ordinals-indexer-utils.js +6 -0
  24. package/src/tx-send/dogecoin.js +2 -2
  25. package/src/tx-send/index.js +426 -418
  26. package/src/tx-sign/common.js +9 -9
  27. package/src/tx-sign/create-get-key-and-purpose.js +2 -2
  28. package/src/tx-sign/create-sign-with-wallet.js +3 -3
  29. package/src/tx-sign/default-entropy.js +1 -3
  30. package/src/tx-sign/default-prepare-for-signing.js +16 -18
  31. package/src/tx-sign/default-sign-hardware.js +2 -1
  32. package/src/tx-sign/taproot.js +4 -0
  33. package/src/tx-utils.js +5 -5
  34. package/src/unconfirmed-ancestor-data.js +1 -0
  35. package/src/utxos-utils.js +12 -6
@@ -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 !== undefined
40
- ? [sigHash, Transaction.SIGHASH_ALL] // `SIGHASH_DEFAULT` is a default safe sig hash, always allow it.
41
- : undefined
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
@@ -1,4 +1,2 @@
1
1
  // extension point so tests can assert signatures deterministically
2
- export function getSchnorrEntropy() {
3
- return undefined
4
- }
2
+ export function getSchnorrEntropy() {}
@@ -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: 25000,
6
- ravencoin: 1000000,
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
- const psbt = Psbt.fromBuffer(psbtBuffer, { eccLib: ecc })
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 (e) {
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
- let derivationPaths = []
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
 
@@ -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
- Array.from(txSet).filter(
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
- !txSet
16
- ? new Set()
17
- : new Set(
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()
@@ -18,6 +18,7 @@ export async function resolveUnconfirmedAncestorData({ utxos, insightClient }) {
18
18
  console.warn(e)
19
19
  }
20
20
  }
21
+
21
22
  return dataMap
22
23
  }
23
24
 
@@ -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 = 10000
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
- !unsafeInscriptions.length,
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