@exodus/bitcoin-api 4.13.0 → 4.14.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [4.14.1](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.14.0...@exodus/bitcoin-api@4.14.1) (2026-04-02)
7
+
8
+ **Note:** Version bump only for package @exodus/bitcoin-api
9
+
10
+
11
+
12
+
13
+
14
+ ## [4.14.0](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.13.0...@exodus/bitcoin-api@4.14.0) (2026-03-27)
15
+
16
+
17
+ ### Features
18
+
19
+
20
+ * feat: add configs for btc mempool api clients (#7670)
21
+
22
+ * feat: add getFeeAsync to bitcoin and bitcoin-like assets (#7616)
23
+
24
+ * feat: add mempool indexer support for btc (#7492)
25
+
26
+
27
+
6
28
  ## [4.13.0](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.12.0...@exodus/bitcoin-api@4.13.0) (2026-03-20)
7
29
 
8
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bitcoin-api",
3
- "version": "4.13.0",
3
+ "version": "4.14.1",
4
4
  "description": "Bitcoin transaction and fee monitors, RPC with the blockchain node, other networking code.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -63,5 +63,5 @@
63
63
  "type": "git",
64
64
  "url": "git+https://github.com/ExodusMovement/assets.git"
65
65
  },
66
- "gitHead": "49d472ae5c602ba68329227e0e0cd3a9b4568fba"
66
+ "gitHead": "00d2c9f1bc5285d90db56abb5f883851f2ac4d3b"
67
67
  }
@@ -0,0 +1,45 @@
1
+ import assert from 'minimalistic-assert'
2
+
3
+ export const getFeeAsyncFactory = ({ createTx, assetClientInterface }) => {
4
+ assert(createTx, 'createTx is required')
5
+ assert(assetClientInterface, 'assetClientInterface is required')
6
+
7
+ return async ({ asset, walletAccount, toAddress, amount, isSendAll, ...extraCreateTxParams }) => {
8
+ assert(asset, 'asset is required')
9
+ assert(walletAccount, 'walletAccount is required')
10
+
11
+ const sendAmount = amount || asset.currency.ZERO
12
+
13
+ try {
14
+ const { fee } = await createTx({
15
+ asset,
16
+ walletAccount,
17
+ toAddress,
18
+ amount: sendAmount,
19
+ isSendAll,
20
+ ...extraCreateTxParams,
21
+ })
22
+
23
+ return { fee }
24
+ } catch {
25
+ const assetName = asset.name
26
+ const [accountState, txSet, feeData] = await Promise.all([
27
+ assetClientInterface.getAccountState({ assetName, walletAccount }),
28
+ assetClientInterface.getTxLog({ assetName, walletAccount }),
29
+ assetClientInterface.getFeeData({ assetName }),
30
+ ])
31
+ const { fee } = asset.api.getFee({
32
+ asset,
33
+ accountState,
34
+ txSet,
35
+ feeData,
36
+ amount: sendAmount,
37
+ isSendAll,
38
+ // customFee,
39
+ // receiveAddress,
40
+ // taprootInputWitnessSize,
41
+ })
42
+ return { fee }
43
+ }
44
+ }
45
+ }
package/src/index.js CHANGED
@@ -27,3 +27,4 @@ export * from './ordinals-utils.js'
27
27
  export { signMessage, signMessageWithSigner } from './sign-message.js'
28
28
  export { writePsbtBlockHeight, readPsbtBlockHeight } from './psbt-proprietary-types.js'
29
29
  export { getActivityTxs } from './get-activity-txs.js'
30
+ export { getFeeAsyncFactory } from './get-fee-async.js'
@@ -210,7 +210,7 @@ export default class MempoolRestClient {
210
210
  baseURL,
211
211
  insightBaseURL,
212
212
  retryWaitTimes = RETRY_WAIT_TIMES,
213
- configMinFeeRate = 0,
213
+ configMinFeeRate = 10,
214
214
  } = {}) {
215
215
  this._baseURL = baseURL
216
216
  this._insightBaseURL = insightBaseURL
@@ -106,8 +106,12 @@ export function toWSUrl(apiUrl) {
106
106
  }
107
107
  }
108
108
 
109
- export function normalizeInsightConfig(config) {
109
+ export function normalizeInsightConfig(config, monitorType) {
110
110
  const apiUrl = config?.insightServers?.[0]
111
- const wsUrl = config?.insightServersWS?.[0] || toWSUrl(apiUrl)
112
- return { apiUrl, wsUrl }
111
+ const mempoolApiUrl = config?.mempoolServer
112
+ const wsUrl =
113
+ monitorType === 'mempool'
114
+ ? config?.mempoolServerWS || toWSUrl(mempoolApiUrl)
115
+ : config?.insightServersWS?.[0] || toWSUrl(apiUrl)
116
+ return { apiUrl, mempoolApiUrl, wsUrl }
113
117
  }
@@ -4,6 +4,7 @@ import lodash from 'lodash'
4
4
  import assert from 'minimalistic-assert'
5
5
  import ms from 'ms'
6
6
 
7
+ import MempoolWSClient from '../insight-api-client/mempool-ws-client.js'
7
8
  import { normalizeInsightConfig, toWSUrl } from '../insight-api-client/util.js'
8
9
  import InsightWSClient from '../insight-api-client/ws.js'
9
10
  import { resolveUnconfirmedAncestorData } from '../unconfirmed-ancestor-data.js'
@@ -20,6 +21,9 @@ export class Monitor extends BaseMonitor {
20
21
  #wsInterval
21
22
  #ws
22
23
  #apiUrl
24
+ #mempoolApiUrl
25
+ #monitorType
26
+ #maxTrackedAddresses
23
27
  #wsUrl
24
28
  #insightClient
25
29
  #yieldToUI
@@ -36,6 +40,9 @@ export class Monitor extends BaseMonitor {
36
40
  logger,
37
41
  insightClient,
38
42
  apiUrl,
43
+ mempoolApiUrl,
44
+ monitorType,
45
+ maxTrackedAddresses,
39
46
  scanner,
40
47
  webSocketEnabled = true,
41
48
  ...extraScannerParams
@@ -47,6 +54,9 @@ export class Monitor extends BaseMonitor {
47
54
  this.#wsInterval = wsInterval
48
55
  this.#ws = null
49
56
  this.#apiUrl = apiUrl
57
+ this.#mempoolApiUrl = mempoolApiUrl
58
+ this.#monitorType = monitorType
59
+ this.#maxTrackedAddresses = maxTrackedAddresses
50
60
  this.#yieldToUI = yieldToUI
51
61
  this.#webSocketEnabled = webSocketEnabled
52
62
  this.#wsUrl = null
@@ -76,13 +86,26 @@ export class Monitor extends BaseMonitor {
76
86
  }
77
87
 
78
88
  setServer(assetConfig = {}) {
79
- const { apiUrl, wsUrl } = normalizeInsightConfig(assetConfig)
80
- if (apiUrl) {
89
+ const { apiUrl, mempoolApiUrl, wsUrl } = normalizeInsightConfig(assetConfig, this.#monitorType)
90
+
91
+ if (this.#monitorType === 'mempool') {
92
+ if (mempoolApiUrl) {
93
+ this.#insightClient.setBaseUrl(mempoolApiUrl)
94
+ }
95
+
96
+ if (apiUrl) {
97
+ this.#insightClient.setInsightBaseUrl(apiUrl)
98
+ }
99
+ } else if (apiUrl) {
81
100
  this.#insightClient.setBaseUrl(apiUrl)
82
101
  }
83
102
 
84
103
  if (!this.#wsUrl || this.#wsUrl !== wsUrl) {
85
- this.#connectWS(wsUrl || this.#wsUrl || toWSUrl(this.#apiUrl))
104
+ this.#connectWS(
105
+ wsUrl ||
106
+ this.#wsUrl ||
107
+ toWSUrl(this.#monitorType === 'mempool' ? this.#mempoolApiUrl : this.#apiUrl)
108
+ )
86
109
  }
87
110
  }
88
111
 
@@ -129,14 +152,22 @@ export class Monitor extends BaseMonitor {
129
152
 
130
153
  this.#addressesByWalletAccount = await this.#getReceiveAddressesByWalletAccount()
131
154
 
132
- const addressesArr = Object.values(this.#addressesByWalletAccount).flat()
155
+ let addressesArr = Object.values(this.#addressesByWalletAccount).flat()
133
156
 
134
157
  if (addressesArr.length === 0) {
135
158
  this.#logWsStatus('no addressesArr to subscribe')
136
159
  return
137
160
  }
138
161
 
139
- this.#ws = new InsightWSClient(wsUrl, this.asset.name)
162
+ if (this.#monitorType === 'mempool') {
163
+ this.#ws = new MempoolWSClient(wsUrl, this.asset.name)
164
+ // Mempool WS rejects oversized track-addresses subscriptions; cap client-side to avoid immediate errors.
165
+ addressesArr = addressesArr.slice(0, this.#maxTrackedAddresses ?? 20)
166
+ } else {
167
+ this.#ws = new InsightWSClient(wsUrl, this.asset.name)
168
+ // Insight/Magnifier tolerates oversized subscribe calls and ignores overflow, so no client-side cap here.
169
+ }
170
+
140
171
  this.#ws.connect(addressesArr)
141
172
  this.#ws.on('connect', () => {
142
173
  this.#logWsStatus('connect to addresses', addressesArr)