@dynamic-labs/bitcoin 4.94.0 → 4.95.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/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
1
 
2
+ ## [4.95.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.94.0...v4.95.0) (2026-07-28)
3
+
4
+
5
+ ### Features
6
+
7
+ * **waas:** expose rawSign sha256/blake2b in SignMessageContext [v4] ([#12076](https://github.com/dynamic-labs/dynamic-auth/issues/12076)) ([5133a71](https://github.com/dynamic-labs/dynamic-auth/commit/5133a713ba5aea0cb19935d99f0795ebbe303d2e))
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * **bitcoin:** resolve the public key of the active wallet, not the first [v4] ([#12090](https://github.com/dynamic-labs/dynamic-auth/issues/12090)) ([a93b55b](https://github.com/dynamic-labs/dynamic-auth/commit/a93b55b882ec3a7ac2adb37e4f653cb935d16193)), closes [#11970](https://github.com/dynamic-labs/dynamic-auth/issues/11970) [#11970](https://github.com/dynamic-labs/dynamic-auth/issues/11970) [#11970](https://github.com/dynamic-labs/dynamic-auth/issues/11970)
13
+ * **client:** ack sdk__loadedChanged in the webview load controller ([#12084](https://github.com/dynamic-labs/dynamic-auth/issues/12084)) ([8688c7d](https://github.com/dynamic-labs/dynamic-auth/commit/8688c7d1cfc320c3ca20913c730326c6f36266e0)), closes [#12071](https://github.com/dynamic-labs/dynamic-auth/issues/12071)
14
+ * fallback to local wallet balance when token balances API returns no tokens ([9ff87c3](https://github.com/dynamic-labs/dynamic-auth/commit/9ff87c3d1836e72a5a1e635ef7bd53464501fc1a))
15
+ * remediate high-severity dependency vulnerabilities ([#12077](https://github.com/dynamic-labs/dynamic-auth/issues/12077)) ([81e2d91](https://github.com/dynamic-labs/dynamic-auth/commit/81e2d91e16edaba1b6251bfa9b9f9c91d09aab80))
16
+ * remediate high-severity dependency vulnerabilities ([#12087](https://github.com/dynamic-labs/dynamic-auth/issues/12087)) ([9250ede](https://github.com/dynamic-labs/dynamic-auth/commit/9250edede5eaa0d0de8faa7d7aad1d164e1c78f7))
17
+
2
18
  ## [4.94.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.93.1...v4.94.0) (2026-07-24)
3
19
 
4
20
 
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.94.0";
6
+ var version = "4.95.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "4.94.0";
2
+ var version = "4.95.0";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/bitcoin",
3
- "version": "4.94.0",
3
+ "version": "4.95.0",
4
4
  "description": "A React SDK for implementing wallet web3 authentication and authorization to your website.",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -22,20 +22,20 @@
22
22
  "@dynamic-labs-wallet/forward-mpc-client": "1.0.1",
23
23
  "@bitcoinerlab/secp256k1": "1.1.1",
24
24
  "@btckit/types": "0.0.19",
25
- "@dynamic-labs/sdk-api-core": "0.0.1082",
25
+ "@dynamic-labs/sdk-api-core": "0.0.1093",
26
26
  "@wallet-standard/app": "1.0.1",
27
27
  "@wallet-standard/base": "1.0.1",
28
28
  "bitcoinjs-lib": "6.1.5",
29
29
  "ecpair": "2.1.0",
30
30
  "sats-connect": "4.2.1",
31
31
  "jsontokens": "4.0.1",
32
- "@dynamic-labs/assert-package-version": "4.94.0",
33
- "@dynamic-labs/logger": "4.94.0",
34
- "@dynamic-labs/types": "4.94.0",
35
- "@dynamic-labs/utils": "4.94.0",
36
- "@dynamic-labs/waas": "4.94.0",
37
- "@dynamic-labs/wallet-book": "4.94.0",
38
- "@dynamic-labs/wallet-connector-core": "4.94.0",
32
+ "@dynamic-labs/assert-package-version": "4.95.0",
33
+ "@dynamic-labs/logger": "4.95.0",
34
+ "@dynamic-labs/types": "4.95.0",
35
+ "@dynamic-labs/utils": "4.95.0",
36
+ "@dynamic-labs/waas": "4.95.0",
37
+ "@dynamic-labs/wallet-book": "4.95.0",
38
+ "@dynamic-labs/wallet-connector-core": "4.95.0",
39
39
  "eventemitter3": "5.0.1"
40
40
  },
41
41
  "peerDependencies": {}
@@ -160,22 +160,57 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
160
160
  return _super.getBalance.call(this, (_a = this.activeAccountAddress) !== null && _a !== void 0 ? _a : address);
161
161
  });
162
162
  }
163
+ /**
164
+ * Finds the credential that owns the active address, either as its primary
165
+ * (mainnet) address or as one of its network-tagged additional addresses.
166
+ *
167
+ * This connector is shared across every Bitcoin wallet of the user —
168
+ * `verifiedCredentials` holds them all — so the owning credential must be
169
+ * looked up by the active address. Reading `verifiedCredential` instead
170
+ * would always answer with the user's *first* wallet.
171
+ */
172
+ findCredentialForActiveAddress() {
173
+ var _a;
174
+ const { activeAccountAddress } = this;
175
+ if (!activeAccountAddress) {
176
+ return undefined;
177
+ }
178
+ return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
179
+ var _a;
180
+ return (credential === null || credential === void 0 ? void 0 : credential.address) === activeAccountAddress ||
181
+ ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === activeAccountAddress);
182
+ });
183
+ }
163
184
  /**
164
185
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
165
186
  * primary (mainnet) address. On testnet the active address is the same
166
187
  * wallet's per-network encoding — WaaS lookups (password, signing) must use
167
188
  * the primary address (the same key signs both encodings).
189
+ *
190
+ * Resolved from the credential that owns the active address, so a user with
191
+ * several Bitcoin wallets gets the identity of the wallet being spent from.
192
+ * Never falls back to another wallet's address: a substituted key produces a
193
+ * signature that looks valid locally and is rejected by the network, so the
194
+ * failure has to surface here instead.
168
195
  */
169
196
  getWalletIdentityAddress() {
170
- var _a, _b;
171
- // The active address is a valid fallback only on mainnet, where it is
172
- // the primary encoding; a switched-network encoding must never be used
173
- // as the wallet identity.
174
- const identity = (_b = (_a = this.verifiedCredential) === null || _a === void 0 ? void 0 : _a.address) !== null && _b !== void 0 ? _b : (this.activeNetworkId === BITCOIN_MAINNET_NETWORK_ID
197
+ var _a, _b, _c, _d;
198
+ const owningCredential = this.findCredentialForActiveAddress();
199
+ // The primary address is normally on the credential itself; fall back to
200
+ // its mainnet-tagged payment address for credentials that only carry
201
+ // network-tagged entries.
202
+ const owningCredentialAddress = (_a = owningCredential === null || owningCredential === void 0 ? void 0 : owningCredential.address) !== null && _a !== void 0 ? _a : (_c = ((_b = owningCredential === null || owningCredential === void 0 ? void 0 : owningCredential.walletAdditionalAddresses) !== null && _b !== void 0 ? _b : []).find((addr) => addr.type === 'payment' &&
203
+ addr.network === 'mainnet')) === null || _c === void 0 ? void 0 : _c.address;
204
+ // With no credential owning the active address there is nothing to
205
+ // identify the wallet by except the active address itself, which on
206
+ // mainnet is the primary encoding. That is still the *requested* wallet,
207
+ // so it is a safe answer — unlike `verifiedCredential`, which is always
208
+ // the user's first wallet and would substitute a different key.
209
+ const identity = owningCredentialAddress !== null && owningCredentialAddress !== void 0 ? owningCredentialAddress : (this.activeNetworkId === BITCOIN_MAINNET_NETWORK_ID
175
210
  ? this.activeAccountAddress
176
211
  : undefined);
177
212
  if (!identity) {
178
- throw new utils.DynamicError('Active account address is required', 'active_account_address_is_required');
213
+ throw new utils.DynamicError(`Could not resolve the wallet identity for active address ${(_d = this.activeAccountAddress) !== null && _d !== void 0 ? _d : '(unset)'}`, 'active_account_address_is_required');
179
214
  }
180
215
  return identity;
181
216
  }
@@ -185,14 +220,18 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
185
220
  * address (wallets created before per-network registration).
186
221
  */
187
222
  getPaymentAddressForNetwork(network) {
188
- var _a, _b, _c;
189
- const tagged = (_b = (_a = this.verifiedCredential) === null || _a === void 0 ? void 0 : _a.walletAdditionalAddresses) === null || _b === void 0 ? void 0 : _b.find((addr) => addr.type === 'payment' &&
223
+ var _a, _b;
224
+ // Resolved against the wallet that is currently active. Reading
225
+ // `verifiedCredential` alone would switch the network on the user's first
226
+ // wallet, handing back an address that belongs to a different wallet.
227
+ const credential = (_a = this.findCredentialForActiveAddress()) !== null && _a !== void 0 ? _a : this.verifiedCredential;
228
+ const tagged = (_b = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) === null || _b === void 0 ? void 0 : _b.find((addr) => addr.type === 'payment' &&
190
229
  addr.network === network);
191
230
  if (tagged === null || tagged === void 0 ? void 0 : tagged.address) {
192
231
  return tagged.address;
193
232
  }
194
233
  if (network === 'mainnet') {
195
- return (_c = this.verifiedCredential) === null || _c === void 0 ? void 0 : _c.address;
234
+ return credential === null || credential === void 0 ? void 0 : credential.address;
196
235
  }
197
236
  return undefined;
198
237
  }
@@ -667,7 +706,16 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
667
706
  // signs both. Look it up by the wallet identity address rather than the
668
707
  // active address, which after a network switch is the testnet encoding.
669
708
  const walletIdentityAddress = this.getWalletIdentityAddress();
670
- for (const credential of allCredentials) {
709
+ // Scoped to the credential that owns the active address when there is one.
710
+ // Searching every credential would let another wallet of the same user
711
+ // answer for this one, and that is the failure this must not produce: the
712
+ // PSBT then carries a witness script derived from the wrong key and is
713
+ // rejected by the network only after broadcast.
714
+ const owningCredential = this.findCredentialForActiveAddress();
715
+ const credentialsToSearch = owningCredential
716
+ ? [owningCredential]
717
+ : allCredentials;
718
+ for (const credential of credentialsToSearch) {
671
719
  const { walletAdditionalAddresses } = credential !== null && credential !== void 0 ? credential : {};
672
720
  if (!walletAdditionalAddresses) {
673
721
  continue;
@@ -677,8 +725,8 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
677
725
  return additionalAddress.publicKey;
678
726
  }
679
727
  }
680
- const allAvailableAddresses = allCredentials
681
- .flatMap((cred) => { var _a; return (_a = cred.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []; })
728
+ const allAvailableAddresses = credentialsToSearch
729
+ .flatMap((cred) => { var _a; return (_a = cred === null || cred === void 0 ? void 0 : cred.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []; })
682
730
  .map((addr) => addr.address)
683
731
  .join(', ');
684
732
  throw new utils.DynamicError(`No additional address found for ${walletIdentityAddress}. Available addresses: ${allAvailableAddresses || 'none'}`, 'no_additional_address_found_for_available');
@@ -279,11 +279,27 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
279
279
  * routing is address-driven).
280
280
  */
281
281
  getBalance(address: string): Promise<string | undefined>;
282
+ /**
283
+ * Finds the credential that owns the active address, either as its primary
284
+ * (mainnet) address or as one of its network-tagged additional addresses.
285
+ *
286
+ * This connector is shared across every Bitcoin wallet of the user —
287
+ * `verifiedCredentials` holds them all — so the owning credential must be
288
+ * looked up by the active address. Reading `verifiedCredential` instead
289
+ * would always answer with the user's *first* wallet.
290
+ */
291
+ private findCredentialForActiveAddress;
282
292
  /**
283
293
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
284
294
  * primary (mainnet) address. On testnet the active address is the same
285
295
  * wallet's per-network encoding — WaaS lookups (password, signing) must use
286
296
  * the primary address (the same key signs both encodings).
297
+ *
298
+ * Resolved from the credential that owns the active address, so a user with
299
+ * several Bitcoin wallets gets the identity of the wallet being spent from.
300
+ * Never falls back to another wallet's address: a substituted key produces a
301
+ * signature that looks valid locally and is rejected by the network, so the
302
+ * failure has to surface here instead.
287
303
  */
288
304
  private getWalletIdentityAddress;
289
305
  /**
@@ -156,22 +156,57 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
156
156
  return _super.getBalance.call(this, (_a = this.activeAccountAddress) !== null && _a !== void 0 ? _a : address);
157
157
  });
158
158
  }
159
+ /**
160
+ * Finds the credential that owns the active address, either as its primary
161
+ * (mainnet) address or as one of its network-tagged additional addresses.
162
+ *
163
+ * This connector is shared across every Bitcoin wallet of the user —
164
+ * `verifiedCredentials` holds them all — so the owning credential must be
165
+ * looked up by the active address. Reading `verifiedCredential` instead
166
+ * would always answer with the user's *first* wallet.
167
+ */
168
+ findCredentialForActiveAddress() {
169
+ var _a;
170
+ const { activeAccountAddress } = this;
171
+ if (!activeAccountAddress) {
172
+ return undefined;
173
+ }
174
+ return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
175
+ var _a;
176
+ return (credential === null || credential === void 0 ? void 0 : credential.address) === activeAccountAddress ||
177
+ ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === activeAccountAddress);
178
+ });
179
+ }
159
180
  /**
160
181
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
161
182
  * primary (mainnet) address. On testnet the active address is the same
162
183
  * wallet's per-network encoding — WaaS lookups (password, signing) must use
163
184
  * the primary address (the same key signs both encodings).
185
+ *
186
+ * Resolved from the credential that owns the active address, so a user with
187
+ * several Bitcoin wallets gets the identity of the wallet being spent from.
188
+ * Never falls back to another wallet's address: a substituted key produces a
189
+ * signature that looks valid locally and is rejected by the network, so the
190
+ * failure has to surface here instead.
164
191
  */
165
192
  getWalletIdentityAddress() {
166
- var _a, _b;
167
- // The active address is a valid fallback only on mainnet, where it is
168
- // the primary encoding; a switched-network encoding must never be used
169
- // as the wallet identity.
170
- const identity = (_b = (_a = this.verifiedCredential) === null || _a === void 0 ? void 0 : _a.address) !== null && _b !== void 0 ? _b : (this.activeNetworkId === BITCOIN_MAINNET_NETWORK_ID
193
+ var _a, _b, _c, _d;
194
+ const owningCredential = this.findCredentialForActiveAddress();
195
+ // The primary address is normally on the credential itself; fall back to
196
+ // its mainnet-tagged payment address for credentials that only carry
197
+ // network-tagged entries.
198
+ const owningCredentialAddress = (_a = owningCredential === null || owningCredential === void 0 ? void 0 : owningCredential.address) !== null && _a !== void 0 ? _a : (_c = ((_b = owningCredential === null || owningCredential === void 0 ? void 0 : owningCredential.walletAdditionalAddresses) !== null && _b !== void 0 ? _b : []).find((addr) => addr.type === 'payment' &&
199
+ addr.network === 'mainnet')) === null || _c === void 0 ? void 0 : _c.address;
200
+ // With no credential owning the active address there is nothing to
201
+ // identify the wallet by except the active address itself, which on
202
+ // mainnet is the primary encoding. That is still the *requested* wallet,
203
+ // so it is a safe answer — unlike `verifiedCredential`, which is always
204
+ // the user's first wallet and would substitute a different key.
205
+ const identity = owningCredentialAddress !== null && owningCredentialAddress !== void 0 ? owningCredentialAddress : (this.activeNetworkId === BITCOIN_MAINNET_NETWORK_ID
171
206
  ? this.activeAccountAddress
172
207
  : undefined);
173
208
  if (!identity) {
174
- throw new DynamicError('Active account address is required', 'active_account_address_is_required');
209
+ throw new DynamicError(`Could not resolve the wallet identity for active address ${(_d = this.activeAccountAddress) !== null && _d !== void 0 ? _d : '(unset)'}`, 'active_account_address_is_required');
175
210
  }
176
211
  return identity;
177
212
  }
@@ -181,14 +216,18 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
181
216
  * address (wallets created before per-network registration).
182
217
  */
183
218
  getPaymentAddressForNetwork(network) {
184
- var _a, _b, _c;
185
- const tagged = (_b = (_a = this.verifiedCredential) === null || _a === void 0 ? void 0 : _a.walletAdditionalAddresses) === null || _b === void 0 ? void 0 : _b.find((addr) => addr.type === 'payment' &&
219
+ var _a, _b;
220
+ // Resolved against the wallet that is currently active. Reading
221
+ // `verifiedCredential` alone would switch the network on the user's first
222
+ // wallet, handing back an address that belongs to a different wallet.
223
+ const credential = (_a = this.findCredentialForActiveAddress()) !== null && _a !== void 0 ? _a : this.verifiedCredential;
224
+ const tagged = (_b = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) === null || _b === void 0 ? void 0 : _b.find((addr) => addr.type === 'payment' &&
186
225
  addr.network === network);
187
226
  if (tagged === null || tagged === void 0 ? void 0 : tagged.address) {
188
227
  return tagged.address;
189
228
  }
190
229
  if (network === 'mainnet') {
191
- return (_c = this.verifiedCredential) === null || _c === void 0 ? void 0 : _c.address;
230
+ return credential === null || credential === void 0 ? void 0 : credential.address;
192
231
  }
193
232
  return undefined;
194
233
  }
@@ -663,7 +702,16 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
663
702
  // signs both. Look it up by the wallet identity address rather than the
664
703
  // active address, which after a network switch is the testnet encoding.
665
704
  const walletIdentityAddress = this.getWalletIdentityAddress();
666
- for (const credential of allCredentials) {
705
+ // Scoped to the credential that owns the active address when there is one.
706
+ // Searching every credential would let another wallet of the same user
707
+ // answer for this one, and that is the failure this must not produce: the
708
+ // PSBT then carries a witness script derived from the wrong key and is
709
+ // rejected by the network only after broadcast.
710
+ const owningCredential = this.findCredentialForActiveAddress();
711
+ const credentialsToSearch = owningCredential
712
+ ? [owningCredential]
713
+ : allCredentials;
714
+ for (const credential of credentialsToSearch) {
667
715
  const { walletAdditionalAddresses } = credential !== null && credential !== void 0 ? credential : {};
668
716
  if (!walletAdditionalAddresses) {
669
717
  continue;
@@ -673,8 +721,8 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
673
721
  return additionalAddress.publicKey;
674
722
  }
675
723
  }
676
- const allAvailableAddresses = allCredentials
677
- .flatMap((cred) => { var _a; return (_a = cred.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []; })
724
+ const allAvailableAddresses = credentialsToSearch
725
+ .flatMap((cred) => { var _a; return (_a = cred === null || cred === void 0 ? void 0 : cred.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []; })
678
726
  .map((addr) => addr.address)
679
727
  .join(', ');
680
728
  throw new DynamicError(`No additional address found for ${walletIdentityAddress}. Available addresses: ${allAvailableAddresses || 'none'}`, 'no_additional_address_found_for_available');
package/src/index.cjs CHANGED
@@ -69,6 +69,7 @@ exports.PsbtParser = PsbtParser.PsbtParser;
69
69
  exports.BitcoinWallet = BitcoinWallet.BitcoinWallet;
70
70
  exports.isBitcoinWallet = isBitcoinWallet.isBitcoinWallet;
71
71
  exports.BitcoinProviderHelper = bitcoinProviderHelper.BitcoinProviderHelper;
72
+ exports.DUST_LIMIT = _const.DUST_LIMIT;
72
73
  exports.HTTP_STATUS_NOT_FOUND = _const.HTTP_STATUS_NOT_FOUND;
73
74
  exports.HTTP_STATUS_TOO_MANY_REQUESTS = _const.HTTP_STATUS_TOO_MANY_REQUESTS;
74
75
  exports.BitcoinWalletConnectors = BitcoinWalletConnectors;
package/src/index.d.ts CHANGED
@@ -6,4 +6,4 @@ export * from './wallet';
6
6
  export { UnisatConnector, BitcoinSatsConnectConnector, DynamicWaasBitcoinConnector, } from './connectors';
7
7
  export declare const BitcoinWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof OkxConnector)[];
8
8
  export { BitcoinProviderHelper } from './bitcoinProviderHelper';
9
- export { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS } from './const';
9
+ export { DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS, } from './const';
package/src/index.js CHANGED
@@ -34,7 +34,7 @@ export { PsbtParser } from './utils/psbtParser/PsbtParser.js';
34
34
  export { BitcoinWallet } from './wallet/BitcoinWallet.js';
35
35
  export { isBitcoinWallet } from './wallet/isBitcoinWallet/isBitcoinWallet.js';
36
36
  export { BitcoinProviderHelper } from './bitcoinProviderHelper.js';
37
- export { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS } from './const.js';
37
+ export { DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS } from './const.js';
38
38
 
39
39
  assertPackageVersion('@dynamic-labs/bitcoin', version);
40
40
  const BitcoinWalletConnectors = (props) => [
@@ -140,7 +140,10 @@ class MempoolApiService {
140
140
  if (!response.ok) {
141
141
  const error = yield response.text();
142
142
  logger.debug(`sendRawTransaction - response not ok: ${JSON.stringify(error)}`);
143
- throw new utils.DynamicError('sendRawTransaction - failed to send transaction', 'sendrawtransaction_failed_to_send_transaction');
143
+ // The node's reject reason is the only thing that distinguishes a bad
144
+ // witness from a fee or mempool problem, so it goes in the thrown
145
+ // message rather than only into a debug log the integrator cannot read.
146
+ throw new utils.DynamicError(`sendRawTransaction - failed to send transaction${error ? `: ${error}` : ''}`, 'sendrawtransaction_failed_to_send_transaction');
144
147
  }
145
148
  return response.text();
146
149
  });
@@ -136,7 +136,10 @@ class MempoolApiService {
136
136
  if (!response.ok) {
137
137
  const error = yield response.text();
138
138
  logger.debug(`sendRawTransaction - response not ok: ${JSON.stringify(error)}`);
139
- throw new DynamicError('sendRawTransaction - failed to send transaction', 'sendrawtransaction_failed_to_send_transaction');
139
+ // The node's reject reason is the only thing that distinguishes a bad
140
+ // witness from a fee or mempool problem, so it goes in the thrown
141
+ // message rather than only into a debug log the integrator cannot read.
142
+ throw new DynamicError(`sendRawTransaction - failed to send transaction${error ? `: ${error}` : ''}`, 'sendrawtransaction_failed_to_send_transaction');
140
143
  }
141
144
  return response.text();
142
145
  });