@dynamic-labs/bitcoin 3.0.0-alpha.8 → 3.0.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +622 -0
  2. package/package.json +7 -6
  3. package/src/BitcoinLocalStorageCache.cjs +0 -16
  4. package/src/BitcoinLocalStorageCache.d.ts +0 -7
  5. package/src/BitcoinLocalStorageCache.js +0 -16
  6. package/src/bitcoinProviderHelper.d.ts +1 -0
  7. package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.cjs +170 -141
  8. package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.d.ts +8 -3
  9. package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.js +171 -142
  10. package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.cjs +216 -0
  11. package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.d.ts +11 -0
  12. package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.js +212 -0
  13. package/src/connectors/BitcoinSatsConnectLegacyConnector/index.d.ts +1 -0
  14. package/src/connectors/BitcoinWalletConnector.cjs +44 -29
  15. package/src/connectors/BitcoinWalletConnector.d.ts +7 -3
  16. package/src/connectors/BitcoinWalletConnector.js +45 -30
  17. package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.cjs +7 -1
  18. package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.d.ts +1 -1
  19. package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.js +7 -1
  20. package/src/connectors/OkxConnector/OkxConnector.cjs +19 -2
  21. package/src/connectors/OkxConnector/OkxConnector.d.ts +1 -1
  22. package/src/connectors/OkxConnector/OkxConnector.js +19 -2
  23. package/src/connectors/PhantomConnector/PhantomConnector.cjs +4 -9
  24. package/src/connectors/PhantomConnector/PhantomConnector.d.ts +1 -2
  25. package/src/connectors/PhantomConnector/PhantomConnector.js +4 -9
  26. package/src/connectors/UnisatConnector/UnisatConnector.cjs +17 -1
  27. package/src/connectors/UnisatConnector/UnisatConnector.d.ts +1 -1
  28. package/src/connectors/UnisatConnector/UnisatConnector.js +17 -1
  29. package/src/connectors/UnknownInjected/UnknownInjected.cjs +7 -1
  30. package/src/connectors/UnknownInjected/UnknownInjected.d.ts +1 -1
  31. package/src/connectors/UnknownInjected/UnknownInjected.js +7 -1
  32. package/src/connectors/index.d.ts +1 -0
  33. package/src/index.cjs +4 -0
  34. package/src/index.d.ts +3 -2
  35. package/src/index.js +2 -0
  36. package/src/types.d.ts +1 -0
  37. package/src/utils/fetchSatsConnectConnectors/fetchSatsConnectConnectors.cjs +15 -3
  38. package/src/utils/fetchSatsConnectConnectors/fetchSatsConnectConnectors.js +15 -3
  39. package/src/utils/psbt/bitcoinNetworkTypeToNetworks.cjs +1 -0
  40. package/src/utils/psbt/bitcoinNetworkTypeToNetworks.d.ts +1 -1
  41. package/src/utils/psbt/bitcoinNetworkTypeToNetworks.js +1 -0
  42. package/src/utils/psbt/createSignPsbtOptions.cjs +22 -1
  43. package/src/utils/psbt/createSignPsbtOptions.d.ts +2 -0
  44. package/src/utils/psbt/createSignPsbtOptions.js +22 -2
  45. package/src/wallet/BitcoinWallet.cjs +69 -0
  46. package/src/wallet/BitcoinWallet.d.ts +36 -0
  47. package/src/wallet/BitcoinWallet.js +65 -0
  48. package/src/wallet/index.d.ts +2 -0
  49. package/src/wallet/isBitcoinWallet/index.d.ts +1 -0
  50. package/src/wallet/isBitcoinWallet/isBitcoinWallet.cjs +8 -0
  51. package/src/wallet/isBitcoinWallet/isBitcoinWallet.d.ts +3 -0
  52. package/src/wallet/isBitcoinWallet/isBitcoinWallet.js +4 -0
@@ -0,0 +1,212 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../_virtual/_tslib.js';
3
+ import { getAddress, AddressPurpose, signMessage, sendBtcTransaction, signTransaction, signMultipleTransactions } from 'sats-connect';
4
+ import { isMobile, template } from '@dynamic-labs/utils';
5
+ import { findWalletBookWallet } from '@dynamic-labs/wallet-book';
6
+ import { SATSCONNECT_FEATURE } from '../../const.js';
7
+ import 'bitcoinjs-lib';
8
+ import '@dynamic-labs/wallet-connector-core';
9
+ import '@dynamic-labs/sdk-api-core';
10
+ import '@wallet-standard/app';
11
+ import { BitcoinSatsConnectConnector } from '../BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.js';
12
+ import { supportsSatsConnect } from '../../utils/supportsSatsConnect.js';
13
+
14
+ class BitcoinSatsConnectLegacyConnector extends BitcoinSatsConnectConnector {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.isLegacy = true;
18
+ }
19
+ getAddress() {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ var _a;
22
+ // xverse doesn't support wallet standard, so we won't have a wallet object,
23
+ // but it's already the default provider for sats-connect, so it's ok
24
+ // for getProvider in getAddress to return undefined
25
+ // if we're not using xverse, we need to check if there is a wallet and
26
+ // that it has the satsconnect feature to return the correct provider to use
27
+ if (!supportsSatsConnect(this)) {
28
+ return;
29
+ }
30
+ const wallet = findWalletBookWallet(this.walletBook, this.key);
31
+ const inAppBrowserUrl = (_a = wallet === null || wallet === void 0 ? void 0 : wallet.mobile) === null || _a === void 0 ? void 0 : _a.inAppBrowser;
32
+ if (isMobile() &&
33
+ !this.isInstalledOnBrowser() &&
34
+ inAppBrowserUrl &&
35
+ this.mobileExperience === 'in-app-browser') {
36
+ const inAppBrowserTemplate = template(inAppBrowserUrl);
37
+ const deepLink = inAppBrowserTemplate({
38
+ encodedDappURI: encodeURIComponent(window.location.toString()),
39
+ });
40
+ window.location.href = deepLink;
41
+ return;
42
+ }
43
+ return new Promise((resolve, reject) => {
44
+ getAddress({
45
+ getProvider: () => __awaiter(this, void 0, void 0, function* () {
46
+ var _a, _b;
47
+ return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features[SATSCONNECT_FEATURE]) === null || _b === void 0 ? void 0 : _b.provider;
48
+ }),
49
+ onCancel: () => {
50
+ const error = new Error();
51
+ error.code = '-32000'; // error code for user cancelled
52
+ reject(error);
53
+ },
54
+ onFinish: (response) => __awaiter(this, void 0, void 0, function* () {
55
+ var _c;
56
+ const { addresses } = response;
57
+ const ordinalsAccount = addresses === null || addresses === void 0 ? void 0 : addresses.find((address) => address.purpose === AddressPurpose.Ordinals);
58
+ const paymentAccount = addresses === null || addresses === void 0 ? void 0 : addresses.find((address) => address.purpose === AddressPurpose.Payment);
59
+ const mainAddress = (_c = ordinalsAccount === null || ordinalsAccount === void 0 ? void 0 : ordinalsAccount.address) !== null && _c !== void 0 ? _c : paymentAccount === null || paymentAccount === void 0 ? void 0 : paymentAccount.address;
60
+ yield this.setConnectedAccountWithAddresses({
61
+ active: true,
62
+ mainAddress,
63
+ ordinalsAddress: ordinalsAccount,
64
+ paymentAddress: paymentAccount,
65
+ });
66
+ resolve(mainAddress);
67
+ }),
68
+ payload: {
69
+ message: 'Address for receiving Ordinals and payments',
70
+ network: {
71
+ type: this.currentNetwork,
72
+ },
73
+ purposes: [AddressPurpose.Ordinals, AddressPurpose.Payment],
74
+ },
75
+ });
76
+ });
77
+ });
78
+ }
79
+ signMessage(messageToSign, withAddress) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ if (!supportsSatsConnect(this)) {
82
+ return;
83
+ }
84
+ return new Promise((resolve, reject) => {
85
+ signMessage({
86
+ getProvider: () => __awaiter(this, void 0, void 0, function* () {
87
+ var _a, _b;
88
+ return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features[SATSCONNECT_FEATURE]) === null || _b === void 0 ? void 0 : _b.provider;
89
+ }),
90
+ onCancel: () => {
91
+ const error = new Error();
92
+ error.code = '-32000'; // error code for user cancelled
93
+ reject(error);
94
+ },
95
+ onFinish: (response) => __awaiter(this, void 0, void 0, function* () {
96
+ if (this.isHardwareWalletEnabled) {
97
+ return resolve(JSON.stringify({
98
+ signedTransaction: {
99
+ data: response,
100
+ },
101
+ }));
102
+ }
103
+ resolve(response);
104
+ }),
105
+ payload: {
106
+ address: withAddress,
107
+ message: messageToSign,
108
+ network: {
109
+ type: this.currentNetwork,
110
+ },
111
+ },
112
+ });
113
+ });
114
+ });
115
+ }
116
+ sendBitcoin(transaction) {
117
+ return __awaiter(this, void 0, void 0, function* () {
118
+ var _a;
119
+ const mainAddress = yield this.getAddress();
120
+ const senderAddress = (_a = (yield this.getAdditionalAddresses(mainAddress)).find((address) => address.type === 'payment')) === null || _a === void 0 ? void 0 : _a.address;
121
+ if (!senderAddress || !supportsSatsConnect(this)) {
122
+ return;
123
+ }
124
+ return new Promise((resolve, reject) => {
125
+ sendBtcTransaction({
126
+ getProvider: () => __awaiter(this, void 0, void 0, function* () {
127
+ var _a, _b;
128
+ return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features[SATSCONNECT_FEATURE]) === null || _b === void 0 ? void 0 : _b.provider;
129
+ }),
130
+ onCancel: () => {
131
+ const error = new Error();
132
+ error.code = '-32000'; // error code for user cancelled
133
+ reject(error);
134
+ },
135
+ onFinish: (response) => {
136
+ resolve(response);
137
+ },
138
+ payload: {
139
+ network: {
140
+ type: this.currentNetwork,
141
+ },
142
+ recipients: [
143
+ {
144
+ address: transaction.recipientAddress,
145
+ amountSats: transaction.amount,
146
+ },
147
+ ],
148
+ senderAddress,
149
+ },
150
+ });
151
+ });
152
+ });
153
+ }
154
+ signTransaction(params) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ const { message, psbtBase64, broadcast, inputsToSign } = params;
157
+ return new Promise((resolve, reject) => {
158
+ signTransaction({
159
+ getProvider: () => __awaiter(this, void 0, void 0, function* () {
160
+ var _a, _b;
161
+ return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features[SATSCONNECT_FEATURE]) === null || _b === void 0 ? void 0 : _b.provider;
162
+ }),
163
+ onCancel: () => {
164
+ const error = new Error();
165
+ error.code = '-32000'; // error code for user cancelled
166
+ reject(error);
167
+ },
168
+ onFinish: (response) => {
169
+ resolve(response);
170
+ },
171
+ payload: {
172
+ broadcast,
173
+ inputsToSign,
174
+ message: message || 'Sign Transaction',
175
+ network: {
176
+ type: this.currentNetwork,
177
+ },
178
+ psbtBase64,
179
+ },
180
+ });
181
+ });
182
+ });
183
+ }
184
+ signTransactions(transactions) {
185
+ return __awaiter(this, void 0, void 0, function* () {
186
+ const { message, psbts, network } = transactions;
187
+ return new Promise((resolve, reject) => {
188
+ signMultipleTransactions({
189
+ getProvider: () => __awaiter(this, void 0, void 0, function* () {
190
+ var _a, _b;
191
+ return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features[SATSCONNECT_FEATURE]) === null || _b === void 0 ? void 0 : _b.provider;
192
+ }),
193
+ onCancel: () => {
194
+ const error = new Error();
195
+ error.code = '-32000'; // error code for user cancelled
196
+ reject(error);
197
+ },
198
+ onFinish: (response) => {
199
+ resolve(response);
200
+ },
201
+ payload: {
202
+ message: message || 'Sign Transaction',
203
+ network,
204
+ psbts,
205
+ },
206
+ });
207
+ });
208
+ });
209
+ }
210
+ }
211
+
212
+ export { BitcoinSatsConnectLegacyConnector };
@@ -0,0 +1 @@
1
+ export { BitcoinSatsConnectLegacyConnector } from './BitcoinSatsConnectLegacyConnector';
@@ -4,6 +4,7 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var _tslib = require('../../_virtual/_tslib.cjs');
7
+ var satsConnect = require('sats-connect');
7
8
  var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
8
9
  var walletBook = require('@dynamic-labs/wallet-book');
9
10
  var utils = require('@dynamic-labs/utils');
@@ -13,11 +14,13 @@ var bitcoinProviderHelper = require('../bitcoinProviderHelper.cjs');
13
14
  var getMempoolApiUrl = require('../utils/getMempoolApiUrl.cjs');
14
15
  var _const = require('../const.cjs');
15
16
  var satoshisToBtc = require('../utils/satoshisToBtc/satoshisToBtc.cjs');
17
+ var BitcoinWallet = require('../wallet/BitcoinWallet.cjs');
16
18
 
17
19
  class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
18
20
  constructor(opts) {
19
21
  var _a;
20
22
  super(opts);
23
+ this.ChainWallet = BitcoinWallet.BitcoinWallet;
21
24
  this.connectedChain = 'BTC';
22
25
  this.supportedChains = ['BTC'];
23
26
  // some wallets don't support fetching connected accounts without prompting for a connection
@@ -26,12 +29,14 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
26
29
  this.verifiedCredentials = [];
27
30
  // this is the key from the wallet book entry so that we don't purely rely on the normalized name
28
31
  this.overrideKey = (_a = opts.overrideKey) !== null && _a !== void 0 ? _a : this.key;
29
- this.bitcoinProviderHelper = new bitcoinProviderHelper.BitcoinProviderHelper(opts.walletData || walletBook.getWalletBookWallet(this.walletBook, this.key));
32
+ const walletBookWallet = opts.walletData || walletBook.getWalletBookWallet(this.walletBook, this.key);
33
+ this.bitcoinProviderHelper = new bitcoinProviderHelper.BitcoinProviderHelper(walletBookWallet);
30
34
  this.wallet = this.bitcoinProviderHelper.findWallet();
31
35
  if (this.wallet) {
32
36
  this.walletMethods = this.bitcoinProviderHelper.getWalletMethods(this.wallet);
33
37
  }
34
38
  this.cache = new BitcoinLocalStorageCache.BitcoinLocalStorageCache(this.overrideKey);
39
+ this.canFetchConnectedAccounts = walletBook.isWalletMethodSupported(walletBookWallet, 'getConnectedAccounts', 'browserExtension');
35
40
  }
36
41
  isSameAccountChangeRequest(to) {
37
42
  return this.lastAccountChange === to;
@@ -59,34 +64,17 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
59
64
  }
60
65
  endSession() {
61
66
  return _tslib.__awaiter(this, void 0, void 0, function* () {
62
- yield Promise.all([
63
- this.cache.clearConnectedAcccounts(),
64
- this.cache.clearLastBalance(),
65
- ]);
67
+ yield this.cache.clearConnectedAcccounts();
66
68
  });
67
69
  }
68
- getBalance() {
70
+ getBalance(address) {
69
71
  return _tslib.__awaiter(this, void 0, void 0, function* () {
70
- var _a, _b;
71
- const [connectedAddress] = yield this.getConnectedAccounts();
72
- if (!connectedAddress) {
73
- throw new utils.DynamicError('getBalance - No connected address found!');
74
- }
75
- const additionalAddresses = yield this.getAdditionalAddresses(connectedAddress);
76
- const ordinalsAdditionalAddress = (_a = additionalAddresses.find((address) => address.type === sdkApiCore.WalletAddressType.Ordinals)) === null || _a === void 0 ? void 0 : _a.address;
77
- const paymentAdditionalAddress = (_b = additionalAddresses.find((address) => address.type === sdkApiCore.WalletAddressType.Payment)) === null || _b === void 0 ? void 0 : _b.address;
78
- // Some BTC wallet connectors only have 1 address type. when this is the case, it would always be `ordinals`
79
- // if a BTC walletConnector does NOT have a payment address, just use the ordinal address
80
- const paymentAddress = paymentAdditionalAddress !== null && paymentAdditionalAddress !== void 0 ? paymentAdditionalAddress : ordinalsAdditionalAddress;
81
- if (!paymentAddress) {
82
- throw new utils.DynamicError('getBalance - No payment address found!');
83
- }
84
- const API_URL = getMempoolApiUrl.getMempoolApiUrl(paymentAddress);
85
- const response = yield fetch(`${API_URL}/address/${paymentAddress}`);
72
+ const API_URL = getMempoolApiUrl.getMempoolApiUrl(address);
73
+ const response = yield fetch(`${API_URL}/address/${address}`);
86
74
  if (!response.ok) {
87
75
  // if the request fails due to rate limits, return cached value
88
76
  if (response.status === _const.HTTP_STATUS_TOO_MANY_REQUESTS) {
89
- return this.cache.getLastBalance();
77
+ return '0';
90
78
  }
91
79
  // new accounts not yet indexed will return a 404
92
80
  if (response.status === _const.HTTP_STATUS_NOT_FOUND) {
@@ -103,7 +91,6 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
103
91
  const unconfirmedBalanceInSats = Number(addressInfo.mempool_stats.funded_txo_sum) -
104
92
  Number(addressInfo.mempool_stats.spent_txo_sum);
105
93
  const balance = satoshisToBtc.satoshisToBtc(confirmedBalanceInSats + unconfirmedBalanceInSats);
106
- yield this.cache.setLastBalance(balance.toString());
107
94
  return balance.toString();
108
95
  });
109
96
  }
@@ -142,7 +129,7 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
142
129
  connectedAccount = yield this.getAddressPromise;
143
130
  }
144
131
  catch (error) {
145
- walletConnectorCore.logger.error(`${this.key} getConnectedAccounts - error fetching connected account`);
132
+ walletConnectorCore.logger.error(`${this.key} getConnectedAccounts - error fetching connected account`, error);
146
133
  //don't throw error just return empty array after clearing the promise
147
134
  }
148
135
  this.getAddressPromise = undefined;
@@ -170,11 +157,12 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
170
157
  }
171
158
  sendRawTransaction(rawTransaction) {
172
159
  return _tslib.__awaiter(this, void 0, void 0, function* () {
173
- if (!rawTransaction)
174
- return;
160
+ if (!rawTransaction) {
161
+ throw new utils.DynamicError('No transaction specified!');
162
+ }
175
163
  const [connectedAddress] = yield this.getConnectedAccounts();
176
164
  if (!connectedAddress) {
177
- throw new utils.DynamicError('sendRawTransaction - No connected address found!');
165
+ throw new utils.DynamicError('No connected address found!');
178
166
  }
179
167
  const API_URL = getMempoolApiUrl.getMempoolApiUrl(connectedAddress);
180
168
  const response = yield fetch(`${API_URL}/tx`, {
@@ -200,6 +188,18 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
200
188
  var _a;
201
189
  return (_a = this.bitcoinProviderHelper) === null || _a === void 0 ? void 0 : _a.getProvider();
202
190
  }
191
+ signPsbts(requests) {
192
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
193
+ const signedPsbtResponses = [];
194
+ for (const request of requests) {
195
+ const signedPsbtResponse = yield this.signPsbt(request);
196
+ if (signedPsbtResponse) {
197
+ signedPsbtResponses.push(signedPsbtResponse);
198
+ }
199
+ }
200
+ return signedPsbtResponses.map((response) => response.signedPsbt);
201
+ });
202
+ }
203
203
  setConnectedAccountWithAddresses(_a) {
204
204
  return _tslib.__awaiter(this, arguments, void 0, function* ({ mainAddress, ordinalsAddress, paymentAddress, active, }) {
205
205
  if (!mainAddress) {
@@ -234,12 +234,14 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
234
234
  const { handleAccountChange, handleChainChange, handleDisconnect } = walletConnectorCore.eventListenerHandlers(this);
235
235
  const handleBitcoinAccountChange = (accounts) => _tslib.__awaiter(this, void 0, void 0, function* () {
236
236
  let connectedAccounts = accounts;
237
+ let ordinalsAccount, paymentAccount;
237
238
  // if accounts is an array of objects, we need to parse them to return only addresses
238
239
  // since ordinals is the main address we use, we should return it as the first address
239
240
  if (typeof accounts[0] === 'object') {
240
241
  connectedAccounts = accounts
241
- .sort((account) => (account.purpose === 'ordinals' ? -1 : 1))
242
+ .sort((account) => account.purpose === satsConnect.AddressPurpose.Ordinals ? -1 : 1)
242
243
  .map((account) => account.address);
244
+ [ordinalsAccount, paymentAccount] = connectedAccounts;
243
245
  }
244
246
  const currentConnectedAccounts = yield this.getConnectedAccountsFromCache();
245
247
  // don't do anything if the connected accounts haven't changed
@@ -251,6 +253,14 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
251
253
  // set the last account change request with the from and to addresses
252
254
  // to ensure that the requests are not duplicated
253
255
  this.setLastAccountChangeRequest(connectedAccounts[0]);
256
+ if (ordinalsAccount || paymentAccount) {
257
+ this.setConnectedAccountWithAddresses({
258
+ active: true,
259
+ mainAddress: ordinalsAccount !== null && ordinalsAccount !== void 0 ? ordinalsAccount : paymentAccount,
260
+ ordinalsAddress: ordinalsAccount,
261
+ paymentAddress: paymentAccount,
262
+ });
263
+ }
254
264
  handleAccountChange(connectedAccounts);
255
265
  });
256
266
  provider.on('accountsChanged', handleBitcoinAccountChange);
@@ -273,6 +283,11 @@ class BitcoinWalletConnector extends walletConnectorCore.WalletConnectorBase {
273
283
  isLedgerAddress(address) {
274
284
  return utils.isLedgerAddressViaVerifiedCredentials(address, this.verifiedCredentials);
275
285
  }
286
+ proveOwnership(address, messageToSign) {
287
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
288
+ return this.signMessage(messageToSign, address);
289
+ });
290
+ }
276
291
  }
277
292
 
278
293
  exports.BitcoinWalletConnector = BitcoinWalletConnector;
@@ -7,13 +7,15 @@ import { WalletBookSchema, WalletSchema } from '@dynamic-labs/wallet-book';
7
7
  import { JwtVerifiedCredential, WalletAdditionalAddress } from '@dynamic-labs/sdk-api-core';
8
8
  import { IBitcoinSessionCache } from '../BitcoinLocalStorageCache';
9
9
  import { BitcoinTransaction, BitcoinSignPsbtRequest, BitcoinSignPsbtResponse, BitcoinWalletStandardMethods, ConnectedAccountWithAddressesProps } from '../types';
10
+ import { BitcoinWallet } from '../wallet';
10
11
  export type BitcoinWalletConnectorOpts = {
11
12
  walletBook: WalletBookSchema;
12
13
  walletData: WalletSchema;
13
14
  overrideKey?: string;
14
15
  };
15
- export declare abstract class BitcoinWalletConnector extends WalletConnectorBase implements IBitcoinWalletConnector {
16
+ export declare abstract class BitcoinWalletConnector extends WalletConnectorBase<typeof BitcoinWallet> implements IBitcoinWalletConnector {
16
17
  cache: IBitcoinSessionCache;
18
+ ChainWallet: typeof BitcoinWallet;
17
19
  connectedChain: Chain;
18
20
  supportedChains: Chain[];
19
21
  private getAddressPromise;
@@ -32,17 +34,19 @@ export declare abstract class BitcoinWalletConnector extends WalletConnectorBase
32
34
  isInstalledOnBrowser(): boolean;
33
35
  getDeepLink(): string | undefined;
34
36
  endSession(): Promise<void>;
35
- getBalance(): Promise<string | undefined>;
37
+ getBalance(address: string): Promise<string | undefined>;
36
38
  getConnectedAccountsFromCache(): Promise<string[]>;
37
39
  getConnectedAccounts(): Promise<string[]>;
38
40
  getAdditionalAddresses(mainAddress?: string): Promise<WalletAdditionalAddress[]>;
39
41
  setAdditionalAddresses(mainAddress: string, additionalAddresses: WalletAdditionalAddress[]): Promise<void>;
40
- sendRawTransaction(rawTransaction: string): Promise<string | undefined>;
42
+ sendRawTransaction(rawTransaction: string): Promise<string>;
41
43
  abstract sendBitcoin(transaction: BitcoinTransaction): Promise<string | undefined>;
42
44
  getProvider<T>(): T & EventEmitter;
43
45
  abstract signPsbt(request: BitcoinSignPsbtRequest): Promise<BitcoinSignPsbtResponse | undefined>;
46
+ signPsbts(requests: BitcoinSignPsbtRequest[]): Promise<string[] | undefined>;
44
47
  setConnectedAccountWithAddresses({ mainAddress, ordinalsAddress, paymentAddress, active, }: ConnectedAccountWithAddressesProps): Promise<void>;
45
48
  setupEventListeners(): void;
46
49
  setVerifiedCredentials(verifiedCredentials: JwtVerifiedCredential[]): void;
47
50
  isLedgerAddress(address: string): boolean;
51
+ proveOwnership(address: string, messageToSign: string): Promise<string | undefined>;
48
52
  }
@@ -1,7 +1,8 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../_virtual/_tslib.js';
3
+ import { AddressPurpose } from 'sats-connect';
3
4
  import { WalletConnectorBase, eventListenerHandlers, logger } from '@dynamic-labs/wallet-connector-core';
4
- import { getWalletBookWallet, findWalletBookWallet } from '@dynamic-labs/wallet-book';
5
+ import { getWalletBookWallet, isWalletMethodSupported, findWalletBookWallet } from '@dynamic-labs/wallet-book';
5
6
  import { isLedgerAddressViaVerifiedCredentials, DynamicError } from '@dynamic-labs/utils';
6
7
  import { WalletAddressType } from '@dynamic-labs/sdk-api-core';
7
8
  import { BitcoinLocalStorageCache } from '../BitcoinLocalStorageCache.js';
@@ -9,11 +10,13 @@ import { BitcoinProviderHelper } from '../bitcoinProviderHelper.js';
9
10
  import { getMempoolApiUrl } from '../utils/getMempoolApiUrl.js';
10
11
  import { HTTP_STATUS_TOO_MANY_REQUESTS, HTTP_STATUS_NOT_FOUND } from '../const.js';
11
12
  import { satoshisToBtc } from '../utils/satoshisToBtc/satoshisToBtc.js';
13
+ import { BitcoinWallet } from '../wallet/BitcoinWallet.js';
12
14
 
13
15
  class BitcoinWalletConnector extends WalletConnectorBase {
14
16
  constructor(opts) {
15
17
  var _a;
16
18
  super(opts);
19
+ this.ChainWallet = BitcoinWallet;
17
20
  this.connectedChain = 'BTC';
18
21
  this.supportedChains = ['BTC'];
19
22
  // some wallets don't support fetching connected accounts without prompting for a connection
@@ -22,12 +25,14 @@ class BitcoinWalletConnector extends WalletConnectorBase {
22
25
  this.verifiedCredentials = [];
23
26
  // this is the key from the wallet book entry so that we don't purely rely on the normalized name
24
27
  this.overrideKey = (_a = opts.overrideKey) !== null && _a !== void 0 ? _a : this.key;
25
- this.bitcoinProviderHelper = new BitcoinProviderHelper(opts.walletData || getWalletBookWallet(this.walletBook, this.key));
28
+ const walletBookWallet = opts.walletData || getWalletBookWallet(this.walletBook, this.key);
29
+ this.bitcoinProviderHelper = new BitcoinProviderHelper(walletBookWallet);
26
30
  this.wallet = this.bitcoinProviderHelper.findWallet();
27
31
  if (this.wallet) {
28
32
  this.walletMethods = this.bitcoinProviderHelper.getWalletMethods(this.wallet);
29
33
  }
30
34
  this.cache = new BitcoinLocalStorageCache(this.overrideKey);
35
+ this.canFetchConnectedAccounts = isWalletMethodSupported(walletBookWallet, 'getConnectedAccounts', 'browserExtension');
31
36
  }
32
37
  isSameAccountChangeRequest(to) {
33
38
  return this.lastAccountChange === to;
@@ -55,34 +60,17 @@ class BitcoinWalletConnector extends WalletConnectorBase {
55
60
  }
56
61
  endSession() {
57
62
  return __awaiter(this, void 0, void 0, function* () {
58
- yield Promise.all([
59
- this.cache.clearConnectedAcccounts(),
60
- this.cache.clearLastBalance(),
61
- ]);
63
+ yield this.cache.clearConnectedAcccounts();
62
64
  });
63
65
  }
64
- getBalance() {
66
+ getBalance(address) {
65
67
  return __awaiter(this, void 0, void 0, function* () {
66
- var _a, _b;
67
- const [connectedAddress] = yield this.getConnectedAccounts();
68
- if (!connectedAddress) {
69
- throw new DynamicError('getBalance - No connected address found!');
70
- }
71
- const additionalAddresses = yield this.getAdditionalAddresses(connectedAddress);
72
- const ordinalsAdditionalAddress = (_a = additionalAddresses.find((address) => address.type === WalletAddressType.Ordinals)) === null || _a === void 0 ? void 0 : _a.address;
73
- const paymentAdditionalAddress = (_b = additionalAddresses.find((address) => address.type === WalletAddressType.Payment)) === null || _b === void 0 ? void 0 : _b.address;
74
- // Some BTC wallet connectors only have 1 address type. when this is the case, it would always be `ordinals`
75
- // if a BTC walletConnector does NOT have a payment address, just use the ordinal address
76
- const paymentAddress = paymentAdditionalAddress !== null && paymentAdditionalAddress !== void 0 ? paymentAdditionalAddress : ordinalsAdditionalAddress;
77
- if (!paymentAddress) {
78
- throw new DynamicError('getBalance - No payment address found!');
79
- }
80
- const API_URL = getMempoolApiUrl(paymentAddress);
81
- const response = yield fetch(`${API_URL}/address/${paymentAddress}`);
68
+ const API_URL = getMempoolApiUrl(address);
69
+ const response = yield fetch(`${API_URL}/address/${address}`);
82
70
  if (!response.ok) {
83
71
  // if the request fails due to rate limits, return cached value
84
72
  if (response.status === HTTP_STATUS_TOO_MANY_REQUESTS) {
85
- return this.cache.getLastBalance();
73
+ return '0';
86
74
  }
87
75
  // new accounts not yet indexed will return a 404
88
76
  if (response.status === HTTP_STATUS_NOT_FOUND) {
@@ -99,7 +87,6 @@ class BitcoinWalletConnector extends WalletConnectorBase {
99
87
  const unconfirmedBalanceInSats = Number(addressInfo.mempool_stats.funded_txo_sum) -
100
88
  Number(addressInfo.mempool_stats.spent_txo_sum);
101
89
  const balance = satoshisToBtc(confirmedBalanceInSats + unconfirmedBalanceInSats);
102
- yield this.cache.setLastBalance(balance.toString());
103
90
  return balance.toString();
104
91
  });
105
92
  }
@@ -138,7 +125,7 @@ class BitcoinWalletConnector extends WalletConnectorBase {
138
125
  connectedAccount = yield this.getAddressPromise;
139
126
  }
140
127
  catch (error) {
141
- logger.error(`${this.key} getConnectedAccounts - error fetching connected account`);
128
+ logger.error(`${this.key} getConnectedAccounts - error fetching connected account`, error);
142
129
  //don't throw error just return empty array after clearing the promise
143
130
  }
144
131
  this.getAddressPromise = undefined;
@@ -166,11 +153,12 @@ class BitcoinWalletConnector extends WalletConnectorBase {
166
153
  }
167
154
  sendRawTransaction(rawTransaction) {
168
155
  return __awaiter(this, void 0, void 0, function* () {
169
- if (!rawTransaction)
170
- return;
156
+ if (!rawTransaction) {
157
+ throw new DynamicError('No transaction specified!');
158
+ }
171
159
  const [connectedAddress] = yield this.getConnectedAccounts();
172
160
  if (!connectedAddress) {
173
- throw new DynamicError('sendRawTransaction - No connected address found!');
161
+ throw new DynamicError('No connected address found!');
174
162
  }
175
163
  const API_URL = getMempoolApiUrl(connectedAddress);
176
164
  const response = yield fetch(`${API_URL}/tx`, {
@@ -196,6 +184,18 @@ class BitcoinWalletConnector extends WalletConnectorBase {
196
184
  var _a;
197
185
  return (_a = this.bitcoinProviderHelper) === null || _a === void 0 ? void 0 : _a.getProvider();
198
186
  }
187
+ signPsbts(requests) {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ const signedPsbtResponses = [];
190
+ for (const request of requests) {
191
+ const signedPsbtResponse = yield this.signPsbt(request);
192
+ if (signedPsbtResponse) {
193
+ signedPsbtResponses.push(signedPsbtResponse);
194
+ }
195
+ }
196
+ return signedPsbtResponses.map((response) => response.signedPsbt);
197
+ });
198
+ }
199
199
  setConnectedAccountWithAddresses(_a) {
200
200
  return __awaiter(this, arguments, void 0, function* ({ mainAddress, ordinalsAddress, paymentAddress, active, }) {
201
201
  if (!mainAddress) {
@@ -230,12 +230,14 @@ class BitcoinWalletConnector extends WalletConnectorBase {
230
230
  const { handleAccountChange, handleChainChange, handleDisconnect } = eventListenerHandlers(this);
231
231
  const handleBitcoinAccountChange = (accounts) => __awaiter(this, void 0, void 0, function* () {
232
232
  let connectedAccounts = accounts;
233
+ let ordinalsAccount, paymentAccount;
233
234
  // if accounts is an array of objects, we need to parse them to return only addresses
234
235
  // since ordinals is the main address we use, we should return it as the first address
235
236
  if (typeof accounts[0] === 'object') {
236
237
  connectedAccounts = accounts
237
- .sort((account) => (account.purpose === 'ordinals' ? -1 : 1))
238
+ .sort((account) => account.purpose === AddressPurpose.Ordinals ? -1 : 1)
238
239
  .map((account) => account.address);
240
+ [ordinalsAccount, paymentAccount] = connectedAccounts;
239
241
  }
240
242
  const currentConnectedAccounts = yield this.getConnectedAccountsFromCache();
241
243
  // don't do anything if the connected accounts haven't changed
@@ -247,6 +249,14 @@ class BitcoinWalletConnector extends WalletConnectorBase {
247
249
  // set the last account change request with the from and to addresses
248
250
  // to ensure that the requests are not duplicated
249
251
  this.setLastAccountChangeRequest(connectedAccounts[0]);
252
+ if (ordinalsAccount || paymentAccount) {
253
+ this.setConnectedAccountWithAddresses({
254
+ active: true,
255
+ mainAddress: ordinalsAccount !== null && ordinalsAccount !== void 0 ? ordinalsAccount : paymentAccount,
256
+ ordinalsAddress: ordinalsAccount,
257
+ paymentAddress: paymentAccount,
258
+ });
259
+ }
250
260
  handleAccountChange(connectedAccounts);
251
261
  });
252
262
  provider.on('accountsChanged', handleBitcoinAccountChange);
@@ -269,6 +279,11 @@ class BitcoinWalletConnector extends WalletConnectorBase {
269
279
  isLedgerAddress(address) {
270
280
  return isLedgerAddressViaVerifiedCredentials(address, this.verifiedCredentials);
271
281
  }
282
+ proveOwnership(address, messageToSign) {
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ return this.signMessage(messageToSign, address);
285
+ });
286
+ }
272
287
  }
273
288
 
274
289
  export { BitcoinWalletConnector };
@@ -12,7 +12,6 @@ class FallbackBitcoinConnector extends BitcoinWalletConnector.BitcoinWalletConne
12
12
  this.name = 'Fallback Connector';
13
13
  this.overrideKey = 'fallbackconnector';
14
14
  this.isAvailable = false;
15
- this.canFetchConnectedAccounts = false;
16
15
  }
17
16
  getAddress() {
18
17
  return _tslib.__awaiter(this, void 0, void 0, function* () {
@@ -26,6 +25,13 @@ class FallbackBitcoinConnector extends BitcoinWalletConnector.BitcoinWalletConne
26
25
  return;
27
26
  });
28
27
  }
28
+ signPsbts(
29
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
30
+ _requests) {
31
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
32
+ return;
33
+ });
34
+ }
29
35
  sendBitcoin(
30
36
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
37
  _transaction) {
@@ -4,9 +4,9 @@ export declare class FallbackBitcoinConnector extends BitcoinWalletConnector {
4
4
  name: string;
5
5
  overrideKey: string;
6
6
  isAvailable: boolean;
7
- canFetchConnectedAccounts: boolean;
8
7
  constructor(opts: BitcoinWalletConnectorOpts);
9
8
  getAddress(): Promise<string | undefined>;
10
9
  signPsbt(_request: BitcoinSignPsbtRequest): Promise<BitcoinSignPsbtResponse | undefined>;
10
+ signPsbts(_requests: BitcoinSignPsbtRequest[]): Promise<string[] | undefined>;
11
11
  sendBitcoin(_transaction: BitcoinTransaction): Promise<string | undefined>;
12
12
  }
@@ -8,7 +8,6 @@ class FallbackBitcoinConnector extends BitcoinWalletConnector {
8
8
  this.name = 'Fallback Connector';
9
9
  this.overrideKey = 'fallbackconnector';
10
10
  this.isAvailable = false;
11
- this.canFetchConnectedAccounts = false;
12
11
  }
13
12
  getAddress() {
14
13
  return __awaiter(this, void 0, void 0, function* () {
@@ -22,6 +21,13 @@ class FallbackBitcoinConnector extends BitcoinWalletConnector {
22
21
  return;
23
22
  });
24
23
  }
24
+ signPsbts(
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
+ _requests) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ return;
29
+ });
30
+ }
25
31
  sendBitcoin(
26
32
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
27
33
  _transaction) {