@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.
- package/CHANGELOG.md +622 -0
- package/package.json +7 -6
- package/src/BitcoinLocalStorageCache.cjs +0 -16
- package/src/BitcoinLocalStorageCache.d.ts +0 -7
- package/src/BitcoinLocalStorageCache.js +0 -16
- package/src/bitcoinProviderHelper.d.ts +1 -0
- package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.cjs +170 -141
- package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.d.ts +8 -3
- package/src/connectors/BitcoinSatsConnectConnector/BitcoinSatsConnectConnector.js +171 -142
- package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.cjs +216 -0
- package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.d.ts +11 -0
- package/src/connectors/BitcoinSatsConnectLegacyConnector/BitcoinSatsConnectLegacyConnector.js +212 -0
- package/src/connectors/BitcoinSatsConnectLegacyConnector/index.d.ts +1 -0
- package/src/connectors/BitcoinWalletConnector.cjs +44 -29
- package/src/connectors/BitcoinWalletConnector.d.ts +7 -3
- package/src/connectors/BitcoinWalletConnector.js +45 -30
- package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.cjs +7 -1
- package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.d.ts +1 -1
- package/src/connectors/FallbackBitcoinConnector/FallbackBitcoinConnector.js +7 -1
- package/src/connectors/OkxConnector/OkxConnector.cjs +19 -2
- package/src/connectors/OkxConnector/OkxConnector.d.ts +1 -1
- package/src/connectors/OkxConnector/OkxConnector.js +19 -2
- package/src/connectors/PhantomConnector/PhantomConnector.cjs +4 -9
- package/src/connectors/PhantomConnector/PhantomConnector.d.ts +1 -2
- package/src/connectors/PhantomConnector/PhantomConnector.js +4 -9
- package/src/connectors/UnisatConnector/UnisatConnector.cjs +17 -1
- package/src/connectors/UnisatConnector/UnisatConnector.d.ts +1 -1
- package/src/connectors/UnisatConnector/UnisatConnector.js +17 -1
- package/src/connectors/UnknownInjected/UnknownInjected.cjs +7 -1
- package/src/connectors/UnknownInjected/UnknownInjected.d.ts +1 -1
- package/src/connectors/UnknownInjected/UnknownInjected.js +7 -1
- package/src/connectors/index.d.ts +1 -0
- package/src/index.cjs +4 -0
- package/src/index.d.ts +3 -2
- package/src/index.js +2 -0
- package/src/types.d.ts +1 -0
- package/src/utils/fetchSatsConnectConnectors/fetchSatsConnectConnectors.cjs +15 -3
- package/src/utils/fetchSatsConnectConnectors/fetchSatsConnectConnectors.js +15 -3
- package/src/utils/psbt/bitcoinNetworkTypeToNetworks.cjs +1 -0
- package/src/utils/psbt/bitcoinNetworkTypeToNetworks.d.ts +1 -1
- package/src/utils/psbt/bitcoinNetworkTypeToNetworks.js +1 -0
- package/src/utils/psbt/createSignPsbtOptions.cjs +22 -1
- package/src/utils/psbt/createSignPsbtOptions.d.ts +2 -0
- package/src/utils/psbt/createSignPsbtOptions.js +22 -2
- package/src/wallet/BitcoinWallet.cjs +69 -0
- package/src/wallet/BitcoinWallet.d.ts +36 -0
- package/src/wallet/BitcoinWallet.js +65 -0
- package/src/wallet/index.d.ts +2 -0
- package/src/wallet/isBitcoinWallet/index.d.ts +1 -0
- package/src/wallet/isBitcoinWallet/isBitcoinWallet.cjs +8 -0
- package/src/wallet/isBitcoinWallet/isBitcoinWallet.d.ts +3 -0
- 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
|
-
|
|
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
|
|
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
|
-
|
|
71
|
-
const
|
|
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
|
|
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
|
-
|
|
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('
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
67
|
-
const
|
|
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
|
|
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
|
-
|
|
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('
|
|
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) =>
|
|
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) {
|