@exodus/bitcoin-api 2.15.0 → 2.16.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.15.0",
3
+ "version": "2.16.0",
4
4
  "description": "Exodus bitcoin-api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -58,5 +58,5 @@
58
58
  "jest-when": "^3.5.1",
59
59
  "safe-buffer": "^5.2.1"
60
60
  },
61
- "gitHead": "364ffb79577938023d87e78e7d24a8e6413af060"
61
+ "gitHead": "f6d3343c14d821405ea319c4bb022983a7bd4e4c"
62
62
  }
@@ -54,6 +54,15 @@ export class BitcoinMonitorScanner {
54
54
  this.#refreshGapLimit = refreshGapLimit
55
55
  }
56
56
 
57
+ async #getGapLimit({ walletAccount, assetName, refresh }) {
58
+ const assetConfig = await this.#assetClientInterface.getAssetConfig?.({
59
+ assetName,
60
+ walletAccount,
61
+ })
62
+ if (typeof assetConfig?.gapLimit === 'number') return assetConfig.gapLimit
63
+ return refresh ? this.#refreshGapLimit : this.#gapLimit
64
+ }
65
+
57
66
  async rescanBlockchainInsight({ walletAccount, refresh }) {
58
67
  const asset = this.#asset
59
68
  const assetClientInterface = this.#assetClientInterface
@@ -100,6 +109,8 @@ export class BitcoinMonitorScanner {
100
109
  assetName,
101
110
  walletAccount,
102
111
  })
112
+
113
+ const resolvedGapLimit = await this.#getGapLimit({ walletAccount, assetName, refresh })
103
114
  /*
104
115
  * The chain fields/variables are number arrays of size 2
105
116
  *
@@ -153,13 +164,23 @@ export class BitcoinMonitorScanner {
153
164
  addressIndex,
154
165
  })
155
166
  .then((address) => {
167
+ const addressObject = this.#asset.address.toLegacyAddress
168
+ ? Address.create(
169
+ this.#asset.address.toLegacyAddress(String(address)),
170
+ address.meta
171
+ )
172
+ : address
173
+
174
+ const addressString = String(addressObject)
175
+
176
+ if (addrMap[addressString]) {
177
+ return null
178
+ }
179
+
180
+ addrMap[addressString] = addressObject
181
+
156
182
  return {
157
- address: this.#asset.address.toLegacyAddress
158
- ? Address.create(
159
- this.#asset.address.toLegacyAddress(String(address)),
160
- address.meta
161
- )
162
- : address,
183
+ address: addressObject,
163
184
  purpose,
164
185
  }
165
186
  })
@@ -168,9 +189,9 @@ export class BitcoinMonitorScanner {
168
189
  }
169
190
 
170
191
  const addresses = []
171
- const result = await Promise.all(promises)
192
+ const allAddresses = await Promise.all(promises)
193
+ const result = allAddresses.filter(Boolean)
172
194
  result.forEach(({ address, purpose }) => {
173
- addrMap[String(address)] = address
174
195
  purposeMap[String(address)] = purpose
175
196
  addresses.push(String(address))
176
197
  })
@@ -185,8 +206,9 @@ export class BitcoinMonitorScanner {
185
206
 
186
207
  const fetchAddressesSize = 25
187
208
  for (let i = 0; i < addresses.length; i += fetchAddressesSize) {
209
+ const fetchAddresses = addresses.slice(i, i + fetchAddressesSize)
188
210
  const promise = insightClient.fetchAllTxData(
189
- addresses.slice(i, i + fetchAddressesSize),
211
+ fetchAddresses,
190
212
  txFetchLimit,
191
213
  fetchTimeout,
192
214
  shouldStop
@@ -224,8 +246,8 @@ export class BitcoinMonitorScanner {
224
246
  purpose,
225
247
  chain,
226
248
  startAddressIndexes: chain.map(() => 0),
227
- endAddressIndexes: chain.map(
228
- (addressIndex) => (refresh ? this.#refreshGapLimit : addressIndex + this.#gapLimit) // right of the || should never happen
249
+ endAddressIndexes: chain.map((addressIndex) =>
250
+ refresh ? resolvedGapLimit : addressIndex + resolvedGapLimit
229
251
  ),
230
252
  }
231
253
  })
@@ -336,7 +358,6 @@ export class BitcoinMonitorScanner {
336
358
  indexData.startAddressIndexes = [...indexData.endAddressIndexes]
337
359
  // eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
338
360
  indexData.endAddressIndexes = indexData.chain.map((addressIndex) => {
339
- const resolvedGapLimit = refresh ? this.#refreshGapLimit : this.#gapLimit
340
361
  return addressIndex + resolvedGapLimit
341
362
  })
342
363
  })
@@ -27,10 +27,14 @@ export function createSignWithWallet({
27
27
  return async (psbt, inputsToSign) => {
28
28
  // The Taproot SIGHASH flag includes all previous outputs,
29
29
  // so signing is only done AFTER all inputs have been updated
30
+ const signingPromises = []
31
+
30
32
  for (let index = 0; index < psbt.inputCount; index++) {
31
33
  const inputInfo = inputsToSign[index]
32
34
  // dApps request to sign only specific transaction inputs.
33
35
  if (!inputInfo) continue
36
+
37
+ const input = psbt.data.inputs[index]
34
38
  const { address, sigHash } = inputInfo
35
39
  // The sighash value from the PSBT input itself will be used.
36
40
  // This list just represents possible sighash values the inputs can have.
@@ -41,8 +45,7 @@ export function createSignWithWallet({
41
45
  const { key, purpose, keyId, publicKey } = await getKeyWithMetadata(address)
42
46
 
43
47
  const isP2SH = purpose === 49
44
- const hasTapLeafScript =
45
- psbt.data.inputs[index].tapLeafScript && psbt.data.inputs[index].tapLeafScript.length > 0
48
+ const hasTapLeafScript = input.tapLeafScript && input.tapLeafScript.length > 0
46
49
  const isTaprootKeySpend = isTaprootPurpose(purpose) && !hasTapLeafScript
47
50
 
48
51
  if (isP2SH) {
@@ -54,7 +57,7 @@ export function createSignWithWallet({
54
57
  const p2sh = payments.p2sh({ redeem: p2wpkh })
55
58
  if (address === p2sh.address) {
56
59
  // Set the redeem script in the psbt in case it's missing.
57
- if (!Buffer.isBuffer(psbt.data.inputs[index].redeemScript)) {
60
+ if (!Buffer.isBuffer(input.redeemScript)) {
58
61
  psbt.updateInput(index, {
59
62
  redeemScript: p2sh.redeem.output,
60
63
  })
@@ -62,7 +65,7 @@ export function createSignWithWallet({
62
65
  } else {
63
66
  throw new Error('Expected P2SH script to be a nested segwit input')
64
67
  }
65
- } else if (isTaprootKeySpend && !Buffer.isBuffer(psbt.data.inputs[index].tapInternalKey)) {
68
+ } else if (isTaprootKeySpend && !Buffer.isBuffer(input.tapInternalKey)) {
66
69
  // tapInternalKey is metadata for signing and not part of the hash to sign.
67
70
  // so modifying it here is fine.
68
71
  psbt.updateInput(index, { tapInternalKey: toXOnly(publicKey) })
@@ -73,7 +76,9 @@ export function createSignWithWallet({
73
76
  : toAsyncSigner({ keyPair: key, isTaprootKeySpend, network })
74
77
 
75
78
  // desktop / BE / mobile with bip-schnorr signing
76
- await psbt.signInputAsync(index, asyncSigner, allowedSigHashTypes)
79
+ signingPromises.push(psbt.signInputAsync(index, asyncSigner, allowedSigHashTypes))
77
80
  }
81
+
82
+ await Promise.all(signingPromises)
78
83
  }
79
84
  }