@exodus/bitcoin-api 2.7.7 → 2.8.0

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.7.7",
3
+ "version": "2.8.0",
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": "4e504c29d0a5e436a5766d42d4664eaf53b06bc2"
45
+ "gitHead": "2b4d4989b82576d03b90f2eb7e53366a7a485df1"
47
46
  }
@@ -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/lib/selectors/get-can-bump-tx-factory'
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`)}?${qs.stringify(options)}`
135
+ const url = `${urlJoin(this._baseURL, `/addrs/txs`)}?${new URLSearchParams(options)}`
137
136
 
138
137
  const fetchOptions = {
139
138
  method: 'post',
@@ -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/lib/utils/get-tx-sequence'
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
- // TODO: we can remove SIGHASH_ALL, it is default.
37
- const sigHashTypes = sigHash !== undefined ? [sigHash || Transaction.SIGHASH_ALL] : undefined
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 }), sigHashTypes)
74
+ await psbt.signInputAsync(index, toAsyncSigner({ keyPair: signingKey }), allowedSigHashTypes)
71
75
  }
72
76
  }
73
77
  }
@@ -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((i) => {
25
+ utxo.inscriptions?.filter((inscription) => {
15
26
  const validInscription = isValidInscription({
16
27
  value: utxo.value.toBaseNumber(),
17
- offset: i.offset,
28
+ offset: inscription.offset,
18
29
  })
19
- return validInscription && !inscriptionIds.includes(i.inscriptionId)
30
+ return (
31
+ validInscription &&
32
+ !inscriptionTxs.includes(getInscriptionTxId(inscription.inscriptionId))
33
+ )
20
34
  }) || []
21
35
  )
22
36
  assert(
@@ -69,7 +83,7 @@ export function getValidInscriptions({ utxo }) {
69
83
  )
70
84
  }
71
85
 
72
- function isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds }) {
86
+ function isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds, ordinalAddress }) {
73
87
  if (!ordinalsEnabled) {
74
88
  return false
75
89
  }
@@ -85,18 +99,28 @@ function isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds }) {
85
99
  }
86
100
 
87
101
  const validInscriptions = getValidInscriptions({ utxo })
88
- return validInscriptions.length > 0
102
+ const hasOrdinals = validInscriptions.length > 0
103
+
104
+ if (ordinalAddress?.toString() === utxo.address.toString()) {
105
+ // if this condition is true, that means this is taproot
106
+ // so we always return true to ensure we accidentally don't spend an ordinal as btc
107
+ if (!hasOrdinals) {
108
+ console.log('Excluding utxo from btc spending:', utxo.address.toString(), utxo)
109
+ }
110
+ return true // assume is ordinal just in case
111
+ }
112
+ return hasOrdinals
89
113
  }
90
114
 
91
- export function partitionUtxos({ allUtxos, ordinalsEnabled, knownBalanceUtxoIds }) {
115
+ export function partitionUtxos({ allUtxos, ordinalsEnabled, knownBalanceUtxoIds, ordinalAddress }) {
92
116
  assert(allUtxos, 'allUtxos is required')
93
- // assert(ordinalAddress, 'ordinalAddress is required') // not used atm we may need to tune by ordinalAddress when unconfirmed or rubbish inscriptions
117
+ if (ordinalsEnabled) assert(ordinalAddress, 'ordinalAddress is required')
94
118
  return {
95
119
  utxos: allUtxos.filter(
96
- (utxo) => !isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds })
120
+ (utxo) => !isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds, ordinalAddress })
97
121
  ),
98
122
  ordinalsUtxos: allUtxos.filter((utxo) =>
99
- isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds })
123
+ isOrdinalUtxo({ utxo, ordinalsEnabled, knownBalanceUtxoIds, ordinalAddress })
100
124
  ),
101
125
  }
102
126
  }