@dynamic-labs/bitcoin 5.3.1 → 5.4.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 +39 -0
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +10 -10
- package/src/connectors/DynamicWaasBitcoinConnector/DynamicWaasBitcoinConnector.cjs +117 -20
- package/src/connectors/DynamicWaasBitcoinConnector/DynamicWaasBitcoinConnector.d.ts +82 -8
- package/src/connectors/DynamicWaasBitcoinConnector/DynamicWaasBitcoinConnector.js +118 -21
- package/src/index.d.ts +2 -2
- package/src/types.d.ts +13 -0
- package/src/utils/psbtParser/PsbtParser.cjs +26 -23
- package/src/utils/psbtParser/PsbtParser.d.ts +7 -3
- package/src/utils/psbtParser/PsbtParser.js +27 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
1
|
|
|
2
|
+
## [5.4.0](https://github.com/dynamic-labs/dynamic-auth/compare/v5.3.2...v5.4.0) (2026-08-25)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **aleo:** wire up signMessage on the WaaS Aleo connector ([#12235](https://github.com/dynamic-labs/dynamic-auth/issues/12235)) ([e56cbf5](https://github.com/dynamic-labs/dynamic-auth/commit/e56cbf5546bdcc21ce916dece43ae36dcea9b808))
|
|
8
|
+
* **waas:** thread isRawScalarImport through importPrivateKey for ed25519 chains ([#12220](https://github.com/dynamic-labs/dynamic-auth/issues/12220)) ([ced9efa](https://github.com/dynamic-labs/dynamic-auth/commit/ced9efac5fa5a4a1280383419f56fe22733722cd))
|
|
9
|
+
* **webview:** add policies message contract and controller ([#12248](https://github.com/dynamic-labs/dynamic-auth/issues/12248)) ([8557c1e](https://github.com/dynamic-labs/dynamic-auth/commit/8557c1ed3861e12f1f06b2bb610184813b577daa))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **bitcoin:** pass the wallet's address type when signing ([#12265](https://github.com/dynamic-labs/dynamic-auth/issues/12265)) ([b8a8eab](https://github.com/dynamic-labs/dynamic-auth/commit/b8a8eab7e4cc294cc307fb10ea6814e76111a274))
|
|
15
|
+
* remediate high-severity tar vulnerability and prune a dead override ([#12268](https://github.com/dynamic-labs/dynamic-auth/issues/12268)) ([6b1b343](https://github.com/dynamic-labs/dynamic-auth/commit/6b1b343e7947e8da30012446677e342ae9bfe14a))
|
|
16
|
+
* **waas-svm:** fix retry-classification and environmentId gaps in [#12240](https://github.com/dynamic-labs/dynamic-auth/issues/12240) ([#12247](https://github.com/dynamic-labs/dynamic-auth/issues/12247)) ([e79cecc](https://github.com/dynamic-labs/dynamic-auth/commit/e79ceccd424c48c3a7f45fdd6ea288c269ac0171))
|
|
17
|
+
* **wallet-connect:** reopen WalletConnect IndexedDB when the browser closes the connection ([#12262](https://github.com/dynamic-labs/dynamic-auth/issues/12262)) ([1a20dde](https://github.com/dynamic-labs/dynamic-auth/commit/1a20ddeaeec590ae3390c9e47ef3c14738379b83))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Performance Improvements
|
|
21
|
+
|
|
22
|
+
* **ethereum-gasless-core:** parallel 7702 auth signing and long-poll sponsored-tx status ([#12225](https://github.com/dynamic-labs/dynamic-auth/issues/12225)) ([53ca916](https://github.com/dynamic-labs/dynamic-auth/commit/53ca91668f8dd839c52d55a0e5d7bb5257f7f415))
|
|
23
|
+
|
|
24
|
+
### [5.3.2](https://github.com/dynamic-labs/dynamic-auth/compare/v5.3.1...v5.3.2) (2026-08-19)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* **bitcoin:** add allowedSighash to embedded wallet signPsbt ([#12233](https://github.com/dynamic-labs/dynamic-auth/issues/12233)) ([d0ff829](https://github.com/dynamic-labs/dynamic-auth/commit/d0ff8291a3d1771d5ca356172acc10af94349b15))
|
|
30
|
+
* **bitcoin:** forward signingIndexes to embedded PSBT signing ([#12211](https://github.com/dynamic-labs/dynamic-auth/issues/12211)) ([733da3d](https://github.com/dynamic-labs/dynamic-auth/commit/733da3d32f39a9ae6d813df84fcff6350ba12eb5))
|
|
31
|
+
* expose createOfflineRecoveryShares SDK function in webview and legacy client ([#12239](https://github.com/dynamic-labs/dynamic-auth/issues/12239)) ([c8056e8](https://github.com/dynamic-labs/dynamic-auth/commit/c8056e8d5a1c66ac0146b046bc7cc198de118f0b))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
* **bitcoin:** parse PSBTs with the active network's address encoding ([#12219](https://github.com/dynamic-labs/dynamic-auth/issues/12219)) ([8b151e2](https://github.com/dynamic-labs/dynamic-auth/commit/8b151e23440094cfa0d48728e1d0f19de567ca05))
|
|
37
|
+
* **bitcoin:** stop ensureActiveAccount from resetting a switched network ([#12215](https://github.com/dynamic-labs/dynamic-auth/issues/12215)) ([86668b7](https://github.com/dynamic-labs/dynamic-auth/commit/86668b79d23cd89b7e96518551cdaecab7dd5ce3))
|
|
38
|
+
* remediate high-severity dependency vulnerabilities ([#12238](https://github.com/dynamic-labs/dynamic-auth/issues/12238)) ([a4fc78c](https://github.com/dynamic-labs/dynamic-auth/commit/a4fc78ca27ee44ce6a1038c4e0d07f55528b4994))
|
|
39
|
+
* **waas-svm:** retry SVM gas sponsorship before falling back, then throw ([#12240](https://github.com/dynamic-labs/dynamic-auth/issues/12240)) ([f599a7a](https://github.com/dynamic-labs/dynamic-auth/commit/f599a7af55727e06373772acf574ee7c43e56bbb))
|
|
40
|
+
|
|
2
41
|
### [5.3.1](https://github.com/dynamic-labs/dynamic-auth/compare/v5.3.0...v5.3.1) (2026-08-14)
|
|
3
42
|
|
|
4
43
|
## [5.3.0](https://github.com/dynamic-labs/dynamic-auth/compare/v5.2.0...v5.3.0) (2026-08-12)
|
package/package.cjs
CHANGED
package/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/bitcoin",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.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,24 +18,24 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://www.dynamic.xyz/",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@dynamic-labs-wallet/browser-wallet-client": "1.0.
|
|
21
|
+
"@dynamic-labs-wallet/browser-wallet-client": "1.0.106",
|
|
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
|
|
25
|
+
"@dynamic-labs/sdk-api-core": "0.12.0",
|
|
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": "5.
|
|
33
|
-
"@dynamic-labs/logger": "5.
|
|
34
|
-
"@dynamic-labs/types": "5.
|
|
35
|
-
"@dynamic-labs/utils": "5.
|
|
36
|
-
"@dynamic-labs/waas": "5.
|
|
37
|
-
"@dynamic-labs/wallet-book": "5.
|
|
38
|
-
"@dynamic-labs/wallet-connector-core": "5.
|
|
32
|
+
"@dynamic-labs/assert-package-version": "5.4.0",
|
|
33
|
+
"@dynamic-labs/logger": "5.4.0",
|
|
34
|
+
"@dynamic-labs/types": "5.4.0",
|
|
35
|
+
"@dynamic-labs/utils": "5.4.0",
|
|
36
|
+
"@dynamic-labs/waas": "5.4.0",
|
|
37
|
+
"@dynamic-labs/wallet-book": "5.4.0",
|
|
38
|
+
"@dynamic-labs/wallet-connector-core": "5.4.0",
|
|
39
39
|
"eventemitter3": "5.0.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {}
|
|
@@ -17,6 +17,7 @@ var BitcoinWalletConnector = require('../BitcoinWalletConnector.cjs');
|
|
|
17
17
|
require('@wallet-standard/app');
|
|
18
18
|
require('jsontokens');
|
|
19
19
|
var btcToSatoshis = require('../../utils/btcToSatoshis/btcToSatoshis.cjs');
|
|
20
|
+
var getBitcoinNetwork = require('../../utils/getBitcoinNetwork/getBitcoinNetwork.cjs');
|
|
20
21
|
var PsbtParser = require('../../utils/psbtParser/PsbtParser.cjs');
|
|
21
22
|
var BitcoinUiTransaction = require('../../utils/BitcoinUiTransaction/BitcoinUiTransaction.cjs');
|
|
22
23
|
|
|
@@ -135,6 +136,32 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
135
136
|
: 'mainnet');
|
|
136
137
|
});
|
|
137
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* The address type the wallet's key was derived under, read back from the
|
|
141
|
+
* address itself.
|
|
142
|
+
*
|
|
143
|
+
* `bitcoinConfig.addressType` is the only thing that selects a BTC
|
|
144
|
+
* derivation path downstream (`getMPCChainConfig` throws without it), and a
|
|
145
|
+
* wallet created by an import carries no server-side derivation metadata to
|
|
146
|
+
* fall back on — so signing an imported wallet failed while a
|
|
147
|
+
* Dynamic-created one signed fine. The address already encodes the answer:
|
|
148
|
+
* witness v0 is P2WPKH (native segwit), v1 is P2TR (taproot), which are
|
|
149
|
+
* exactly the two types `importPrivateKey` accepts.
|
|
150
|
+
*
|
|
151
|
+
* Falls back to native segwit for an address that is not bech32 (a legacy
|
|
152
|
+
* P2PKH/P2SH encoding cannot come from this connector's own import or
|
|
153
|
+
* create paths) so a decode failure can never make signing impossible.
|
|
154
|
+
*/
|
|
155
|
+
getAddressTypeForSigning(walletAddress) {
|
|
156
|
+
try {
|
|
157
|
+
const { version } = bitcoinjsLib.address.fromBech32(walletAddress);
|
|
158
|
+
return (version === 1 ? 'taproot' : 'native_segwit');
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
this.logger.warn('Could not read the address type from the wallet address; assuming native segwit', { error, walletAddress });
|
|
162
|
+
return 'native_segwit';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
138
165
|
supportsNetworkSwitching() {
|
|
139
166
|
return true;
|
|
140
167
|
}
|
|
@@ -161,26 +188,65 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
161
188
|
});
|
|
162
189
|
}
|
|
163
190
|
/**
|
|
164
|
-
* Finds the credential that owns
|
|
165
|
-
*
|
|
191
|
+
* Finds the credential that owns `address`, either as its primary (mainnet)
|
|
192
|
+
* address or as one of its network-tagged additional addresses.
|
|
166
193
|
*
|
|
167
194
|
* This connector is shared across every Bitcoin wallet of the user —
|
|
168
195
|
* `verifiedCredentials` holds them all — so the owning credential must be
|
|
169
|
-
* looked up by
|
|
170
|
-
*
|
|
196
|
+
* looked up by address. Reading `verifiedCredential` instead would always
|
|
197
|
+
* answer with the user's *first* wallet.
|
|
171
198
|
*/
|
|
172
|
-
|
|
199
|
+
findCredentialForAddress(address) {
|
|
173
200
|
var _a;
|
|
174
|
-
|
|
175
|
-
if (!activeAccountAddress) {
|
|
201
|
+
if (!address) {
|
|
176
202
|
return undefined;
|
|
177
203
|
}
|
|
178
204
|
return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
|
|
179
205
|
var _a;
|
|
180
|
-
return (credential === null || credential === void 0 ? void 0 : credential.address) ===
|
|
181
|
-
((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address ===
|
|
206
|
+
return (credential === null || credential === void 0 ? void 0 : credential.address) === address ||
|
|
207
|
+
((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === address);
|
|
182
208
|
});
|
|
183
209
|
}
|
|
210
|
+
/** @see findCredentialForAddress */
|
|
211
|
+
findCredentialForActiveAddress() {
|
|
212
|
+
return this.findCredentialForAddress(this.activeAccountAddress);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* True when `accountAddress` belongs to the same wallet as the currently
|
|
216
|
+
* active address — including when the active address is a *different*
|
|
217
|
+
* network-tagged encoding of that same wallet (e.g. the testnet address
|
|
218
|
+
* set by switchNetwork, compared against the wallet's primary mainnet
|
|
219
|
+
* address).
|
|
220
|
+
*
|
|
221
|
+
* Used by getWalletClientByAddress to avoid clobbering an explicit
|
|
222
|
+
* switchNetwork: callers like ensureActiveAccount re-assert the wallet's
|
|
223
|
+
* primary address before every send/sign, and setting activeAccountAddress
|
|
224
|
+
* back to that primary address would silently undo the network switch —
|
|
225
|
+
* UTXO/PSBT/broadcast calls would then run against the wrong (likely
|
|
226
|
+
* unfunded) encoding while getNetwork still reports the switched network.
|
|
227
|
+
*
|
|
228
|
+
* Compares the two resolved credential *objects* by reference rather than
|
|
229
|
+
* by id: both lookups run against the same verifiedCredentials array in
|
|
230
|
+
* the same synchronous call, so `.find()` returns the identical element
|
|
231
|
+
* for both addresses whenever they belong to the same wallet. Comparing
|
|
232
|
+
* `.id` instead would be wrong whenever accountAddress doesn't resolve to
|
|
233
|
+
* any known credential yet (e.g. a brand-new wallet not yet synced) —
|
|
234
|
+
* `undefined === undefined` would falsely read as "same wallet".
|
|
235
|
+
*/
|
|
236
|
+
isSameWalletAddress(accountAddress) {
|
|
237
|
+
if (!this.activeAccountAddress) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (accountAddress === this.activeAccountAddress) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
const activeCredential = this.findCredentialForActiveAddress();
|
|
244
|
+
if (!activeCredential) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const candidateCredential = this.findCredentialForAddress(accountAddress);
|
|
248
|
+
return (Boolean(candidateCredential) && candidateCredential === activeCredential);
|
|
249
|
+
}
|
|
184
250
|
/**
|
|
185
251
|
* Wallet identity: keyshares/wallet records are keyed by the wallet's
|
|
186
252
|
* primary (mainnet) address. On testnet the active address is the same
|
|
@@ -302,7 +368,11 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
302
368
|
* Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
|
|
303
369
|
*
|
|
304
370
|
* Embedded wallets only support PSBT format and automatically sign all inputs
|
|
305
|
-
* that belong to the wallet address
|
|
371
|
+
* that belong to the wallet address, unless `signingIndexes` narrows that set.
|
|
372
|
+
*
|
|
373
|
+
* The sighash type is read from the PSBT itself, falling back to
|
|
374
|
+
* SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
|
|
375
|
+
* `allowedSighash` restricts which declared types are accepted.
|
|
306
376
|
*
|
|
307
377
|
* @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
|
|
308
378
|
* @returns The signed (but not finalized) PSBT response
|
|
@@ -331,12 +401,14 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
331
401
|
accountAddress: walletIdentityAddress,
|
|
332
402
|
});
|
|
333
403
|
const signedTransaction = yield walletClient.signTransaction({
|
|
404
|
+
allowedSighash: request.allowedSighash,
|
|
334
405
|
authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
|
|
335
406
|
elevatedAccessToken,
|
|
336
407
|
mfaToken,
|
|
337
408
|
password,
|
|
338
409
|
senderAddress: walletIdentityAddress,
|
|
339
410
|
signedSessionId,
|
|
411
|
+
signingIndexes: request.signingIndexes,
|
|
340
412
|
transaction: request.unsignedPsbtBase64,
|
|
341
413
|
});
|
|
342
414
|
return {
|
|
@@ -472,12 +544,18 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
472
544
|
});
|
|
473
545
|
}
|
|
474
546
|
/**
|
|
475
|
-
* Gets the wallet client for a specific account address and sets it as
|
|
547
|
+
* Gets the wallet client for a specific account address and sets it as
|
|
548
|
+
* active — unless `accountAddress` is just a different network-tagged
|
|
549
|
+
* encoding of the wallet that's already active (see isSameWalletAddress),
|
|
550
|
+
* in which case the current (possibly switchNetwork'd) active address is
|
|
551
|
+
* left untouched.
|
|
476
552
|
* @param accountAddress - The Bitcoin account address
|
|
477
553
|
* @returns The WaaS wallet client instance
|
|
478
554
|
*/
|
|
479
555
|
getWalletClientByAddress({ accountAddress }) {
|
|
480
|
-
this.
|
|
556
|
+
if (!this.isSameWalletAddress(accountAddress)) {
|
|
557
|
+
this.setActiveAccountAddress(accountAddress);
|
|
558
|
+
}
|
|
481
559
|
return this.getWaasWalletClient();
|
|
482
560
|
}
|
|
483
561
|
/**
|
|
@@ -497,7 +575,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
497
575
|
*/
|
|
498
576
|
validateActiveWallet(expectedAddress) {
|
|
499
577
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
500
|
-
var _a
|
|
578
|
+
var _a;
|
|
501
579
|
const walletClient = yield this.getWaasWalletClient();
|
|
502
580
|
const targetWallet = yield walletClient.getWallet({
|
|
503
581
|
accountAddress: expectedAddress,
|
|
@@ -511,8 +589,12 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
511
589
|
const isWalletActive = walletConnectorCore.isSameAddress(targetWallet.accountAddress, this.activeAccountAddress || '', this.connectedChain);
|
|
512
590
|
// The active address may be a per-network encoding of this same wallet
|
|
513
591
|
// (one key, network-tagged additional addresses). Resetting it here would
|
|
514
|
-
// silently un-switch the selected network.
|
|
515
|
-
|
|
592
|
+
// silently un-switch the selected network. Resolved via isSameWalletAddress
|
|
593
|
+
// (which looks up the credential that actually owns the active address)
|
|
594
|
+
// rather than `verifiedCredential`, which is always the user's *first*
|
|
595
|
+
// wallet — using it here would wrongly reset the address for any other
|
|
596
|
+
// wallet the user validates.
|
|
597
|
+
const isPerNetworkVariantOfWallet = this.isSameWalletAddress(targetWallet.accountAddress);
|
|
516
598
|
if (!isWalletActive && !isPerNetworkVariantOfWallet) {
|
|
517
599
|
this.activeAccountAddress = targetWallet.accountAddress;
|
|
518
600
|
}
|
|
@@ -547,10 +629,14 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
547
629
|
accountAddress: this.getWalletIdentityAddress(),
|
|
548
630
|
});
|
|
549
631
|
const messageString = typeof message === 'string' ? message : message.raw;
|
|
632
|
+
const walletIdentityAddress = this.getWalletIdentityAddress();
|
|
550
633
|
return walletClient.signMessage({
|
|
551
|
-
accountAddress:
|
|
634
|
+
accountAddress: walletIdentityAddress,
|
|
552
635
|
authToken: (_e = this.getAuthToken) === null || _e === void 0 ? void 0 : _e.call(this),
|
|
553
|
-
bitcoinConfig: {
|
|
636
|
+
bitcoinConfig: {
|
|
637
|
+
addressType: this.getAddressTypeForSigning(walletIdentityAddress),
|
|
638
|
+
network: yield this.getBitcoinNetworkEnum(),
|
|
639
|
+
},
|
|
554
640
|
context,
|
|
555
641
|
elevatedAccessToken,
|
|
556
642
|
message: messageString,
|
|
@@ -665,7 +751,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
665
751
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
666
752
|
*/
|
|
667
753
|
parsePsbt(psbtInput) {
|
|
668
|
-
return PsbtParser.PsbtParser.parsePsbt(psbtInput);
|
|
754
|
+
return PsbtParser.PsbtParser.parsePsbt(psbtInput, this.getPsbtNetwork());
|
|
669
755
|
}
|
|
670
756
|
/**
|
|
671
757
|
* Parse a PSBT or finalized transaction from hex format
|
|
@@ -673,7 +759,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
673
759
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
674
760
|
*/
|
|
675
761
|
parseHexPsbt(psbtHex) {
|
|
676
|
-
return PsbtParser.PsbtParser.parseHexPsbt(psbtHex);
|
|
762
|
+
return PsbtParser.PsbtParser.parseHexPsbt(psbtHex, this.getPsbtNetwork());
|
|
677
763
|
}
|
|
678
764
|
/**
|
|
679
765
|
* Parse a PSBT or finalized transaction from base64 format
|
|
@@ -681,7 +767,17 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
681
767
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
682
768
|
*/
|
|
683
769
|
parseBase64Psbt(psbtBase64) {
|
|
684
|
-
return PsbtParser.PsbtParser.parseBase64Psbt(psbtBase64);
|
|
770
|
+
return PsbtParser.PsbtParser.parseBase64Psbt(psbtBase64, this.getPsbtNetwork());
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* bitcoinjs network for the address encoding the parsers should emit.
|
|
774
|
+
* Derived from the active address rather than activeNetworkId, which is
|
|
775
|
+
* in-memory only and can report mainnet while a testnet address is active.
|
|
776
|
+
*/
|
|
777
|
+
getPsbtNetwork() {
|
|
778
|
+
return this.activeAccountAddress
|
|
779
|
+
? getBitcoinNetwork.getBitcoinNetwork(this.activeAccountAddress)
|
|
780
|
+
: bitcoinjsLib.networks.bitcoin;
|
|
685
781
|
}
|
|
686
782
|
/**
|
|
687
783
|
* Gets the public key for the active account
|
|
@@ -772,6 +868,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
|
|
|
772
868
|
accountAddress: this.getWalletIdentityAddress(),
|
|
773
869
|
authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
|
|
774
870
|
bitcoinConfig: {
|
|
871
|
+
addressType: this.getAddressTypeForSigning(this.getWalletIdentityAddress()),
|
|
775
872
|
network: yield this.getBitcoinNetworkEnum(),
|
|
776
873
|
},
|
|
777
874
|
elevatedAccessToken,
|
|
@@ -92,13 +92,14 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
|
|
|
92
92
|
}): Promise<{
|
|
93
93
|
shareSetId: string;
|
|
94
94
|
}>;
|
|
95
|
-
importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, legacyWalletId, password, }: {
|
|
95
|
+
importPrivateKey({ privateKey, thresholdSignatureScheme, publicAddressCheck, addressType, legacyWalletId, password, isRawScalarImport, }: {
|
|
96
96
|
privateKey: string;
|
|
97
97
|
thresholdSignatureScheme?: string | undefined;
|
|
98
98
|
publicAddressCheck?: string | undefined;
|
|
99
99
|
addressType?: string | undefined;
|
|
100
100
|
legacyWalletId?: string | undefined;
|
|
101
101
|
password?: string | undefined;
|
|
102
|
+
isRawScalarImport?: boolean | undefined;
|
|
102
103
|
}): Promise<void>;
|
|
103
104
|
migrateFromFireblocks({ deviceId, jwt, walletPassword, ncwStorage, expectedAddresses, coinTypes, password, }: {
|
|
104
105
|
deviceId: string;
|
|
@@ -189,13 +190,30 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
|
|
|
189
190
|
getWalletRecoveryState({ accountAddress, }: {
|
|
190
191
|
accountAddress: string;
|
|
191
192
|
}): Promise<import("@dynamic-labs-wallet/browser-wallet-client").WalletRecoveryState>;
|
|
193
|
+
createOfflineRecoveryShares({ accountAddress, password, cloudProviderAccessToken, mfaToken, }: {
|
|
194
|
+
accountAddress: string;
|
|
195
|
+
password?: string | undefined;
|
|
196
|
+
cloudProviderAccessToken?: string | undefined;
|
|
197
|
+
mfaToken?: string | undefined;
|
|
198
|
+
}): Promise<void>;
|
|
192
199
|
endSession(reason?: import("@dynamic-labs-sdk/client").LogoutReason | undefined): Promise<void>;
|
|
193
200
|
getActiveAccountAddress(): Promise<string | undefined>;
|
|
194
201
|
getConnectedAccounts(): Promise<string[]>;
|
|
195
202
|
generateTraceId(): string;
|
|
196
203
|
buildErrorInstrumentContext(error: unknown): {
|
|
197
204
|
errorCode: string | import("@dynamic-labs/utils").ErrorCode;
|
|
198
|
-
errorMessage: string;
|
|
205
|
+
errorMessage: string; /**
|
|
206
|
+
* Wallet identity: keyshares/wallet records are keyed by the wallet's
|
|
207
|
+
* primary (mainnet) address. On testnet the active address is the same
|
|
208
|
+
* wallet's per-network encoding — WaaS lookups (password, signing) must use
|
|
209
|
+
* the primary address (the same key signs both encodings).
|
|
210
|
+
*
|
|
211
|
+
* Resolved from the credential that owns the active address, so a user with
|
|
212
|
+
* several Bitcoin wallets gets the identity of the wallet being spent from.
|
|
213
|
+
* Never falls back to another wallet's address: a substituted key produces a
|
|
214
|
+
* signature that looks valid locally and is rejected by the network, so the
|
|
215
|
+
* failure has to surface here instead.
|
|
216
|
+
*/
|
|
199
217
|
errorType: string | undefined;
|
|
200
218
|
} | {
|
|
201
219
|
errorCode: string;
|
|
@@ -281,6 +299,23 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
|
|
|
281
299
|
* the active address automatically.
|
|
282
300
|
*/
|
|
283
301
|
private getBitcoinNetworkEnum;
|
|
302
|
+
/**
|
|
303
|
+
* The address type the wallet's key was derived under, read back from the
|
|
304
|
+
* address itself.
|
|
305
|
+
*
|
|
306
|
+
* `bitcoinConfig.addressType` is the only thing that selects a BTC
|
|
307
|
+
* derivation path downstream (`getMPCChainConfig` throws without it), and a
|
|
308
|
+
* wallet created by an import carries no server-side derivation metadata to
|
|
309
|
+
* fall back on — so signing an imported wallet failed while a
|
|
310
|
+
* Dynamic-created one signed fine. The address already encodes the answer:
|
|
311
|
+
* witness v0 is P2WPKH (native segwit), v1 is P2TR (taproot), which are
|
|
312
|
+
* exactly the two types `importPrivateKey` accepts.
|
|
313
|
+
*
|
|
314
|
+
* Falls back to native segwit for an address that is not bech32 (a legacy
|
|
315
|
+
* P2PKH/P2SH encoding cannot come from this connector's own import or
|
|
316
|
+
* create paths) so a decode failure can never make signing impossible.
|
|
317
|
+
*/
|
|
318
|
+
private getAddressTypeForSigning;
|
|
284
319
|
supportsNetworkSwitching(): boolean;
|
|
285
320
|
/**
|
|
286
321
|
* Testnet when the testnet network (id 2) is selected — drives the widget's
|
|
@@ -295,15 +330,40 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
|
|
|
295
330
|
*/
|
|
296
331
|
getBalance(address: string): Promise<string | undefined>;
|
|
297
332
|
/**
|
|
298
|
-
* Finds the credential that owns
|
|
299
|
-
*
|
|
333
|
+
* Finds the credential that owns `address`, either as its primary (mainnet)
|
|
334
|
+
* address or as one of its network-tagged additional addresses.
|
|
300
335
|
*
|
|
301
336
|
* This connector is shared across every Bitcoin wallet of the user —
|
|
302
337
|
* `verifiedCredentials` holds them all — so the owning credential must be
|
|
303
|
-
* looked up by
|
|
304
|
-
*
|
|
338
|
+
* looked up by address. Reading `verifiedCredential` instead would always
|
|
339
|
+
* answer with the user's *first* wallet.
|
|
305
340
|
*/
|
|
341
|
+
private findCredentialForAddress;
|
|
342
|
+
/** @see findCredentialForAddress */
|
|
306
343
|
private findCredentialForActiveAddress;
|
|
344
|
+
/**
|
|
345
|
+
* True when `accountAddress` belongs to the same wallet as the currently
|
|
346
|
+
* active address — including when the active address is a *different*
|
|
347
|
+
* network-tagged encoding of that same wallet (e.g. the testnet address
|
|
348
|
+
* set by switchNetwork, compared against the wallet's primary mainnet
|
|
349
|
+
* address).
|
|
350
|
+
*
|
|
351
|
+
* Used by getWalletClientByAddress to avoid clobbering an explicit
|
|
352
|
+
* switchNetwork: callers like ensureActiveAccount re-assert the wallet's
|
|
353
|
+
* primary address before every send/sign, and setting activeAccountAddress
|
|
354
|
+
* back to that primary address would silently undo the network switch —
|
|
355
|
+
* UTXO/PSBT/broadcast calls would then run against the wrong (likely
|
|
356
|
+
* unfunded) encoding while getNetwork still reports the switched network.
|
|
357
|
+
*
|
|
358
|
+
* Compares the two resolved credential *objects* by reference rather than
|
|
359
|
+
* by id: both lookups run against the same verifiedCredentials array in
|
|
360
|
+
* the same synchronous call, so `.find()` returns the identical element
|
|
361
|
+
* for both addresses whenever they belong to the same wallet. Comparing
|
|
362
|
+
* `.id` instead would be wrong whenever accountAddress doesn't resolve to
|
|
363
|
+
* any known credential yet (e.g. a brand-new wallet not yet synced) —
|
|
364
|
+
* `undefined === undefined` would falsely read as "same wallet".
|
|
365
|
+
*/
|
|
366
|
+
private isSameWalletAddress;
|
|
307
367
|
/**
|
|
308
368
|
* Wallet identity: keyshares/wallet records are keyed by the wallet's
|
|
309
369
|
* primary (mainnet) address. On testnet the active address is the same
|
|
@@ -354,7 +414,11 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
|
|
|
354
414
|
* Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
|
|
355
415
|
*
|
|
356
416
|
* Embedded wallets only support PSBT format and automatically sign all inputs
|
|
357
|
-
* that belong to the wallet address
|
|
417
|
+
* that belong to the wallet address, unless `signingIndexes` narrows that set.
|
|
418
|
+
*
|
|
419
|
+
* The sighash type is read from the PSBT itself, falling back to
|
|
420
|
+
* SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
|
|
421
|
+
* `allowedSighash` restricts which declared types are accepted.
|
|
358
422
|
*
|
|
359
423
|
* @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
|
|
360
424
|
* @returns The signed (but not finalized) PSBT response
|
|
@@ -414,7 +478,11 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
|
|
|
414
478
|
legacyWalletId?: string;
|
|
415
479
|
}): Promise<void>;
|
|
416
480
|
/**
|
|
417
|
-
* Gets the wallet client for a specific account address and sets it as
|
|
481
|
+
* Gets the wallet client for a specific account address and sets it as
|
|
482
|
+
* active — unless `accountAddress` is just a different network-tagged
|
|
483
|
+
* encoding of the wallet that's already active (see isSameWalletAddress),
|
|
484
|
+
* in which case the current (possibly switchNetwork'd) active address is
|
|
485
|
+
* left untouched.
|
|
418
486
|
* @param accountAddress - The Bitcoin account address
|
|
419
487
|
* @returns The WaaS wallet client instance
|
|
420
488
|
*/
|
|
@@ -480,6 +548,12 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
|
|
|
480
548
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
481
549
|
*/
|
|
482
550
|
parseBase64Psbt(psbtBase64: string): ParsedTransaction | null;
|
|
551
|
+
/**
|
|
552
|
+
* bitcoinjs network for the address encoding the parsers should emit.
|
|
553
|
+
* Derived from the active address rather than activeNetworkId, which is
|
|
554
|
+
* in-memory only and can report mainnet while a testnet address is active.
|
|
555
|
+
*/
|
|
556
|
+
private getPsbtNetwork;
|
|
483
557
|
/**
|
|
484
558
|
* Gets the public key for the active account
|
|
485
559
|
* Falls back to the account address if public key retrieval fails
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import { __awaiter } from '../../../_virtual/_tslib.js';
|
|
3
|
-
import { networks, Psbt } from 'bitcoinjs-lib';
|
|
3
|
+
import { address, networks, Psbt } from 'bitcoinjs-lib';
|
|
4
4
|
import { Logger } from '@dynamic-labs/logger';
|
|
5
5
|
import { MFAAction, TokenScope } from '@dynamic-labs/sdk-api-core';
|
|
6
6
|
import { DynamicError } from '@dynamic-labs/utils';
|
|
@@ -13,6 +13,7 @@ import { BitcoinWalletConnector } from '../BitcoinWalletConnector.js';
|
|
|
13
13
|
import '@wallet-standard/app';
|
|
14
14
|
import 'jsontokens';
|
|
15
15
|
import { btcToSatoshis } from '../../utils/btcToSatoshis/btcToSatoshis.js';
|
|
16
|
+
import { getBitcoinNetwork } from '../../utils/getBitcoinNetwork/getBitcoinNetwork.js';
|
|
16
17
|
import { PsbtParser } from '../../utils/psbtParser/PsbtParser.js';
|
|
17
18
|
import { BitcoinUiTransaction } from '../../utils/BitcoinUiTransaction/BitcoinUiTransaction.js';
|
|
18
19
|
|
|
@@ -131,6 +132,32 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
131
132
|
: 'mainnet');
|
|
132
133
|
});
|
|
133
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The address type the wallet's key was derived under, read back from the
|
|
137
|
+
* address itself.
|
|
138
|
+
*
|
|
139
|
+
* `bitcoinConfig.addressType` is the only thing that selects a BTC
|
|
140
|
+
* derivation path downstream (`getMPCChainConfig` throws without it), and a
|
|
141
|
+
* wallet created by an import carries no server-side derivation metadata to
|
|
142
|
+
* fall back on — so signing an imported wallet failed while a
|
|
143
|
+
* Dynamic-created one signed fine. The address already encodes the answer:
|
|
144
|
+
* witness v0 is P2WPKH (native segwit), v1 is P2TR (taproot), which are
|
|
145
|
+
* exactly the two types `importPrivateKey` accepts.
|
|
146
|
+
*
|
|
147
|
+
* Falls back to native segwit for an address that is not bech32 (a legacy
|
|
148
|
+
* P2PKH/P2SH encoding cannot come from this connector's own import or
|
|
149
|
+
* create paths) so a decode failure can never make signing impossible.
|
|
150
|
+
*/
|
|
151
|
+
getAddressTypeForSigning(walletAddress) {
|
|
152
|
+
try {
|
|
153
|
+
const { version } = address.fromBech32(walletAddress);
|
|
154
|
+
return (version === 1 ? 'taproot' : 'native_segwit');
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
this.logger.warn('Could not read the address type from the wallet address; assuming native segwit', { error, walletAddress });
|
|
158
|
+
return 'native_segwit';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
134
161
|
supportsNetworkSwitching() {
|
|
135
162
|
return true;
|
|
136
163
|
}
|
|
@@ -157,26 +184,65 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
157
184
|
});
|
|
158
185
|
}
|
|
159
186
|
/**
|
|
160
|
-
* Finds the credential that owns
|
|
161
|
-
*
|
|
187
|
+
* Finds the credential that owns `address`, either as its primary (mainnet)
|
|
188
|
+
* address or as one of its network-tagged additional addresses.
|
|
162
189
|
*
|
|
163
190
|
* This connector is shared across every Bitcoin wallet of the user —
|
|
164
191
|
* `verifiedCredentials` holds them all — so the owning credential must be
|
|
165
|
-
* looked up by
|
|
166
|
-
*
|
|
192
|
+
* looked up by address. Reading `verifiedCredential` instead would always
|
|
193
|
+
* answer with the user's *first* wallet.
|
|
167
194
|
*/
|
|
168
|
-
|
|
195
|
+
findCredentialForAddress(address) {
|
|
169
196
|
var _a;
|
|
170
|
-
|
|
171
|
-
if (!activeAccountAddress) {
|
|
197
|
+
if (!address) {
|
|
172
198
|
return undefined;
|
|
173
199
|
}
|
|
174
200
|
return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
|
|
175
201
|
var _a;
|
|
176
|
-
return (credential === null || credential === void 0 ? void 0 : credential.address) ===
|
|
177
|
-
((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address ===
|
|
202
|
+
return (credential === null || credential === void 0 ? void 0 : credential.address) === address ||
|
|
203
|
+
((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === address);
|
|
178
204
|
});
|
|
179
205
|
}
|
|
206
|
+
/** @see findCredentialForAddress */
|
|
207
|
+
findCredentialForActiveAddress() {
|
|
208
|
+
return this.findCredentialForAddress(this.activeAccountAddress);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* True when `accountAddress` belongs to the same wallet as the currently
|
|
212
|
+
* active address — including when the active address is a *different*
|
|
213
|
+
* network-tagged encoding of that same wallet (e.g. the testnet address
|
|
214
|
+
* set by switchNetwork, compared against the wallet's primary mainnet
|
|
215
|
+
* address).
|
|
216
|
+
*
|
|
217
|
+
* Used by getWalletClientByAddress to avoid clobbering an explicit
|
|
218
|
+
* switchNetwork: callers like ensureActiveAccount re-assert the wallet's
|
|
219
|
+
* primary address before every send/sign, and setting activeAccountAddress
|
|
220
|
+
* back to that primary address would silently undo the network switch —
|
|
221
|
+
* UTXO/PSBT/broadcast calls would then run against the wrong (likely
|
|
222
|
+
* unfunded) encoding while getNetwork still reports the switched network.
|
|
223
|
+
*
|
|
224
|
+
* Compares the two resolved credential *objects* by reference rather than
|
|
225
|
+
* by id: both lookups run against the same verifiedCredentials array in
|
|
226
|
+
* the same synchronous call, so `.find()` returns the identical element
|
|
227
|
+
* for both addresses whenever they belong to the same wallet. Comparing
|
|
228
|
+
* `.id` instead would be wrong whenever accountAddress doesn't resolve to
|
|
229
|
+
* any known credential yet (e.g. a brand-new wallet not yet synced) —
|
|
230
|
+
* `undefined === undefined` would falsely read as "same wallet".
|
|
231
|
+
*/
|
|
232
|
+
isSameWalletAddress(accountAddress) {
|
|
233
|
+
if (!this.activeAccountAddress) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
if (accountAddress === this.activeAccountAddress) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
const activeCredential = this.findCredentialForActiveAddress();
|
|
240
|
+
if (!activeCredential) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const candidateCredential = this.findCredentialForAddress(accountAddress);
|
|
244
|
+
return (Boolean(candidateCredential) && candidateCredential === activeCredential);
|
|
245
|
+
}
|
|
180
246
|
/**
|
|
181
247
|
* Wallet identity: keyshares/wallet records are keyed by the wallet's
|
|
182
248
|
* primary (mainnet) address. On testnet the active address is the same
|
|
@@ -298,7 +364,11 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
298
364
|
* Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
|
|
299
365
|
*
|
|
300
366
|
* Embedded wallets only support PSBT format and automatically sign all inputs
|
|
301
|
-
* that belong to the wallet address
|
|
367
|
+
* that belong to the wallet address, unless `signingIndexes` narrows that set.
|
|
368
|
+
*
|
|
369
|
+
* The sighash type is read from the PSBT itself, falling back to
|
|
370
|
+
* SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
|
|
371
|
+
* `allowedSighash` restricts which declared types are accepted.
|
|
302
372
|
*
|
|
303
373
|
* @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
|
|
304
374
|
* @returns The signed (but not finalized) PSBT response
|
|
@@ -327,12 +397,14 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
327
397
|
accountAddress: walletIdentityAddress,
|
|
328
398
|
});
|
|
329
399
|
const signedTransaction = yield walletClient.signTransaction({
|
|
400
|
+
allowedSighash: request.allowedSighash,
|
|
330
401
|
authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
|
|
331
402
|
elevatedAccessToken,
|
|
332
403
|
mfaToken,
|
|
333
404
|
password,
|
|
334
405
|
senderAddress: walletIdentityAddress,
|
|
335
406
|
signedSessionId,
|
|
407
|
+
signingIndexes: request.signingIndexes,
|
|
336
408
|
transaction: request.unsignedPsbtBase64,
|
|
337
409
|
});
|
|
338
410
|
return {
|
|
@@ -468,12 +540,18 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
468
540
|
});
|
|
469
541
|
}
|
|
470
542
|
/**
|
|
471
|
-
* Gets the wallet client for a specific account address and sets it as
|
|
543
|
+
* Gets the wallet client for a specific account address and sets it as
|
|
544
|
+
* active — unless `accountAddress` is just a different network-tagged
|
|
545
|
+
* encoding of the wallet that's already active (see isSameWalletAddress),
|
|
546
|
+
* in which case the current (possibly switchNetwork'd) active address is
|
|
547
|
+
* left untouched.
|
|
472
548
|
* @param accountAddress - The Bitcoin account address
|
|
473
549
|
* @returns The WaaS wallet client instance
|
|
474
550
|
*/
|
|
475
551
|
getWalletClientByAddress({ accountAddress }) {
|
|
476
|
-
this.
|
|
552
|
+
if (!this.isSameWalletAddress(accountAddress)) {
|
|
553
|
+
this.setActiveAccountAddress(accountAddress);
|
|
554
|
+
}
|
|
477
555
|
return this.getWaasWalletClient();
|
|
478
556
|
}
|
|
479
557
|
/**
|
|
@@ -493,7 +571,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
493
571
|
*/
|
|
494
572
|
validateActiveWallet(expectedAddress) {
|
|
495
573
|
return __awaiter(this, void 0, void 0, function* () {
|
|
496
|
-
var _a
|
|
574
|
+
var _a;
|
|
497
575
|
const walletClient = yield this.getWaasWalletClient();
|
|
498
576
|
const targetWallet = yield walletClient.getWallet({
|
|
499
577
|
accountAddress: expectedAddress,
|
|
@@ -507,8 +585,12 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
507
585
|
const isWalletActive = isSameAddress(targetWallet.accountAddress, this.activeAccountAddress || '', this.connectedChain);
|
|
508
586
|
// The active address may be a per-network encoding of this same wallet
|
|
509
587
|
// (one key, network-tagged additional addresses). Resetting it here would
|
|
510
|
-
// silently un-switch the selected network.
|
|
511
|
-
|
|
588
|
+
// silently un-switch the selected network. Resolved via isSameWalletAddress
|
|
589
|
+
// (which looks up the credential that actually owns the active address)
|
|
590
|
+
// rather than `verifiedCredential`, which is always the user's *first*
|
|
591
|
+
// wallet — using it here would wrongly reset the address for any other
|
|
592
|
+
// wallet the user validates.
|
|
593
|
+
const isPerNetworkVariantOfWallet = this.isSameWalletAddress(targetWallet.accountAddress);
|
|
512
594
|
if (!isWalletActive && !isPerNetworkVariantOfWallet) {
|
|
513
595
|
this.activeAccountAddress = targetWallet.accountAddress;
|
|
514
596
|
}
|
|
@@ -543,10 +625,14 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
543
625
|
accountAddress: this.getWalletIdentityAddress(),
|
|
544
626
|
});
|
|
545
627
|
const messageString = typeof message === 'string' ? message : message.raw;
|
|
628
|
+
const walletIdentityAddress = this.getWalletIdentityAddress();
|
|
546
629
|
return walletClient.signMessage({
|
|
547
|
-
accountAddress:
|
|
630
|
+
accountAddress: walletIdentityAddress,
|
|
548
631
|
authToken: (_e = this.getAuthToken) === null || _e === void 0 ? void 0 : _e.call(this),
|
|
549
|
-
bitcoinConfig: {
|
|
632
|
+
bitcoinConfig: {
|
|
633
|
+
addressType: this.getAddressTypeForSigning(walletIdentityAddress),
|
|
634
|
+
network: yield this.getBitcoinNetworkEnum(),
|
|
635
|
+
},
|
|
550
636
|
context,
|
|
551
637
|
elevatedAccessToken,
|
|
552
638
|
message: messageString,
|
|
@@ -661,7 +747,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
661
747
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
662
748
|
*/
|
|
663
749
|
parsePsbt(psbtInput) {
|
|
664
|
-
return PsbtParser.parsePsbt(psbtInput);
|
|
750
|
+
return PsbtParser.parsePsbt(psbtInput, this.getPsbtNetwork());
|
|
665
751
|
}
|
|
666
752
|
/**
|
|
667
753
|
* Parse a PSBT or finalized transaction from hex format
|
|
@@ -669,7 +755,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
669
755
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
670
756
|
*/
|
|
671
757
|
parseHexPsbt(psbtHex) {
|
|
672
|
-
return PsbtParser.parseHexPsbt(psbtHex);
|
|
758
|
+
return PsbtParser.parseHexPsbt(psbtHex, this.getPsbtNetwork());
|
|
673
759
|
}
|
|
674
760
|
/**
|
|
675
761
|
* Parse a PSBT or finalized transaction from base64 format
|
|
@@ -677,7 +763,17 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
677
763
|
* @returns Parsed transaction data with inputs and outputs, or null if parsing fails
|
|
678
764
|
*/
|
|
679
765
|
parseBase64Psbt(psbtBase64) {
|
|
680
|
-
return PsbtParser.parseBase64Psbt(psbtBase64);
|
|
766
|
+
return PsbtParser.parseBase64Psbt(psbtBase64, this.getPsbtNetwork());
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* bitcoinjs network for the address encoding the parsers should emit.
|
|
770
|
+
* Derived from the active address rather than activeNetworkId, which is
|
|
771
|
+
* in-memory only and can report mainnet while a testnet address is active.
|
|
772
|
+
*/
|
|
773
|
+
getPsbtNetwork() {
|
|
774
|
+
return this.activeAccountAddress
|
|
775
|
+
? getBitcoinNetwork(this.activeAccountAddress)
|
|
776
|
+
: networks.bitcoin;
|
|
681
777
|
}
|
|
682
778
|
/**
|
|
683
779
|
* Gets the public key for the active account
|
|
@@ -768,6 +864,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
|
|
|
768
864
|
accountAddress: this.getWalletIdentityAddress(),
|
|
769
865
|
authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
|
|
770
866
|
bitcoinConfig: {
|
|
867
|
+
addressType: this.getAddressTypeForSigning(this.getWalletIdentityAddress()),
|
|
771
868
|
network: yield this.getBitcoinNetworkEnum(),
|
|
772
869
|
},
|
|
773
870
|
elevatedAccessToken,
|
package/src/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { OkxConnector } from './connectors';
|
|
1
|
+
import { OkxConnector, DynamicWaasBitcoinConnector } from './connectors';
|
|
2
2
|
export { BitcoinWalletConnector, type BitcoinWalletConnectorOpts, } from './connectors';
|
|
3
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';
|
|
7
|
-
export declare const BitcoinWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof OkxConnector)[];
|
|
7
|
+
export declare const BitcoinWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof OkxConnector | typeof DynamicWaasBitcoinConnector)[];
|
|
8
8
|
export { BitcoinProviderHelper } from './bitcoinProviderHelper';
|
|
9
9
|
export { DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS, } from './const';
|
package/src/types.d.ts
CHANGED
|
@@ -67,6 +67,19 @@ export type EmbeddedWalletSignPsbtRequest = {
|
|
|
67
67
|
* Embedded wallets only support PSBT format, not raw transaction hex.
|
|
68
68
|
*/
|
|
69
69
|
unsignedPsbtBase64: string;
|
|
70
|
+
/**
|
|
71
|
+
* Optional subset of PSBT input indexes to sign. When provided, only these
|
|
72
|
+
* indexes are signed (they must still belong to the wallet's own address).
|
|
73
|
+
* When omitted, behavior is unchanged: all wallet-owned inputs are signed.
|
|
74
|
+
*/
|
|
75
|
+
signingIndexes?: number[];
|
|
76
|
+
/**
|
|
77
|
+
* Optional allow-list of sighash types. The sighash type itself is read from
|
|
78
|
+
* the PSBT (BIP-174 `PSBT_IN_SIGHASH_TYPE`) — this only restricts which
|
|
79
|
+
* declared types are accepted, and signing throws if an input declares one
|
|
80
|
+
* outside the list. When omitted, any declared type is signed.
|
|
81
|
+
*/
|
|
82
|
+
allowedSighash?: number[];
|
|
70
83
|
};
|
|
71
84
|
export type SatsConnectSignTransactionInput = {
|
|
72
85
|
message?: string;
|
|
@@ -13,16 +13,19 @@ class PsbtParser {
|
|
|
13
13
|
* Parse a PSBT or finalized transaction and extract transaction information
|
|
14
14
|
* Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
|
|
15
15
|
* @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
|
|
16
|
+
* @param network - Network used to encode the extracted addresses. Scripts are
|
|
17
|
+
* network-agnostic, so passing the wrong one silently renders a valid address
|
|
18
|
+
* under the wrong prefix (a testnet output shown as `bc1…`).
|
|
16
19
|
* @returns Parsed transaction data with inputs and outputs
|
|
17
20
|
* @throws Error if parsing fails
|
|
18
21
|
*/
|
|
19
|
-
static parsePsbt(psbtInput) {
|
|
22
|
+
static parsePsbt(psbtInput, network = bitcoinjsLib.networks.bitcoin) {
|
|
20
23
|
const isHex = /^[0-9a-fA-F]+$/.test(psbtInput) && psbtInput.length > 100;
|
|
21
24
|
if (isHex) {
|
|
22
|
-
return PsbtParser.parseHexPsbt(psbtInput);
|
|
25
|
+
return PsbtParser.parseHexPsbt(psbtInput, network);
|
|
23
26
|
}
|
|
24
27
|
else {
|
|
25
|
-
return PsbtParser.parseBase64Psbt(psbtInput);
|
|
28
|
+
return PsbtParser.parseBase64Psbt(psbtInput, network);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
@@ -31,14 +34,14 @@ class PsbtParser {
|
|
|
31
34
|
* @returns Parsed transaction data with inputs and outputs
|
|
32
35
|
* @throws Error if parsing fails
|
|
33
36
|
*/
|
|
34
|
-
static parseHexPsbt(psbtHex) {
|
|
37
|
+
static parseHexPsbt(psbtHex, network = bitcoinjsLib.networks.bitcoin) {
|
|
35
38
|
try {
|
|
36
39
|
try {
|
|
37
|
-
const psbt = bitcoinjsLib.Psbt.fromHex(psbtHex, { network
|
|
38
|
-
return PsbtParser.extractPsbtData(psbt);
|
|
40
|
+
const psbt = bitcoinjsLib.Psbt.fromHex(psbtHex, { network });
|
|
41
|
+
return PsbtParser.extractPsbtData(psbt, network);
|
|
39
42
|
}
|
|
40
43
|
catch (psbtError) {
|
|
41
|
-
return PsbtParser.parseFinalizedTransactionHex(psbtHex);
|
|
44
|
+
return PsbtParser.parseFinalizedTransactionHex(psbtHex, network);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
catch (error) {
|
|
@@ -51,14 +54,14 @@ class PsbtParser {
|
|
|
51
54
|
* @returns Parsed transaction data with inputs and outputs
|
|
52
55
|
* @throws Error if parsing fails
|
|
53
56
|
*/
|
|
54
|
-
static parseBase64Psbt(psbtBase64) {
|
|
57
|
+
static parseBase64Psbt(psbtBase64, network = bitcoinjsLib.networks.bitcoin) {
|
|
55
58
|
try {
|
|
56
59
|
try {
|
|
57
|
-
const psbt = bitcoinjsLib.Psbt.fromBase64(psbtBase64, { network
|
|
58
|
-
return PsbtParser.extractPsbtData(psbt);
|
|
60
|
+
const psbt = bitcoinjsLib.Psbt.fromBase64(psbtBase64, { network });
|
|
61
|
+
return PsbtParser.extractPsbtData(psbt, network);
|
|
59
62
|
}
|
|
60
63
|
catch (psbtError) {
|
|
61
|
-
return PsbtParser.parseFinalizedTransactionBase64(psbtBase64);
|
|
64
|
+
return PsbtParser.parseFinalizedTransactionBase64(psbtBase64, network);
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
catch (error) {
|
|
@@ -71,7 +74,7 @@ class PsbtParser {
|
|
|
71
74
|
* @param psbt - The parsed PSBT object
|
|
72
75
|
* @returns Parsed transaction data with inputs and outputs
|
|
73
76
|
*/
|
|
74
|
-
static extractPsbtData(psbt) {
|
|
77
|
+
static extractPsbtData(psbt, network) {
|
|
75
78
|
const inputs = [];
|
|
76
79
|
const outputs = [];
|
|
77
80
|
psbt.txInputs.forEach((txInput, index) => {
|
|
@@ -83,7 +86,7 @@ class PsbtParser {
|
|
|
83
86
|
if (input.witnessUtxo) {
|
|
84
87
|
inputData.value = input.witnessUtxo.value;
|
|
85
88
|
try {
|
|
86
|
-
inputData.address = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script,
|
|
89
|
+
inputData.address = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script, network);
|
|
87
90
|
}
|
|
88
91
|
catch (e) {
|
|
89
92
|
// Address extraction failed
|
|
@@ -95,7 +98,7 @@ class PsbtParser {
|
|
|
95
98
|
const prevOut = prevTx.outs[txInput.index];
|
|
96
99
|
inputData.value = prevOut.value;
|
|
97
100
|
try {
|
|
98
|
-
inputData.address = bitcoinjsLib.address.fromOutputScript(prevOut.script,
|
|
101
|
+
inputData.address = bitcoinjsLib.address.fromOutputScript(prevOut.script, network);
|
|
99
102
|
}
|
|
100
103
|
catch (e) {
|
|
101
104
|
// Address extraction failed
|
|
@@ -107,7 +110,7 @@ class PsbtParser {
|
|
|
107
110
|
}
|
|
108
111
|
inputs.push(inputData);
|
|
109
112
|
});
|
|
110
|
-
PsbtParser.extractOutputs(psbt.txOutputs, outputs);
|
|
113
|
+
PsbtParser.extractOutputs(psbt.txOutputs, outputs, network);
|
|
111
114
|
return { inputs, outputs };
|
|
112
115
|
}
|
|
113
116
|
/**
|
|
@@ -116,13 +119,13 @@ class PsbtParser {
|
|
|
116
119
|
* @param txOutputs - Array of transaction outputs (from PSBT or Transaction)
|
|
117
120
|
* @param outputs - Array to populate with parsed output data
|
|
118
121
|
*/
|
|
119
|
-
static extractOutputs(txOutputs, outputs) {
|
|
122
|
+
static extractOutputs(txOutputs, outputs, network) {
|
|
120
123
|
txOutputs.forEach((txOutput) => {
|
|
121
124
|
const outputData = {
|
|
122
125
|
value: txOutput.value,
|
|
123
126
|
};
|
|
124
127
|
try {
|
|
125
|
-
outputData.address = bitcoinjsLib.address.fromOutputScript(txOutput.script,
|
|
128
|
+
outputData.address = bitcoinjsLib.address.fromOutputScript(txOutput.script, network);
|
|
126
129
|
}
|
|
127
130
|
catch (e) {
|
|
128
131
|
// Address extraction failed - continue without address
|
|
@@ -136,10 +139,10 @@ class PsbtParser {
|
|
|
136
139
|
* @returns Parsed transaction data with inputs and outputs
|
|
137
140
|
* @throws Error if parsing fails
|
|
138
141
|
*/
|
|
139
|
-
static parseFinalizedTransactionHex(txHex) {
|
|
142
|
+
static parseFinalizedTransactionHex(txHex, network) {
|
|
140
143
|
try {
|
|
141
144
|
const tx = bitcoinjsLib.Transaction.fromHex(txHex);
|
|
142
|
-
return PsbtParser.extractTransactionData(tx);
|
|
145
|
+
return PsbtParser.extractTransactionData(tx, network);
|
|
143
146
|
}
|
|
144
147
|
catch (error) {
|
|
145
148
|
throw new Error(`Failed to parse finalized transaction hex: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -151,11 +154,11 @@ class PsbtParser {
|
|
|
151
154
|
* @returns Parsed transaction data with inputs and outputs
|
|
152
155
|
* @throws Error if parsing fails
|
|
153
156
|
*/
|
|
154
|
-
static parseFinalizedTransactionBase64(txBase64) {
|
|
157
|
+
static parseFinalizedTransactionBase64(txBase64, network) {
|
|
155
158
|
try {
|
|
156
159
|
const buffer = Buffer.from(txBase64, 'base64');
|
|
157
160
|
const tx = bitcoinjsLib.Transaction.fromBuffer(buffer);
|
|
158
|
-
return PsbtParser.extractTransactionData(tx);
|
|
161
|
+
return PsbtParser.extractTransactionData(tx, network);
|
|
159
162
|
}
|
|
160
163
|
catch (error) {
|
|
161
164
|
throw new Error(`Failed to parse finalized transaction base64: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -167,7 +170,7 @@ class PsbtParser {
|
|
|
167
170
|
* @param tx - The parsed Transaction object
|
|
168
171
|
* @returns Parsed transaction data with inputs and outputs
|
|
169
172
|
*/
|
|
170
|
-
static extractTransactionData(tx) {
|
|
173
|
+
static extractTransactionData(tx, network) {
|
|
171
174
|
const inputs = [];
|
|
172
175
|
const outputs = [];
|
|
173
176
|
tx.ins.forEach((input) => {
|
|
@@ -177,7 +180,7 @@ class PsbtParser {
|
|
|
177
180
|
};
|
|
178
181
|
inputs.push(inputData);
|
|
179
182
|
});
|
|
180
|
-
PsbtParser.extractOutputs(tx.outs, outputs);
|
|
183
|
+
PsbtParser.extractOutputs(tx.outs, outputs, network);
|
|
181
184
|
return { inputs, outputs };
|
|
182
185
|
}
|
|
183
186
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Network } from 'bitcoinjs-lib';
|
|
1
2
|
import type { ParsedTransaction } from '../../types';
|
|
2
3
|
/**
|
|
3
4
|
* Utility class for parsing PSBTs and finalized Bitcoin transactions
|
|
@@ -7,24 +8,27 @@ export declare class PsbtParser {
|
|
|
7
8
|
* Parse a PSBT or finalized transaction and extract transaction information
|
|
8
9
|
* Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
|
|
9
10
|
* @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
|
|
11
|
+
* @param network - Network used to encode the extracted addresses. Scripts are
|
|
12
|
+
* network-agnostic, so passing the wrong one silently renders a valid address
|
|
13
|
+
* under the wrong prefix (a testnet output shown as `bc1…`).
|
|
10
14
|
* @returns Parsed transaction data with inputs and outputs
|
|
11
15
|
* @throws Error if parsing fails
|
|
12
16
|
*/
|
|
13
|
-
static parsePsbt(psbtInput: string): ParsedTransaction;
|
|
17
|
+
static parsePsbt(psbtInput: string, network?: Network): ParsedTransaction;
|
|
14
18
|
/**
|
|
15
19
|
* Parse a PSBT or finalized transaction from hex format
|
|
16
20
|
* @param psbtHex - The PSBT or finalized transaction in hex format
|
|
17
21
|
* @returns Parsed transaction data with inputs and outputs
|
|
18
22
|
* @throws Error if parsing fails
|
|
19
23
|
*/
|
|
20
|
-
static parseHexPsbt(psbtHex: string): ParsedTransaction;
|
|
24
|
+
static parseHexPsbt(psbtHex: string, network?: Network): ParsedTransaction;
|
|
21
25
|
/**
|
|
22
26
|
* Parse a PSBT or finalized transaction from base64 format
|
|
23
27
|
* @param psbtBase64 - The PSBT or finalized transaction in base64 format
|
|
24
28
|
* @returns Parsed transaction data with inputs and outputs
|
|
25
29
|
* @throws Error if parsing fails
|
|
26
30
|
*/
|
|
27
|
-
static parseBase64Psbt(psbtBase64: string): ParsedTransaction;
|
|
31
|
+
static parseBase64Psbt(psbtBase64: string, network?: Network): ParsedTransaction;
|
|
28
32
|
/**
|
|
29
33
|
* Extract transaction data from a PSBT
|
|
30
34
|
* Shared logic used by both parseHexPsbt and parseBase64Psbt
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import {
|
|
2
|
+
import { networks, Psbt, address, Transaction } from 'bitcoinjs-lib';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Utility class for parsing PSBTs and finalized Bitcoin transactions
|
|
@@ -9,16 +9,19 @@ class PsbtParser {
|
|
|
9
9
|
* Parse a PSBT or finalized transaction and extract transaction information
|
|
10
10
|
* Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
|
|
11
11
|
* @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
|
|
12
|
+
* @param network - Network used to encode the extracted addresses. Scripts are
|
|
13
|
+
* network-agnostic, so passing the wrong one silently renders a valid address
|
|
14
|
+
* under the wrong prefix (a testnet output shown as `bc1…`).
|
|
12
15
|
* @returns Parsed transaction data with inputs and outputs
|
|
13
16
|
* @throws Error if parsing fails
|
|
14
17
|
*/
|
|
15
|
-
static parsePsbt(psbtInput) {
|
|
18
|
+
static parsePsbt(psbtInput, network = networks.bitcoin) {
|
|
16
19
|
const isHex = /^[0-9a-fA-F]+$/.test(psbtInput) && psbtInput.length > 100;
|
|
17
20
|
if (isHex) {
|
|
18
|
-
return PsbtParser.parseHexPsbt(psbtInput);
|
|
21
|
+
return PsbtParser.parseHexPsbt(psbtInput, network);
|
|
19
22
|
}
|
|
20
23
|
else {
|
|
21
|
-
return PsbtParser.parseBase64Psbt(psbtInput);
|
|
24
|
+
return PsbtParser.parseBase64Psbt(psbtInput, network);
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
@@ -27,14 +30,14 @@ class PsbtParser {
|
|
|
27
30
|
* @returns Parsed transaction data with inputs and outputs
|
|
28
31
|
* @throws Error if parsing fails
|
|
29
32
|
*/
|
|
30
|
-
static parseHexPsbt(psbtHex) {
|
|
33
|
+
static parseHexPsbt(psbtHex, network = networks.bitcoin) {
|
|
31
34
|
try {
|
|
32
35
|
try {
|
|
33
|
-
const psbt = Psbt.fromHex(psbtHex, { network
|
|
34
|
-
return PsbtParser.extractPsbtData(psbt);
|
|
36
|
+
const psbt = Psbt.fromHex(psbtHex, { network });
|
|
37
|
+
return PsbtParser.extractPsbtData(psbt, network);
|
|
35
38
|
}
|
|
36
39
|
catch (psbtError) {
|
|
37
|
-
return PsbtParser.parseFinalizedTransactionHex(psbtHex);
|
|
40
|
+
return PsbtParser.parseFinalizedTransactionHex(psbtHex, network);
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
catch (error) {
|
|
@@ -47,14 +50,14 @@ class PsbtParser {
|
|
|
47
50
|
* @returns Parsed transaction data with inputs and outputs
|
|
48
51
|
* @throws Error if parsing fails
|
|
49
52
|
*/
|
|
50
|
-
static parseBase64Psbt(psbtBase64) {
|
|
53
|
+
static parseBase64Psbt(psbtBase64, network = networks.bitcoin) {
|
|
51
54
|
try {
|
|
52
55
|
try {
|
|
53
|
-
const psbt = Psbt.fromBase64(psbtBase64, { network
|
|
54
|
-
return PsbtParser.extractPsbtData(psbt);
|
|
56
|
+
const psbt = Psbt.fromBase64(psbtBase64, { network });
|
|
57
|
+
return PsbtParser.extractPsbtData(psbt, network);
|
|
55
58
|
}
|
|
56
59
|
catch (psbtError) {
|
|
57
|
-
return PsbtParser.parseFinalizedTransactionBase64(psbtBase64);
|
|
60
|
+
return PsbtParser.parseFinalizedTransactionBase64(psbtBase64, network);
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
catch (error) {
|
|
@@ -67,7 +70,7 @@ class PsbtParser {
|
|
|
67
70
|
* @param psbt - The parsed PSBT object
|
|
68
71
|
* @returns Parsed transaction data with inputs and outputs
|
|
69
72
|
*/
|
|
70
|
-
static extractPsbtData(psbt) {
|
|
73
|
+
static extractPsbtData(psbt, network) {
|
|
71
74
|
const inputs = [];
|
|
72
75
|
const outputs = [];
|
|
73
76
|
psbt.txInputs.forEach((txInput, index) => {
|
|
@@ -79,7 +82,7 @@ class PsbtParser {
|
|
|
79
82
|
if (input.witnessUtxo) {
|
|
80
83
|
inputData.value = input.witnessUtxo.value;
|
|
81
84
|
try {
|
|
82
|
-
inputData.address = address.fromOutputScript(input.witnessUtxo.script,
|
|
85
|
+
inputData.address = address.fromOutputScript(input.witnessUtxo.script, network);
|
|
83
86
|
}
|
|
84
87
|
catch (e) {
|
|
85
88
|
// Address extraction failed
|
|
@@ -91,7 +94,7 @@ class PsbtParser {
|
|
|
91
94
|
const prevOut = prevTx.outs[txInput.index];
|
|
92
95
|
inputData.value = prevOut.value;
|
|
93
96
|
try {
|
|
94
|
-
inputData.address = address.fromOutputScript(prevOut.script,
|
|
97
|
+
inputData.address = address.fromOutputScript(prevOut.script, network);
|
|
95
98
|
}
|
|
96
99
|
catch (e) {
|
|
97
100
|
// Address extraction failed
|
|
@@ -103,7 +106,7 @@ class PsbtParser {
|
|
|
103
106
|
}
|
|
104
107
|
inputs.push(inputData);
|
|
105
108
|
});
|
|
106
|
-
PsbtParser.extractOutputs(psbt.txOutputs, outputs);
|
|
109
|
+
PsbtParser.extractOutputs(psbt.txOutputs, outputs, network);
|
|
107
110
|
return { inputs, outputs };
|
|
108
111
|
}
|
|
109
112
|
/**
|
|
@@ -112,13 +115,13 @@ class PsbtParser {
|
|
|
112
115
|
* @param txOutputs - Array of transaction outputs (from PSBT or Transaction)
|
|
113
116
|
* @param outputs - Array to populate with parsed output data
|
|
114
117
|
*/
|
|
115
|
-
static extractOutputs(txOutputs, outputs) {
|
|
118
|
+
static extractOutputs(txOutputs, outputs, network) {
|
|
116
119
|
txOutputs.forEach((txOutput) => {
|
|
117
120
|
const outputData = {
|
|
118
121
|
value: txOutput.value,
|
|
119
122
|
};
|
|
120
123
|
try {
|
|
121
|
-
outputData.address = address.fromOutputScript(txOutput.script,
|
|
124
|
+
outputData.address = address.fromOutputScript(txOutput.script, network);
|
|
122
125
|
}
|
|
123
126
|
catch (e) {
|
|
124
127
|
// Address extraction failed - continue without address
|
|
@@ -132,10 +135,10 @@ class PsbtParser {
|
|
|
132
135
|
* @returns Parsed transaction data with inputs and outputs
|
|
133
136
|
* @throws Error if parsing fails
|
|
134
137
|
*/
|
|
135
|
-
static parseFinalizedTransactionHex(txHex) {
|
|
138
|
+
static parseFinalizedTransactionHex(txHex, network) {
|
|
136
139
|
try {
|
|
137
140
|
const tx = Transaction.fromHex(txHex);
|
|
138
|
-
return PsbtParser.extractTransactionData(tx);
|
|
141
|
+
return PsbtParser.extractTransactionData(tx, network);
|
|
139
142
|
}
|
|
140
143
|
catch (error) {
|
|
141
144
|
throw new Error(`Failed to parse finalized transaction hex: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -147,11 +150,11 @@ class PsbtParser {
|
|
|
147
150
|
* @returns Parsed transaction data with inputs and outputs
|
|
148
151
|
* @throws Error if parsing fails
|
|
149
152
|
*/
|
|
150
|
-
static parseFinalizedTransactionBase64(txBase64) {
|
|
153
|
+
static parseFinalizedTransactionBase64(txBase64, network) {
|
|
151
154
|
try {
|
|
152
155
|
const buffer = Buffer.from(txBase64, 'base64');
|
|
153
156
|
const tx = Transaction.fromBuffer(buffer);
|
|
154
|
-
return PsbtParser.extractTransactionData(tx);
|
|
157
|
+
return PsbtParser.extractTransactionData(tx, network);
|
|
155
158
|
}
|
|
156
159
|
catch (error) {
|
|
157
160
|
throw new Error(`Failed to parse finalized transaction base64: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -163,7 +166,7 @@ class PsbtParser {
|
|
|
163
166
|
* @param tx - The parsed Transaction object
|
|
164
167
|
* @returns Parsed transaction data with inputs and outputs
|
|
165
168
|
*/
|
|
166
|
-
static extractTransactionData(tx) {
|
|
169
|
+
static extractTransactionData(tx, network) {
|
|
167
170
|
const inputs = [];
|
|
168
171
|
const outputs = [];
|
|
169
172
|
tx.ins.forEach((input) => {
|
|
@@ -173,7 +176,7 @@ class PsbtParser {
|
|
|
173
176
|
};
|
|
174
177
|
inputs.push(inputData);
|
|
175
178
|
});
|
|
176
|
-
PsbtParser.extractOutputs(tx.outs, outputs);
|
|
179
|
+
PsbtParser.extractOutputs(tx.outs, outputs, network);
|
|
177
180
|
return { inputs, outputs };
|
|
178
181
|
}
|
|
179
182
|
}
|