@exodus/bitcoin-api 1.0.3 → 1.0.4

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": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Exodus bitcoin-api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -25,6 +25,7 @@
25
25
  "@exodus/models": "^8.10.4",
26
26
  "@exodus/secp256k1": "4.0.2-exodus.0",
27
27
  "@exodus/simple-retry": "0.0.6",
28
+ "bech32": "^1.1.3",
28
29
  "bip44-constants": "55.0.0",
29
30
  "coininfo": "5.1.0",
30
31
  "delay": "4.0.1",
@@ -38,5 +39,5 @@
38
39
  "@exodus/bip-schnorr": "0.6.6-fork-1",
39
40
  "@noble/secp256k1": "~1.5.3"
40
41
  },
41
- "gitHead": "6da3cc2b9aaba76c1e3523d9598e465c4b4f45eb"
42
+ "gitHead": "00377ab9ad8a29114f5064efcb0197d4257056d1"
42
43
  }
@@ -4,6 +4,25 @@ import urlJoin from 'url-join'
4
4
  import qs from 'querystring'
5
5
  import delay from 'delay'
6
6
 
7
+ const getTextFromResponse = async (response) => {
8
+ try {
9
+ const responseBody = await response.text()
10
+ return responseBody.substring(0, 100)
11
+ } catch (e) {
12
+ return ''
13
+ }
14
+ }
15
+
16
+ const fetchJson = async (url, fetchOptions) => {
17
+ const response = await fetch(url, fetchOptions)
18
+ if (!response.ok)
19
+ throw new Error(
20
+ `${url} returned ${response.status}: ${response.statusText ||
21
+ 'Unknown Status Text'}. Body: ${await getTextFromResponse(response)}`
22
+ )
23
+ return response.json()
24
+ }
25
+
7
26
  // TODO: use p-retry
8
27
  async function fetchJsonRetry(url, fetchOptions) {
9
28
  const waitTimes = [5, 10, 20, 30].map((t) => t * 1000)
@@ -22,12 +41,6 @@ async function fetchJsonRetry(url, fetchOptions) {
22
41
  }
23
42
  }
24
43
  }
25
-
26
- async function fetchJson(url, fetchOptions) {
27
- const response = await fetch(url, fetchOptions)
28
- if (!response.ok) throw new Error(`${url} returned ${response.status}: ${response.statusText}`)
29
- return response.json()
30
- }
31
44
  }
32
45
 
33
46
  export default class InsightAPIClient {
@@ -41,9 +54,7 @@ export default class InsightAPIClient {
41
54
 
42
55
  async isNetworkConnected() {
43
56
  const url = urlJoin(this._baseURL, '/peer')
44
- const resp = await fetch(url, { timeout: 10000 })
45
- const peerStatus = await resp.json()
46
-
57
+ const peerStatus = await fetchJson(url, { timeout: 10000 })
47
58
  return !!peerStatus.connected
48
59
  }
49
60
 
@@ -56,9 +67,7 @@ export default class InsightAPIClient {
56
67
 
57
68
  async fetchBlockHeight() {
58
69
  const url = urlJoin(this._baseURL, '/status')
59
- const resp = await fetch(url, { timeout: 10000 })
60
- const status = await resp.json()
61
-
70
+ const status = await fetchJson(url, { timeout: 10000 })
62
71
  return status.info.blocks
63
72
  }
64
73
 
@@ -68,9 +77,7 @@ export default class InsightAPIClient {
68
77
  this._baseURL,
69
78
  opts.includeTxs ? `/addr/${encodedAddress}` : `/addr/${encodedAddress}?noTxList=1`
70
79
  )
71
- const response = await fetch(url)
72
-
73
- return response.json()
80
+ return fetchJson(url)
74
81
  }
75
82
 
76
83
  async fetchUTXOs(addresses, { assetNames = [] } = {}) {
@@ -81,8 +88,7 @@ export default class InsightAPIClient {
81
88
  }
82
89
  const encodedAddresses = encodeURIComponent(addresses)
83
90
  const url = urlJoin(this._baseURL, `/addrs/${encodedAddresses}/utxo?${query}`)
84
- const response = await fetch(url)
85
- const utxos = await response.json()
91
+ const utxos = await fetchJson(url)
86
92
 
87
93
  return utxos.map((utxo) => ({
88
94
  address: utxo.address,
@@ -111,8 +117,7 @@ export default class InsightAPIClient {
111
117
  async fetchRawTx(txId: string) {
112
118
  const encodedTxId = encodeURIComponent(txId)
113
119
  const url = urlJoin(this._baseURL, `/rawtx/${encodedTxId}`)
114
- const response = await fetch(url)
115
- const { rawtx } = await response.json()
120
+ const { rawtx } = await fetchJson(url)
116
121
  return rawtx
117
122
  }
118
123
 
@@ -155,14 +160,12 @@ export default class InsightAPIClient {
155
160
  async fetchUnconfirmedAncestorData(txId: string) {
156
161
  const encodedTxId = encodeURIComponent(txId)
157
162
  const url = urlJoin(this._baseURL, `/unconfirmed_ancestor/${encodedTxId}`)
158
- const response = await fetch(url)
159
- return response.json()
163
+ return fetchJson(url)
160
164
  }
161
165
 
162
166
  async fetchFeeRate() {
163
167
  const url = urlJoin(this._baseURL, '/v2/fees')
164
- const response = await fetch(url)
165
- return response.json()
168
+ return fetchJson(url)
166
169
  }
167
170
 
168
171
  async broadcastTx(rawTx) {
@@ -200,16 +203,12 @@ export default class InsightAPIClient {
200
203
  async getClaimable(address) {
201
204
  const encodedAddress = encodeURIComponent(address)
202
205
  const url = urlJoin(this._baseURL, `/addr/${encodedAddress}/claimable`)
203
- const response = await fetch(url)
204
- if (!response.ok) throw new Error(`${url} returned ${response.status}: ${response.statusText}`)
205
- return response.json()
206
+ return fetchJson(url)
206
207
  }
207
208
 
208
209
  async getUnclaimed(address) {
209
210
  const encodedAddress = encodeURIComponent(address)
210
211
  const url = urlJoin(this._baseURL, `/addr/${encodedAddress}/unclaimed`)
211
- const response = await fetch(url)
212
- if (!response.ok) throw new Error(`${url} returned ${response.status}: ${response.statusText}`)
213
- return response.json()
212
+ return fetchJson(url)
214
213
  }
215
214
  }
@@ -1,7 +1,7 @@
1
1
  import assert from 'minimalistic-assert'
2
2
  import lodash from 'lodash'
3
3
  import ECPairFactory from 'ecpair'
4
- import { Psbt } from '@exodus/bitcoinjs-lib'
4
+ import { Psbt, Transaction } from '@exodus/bitcoinjs-lib'
5
5
 
6
6
  import { toAsyncSigner, tweakSigner } from './taproot'
7
7
 
@@ -12,6 +12,15 @@ const _MAXIMUM_FEE_RATES = {
12
12
  ravencoin: 1000000,
13
13
  }
14
14
 
15
+ const canParseTx = (rawTxBuffer) => {
16
+ try {
17
+ Transaction.fromBuffer(rawTxBuffer)
18
+ return true
19
+ } catch (e) {
20
+ return false
21
+ }
22
+ }
23
+
15
24
  export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, network, ecc }) => {
16
25
  assert(assetName, 'assetName is required')
17
26
  assert(resolvePurpose, 'resolvePurpose is required')
@@ -62,10 +71,18 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
62
71
  // witness outputs only require the value and the script, not the full transaction
63
72
  txIn.witnessUtxo = { value, script: Buffer.from(script, 'hex') }
64
73
  } else {
65
- // non-witness outptus require the full transaction
66
74
  const rawTx = (rawTxs || []).find((t) => t.txId === txId)
75
+ // non-witness outptus require the full transaction
67
76
  assert(!!rawTx, 'Non-witness outputs require the full previous transaction.')
68
- txIn.nonWitnessUtxo = Buffer.from(rawTx.rawData, 'hex')
77
+ const rawTxBuffer = Buffer.from(rawTx.rawData, 'hex')
78
+ if (canParseTx(rawTxBuffer)) {
79
+ txIn.nonWitnessUtxo = rawTxBuffer
80
+ } else {
81
+ // temp fix for https://exodusio.slack.com/archives/CP202D90Q/p1671014704829939 until bitcoinjs could parse a mweb tx without failing
82
+ console.warn(`Setting psbt.__CACHE.__UNSAFE_SIGN_NONSEGWIT = true for asset ${assetName}`)
83
+ psbt.__CACHE.__UNSAFE_SIGN_NONSEGWIT = true
84
+ txIn.witnessUtxo = { value, script: Buffer.from(script, 'hex') }
85
+ }
69
86
  }
70
87
  psbt.addInput(txIn)
71
88
  }