@exodus/bitcoin-api 2.6.2 → 2.6.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": "2.6.2",
3
+ "version": "2.6.4",
4
4
  "description": "Exodus bitcoin-api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -22,7 +22,7 @@
22
22
  "@exodus/basic-utils": "^2.1.0",
23
23
  "@exodus/bip-schnorr": "0.6.6-fork-1",
24
24
  "@exodus/bip44-constants": "^195.0.0",
25
- "@exodus/models": "^10.1.0",
25
+ "@exodus/models": "^11.0.0",
26
26
  "@exodus/secp256k1": "4.0.2-exodus.0",
27
27
  "@exodus/simple-retry": "0.0.6",
28
28
  "@exodus/timer": "^1.0.0",
@@ -38,10 +38,10 @@
38
38
  "url-join": "4.0.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@exodus/bitcoin-meta": "^1.0.1",
41
+ "@exodus/bitcoin-meta": "^1.0.2",
42
42
  "@scure/base": "^1.1.3",
43
43
  "@scure/btc-signer": "^1.1.0",
44
44
  "jest-when": "^3.5.1"
45
45
  },
46
- "gitHead": "a9f5e8c6f0ac0655cdd2721cf20813f86a373678"
46
+ "gitHead": "33c832c0c550fa4a885aee9b34f7649bfb5fa464"
47
47
  }
@@ -1,10 +1,10 @@
1
1
  import assert from 'minimalistic-assert'
2
2
 
3
- export function isReceiveAddress(address): boolean {
3
+ export function isReceiveAddress(address) {
4
4
  return parsePath(address)[0] === 0
5
5
  }
6
6
 
7
- export function isChangeAddress(address): boolean {
7
+ export function isChangeAddress(address) {
8
8
  return parsePath(address)[0] === 1
9
9
  }
10
10
 
@@ -5,24 +5,48 @@ import { toXOnly } from '../ecc-utils'
5
5
  * Common ecc functions between mobile and desktop. Once mobile accepts @noble/secp256k1, we can unify both
6
6
  */
7
7
  export const common = {
8
- // These methods have been addded in order to comply with the public interface
9
- // In practice the async version will be used
10
- sign: (h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array =>
11
- secp256k1.ecdsaSign(h, d, { data: e }).signature,
12
- verify: (h: Uint8Array, Q: Uint8Array, signature: Uint8Array, strict?: boolean): boolean =>
13
- secp256k1.ecdsaVerify(signature, h, Q),
8
+ /**
9
+ *
10
+ * @param msg32 {Uint8Array} the message
11
+ * @param seckey {Uint8Array} the private key
12
+ * @param data {Uint8Array} the data to sign
13
+ */
14
+ sign: (msg32, seckey, data) => secp256k1.ecdsaSign(msg32, seckey, { data }).signature,
14
15
 
15
- privateAdd: (d: Uint8Array, tweak: Uint8Array): Uint8Array | null =>
16
+ /**
17
+ *
18
+ * @param msg32 {Uint8Array} the message to verify
19
+ * @param publicKey {Uint8Array} the public key
20
+ * @param signature {Uint8Array} the signature
21
+ * @returns {boolean}
22
+ */
23
+ verify: (msg32, publicKey, signature) => secp256k1.ecdsaVerify(signature, msg32, publicKey),
24
+
25
+ /**
26
+ *
27
+ * @param seckey {Uint8Array}
28
+ * @param tweak {Uint8Array}
29
+ */
30
+ privateAdd: (seckey, tweak) =>
16
31
  // cloning input. secp256k1 modifies it and it cannot be reused/cached
17
- secp256k1.privateKeyTweakAdd(Buffer.from(d), tweak),
32
+ secp256k1.privateKeyTweakAdd(Buffer.from(seckey), tweak),
18
33
 
19
- privateNegate: (d: Uint8Array): Uint8Array =>
34
+ /**
35
+ * @param seckey {Uint8Array} the public key
36
+ */
37
+ privateNegate: (seckey) =>
20
38
  // cloning input. secp256k1 modifies it and it cannot be reused/cached
21
- secp256k1.privateKeyNegate(Buffer.from(d)),
39
+ secp256k1.privateKeyNegate(Buffer.from(seckey)),
22
40
 
23
- xOnlyPointAddTweak: (p: Uint8Array, tweak: Uint8Array) => {
41
+ /**
42
+ *
43
+ * @param publicKey {Uint8Array}
44
+ * @param tweak {Uint8Array}
45
+ * @returns {{parity: (number), xOnlyPubkey}|null}
46
+ */
47
+ xOnlyPointAddTweak: (publicKey, tweak) => {
24
48
  try {
25
- const t = secp256k1.publicKeyTweakAdd(toPubKey(p), tweak)
49
+ const t = secp256k1.publicKeyTweakAdd(toPubKey(publicKey), tweak)
26
50
  return {
27
51
  parity: t[0] === 0x02 ? 0 : 1,
28
52
  xOnlyPubkey: toXOnly(t),
@@ -32,12 +56,24 @@ export const common = {
32
56
  }
33
57
  },
34
58
 
35
- isPrivate: (d: Uint8Array): boolean => secp256k1.privateKeyVerify(d),
36
- pointFromScalar: (d: Uint8Array, compressed?: boolean): Uint8Array | null =>
37
- secp256k1.publicKeyCreate(d, compressed),
59
+ /**
60
+ * @param seckey {Uint8Array}
61
+ * @returns {boolean}
62
+ */
63
+ isPrivate: (seckey) => secp256k1.privateKeyVerify(seckey),
64
+ /**
65
+ * @param seckey {Uint8Array}
66
+ * @param compressed {boolean}
67
+ */
68
+ pointFromScalar: (seckey, compressed) => secp256k1.publicKeyCreate(seckey, compressed),
38
69
  }
39
70
 
40
- export const toPubKey = (xOnly: Uint8Array) => {
71
+ /**
72
+ *
73
+ * @param xOnly {Uint8Array}
74
+ * @returns {Uint8Array}
75
+ */
76
+ export const toPubKey = (xOnly) => {
41
77
  const p = new Uint8Array(33)
42
78
  p.set([0x02])
43
79
  p.set(xOnly, 1)
@@ -1,4 +1,4 @@
1
- import { TinySecp256k1Interface, initEccLib } from 'bitcoinjs-lib'
1
+ import { initEccLib } from 'bitcoinjs-lib'
2
2
  import { Point, schnorr, sign } from '@noble/secp256k1'
3
3
  import { common, toPubKey } from './common'
4
4
 
@@ -6,20 +6,39 @@ import { common, toPubKey } from './common'
6
6
  * Wrapper around `secp256k1` in order to follow the bitcoinjs-lib `TinySecp256k1Interface`
7
7
  * Schnorr signatures are offered by @noble/secp256k1
8
8
  */
9
- export const desktopEcc: TinySecp256k1Interface = {
9
+ export const desktopEcc = {
10
10
  ...common,
11
11
 
12
- signAsync: async (h: Uint8Array, d: Uint8Array, extraEntropy?: Uint8Array): Uint8Array =>
13
- sign(h, d, {
12
+ /**
13
+ * @param message {Uint8Array}
14
+ * @param privateKey {Uint8Array}
15
+ * @param extraEntropy {Uint8Array}
16
+ * @returns {Promise<Uint8Array>}
17
+ */
18
+ signAsync: async (message, privateKey, extraEntropy) =>
19
+ sign(message, privateKey, {
14
20
  extraEntropy,
15
21
  canonical: true,
16
22
  der: false,
17
23
  }),
18
24
 
19
- signSchnorrAsync: async (h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array =>
20
- schnorr.sign(h, d, e),
21
- verifySchnorrAsync: async (h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean =>
22
- schnorr.verify(signature, h, Q),
25
+ /**
26
+ * @param message {Uint8Array}
27
+ * @param privateKey {Uint8Array}
28
+ * @param extraEntropy {Uint8Array}
29
+ * @returns {Promise<Uint8Array>}
30
+ */
31
+ signSchnorrAsync: async (message, privateKey, extraEntropy) =>
32
+ schnorr.sign(message, privateKey, extraEntropy),
33
+
34
+ /**
35
+ * @param message {Uint8Array}
36
+ * @param publicKey {Uint8Array}
37
+ * @param signature {Uint8Array}
38
+ * @returns {Promise<boolean>}
39
+ */
40
+ verifySchnorrAsync: async (message, publicKey, signature) =>
41
+ schnorr.verify(signature, message, publicKey),
23
42
 
24
43
  // The underlying library does not expose sync functions for Schnorr sign and verify.
25
44
  // These function are explicitly defined here as `null` for documentation purposes.
@@ -27,26 +46,38 @@ export const desktopEcc: TinySecp256k1Interface = {
27
46
  signSchnorr: null,
28
47
  verifySchnorr: null,
29
48
 
30
- isPoint: (p: Uint8Array): boolean => {
49
+ /**
50
+ * @param publicKey {Uint8Array}
51
+ * @returns {boolean}
52
+ */
53
+ isPoint: (publicKey) => {
31
54
  try {
32
- Point.fromHex(p).assertValidity()
55
+ Point.fromHex(publicKey).assertValidity()
33
56
  return true
34
57
  } catch {
35
58
  return false
36
59
  }
37
60
  },
38
61
 
39
- isXOnlyPoint: (p: Uint8Array): boolean => {
62
+ /**
63
+ * @param publicKey {Uint8Array}
64
+ * @returns {boolean}
65
+ */
66
+ isXOnlyPoint: (publicKey) => {
40
67
  try {
41
- Point.fromHex(toPubKey(p)).assertValidity()
68
+ Point.fromHex(toPubKey(publicKey)).assertValidity()
42
69
  return true
43
70
  } catch {
44
71
  return false
45
72
  }
46
73
  },
47
74
 
48
- pointCompress: (p: Uint8Array, compressed?: boolean): Uint8Array =>
49
- Point.fromHex(p).toRawBytes(compressed),
75
+ /**
76
+ * @param publicKey {Uint8Array}
77
+ * @param compressed {boolean}
78
+ * @returns {Uint8Array}
79
+ */
80
+ pointCompress: (publicKey, compressed) => Point.fromHex(publicKey).toRawBytes(compressed),
50
81
  }
51
82
 
52
83
  initEccLib(desktopEcc)
@@ -1,4 +1,4 @@
1
- import { TinySecp256k1Interface, initEccLib } from 'bitcoinjs-lib'
1
+ import { initEccLib } from 'bitcoinjs-lib'
2
2
  import secp256k1 from '@exodus/secp256k1'
3
3
  // TODO: temp import until '@noble/secp256k1' can be used
4
4
  import { isPoint } from 'tiny-secp256k1'
@@ -11,50 +11,92 @@ import schnorr from '@exodus/bip-schnorr'
11
11
  *
12
12
  */
13
13
 
14
- export const mobileEcc: TinySecp256k1Interface = {
14
+ export const mobileEcc = {
15
15
  ...common,
16
16
 
17
- signAsync: async (h: Uint8Array, d: Uint8Array, extraEntropy?: Uint8Array): Uint8Array =>
18
- secp256k1.ecdsaSign(h, d, { data: extraEntropy }).signature,
17
+ /**
18
+ *
19
+ * @param message {Uint8Array}
20
+ * @param seckey {Uint8Array}
21
+ * @param extraEntropy {Uint8Array}
22
+ * @returns {Promise<(function(*): Uint8Array)|*>}
23
+ */
24
+ signAsync: async (message, seckey, extraEntropy) =>
25
+ secp256k1.ecdsaSign(message, seckey, { data: extraEntropy }).signature,
19
26
 
20
- signSchnorr: (h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array =>
21
- schnorr.sign(d.toString('hex'), h, e),
27
+ /**
28
+ *
29
+ * @param message {Uint8Array}
30
+ * @param privateKey {Uint8Array}
31
+ * @param extraEntropy {Uint8Array}
32
+ * @returns {Buffer}
33
+ */
34
+ signSchnorr: (message, privateKey, extraEntropy) =>
35
+ schnorr.sign(privateKey.toString('hex'), message, extraEntropy),
22
36
 
23
- signSchnorrAsync: async (h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array =>
24
- mobileEcc.signSchnorr(h, d, e),
37
+ /**
38
+ * @param message {Uint8Array}
39
+ * @param privateKey {Uint8Array}
40
+ * @param extraEntropy {Uint8Array}
41
+ * @returns {Promise<Buffer>}
42
+ */
43
+ signSchnorrAsync: async (message, privateKey, extraEntropy) =>
44
+ mobileEcc.signSchnorr(message, privateKey, extraEntropy),
25
45
 
26
- verifySchnorr: (h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean => {
46
+ /**
47
+ * @param publicKey {Uint8Array}
48
+ * @param message {Uint8Array}
49
+ * @param signature {Uint8Array}
50
+ * @returns {boolean}
51
+ */
52
+ verifySchnorr: (publicKey, message, signature) => {
27
53
  try {
28
- schnorr.verify(Q, h, signature)
54
+ schnorr.verify(message, publicKey, signature)
29
55
  return true
30
56
  } catch (e) {
31
57
  return false
32
58
  }
33
59
  },
34
60
 
35
- verifySchnorrAsync: async (h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean =>
36
- mobileEcc.verifySchnorr(h, Q, signature),
61
+ /**
62
+ * @param publicKey {Uint8Array}
63
+ * @param message {Uint8Array}
64
+ * @param signature {Uint8Array}
65
+ * @returns {Promise<boolean>}
66
+ */
67
+ verifySchnorrAsync: async (publicKey, message, signature) =>
68
+ mobileEcc.verifySchnorr(publicKey, message, signature),
37
69
 
38
- isPoint: (p: Uint8Array): boolean => {
70
+ /**
71
+ * @param publicKey {Uint8Array}
72
+ * @returns {boolean}
73
+ */
74
+ isPoint: (publicKey) => {
39
75
  try {
40
76
  // temp solution secp256k1 does not actually verify the value range, only the data length
41
- return isPoint(Buffer.from(p))
77
+ return isPoint(Buffer.from(publicKey))
42
78
  } catch (err) {
43
79
  return false
44
80
  }
45
81
  },
46
82
 
47
- isXOnlyPoint: (p: Uint8Array): boolean => {
83
+ /**
84
+ * @param publicKey {Uint8Array}
85
+ * @returns {boolean}
86
+ */
87
+ isXOnlyPoint: (publicKey) => {
48
88
  try {
49
89
  // temp solution secp256k1 does not actually verify the value range, only the data length
50
- return isPoint(Buffer.from(toPubKey(p)))
90
+ return isPoint(Buffer.from(toPubKey(publicKey)))
51
91
  } catch (err) {
52
92
  return false
53
93
  }
54
94
  },
55
95
 
56
- pointCompress: (p: Uint8Array, compressed?: boolean): Uint8Array =>
57
- secp256k1.publicKeyConvert(p, compressed),
96
+ /**
97
+ * @param publicKey {Uint8Array}
98
+ */
99
+ pointCompress: (publicKey, compressed) => secp256k1.publicKeyConvert(publicKey, compressed),
58
100
  }
59
101
 
60
102
  initEccLib(mobileEcc)
@@ -1,7 +1,7 @@
1
1
  import { payments } from 'bitcoinjs-lib'
2
2
 
3
- function isPaymentFactory(payment: any): (script: Buffer, eccLib?: any) => boolean {
4
- return (script: Buffer, eccLib?: any): boolean => {
3
+ function isPaymentFactory(payment) {
4
+ return (script, eccLib) => {
5
5
  try {
6
6
  payment({ output: script }, { eccLib })
7
7
  return true
@@ -30,7 +30,7 @@ const types = {
30
30
  NONSTANDARD: 'nonstandard',
31
31
  }
32
32
 
33
- const outputFactory = () => (script: Buffer) => {
33
+ const outputFactory = () => (script) => {
34
34
  if (isP2WPKH(script)) return types.P2WPKH
35
35
  if (isP2TR(script)) return types.P2TR
36
36
  if (isP2PKH(script)) return types.P2PKH
@@ -89,7 +89,7 @@ export const createBtcLikeKeys = ({
89
89
  const encodePublicTaproot =
90
90
  encodePublicTaprootCustom ||
91
91
  (useBip86
92
- ? (publicKey: Buffer): string => {
92
+ ? (publicKey) => {
93
93
  const network = coinInfo.toBitcoinJS()
94
94
  return bitcoinjsLib.payments.p2tr({ internalPubkey: toXOnly(publicKey), network }).address
95
95
  }
@@ -1,4 +1,3 @@
1
- // @flow
2
1
  import assert from 'minimalistic-assert'
3
2
  import * as varuint from 'varuint-bitcoin'
4
3
  import { UtxoCollection } from '@exodus/models'
@@ -59,12 +58,7 @@ export const getSizeFactory = ({ defaultOutputType, addressApi }) => {
59
58
 
60
59
  const scriptClassifier = scriptClassifierFactory({ addressApi })
61
60
 
62
- return (
63
- asset: Object,
64
- inputs: Array | UtxoCollection,
65
- outputs: Array,
66
- { compressed = true } = {}
67
- ) => {
61
+ return (asset, inputs, outputs, { compressed = true } = {}) => {
68
62
  if (inputs instanceof UtxoCollection) {
69
63
  inputs = Array.from(inputs).map((utxo) => utxo.script || null)
70
64
  }
@@ -1,11 +1,9 @@
1
- // @flow
2
-
3
- import NumberUnit, { isNumberUnit, UnitType } from '@exodus/currency'
1
+ import { isNumberUnit, UnitType } from '@exodus/currency'
4
2
  import { resolveExtraFeeOfTx } from '../unconfirmed-ancestor-data'
5
3
  import { UtxoCollection } from '@exodus/models'
6
4
  import assert from 'minimalistic-assert'
7
5
 
8
- export const isHex = (s: string) => typeof s === 'string' && /[0-9a-f]*/.test(s.toLowerCase())
6
+ export const isHex = (s) => typeof s === 'string' && /[0-9a-f]*/.test(s.toLowerCase())
9
7
 
10
8
  export function getExtraFee({ asset, inputs, feePerKB }) {
11
9
  let extraFee = 0
@@ -27,19 +25,19 @@ export function getExtraFee({ asset, inputs, feePerKB }) {
27
25
  return extraFee
28
26
  }
29
27
 
30
- export default function createDefaultFeeEstimator(getSize: () => number) {
28
+ export default function createDefaultFeeEstimator(getSize) {
31
29
  return (asset, feePerKB, options) => {
32
- return ({ inputs = options.inputs, outputs = options.outputs } = {}): NumberUnit => {
30
+ return ({ inputs = options.inputs, outputs = options.outputs } = {}) => {
33
31
  const extraFee = getExtraFee({ asset, inputs, feePerKB })
34
32
  // Yes, it's suppose to be '1000' and not '1024'
35
33
  // https://bitcoin.stackexchange.com/questions/24000/a-fee-is-added-per-kilobyte-of-data-that-means-1000-bytes-or-1024
36
- const size: number = getSize(asset, inputs, outputs, options)
37
- const feeRaw: number = Math.ceil((feePerKB.toBaseNumber() * size) / 1000)
34
+ const size = getSize(asset, inputs, outputs, options)
35
+ const feeRaw = Math.ceil((feePerKB.toBaseNumber() * size) / 1000)
38
36
  return asset.currency.baseUnit(feeRaw + extraFee)
39
37
  }
40
38
  }
41
39
  }
42
- export function parseCurrency(val: string | Object, currency: Object) {
40
+ export function parseCurrency(val, currency) {
43
41
  assert(currency instanceof UnitType, 'Currency must be supples as a UnitType')
44
42
 
45
43
  if (isNumberUnit(val)) return val // TODO: consider checking if the unitType.equals(currency) (if currency is object)
@@ -1,4 +1,3 @@
1
- /* @flow */
2
1
  /* global fetch */
3
2
  import urlJoin from 'url-join'
4
3
  import qs from 'querystring'
@@ -102,7 +101,7 @@ export default class InsightAPIClient {
102
101
  }))
103
102
  }
104
103
 
105
- async fetchTx(txId: string) {
104
+ async fetchTx(txId) {
106
105
  const encodedTxId = encodeURIComponent(txId)
107
106
  const url = urlJoin(this._baseURL, `/tx/${encodedTxId}`)
108
107
  const response = await fetch(url)
@@ -114,14 +113,14 @@ export default class InsightAPIClient {
114
113
  return response.json()
115
114
  }
116
115
 
117
- async fetchRawTx(txId: string) {
116
+ async fetchRawTx(txId) {
118
117
  const encodedTxId = encodeURIComponent(txId)
119
118
  const url = urlJoin(this._baseURL, `/rawtx/${encodedTxId}`)
120
119
  const { rawtx } = await fetchJson(url)
121
120
  return rawtx
122
121
  }
123
122
 
124
- async fetchTxData(addrs: Array, options = {}) {
123
+ async fetchTxData(addrs, options = {}) {
125
124
  if (!Array.isArray(addrs) || addrs.length === 0) return { items: [], totalItems: 0 }
126
125
 
127
126
  options = { noScriptSig: 1, noAsm: 1, noSpent: 0, from: 0, to: 10, ...options }
@@ -157,7 +156,7 @@ export default class InsightAPIClient {
157
156
  return txs
158
157
  }
159
158
 
160
- async fetchUnconfirmedAncestorData(txId: string) {
159
+ async fetchUnconfirmedAncestorData(txId) {
161
160
  const encodedTxId = encodeURIComponent(txId)
162
161
  const url = urlJoin(this._baseURL, `/unconfirmed_ancestor/${encodedTxId}`)
163
162
  return fetchJson(url)
@@ -17,7 +17,7 @@ import { groupBy, sortBy } from 'lodash'
17
17
 
18
18
  A B C check A, no inputs
19
19
  */
20
- export function orderTxs(txs: Array) {
20
+ export function orderTxs(txs) {
21
21
  if (txs.length === 1) return [...txs]
22
22
 
23
23
  // filter duplicates
@@ -1,4 +1,3 @@
1
- /* @flow */
2
1
  import { orderTxs } from '../insight-api-client/util'
3
2
  import { Address, UtxoCollection } from '@exodus/models'
4
3
  import { isEqual, compact, uniq } from 'lodash'
@@ -20,7 +19,8 @@ export class BitcoinMonitorScanner {
20
19
  #yieldToUI
21
20
  #ordinalsEnabled
22
21
  #ordinalChainIndex
23
-
22
+ #gapLimit
23
+ #refreshGapLimit
24
24
  constructor({
25
25
  asset,
26
26
  assetClientInterface,
@@ -30,6 +30,8 @@ export class BitcoinMonitorScanner {
30
30
  txFetchLimitResolver = ({ refresh }) => (refresh ? 50 : 10),
31
31
  ordinalsEnabled,
32
32
  ordinalChainIndex,
33
+ gapLimit = 10,
34
+ refreshGapLimit = 10,
33
35
  }) {
34
36
  assert(asset, 'asset is required!')
35
37
  assert(assetClientInterface, 'assetClientInterface is required!')
@@ -37,6 +39,8 @@ export class BitcoinMonitorScanner {
37
39
  assert(typeof yieldToUI === 'function', 'yieldToUI must be a function')
38
40
  assert(typeof txFetchLimitResolver === 'function', 'txFetchLimitResolver must be a function')
39
41
  assert(typeof shouldExcludeVoutUtxo === 'function', 'shouldExcludeVoutUtxo must be a function')
42
+ assert(typeof gapLimit === 'number', 'gapLimit must be a number')
43
+ assert(typeof refreshGapLimit === 'number', 'refreshGapLimit must be a number')
40
44
 
41
45
  this.#asset = asset
42
46
  this.#insightClient = insightClient
@@ -45,6 +49,8 @@ export class BitcoinMonitorScanner {
45
49
  this.#shouldExcludeVoutUtxo = shouldExcludeVoutUtxo
46
50
  this.#ordinalsEnabled = ordinalsEnabled
47
51
  this.#ordinalChainIndex = ordinalChainIndex
52
+ this.#gapLimit = gapLimit
53
+ this.#refreshGapLimit = refreshGapLimit
48
54
  }
49
55
 
50
56
  async rescanBlockchainInsight({ walletAccount, refresh }) {
@@ -188,18 +194,13 @@ export class BitcoinMonitorScanner {
188
194
  return txArrays.reduce((total, some) => total.concat(some), [])
189
195
  }
190
196
 
191
- const receiveGapLimit = 10
192
- const restoreGapLimit = 10
193
- const changeGapLimit = 10
194
- const gapLimits = [receiveGapLimit, changeGapLimit]
195
197
  const gapSearchParameters = newChains.map(({ purpose, chain }) => {
196
198
  return {
197
199
  purpose,
198
200
  chain,
199
201
  startAddressIndexes: chain.map(() => 0),
200
202
  endAddressIndexes: chain.map(
201
- (addressIndex, chainIndex) =>
202
- refresh ? restoreGapLimit : addressIndex + (gapLimits[chainIndex] || receiveGapLimit) // right of the || should never happen
203
+ (addressIndex) => (refresh ? this.#refreshGapLimit : addressIndex + this.#gapLimit) // right of the || should never happen
203
204
  ),
204
205
  }
205
206
  })
@@ -303,13 +304,9 @@ export class BitcoinMonitorScanner {
303
304
 
304
305
  gapSearchParameters.forEach((indexData) => {
305
306
  indexData.startAddressIndexes = [...indexData.endAddressIndexes]
306
- indexData.endAddressIndexes = indexData.chain.map((addressIndex, chainIndex) => {
307
- return (
308
- addressIndex +
309
- (refresh && addressIndex === indexData.endAddressIndexes[chainIndex]
310
- ? restoreGapLimit
311
- : gapLimits[chainIndex] || receiveGapLimit)
312
- )
307
+ indexData.endAddressIndexes = indexData.chain.map((addressIndex) => {
308
+ const resolvedGapLimit = refresh ? this.#refreshGapLimit : this.#gapLimit
309
+ return addressIndex + resolvedGapLimit
313
310
  })
314
311
  })
315
312
 
@@ -94,7 +94,7 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
94
94
  assert(keys, 'keys is required')
95
95
  assert(coinInfo, 'coinInfo is required')
96
96
 
97
- return async ({ unsignedTx, hdkeys, privateKeysAddressMap }): Object => {
97
+ return async ({ unsignedTx, hdkeys, privateKeysAddressMap }) => {
98
98
  assert(unsignedTx, 'unsignedTx is required')
99
99
  assert(hdkeys || privateKeysAddressMap, 'hdkeys or privateKeysAddressMap is required')
100
100
  const { addressPathsMap } = unsignedTx.txMeta
@@ -143,10 +143,11 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
143
143
  // dApps request to sign only specific transaction inputs.
144
144
  if (!inputInfo) continue
145
145
  const { address, sigHash } = inputInfo
146
- const sigHashTypes = sigHash ? [sigHash] : undefined
146
+ const sigHashTypes = sigHash !== undefined ? [sigHash || Transaction.SIGHASH_ALL] : undefined
147
147
  const { key, purpose, publicKey } = getKeyAndPurpose(address)
148
148
 
149
- if (purpose === 49) {
149
+ // We shouldn't modify dApp PSBTs.
150
+ if (purpose === 49 && !isPsbtBufferPassed) {
150
151
  // If spending from a P2SH address, we assume the address is P2SH wrapping
151
152
  // P2WPKH. Exodus doesn't use P2SH addresses so we should only ever be
152
153
  // signing a P2SH input if we are importing a private key
@@ -9,7 +9,7 @@ const ecc = eccFactory()
9
9
  export function tweakSigner({ signer, ECPair, tweakHash, network }) {
10
10
  assert(signer, 'signer is required')
11
11
  assert(ECPair, 'ECPair is required')
12
- let privateKey: Uint8Array | undefined = signer.privateKey
12
+ let privateKey = signer.privateKey
13
13
  if (!privateKey) {
14
14
  throw new Error('Private key is required for tweaking signer!')
15
15
  }
@@ -30,7 +30,7 @@ export function tweakSigner({ signer, ECPair, tweakHash, network }) {
30
30
  })
31
31
  }
32
32
 
33
- function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
33
+ function tapTweakHash(pubKey, h) {
34
34
  return crypto.taggedHash('TapTweak', Buffer.concat(h ? [pubKey, h] : [pubKey]))
35
35
  }
36
36