@dynamic-labs/bitcoin 4.53.1 → 4.54.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,29 @@
1
1
 
2
+ ## [4.54.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.53.2...v4.54.0) (2026-01-16)
3
+
4
+
5
+ ### Features
6
+
7
+ * add iCloud backup method for wallet backup ([#10221](https://github.com/dynamic-labs/dynamic-auth/issues/10221)) ([36f5b8a](https://github.com/dynamic-labs/dynamic-auth/commit/36f5b8a0df50139fabbc6d6256f396a6d40313f4))
8
+ * add iCloud backup support for wallet key shares ([#10220](https://github.com/dynamic-labs/dynamic-auth/issues/10220)) ([f5f8135](https://github.com/dynamic-labs/dynamic-auth/commit/f5f813593d6ec834fc94f873fd7151b1f3e1a0ca))
9
+ * add legacyWalletId parameter to importPrivateKey ([#10244](https://github.com/dynamic-labs/dynamic-auth/issues/10244)) ([d281dd7](https://github.com/dynamic-labs/dynamic-auth/commit/d281dd7128ac1211e8ca0b72818e109ece7b9837))
10
+
11
+ ### [4.53.2](https://github.com/dynamic-labs/dynamic-auth/compare/v4.53.1...v4.53.2) (2026-01-16)
12
+
13
+
14
+ ### Features
15
+
16
+ * add iCloud backup functionality ([#10219](https://github.com/dynamic-labs/dynamic-auth/issues/10219)) ([44e95e5](https://github.com/dynamic-labs/dynamic-auth/commit/44e95e5a5dc99f83918a382ab1c69d452359c346))
17
+ * update PSBT building with Largest-First UTXO selection and fee priorities (high/medium/low) ([#10227](https://github.com/dynamic-labs/dynamic-auth/issues/10227)) ([94c5f5c](https://github.com/dynamic-labs/dynamic-auth/commit/94c5f5cb97432bb97374b754cb95bc23290dd184))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * allow late registered solana wallets to appear in the wallet list ([#10224](https://github.com/dynamic-labs/dynamic-auth/issues/10224)) ([2f418d4](https://github.com/dynamic-labs/dynamic-auth/commit/2f418d4f3e0543bdd829a45807329f89da1e41a7))
23
+ * correctly show app name in wallet app for wallet connect evm connections ([#10218](https://github.com/dynamic-labs/dynamic-auth/issues/10218)) ([fec0009](https://github.com/dynamic-labs/dynamic-auth/commit/fec0009177439baa67015050b4ad799119615f4f))
24
+ * destructure wallets from getWalletStandardWallets before calling find ([#10234](https://github.com/dynamic-labs/dynamic-auth/issues/10234)) ([b59617a](https://github.com/dynamic-labs/dynamic-auth/commit/b59617a8579b9c7d8a5f744a2ea9363ccb4aee58))
25
+ * **react-native:** filter connectors by enabled chains and add chain parameter to connectWallet ([#10230](https://github.com/dynamic-labs/dynamic-auth/issues/10230)) ([a2bbd03](https://github.com/dynamic-labs/dynamic-auth/commit/a2bbd03ece52950711d2eda18cb2345df15710dd))
26
+
2
27
  ### [4.53.1](https://github.com/dynamic-labs/dynamic-auth/compare/v4.53.0...v4.53.1) (2026-01-14)
3
28
 
4
29
  ## [4.53.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.52.5...v4.53.0) (2026-01-13)
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.53.1";
6
+ var version = "4.54.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "4.53.1";
2
+ var version = "4.54.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.53.1",
3
+ "version": "4.54.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",
@@ -18,23 +18,23 @@
18
18
  },
19
19
  "homepage": "https://www.dynamic.xyz/",
20
20
  "dependencies": {
21
- "@dynamic-labs-wallet/browser-wallet-client": "0.0.237",
21
+ "@dynamic-labs-wallet/browser-wallet-client": "0.0.248",
22
22
  "@bitcoinerlab/secp256k1": "1.1.1",
23
23
  "@btckit/types": "0.0.19",
24
- "@dynamic-labs/sdk-api-core": "0.0.843",
24
+ "@dynamic-labs/sdk-api-core": "0.0.855",
25
25
  "@wallet-standard/app": "1.0.1",
26
26
  "@wallet-standard/base": "1.0.1",
27
27
  "bitcoinjs-lib": "6.1.5",
28
28
  "ecpair": "2.1.0",
29
29
  "sats-connect": "4.2.0",
30
30
  "jsontokens": "4.0.1",
31
- "@dynamic-labs/assert-package-version": "4.53.1",
32
- "@dynamic-labs/logger": "4.53.1",
33
- "@dynamic-labs/types": "4.53.1",
34
- "@dynamic-labs/utils": "4.53.1",
35
- "@dynamic-labs/waas": "4.53.1",
36
- "@dynamic-labs/wallet-book": "4.53.1",
37
- "@dynamic-labs/wallet-connector-core": "4.53.1",
31
+ "@dynamic-labs/assert-package-version": "4.54.0",
32
+ "@dynamic-labs/logger": "4.54.0",
33
+ "@dynamic-labs/types": "4.54.0",
34
+ "@dynamic-labs/utils": "4.54.0",
35
+ "@dynamic-labs/waas": "4.54.0",
36
+ "@dynamic-labs/wallet-book": "4.54.0",
37
+ "@dynamic-labs/wallet-connector-core": "4.54.0",
38
38
  "eventemitter3": "5.0.1"
39
39
  },
40
40
  "peerDependencies": {}
@@ -128,11 +128,15 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
128
128
  });
129
129
  }
130
130
  /**
131
- * Signs a Partially Signed Bitcoin Transaction (PSBT)
132
- * @param request - The PSBT signing request containing the unsigned PSBT
133
- * @returns The signed PSBT response
131
+ * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
132
+ *
133
+ * Embedded wallets only support PSBT format and automatically sign all inputs
134
+ * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
135
+ *
136
+ * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
137
+ * @returns The signed (but not finalized) PSBT response
134
138
  * @throws {DynamicError} If active account address is not set
135
- * @throws {DynamicError} If signed session ID is not available or signature is provided
139
+ * @throws {DynamicError} If signed session ID is not available
136
140
  */
137
141
  signPsbt(request) {
138
142
  return _tslib.__awaiter(this, void 0, void 0, function* () {
@@ -148,9 +152,6 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
148
152
  const mfaToken = yield ((_b = this.getMfaToken) === null || _b === void 0 ? void 0 : _b.call(this, {
149
153
  mfaAction: sdkApiCore.MFAAction.WalletWaasSign,
150
154
  }));
151
- if (request.signature && request.signature.length > 0) {
152
- throw new utils.DynamicError('Signature is not supported for waas at the moment');
153
- }
154
155
  const signedTransaction = yield walletClient.signTransaction({
155
156
  authToken: (_c = this.getAuthToken) === null || _c === void 0 ? void 0 : _c.call(this),
156
157
  mfaToken,
@@ -192,9 +193,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
192
193
  // Step 1: Build the PSBT
193
194
  const unsignedPsbt = yield this.buildPsbt(transaction);
194
195
  // Step 2: Sign the PSBT
195
- // SIGHASH_ALL (0x01) is the most common sighash type for Bitcoin transactions (Eventually can be configurable)
196
196
  const signedPsbtResponse = yield this.signPsbt({
197
- allowedSighash: [0x01],
198
197
  unsignedPsbtBase64: unsignedPsbt,
199
198
  });
200
199
  if (!signedPsbtResponse) {
@@ -238,13 +237,14 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
238
237
  * @param thresholdSignatureScheme - The threshold signature scheme (default: 'TWO_OF_TWO')
239
238
  * @param publicAddressCheck - Optional public address to verify against
240
239
  * @param addressType - Required address type for Bitcoin ('native_segwit' or 'taproot')
240
+ * @param legacyWalletId - Optional ID of the legacy wallet being upgraded
241
241
  * @throws {DynamicError} If addressType is missing or invalid for BTC
242
242
  */
243
243
  importPrivateKey(_a) {
244
244
  const _super = Object.create(null, {
245
245
  importPrivateKey: { get: () => super.importPrivateKey }
246
246
  });
247
- return _tslib.__awaiter(this, arguments, void 0, function* ({ privateKey, thresholdSignatureScheme = 'TWO_OF_TWO', publicAddressCheck, addressType, }) {
247
+ return _tslib.__awaiter(this, arguments, void 0, function* ({ privateKey, thresholdSignatureScheme = 'TWO_OF_TWO', publicAddressCheck, addressType, legacyWalletId, }) {
248
248
  if (!addressType) {
249
249
  throw new utils.DynamicError('addressType is required for BTC importPrivateKey');
250
250
  }
@@ -254,6 +254,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
254
254
  }
255
255
  return _super.importPrivateKey.call(this, {
256
256
  addressType,
257
+ legacyWalletId,
257
258
  privateKey,
258
259
  publicAddressCheck,
259
260
  thresholdSignatureScheme,
@@ -337,7 +338,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
337
338
  }
338
339
  /**
339
340
  * Builds a PSBT for a Bitcoin transaction with real UTXOs
340
- * @param transaction - The Bitcoin transaction containing recipient address and amount in satoshis to send
341
+ * @param transaction - Bitcoin transaction with recipient address, amount in satoshis, and optional fee priority
341
342
  * @returns A PSBT in Base64 format
342
343
  * @throws {DynamicError} If no active account address, insufficient funds, or other errors
343
344
  */
@@ -347,7 +348,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
347
348
  throw new utils.DynamicError('Active account address is required');
348
349
  }
349
350
  const publicKeyHex = yield this.getPublicKey();
350
- const buildOptions = PsbtBuilderService.PsbtBuilderService.createBuildOptions(this.activeAccountAddress, transaction, publicKeyHex);
351
+ const buildOptions = PsbtBuilderService.PsbtBuilderService.createBuildOptions(this.activeAccountAddress, transaction, publicKeyHex, transaction.feePriority || 'medium');
351
352
  return this.psbtBuilderService.buildPsbt(buildOptions);
352
353
  });
353
354
  }
@@ -2,8 +2,8 @@ import { BitcoinConfig, BitcoinNetwork } from '@dynamic-labs-wallet/browser-wall
2
2
  import { JwtVerifiedCredential, MFAAction, SignMessageContext } from '@dynamic-labs/sdk-api-core';
3
3
  import { Logger } from '@dynamic-labs/logger';
4
4
  import { WalletUiUtils } from '@dynamic-labs/types';
5
- import { IDynamicWaasConnector, InternalWalletConnector, Chain, BitcoinSignPsbtRequest, BitcoinSignPsbtResponse } from '@dynamic-labs/wallet-connector-core';
6
- import { BitcoinTransaction } from '../../types';
5
+ import { IDynamicWaasConnector, InternalWalletConnector, Chain, BitcoinSignPsbtResponse } from '@dynamic-labs/wallet-connector-core';
6
+ import { BitcoinTransaction, EmbeddedWalletSignPsbtRequest } from '../../types';
7
7
  import { BitcoinWalletConnector } from '../BitcoinWalletConnector';
8
8
  import type { ParsedTransaction, DynamicWaasBitcoinConnectorProps } from '../../types';
9
9
  declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) => {
@@ -35,7 +35,10 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
35
35
  setBaseApiUrl(baseApiUrl: string): void;
36
36
  setBaseClientKeysharesRelayApiUrl(baseClientKeysharesRelayApiUrl?: string | undefined): void;
37
37
  setRelayUrl(relayUrl: string): void;
38
- setGetSignedSessionIdFunction(getSignedSessionId: () => Promise<string>): void;
38
+ setGetSignedSessionIdFunction(getSignedSessionId: () => Promise<string>): void; /**
39
+ * The primary/active verified credential (first from the filtered array)
40
+ * This is used for the active account address
41
+ */
39
42
  delegateKeyShares({ accountAddress, password, }: {
40
43
  accountAddress: string;
41
44
  password?: string | undefined;
@@ -52,11 +55,12 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
52
55
  publicKeyHex: string;
53
56
  rawPublicKey: string | Uint8Array | undefined;
54
57
  }>;
55
- importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, }: {
58
+ importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, legacyWalletId, }: {
56
59
  privateKey: string;
57
60
  thresholdSignatureScheme?: string | undefined;
58
61
  publicAddressCheck?: string | undefined;
59
62
  addressType?: string | undefined;
63
+ legacyWalletId?: string | undefined;
60
64
  }): Promise<void>;
61
65
  exportPrivateKey({ accountAddress, displayContainer, password, }?: {
62
66
  accountAddress?: string | undefined;
@@ -78,6 +82,15 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
78
82
  accountAddress: string;
79
83
  password?: string | undefined;
80
84
  }): Promise<void>;
85
+ backupKeySharesToICloud({ accountAddress, password, }: {
86
+ accountAddress: string;
87
+ password?: string | undefined;
88
+ }): Promise<void>;
89
+ displayICloudSignIn({ displayContainer, }: {
90
+ displayContainer: HTMLElement;
91
+ }): Promise<void>;
92
+ hideICloudSignIn(): Promise<void>;
93
+ isICloudAuthenticated(): Promise<boolean>;
81
94
  refreshWalletAccountShares({ accountAddress, password, }: {
82
95
  accountAddress: string;
83
96
  password?: string | undefined;
@@ -169,13 +182,17 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
169
182
  */
170
183
  signMessage(message: string): Promise<string>;
171
184
  /**
172
- * Signs a Partially Signed Bitcoin Transaction (PSBT)
173
- * @param request - The PSBT signing request containing the unsigned PSBT
174
- * @returns The signed PSBT response
185
+ * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
186
+ *
187
+ * Embedded wallets only support PSBT format and automatically sign all inputs
188
+ * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
189
+ *
190
+ * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
191
+ * @returns The signed (but not finalized) PSBT response
175
192
  * @throws {DynamicError} If active account address is not set
176
- * @throws {DynamicError} If signed session ID is not available or signature is provided
193
+ * @throws {DynamicError} If signed session ID is not available
177
194
  */
178
- signPsbt(request: BitcoinSignPsbtRequest): Promise<BitcoinSignPsbtResponse>;
195
+ signPsbt(request: EmbeddedWalletSignPsbtRequest): Promise<BitcoinSignPsbtResponse>;
179
196
  /**
180
197
  * Sends a raw Bitcoin transaction to the mempool
181
198
  * @param rawTransaction - The raw transaction in hex format
@@ -214,13 +231,15 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
214
231
  * @param thresholdSignatureScheme - The threshold signature scheme (default: 'TWO_OF_TWO')
215
232
  * @param publicAddressCheck - Optional public address to verify against
216
233
  * @param addressType - Required address type for Bitcoin ('native_segwit' or 'taproot')
234
+ * @param legacyWalletId - Optional ID of the legacy wallet being upgraded
217
235
  * @throws {DynamicError} If addressType is missing or invalid for BTC
218
236
  */
219
- importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, }: {
237
+ importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, legacyWalletId, }: {
220
238
  privateKey: string;
221
239
  thresholdSignatureScheme?: string;
222
240
  publicAddressCheck?: string;
223
241
  addressType?: string;
242
+ legacyWalletId?: string;
224
243
  }): Promise<void>;
225
244
  /**
226
245
  * Gets the wallet client for a specific account address and sets it as active
@@ -258,7 +277,7 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
258
277
  }): Promise<string>;
259
278
  /**
260
279
  * Builds a PSBT for a Bitcoin transaction with real UTXOs
261
- * @param transaction - The Bitcoin transaction containing recipient address and amount in satoshis to send
280
+ * @param transaction - Bitcoin transaction with recipient address, amount in satoshis, and optional fee priority
262
281
  * @returns A PSBT in Base64 format
263
282
  * @throws {DynamicError} If no active account address, insufficient funds, or other errors
264
283
  */
@@ -124,11 +124,15 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
124
124
  });
125
125
  }
126
126
  /**
127
- * Signs a Partially Signed Bitcoin Transaction (PSBT)
128
- * @param request - The PSBT signing request containing the unsigned PSBT
129
- * @returns The signed PSBT response
127
+ * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
128
+ *
129
+ * Embedded wallets only support PSBT format and automatically sign all inputs
130
+ * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
131
+ *
132
+ * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
133
+ * @returns The signed (but not finalized) PSBT response
130
134
  * @throws {DynamicError} If active account address is not set
131
- * @throws {DynamicError} If signed session ID is not available or signature is provided
135
+ * @throws {DynamicError} If signed session ID is not available
132
136
  */
133
137
  signPsbt(request) {
134
138
  return __awaiter(this, void 0, void 0, function* () {
@@ -144,9 +148,6 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
144
148
  const mfaToken = yield ((_b = this.getMfaToken) === null || _b === void 0 ? void 0 : _b.call(this, {
145
149
  mfaAction: MFAAction.WalletWaasSign,
146
150
  }));
147
- if (request.signature && request.signature.length > 0) {
148
- throw new DynamicError('Signature is not supported for waas at the moment');
149
- }
150
151
  const signedTransaction = yield walletClient.signTransaction({
151
152
  authToken: (_c = this.getAuthToken) === null || _c === void 0 ? void 0 : _c.call(this),
152
153
  mfaToken,
@@ -188,9 +189,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
188
189
  // Step 1: Build the PSBT
189
190
  const unsignedPsbt = yield this.buildPsbt(transaction);
190
191
  // Step 2: Sign the PSBT
191
- // SIGHASH_ALL (0x01) is the most common sighash type for Bitcoin transactions (Eventually can be configurable)
192
192
  const signedPsbtResponse = yield this.signPsbt({
193
- allowedSighash: [0x01],
194
193
  unsignedPsbtBase64: unsignedPsbt,
195
194
  });
196
195
  if (!signedPsbtResponse) {
@@ -234,13 +233,14 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
234
233
  * @param thresholdSignatureScheme - The threshold signature scheme (default: 'TWO_OF_TWO')
235
234
  * @param publicAddressCheck - Optional public address to verify against
236
235
  * @param addressType - Required address type for Bitcoin ('native_segwit' or 'taproot')
236
+ * @param legacyWalletId - Optional ID of the legacy wallet being upgraded
237
237
  * @throws {DynamicError} If addressType is missing or invalid for BTC
238
238
  */
239
239
  importPrivateKey(_a) {
240
240
  const _super = Object.create(null, {
241
241
  importPrivateKey: { get: () => super.importPrivateKey }
242
242
  });
243
- return __awaiter(this, arguments, void 0, function* ({ privateKey, thresholdSignatureScheme = 'TWO_OF_TWO', publicAddressCheck, addressType, }) {
243
+ return __awaiter(this, arguments, void 0, function* ({ privateKey, thresholdSignatureScheme = 'TWO_OF_TWO', publicAddressCheck, addressType, legacyWalletId, }) {
244
244
  if (!addressType) {
245
245
  throw new DynamicError('addressType is required for BTC importPrivateKey');
246
246
  }
@@ -250,6 +250,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
250
250
  }
251
251
  return _super.importPrivateKey.call(this, {
252
252
  addressType,
253
+ legacyWalletId,
253
254
  privateKey,
254
255
  publicAddressCheck,
255
256
  thresholdSignatureScheme,
@@ -333,7 +334,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
333
334
  }
334
335
  /**
335
336
  * Builds a PSBT for a Bitcoin transaction with real UTXOs
336
- * @param transaction - The Bitcoin transaction containing recipient address and amount in satoshis to send
337
+ * @param transaction - Bitcoin transaction with recipient address, amount in satoshis, and optional fee priority
337
338
  * @returns A PSBT in Base64 format
338
339
  * @throws {DynamicError} If no active account address, insufficient funds, or other errors
339
340
  */
@@ -343,7 +344,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
343
344
  throw new DynamicError('Active account address is required');
344
345
  }
345
346
  const publicKeyHex = yield this.getPublicKey();
346
- const buildOptions = PsbtBuilderService.createBuildOptions(this.activeAccountAddress, transaction, publicKeyHex);
347
+ const buildOptions = PsbtBuilderService.createBuildOptions(this.activeAccountAddress, transaction, publicKeyHex, transaction.feePriority || 'medium');
347
348
  return this.psbtBuilderService.buildPsbt(buildOptions);
348
349
  });
349
350
  }
package/src/const.cjs CHANGED
@@ -12,20 +12,28 @@ const MEMPOOL_API_URL_TESTNET = 'https://mempool.space/testnet/api';
12
12
  // WaaS Bitcoin constants
13
13
  const SATOSHIS_PER_BTC = 100000000;
14
14
  const DUST_LIMIT = 546; // Bitcoin's dust limit in satoshis
15
- const INPUT_BYTE_SIZE_UPPER_BOUND = 90;
16
- const OUTPUT_BYTE_SIZE_UPPER_BOUND = 45;
15
+ // Accurate vSize constants for Native SegWit (P2WPKH) transactions
16
+ // These are used for precise fee estimation
17
+ const VSIZE_OVERHEAD = 10.5; // Base transaction overhead in vBytes
18
+ const VSIZE_INPUT_P2WPKH = 68; // Each P2WPKH input in vBytes
19
+ const VSIZE_OUTPUT_P2WPKH = 31; // Each P2WPKH output in vBytes
17
20
  const MIN_RELAY_FEE = 111;
18
21
  const DEFAULT_FEE_ESTIMATE = 1000; // Conservative default fee estimate in satoshis
22
+ // RBF (Replace-By-Fee) sequence number
23
+ // 0xfffffffd = 4294967293 (enables RBF, not final)
24
+ const RBF_SEQUENCE = 0xfffffffd;
19
25
 
20
26
  exports.BTCKIT_INTERFACE = BTCKIT_INTERFACE;
21
27
  exports.DEFAULT_FEE_ESTIMATE = DEFAULT_FEE_ESTIMATE;
22
28
  exports.DUST_LIMIT = DUST_LIMIT;
23
29
  exports.HTTP_STATUS_NOT_FOUND = HTTP_STATUS_NOT_FOUND;
24
30
  exports.HTTP_STATUS_TOO_MANY_REQUESTS = HTTP_STATUS_TOO_MANY_REQUESTS;
25
- exports.INPUT_BYTE_SIZE_UPPER_BOUND = INPUT_BYTE_SIZE_UPPER_BOUND;
26
31
  exports.MEMPOOL_API_URL = MEMPOOL_API_URL;
27
32
  exports.MEMPOOL_API_URL_TESTNET = MEMPOOL_API_URL_TESTNET;
28
33
  exports.MIN_RELAY_FEE = MIN_RELAY_FEE;
29
- exports.OUTPUT_BYTE_SIZE_UPPER_BOUND = OUTPUT_BYTE_SIZE_UPPER_BOUND;
34
+ exports.RBF_SEQUENCE = RBF_SEQUENCE;
30
35
  exports.SATOSHIS_PER_BTC = SATOSHIS_PER_BTC;
31
36
  exports.SATSCONNECT_FEATURE = SATSCONNECT_FEATURE;
37
+ exports.VSIZE_INPUT_P2WPKH = VSIZE_INPUT_P2WPKH;
38
+ exports.VSIZE_OUTPUT_P2WPKH = VSIZE_OUTPUT_P2WPKH;
39
+ exports.VSIZE_OVERHEAD = VSIZE_OVERHEAD;
package/src/const.d.ts CHANGED
@@ -7,7 +7,9 @@ export declare const MEMPOOL_API_URL = "https://mempool.space/api";
7
7
  export declare const MEMPOOL_API_URL_TESTNET = "https://mempool.space/testnet/api";
8
8
  export declare const SATOSHIS_PER_BTC = 100000000;
9
9
  export declare const DUST_LIMIT = 546;
10
- export declare const INPUT_BYTE_SIZE_UPPER_BOUND = 90;
11
- export declare const OUTPUT_BYTE_SIZE_UPPER_BOUND = 45;
10
+ export declare const VSIZE_OVERHEAD = 10.5;
11
+ export declare const VSIZE_INPUT_P2WPKH = 68;
12
+ export declare const VSIZE_OUTPUT_P2WPKH = 31;
12
13
  export declare const MIN_RELAY_FEE = 111;
13
14
  export declare const DEFAULT_FEE_ESTIMATE = 1000;
15
+ export declare const RBF_SEQUENCE = 4294967293;
package/src/const.js CHANGED
@@ -8,9 +8,15 @@ const MEMPOOL_API_URL_TESTNET = 'https://mempool.space/testnet/api';
8
8
  // WaaS Bitcoin constants
9
9
  const SATOSHIS_PER_BTC = 100000000;
10
10
  const DUST_LIMIT = 546; // Bitcoin's dust limit in satoshis
11
- const INPUT_BYTE_SIZE_UPPER_BOUND = 90;
12
- const OUTPUT_BYTE_SIZE_UPPER_BOUND = 45;
11
+ // Accurate vSize constants for Native SegWit (P2WPKH) transactions
12
+ // These are used for precise fee estimation
13
+ const VSIZE_OVERHEAD = 10.5; // Base transaction overhead in vBytes
14
+ const VSIZE_INPUT_P2WPKH = 68; // Each P2WPKH input in vBytes
15
+ const VSIZE_OUTPUT_P2WPKH = 31; // Each P2WPKH output in vBytes
13
16
  const MIN_RELAY_FEE = 111;
14
17
  const DEFAULT_FEE_ESTIMATE = 1000; // Conservative default fee estimate in satoshis
18
+ // RBF (Replace-By-Fee) sequence number
19
+ // 0xfffffffd = 4294967293 (enables RBF, not final)
20
+ const RBF_SEQUENCE = 0xfffffffd;
15
21
 
16
- export { BTCKIT_INTERFACE, DEFAULT_FEE_ESTIMATE, DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS, INPUT_BYTE_SIZE_UPPER_BOUND, MEMPOOL_API_URL, MEMPOOL_API_URL_TESTNET, MIN_RELAY_FEE, OUTPUT_BYTE_SIZE_UPPER_BOUND, SATOSHIS_PER_BTC, SATSCONNECT_FEATURE };
22
+ export { BTCKIT_INTERFACE, DEFAULT_FEE_ESTIMATE, DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS, MEMPOOL_API_URL, MEMPOOL_API_URL_TESTNET, MIN_RELAY_FEE, RBF_SEQUENCE, SATOSHIS_PER_BTC, SATSCONNECT_FEATURE, VSIZE_INPUT_P2WPKH, VSIZE_OUTPUT_P2WPKH, VSIZE_OVERHEAD };
package/src/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { OkxConnector } from './connectors';
2
2
  export { BitcoinWalletConnector, type BitcoinWalletConnectorOpts, } from './connectors';
3
- export type { BitcoinTransaction, BitcoinSignProtocol, BitcoinSignPsbtRequest, BitcoinSignPsbtResponse, BitcoinWalletStandardMethods, SignPsbtOptions, } from './types';
3
+ export type { BitcoinTransaction, BitcoinSignProtocol, BitcoinSignPsbtRequest, BitcoinSignPsbtResponse, BitcoinWalletStandardMethods, SignPsbtOptions, EmbeddedWalletSignPsbtRequest, } from './types';
4
4
  export * from './utils';
5
5
  export * from './wallet';
6
6
  export { UnisatConnector, BitcoinSatsConnectConnector, DynamicWaasBitcoinConnector, } from './connectors';
@@ -70,21 +70,44 @@ class MempoolApiService {
70
70
  });
71
71
  }
72
72
  /**
73
- * Estimates transaction fees based on number of inputs and outputs
73
+ * Estimates transaction fees based on number of inputs and outputs using accurate vSize
74
74
  * @param address - The Bitcoin address to determine the network from
75
75
  * @param numInputs - Number of transaction inputs
76
76
  * @param numOutputs - Number of transaction outputs
77
+ * @param feePriority - Fee priority level (high/medium/low)
77
78
  * @returns Estimated fee in satoshis
78
79
  */
79
- estimateTransactionFee(address, numInputs, numOutputs) {
80
- return _tslib.__awaiter(this, void 0, void 0, function* () {
80
+ estimateTransactionFee(address_1, numInputs_1, numOutputs_1) {
81
+ return _tslib.__awaiter(this, arguments, void 0, function* (address, numInputs, numOutputs, feePriority = 'medium') {
81
82
  try {
82
83
  const feeData = yield this.getFeeRecommendations(address);
83
- const feePerByte = feeData.hourFee || feeData.economyFee || 1;
84
- const estimatedFee = feePerByte *
85
- (_const.INPUT_BYTE_SIZE_UPPER_BOUND * numInputs +
86
- _const.OUTPUT_BYTE_SIZE_UPPER_BOUND * numOutputs) +
87
- _const.MIN_RELAY_FEE;
84
+ // High (Fastest): fastestFee -> Block 1
85
+ // Medium (Fast): halfHourFee -> Blocks 2-3
86
+ // Low (Eco): economyFee (preferred) or hourFee -> Blocks 6+
87
+ let feePerByte;
88
+ switch (feePriority) {
89
+ case 'high':
90
+ feePerByte =
91
+ feeData.fastestFee || feeData.halfHourFee || feeData.hourFee || 1;
92
+ break;
93
+ case 'low':
94
+ feePerByte = feeData.economyFee || feeData.hourFee || 1;
95
+ break;
96
+ case 'medium':
97
+ default:
98
+ feePerByte =
99
+ feeData.halfHourFee || feeData.hourFee || feeData.economyFee || 1;
100
+ break;
101
+ }
102
+ logger.debug(`Fee estimation - Priority: ${feePriority}, fastestFee: ${feeData.fastestFee}, halfHourFee: ${feeData.halfHourFee}, hourFee: ${feeData.hourFee}, economyFee: ${feeData.economyFee}, selected: ${feePerByte} sat/vB`);
103
+ // Use accurate vSize calculation for Native SegWit (P2WPKH)
104
+ // Formula: overhead + (inputs × 68) + (outputs × 31)
105
+ const vSize = _const.VSIZE_OVERHEAD +
106
+ numInputs * _const.VSIZE_INPUT_P2WPKH +
107
+ numOutputs * _const.VSIZE_OUTPUT_P2WPKH;
108
+ const estimatedFee = Math.ceil(feePerByte * vSize) + _const.MIN_RELAY_FEE;
109
+ logger.debug(`Fee calculation - Priority: ${feePriority}, vSize: ${vSize}, feePerByte: ${feePerByte} sat/vB, estimatedFee: ${estimatedFee} satoshis`);
110
+ logger.debug(`[MempoolApiService] Fee Priority: ${feePriority}, Selected Rate: ${feePerByte} sat/vB, vSize: ${vSize}, Estimated Fee: ${estimatedFee} satoshis`);
88
111
  return estimatedFee;
89
112
  }
90
113
  catch (error) {
@@ -24,13 +24,14 @@ export declare class MempoolApiService {
24
24
  */
25
25
  getFeeRecommendations(address: string): Promise<FeeRecommendations>;
26
26
  /**
27
- * Estimates transaction fees based on number of inputs and outputs
27
+ * Estimates transaction fees based on number of inputs and outputs using accurate vSize
28
28
  * @param address - The Bitcoin address to determine the network from
29
29
  * @param numInputs - Number of transaction inputs
30
30
  * @param numOutputs - Number of transaction outputs
31
+ * @param feePriority - Fee priority level (high/medium/low)
31
32
  * @returns Estimated fee in satoshis
32
33
  */
33
- estimateTransactionFee(address: string, numInputs: number, numOutputs: number): Promise<number>;
34
+ estimateTransactionFee(address: string, numInputs: number, numOutputs: number, feePriority?: 'high' | 'medium' | 'low'): Promise<number>;
34
35
  /**
35
36
  * Sends a raw Bitcoin transaction to the mempool
36
37
  * @param address - The Bitcoin address to determine the network from
@@ -9,7 +9,7 @@ import '@dynamic-labs/wallet-book';
9
9
  import '@dynamic-labs/sdk-api-core';
10
10
  import '@wallet-standard/app';
11
11
  import { getMempoolApiUrl } from '../utils/getMempoolApiUrl.js';
12
- import { INPUT_BYTE_SIZE_UPPER_BOUND, OUTPUT_BYTE_SIZE_UPPER_BOUND, MIN_RELAY_FEE, DEFAULT_FEE_ESTIMATE } from '../const.js';
12
+ import { VSIZE_OVERHEAD, VSIZE_INPUT_P2WPKH, VSIZE_OUTPUT_P2WPKH, MIN_RELAY_FEE, DEFAULT_FEE_ESTIMATE } from '../const.js';
13
13
  import 'jsontokens';
14
14
  import '../connectors/DynamicWaasBitcoinConnector/DynamicWaasBitcoinConnector.js';
15
15
 
@@ -66,21 +66,44 @@ class MempoolApiService {
66
66
  });
67
67
  }
68
68
  /**
69
- * Estimates transaction fees based on number of inputs and outputs
69
+ * Estimates transaction fees based on number of inputs and outputs using accurate vSize
70
70
  * @param address - The Bitcoin address to determine the network from
71
71
  * @param numInputs - Number of transaction inputs
72
72
  * @param numOutputs - Number of transaction outputs
73
+ * @param feePriority - Fee priority level (high/medium/low)
73
74
  * @returns Estimated fee in satoshis
74
75
  */
75
- estimateTransactionFee(address, numInputs, numOutputs) {
76
- return __awaiter(this, void 0, void 0, function* () {
76
+ estimateTransactionFee(address_1, numInputs_1, numOutputs_1) {
77
+ return __awaiter(this, arguments, void 0, function* (address, numInputs, numOutputs, feePriority = 'medium') {
77
78
  try {
78
79
  const feeData = yield this.getFeeRecommendations(address);
79
- const feePerByte = feeData.hourFee || feeData.economyFee || 1;
80
- const estimatedFee = feePerByte *
81
- (INPUT_BYTE_SIZE_UPPER_BOUND * numInputs +
82
- OUTPUT_BYTE_SIZE_UPPER_BOUND * numOutputs) +
83
- MIN_RELAY_FEE;
80
+ // High (Fastest): fastestFee -> Block 1
81
+ // Medium (Fast): halfHourFee -> Blocks 2-3
82
+ // Low (Eco): economyFee (preferred) or hourFee -> Blocks 6+
83
+ let feePerByte;
84
+ switch (feePriority) {
85
+ case 'high':
86
+ feePerByte =
87
+ feeData.fastestFee || feeData.halfHourFee || feeData.hourFee || 1;
88
+ break;
89
+ case 'low':
90
+ feePerByte = feeData.economyFee || feeData.hourFee || 1;
91
+ break;
92
+ case 'medium':
93
+ default:
94
+ feePerByte =
95
+ feeData.halfHourFee || feeData.hourFee || feeData.economyFee || 1;
96
+ break;
97
+ }
98
+ logger.debug(`Fee estimation - Priority: ${feePriority}, fastestFee: ${feeData.fastestFee}, halfHourFee: ${feeData.halfHourFee}, hourFee: ${feeData.hourFee}, economyFee: ${feeData.economyFee}, selected: ${feePerByte} sat/vB`);
99
+ // Use accurate vSize calculation for Native SegWit (P2WPKH)
100
+ // Formula: overhead + (inputs × 68) + (outputs × 31)
101
+ const vSize = VSIZE_OVERHEAD +
102
+ numInputs * VSIZE_INPUT_P2WPKH +
103
+ numOutputs * VSIZE_OUTPUT_P2WPKH;
104
+ const estimatedFee = Math.ceil(feePerByte * vSize) + MIN_RELAY_FEE;
105
+ logger.debug(`Fee calculation - Priority: ${feePriority}, vSize: ${vSize}, feePerByte: ${feePerByte} sat/vB, estimatedFee: ${estimatedFee} satoshis`);
106
+ logger.debug(`[MempoolApiService] Fee Priority: ${feePriority}, Selected Rate: ${feePerByte} sat/vB, vSize: ${vSize}, Estimated Fee: ${estimatedFee} satoshis`);
84
107
  return estimatedFee;
85
108
  }
86
109
  catch (error) {