@dynamic-labs-sdk/bitcoin 0.1.0-alpha.21 → 0.1.0-alpha.22

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 (24) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/addBitcoinInjectedWalletsExtension.cjs.js +490 -198
  3. package/addBitcoinInjectedWalletsExtension.esm.js +494 -202
  4. package/index.cjs.js +1 -0
  5. package/index.esm.js +1 -0
  6. package/injected.cjs.js +1 -0
  7. package/injected.esm.js +1 -0
  8. package/package.json +5 -4
  9. package/src/injected/addBitcoinInjectedWalletsExtension/addBitcoinInjectedWalletsExtension.d.ts.map +1 -1
  10. package/src/injected/utils/magicEden/createMagicEdenBitcoinWalletProvider/createMagicEdenBitcoinWalletProvider.d.ts +11 -0
  11. package/src/injected/utils/magicEden/createMagicEdenBitcoinWalletProvider/createMagicEdenBitcoinWalletProvider.d.ts.map +1 -0
  12. package/src/injected/utils/magicEden/createMagicEdenBitcoinWalletProvider/index.d.ts +2 -0
  13. package/src/injected/utils/magicEden/createMagicEdenBitcoinWalletProvider/index.d.ts.map +1 -0
  14. package/src/injected/utils/magicEden/getMagicEdenInjectedProvider/getMagicEdenInjectedProvider.d.ts +2 -0
  15. package/src/injected/utils/magicEden/getMagicEdenInjectedProvider/getMagicEdenInjectedProvider.d.ts.map +1 -0
  16. package/src/injected/utils/magicEden/getMagicEdenInjectedProvider/index.d.ts +2 -0
  17. package/src/injected/utils/magicEden/getMagicEdenInjectedProvider/index.d.ts.map +1 -0
  18. package/src/injected/utils/phantom/createPhantomBitcoinWalletProvider/createPhantomBitcoinWalletProvider.d.ts.map +1 -1
  19. package/src/injected/utils/unisat/createUnisatWalletProvider/createUnisatWalletProvider.d.ts.map +1 -1
  20. package/src/injected/utils/xverse/createXverseBitcoinWalletProvider/createXverseBitcoinWalletProvider.d.ts.map +1 -1
  21. package/src/utils/parseBitcoinConnectionResult/index.d.ts +2 -0
  22. package/src/utils/parseBitcoinConnectionResult/index.d.ts.map +1 -0
  23. package/src/utils/parseBitcoinConnectionResult/parseBitcoinConnectionResult.d.ts +12 -0
  24. package/src/utils/parseBitcoinConnectionResult/parseBitcoinConnectionResult.d.ts.map +1 -0
@@ -4,10 +4,11 @@ var core = require('@dynamic-labs-sdk/client/core');
4
4
  var client = require('@dynamic-labs-sdk/client');
5
5
  var sdkApiCore = require('@dynamic-labs/sdk-api-core');
6
6
  var bitcoinjsLib = require('bitcoinjs-lib');
7
+ var jsontokens = require('jsontokens');
7
8
  var satsConnect = require('sats-connect');
8
9
 
9
10
  var name = "@dynamic-labs-sdk/bitcoin";
10
- var version = "0.1.0-alpha.21";
11
+ var version = "0.1.0-alpha.22";
11
12
 
12
13
  function _extends() {
13
14
  _extends = Object.assign || function assign(target) {
@@ -64,6 +65,468 @@ const registerBitcoinNetworkProviderBuilder = (client)=>{
64
65
  });
65
66
  };
66
67
 
68
+ class InvalidPsbtError extends client.BaseError {
69
+ constructor(message){
70
+ super({
71
+ cause: null,
72
+ code: 'invalid_psbt_error',
73
+ docsUrl: null,
74
+ name: 'InvalidPsbtError',
75
+ shortMessage: message
76
+ });
77
+ }
78
+ }
79
+
80
+ const convertNetworkIdForPsbt = (networkId)=>{
81
+ if (networkId === '1') {
82
+ return bitcoinjsLib.networks.bitcoin;
83
+ }
84
+ if (networkId === '2') {
85
+ return bitcoinjsLib.networks.testnet;
86
+ }
87
+ return undefined;
88
+ };
89
+
90
+ const convertNetworkIdToSatsConnectNetworkType = (networkId)=>{
91
+ if (networkId === '2') {
92
+ return satsConnect.BitcoinNetworkType.Testnet;
93
+ }
94
+ // fallback to mainnet
95
+ return satsConnect.BitcoinNetworkType.Mainnet;
96
+ };
97
+
98
+ /**
99
+ * This method will return the signature hash type for the current input.
100
+ * If there is a sighashType, it will return that
101
+ * If there is a witnessUtxo AND it is a taproot address, then it will return SIGHASH_DEFAULT
102
+ * Otherwise, it will return SIGHASH_ALL
103
+ */ const getSigHashType = ({ input })=>{
104
+ var _input_witnessUtxo;
105
+ if (input == null ? void 0 : input.sighashType) {
106
+ return input.sighashType;
107
+ }
108
+ let isTaprootAddress = false;
109
+ if ((_input_witnessUtxo = input.witnessUtxo) == null ? void 0 : _input_witnessUtxo.script) {
110
+ try {
111
+ bitcoinjsLib.payments.p2tr({
112
+ output: input.witnessUtxo.script
113
+ });
114
+ isTaprootAddress = true;
115
+ } catch (e) {
116
+ // do nothing - address is not taproot
117
+ }
118
+ }
119
+ return isTaprootAddress ? bitcoinjsLib.Transaction.SIGHASH_DEFAULT : bitcoinjsLib.Transaction.SIGHASH_ALL;
120
+ };
121
+
122
+ const validateSigHash = ({ allowedSigHashTypes, input })=>{
123
+ const sigHashType = getSigHashType({
124
+ input
125
+ });
126
+ // if the request has allowedSigHashTypes, then we need to make sure that the sigHashType
127
+ // is a member of that array before continuing
128
+ if ((allowedSigHashTypes == null ? void 0 : allowedSigHashTypes.length) && !allowedSigHashTypes.includes(sigHashType)) {
129
+ throw new InvalidPsbtError(`sigHashType ${sigHashType} not in allowed list`);
130
+ }
131
+ };
132
+
133
+ /**
134
+ * This method extracts the address from the input data of the psbt.
135
+ * The address is stored as script (Buffer) in either the witnessUtxo or nonWitnessUtxo as an output
136
+ */ const extractAddressFromInput = ({ index, input, psbt })=>{
137
+ let extractedAddress;
138
+ try {
139
+ var _input_witnessUtxo;
140
+ if ((_input_witnessUtxo = input.witnessUtxo) == null ? void 0 : _input_witnessUtxo.script) {
141
+ extractedAddress = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script);
142
+ }
143
+ if (input.nonWitnessUtxo) {
144
+ const nonWitnessTxn = bitcoinjsLib.Transaction.fromBuffer(input.nonWitnessUtxo);
145
+ const txOut = nonWitnessTxn.outs[psbt.txInputs[index].index];
146
+ extractedAddress = bitcoinjsLib.address.fromOutputScript(txOut.script);
147
+ }
148
+ return extractedAddress;
149
+ } catch (e) {
150
+ return extractedAddress;
151
+ }
152
+ };
153
+
154
+ const validateSigningAddress = ({ index, inputAtIndex, psbt, signingAddress })=>{
155
+ // we need to extract the address from the input at the current signing index
156
+ // to be able to compare it to the address provided in the request for the current index
157
+ const extractedAddress = extractAddressFromInput({
158
+ index,
159
+ input: inputAtIndex,
160
+ psbt
161
+ });
162
+ if (!extractedAddress) {
163
+ throw new InvalidPsbtError(`Could not extract address from input at index ${index}`);
164
+ }
165
+ if (extractedAddress !== signingAddress) {
166
+ throw new InvalidPsbtError(`Signing address does not match with address extracted from input at index ${index}`);
167
+ }
168
+ };
169
+
170
+ /**
171
+ * This method will validate the psbt against the signature data provided in the request
172
+ * It checks 3 things:
173
+ * - That the signing index exists in the input
174
+ * - That the address provided in the request matches the address in the input,
175
+ * unless the disableAddressValidation flag is set
176
+ * - That the sigHashType of the input is a member of the allowedSigHashTypes array
177
+ */ const validatePsbt = ({ allowedSigHashTypes, psbt, signatureData })=>{
178
+ if (!(signatureData == null ? void 0 : signatureData.length)) {
179
+ return;
180
+ }
181
+ for (const input of signatureData){
182
+ const { address: signingAddress, signingIndexes, // request from ME in cases of multi-sig. Steven wanted this defaulted to true
183
+ disableAddressValidation = true } = input;
184
+ if (!(signingIndexes == null ? void 0 : signingIndexes.length)) {
185
+ return;
186
+ }
187
+ if (!signingAddress) {
188
+ throw new InvalidPsbtError('Missing signing address');
189
+ }
190
+ for (const index of signingIndexes){
191
+ const inputAtIndex = psbt.data.inputs[index];
192
+ if (!inputAtIndex) {
193
+ throw new InvalidPsbtError(`Missing input for index ${index}`);
194
+ }
195
+ if (!disableAddressValidation) {
196
+ validateSigningAddress({
197
+ index,
198
+ inputAtIndex,
199
+ psbt,
200
+ signingAddress
201
+ });
202
+ }
203
+ validateSigHash({
204
+ allowedSigHashTypes,
205
+ input: inputAtIndex
206
+ });
207
+ }
208
+ }
209
+ };
210
+
211
+ /**
212
+ * This method will create the psbt sign options for SatsConnect for the given request
213
+ * It will validate the psbt against the signature data provided in the request
214
+ * It will return the inputs to sign if the signature data is provided
215
+ */ const getPsbtInputsToSignForSatsConnect = ({ psbt, request, isLegacySatsConnect })=>{
216
+ if (!request.signature) {
217
+ return [];
218
+ }
219
+ validatePsbt({
220
+ allowedSigHashTypes: request.allowedSighash,
221
+ psbt,
222
+ signatureData: request.signature
223
+ });
224
+ const inputsToSign = [];
225
+ for (const signature of request.signature){
226
+ var _signature_signingIndexes;
227
+ if ((_signature_signingIndexes = signature.signingIndexes) == null ? void 0 : _signature_signingIndexes.length) {
228
+ for (const index of signature.signingIndexes){
229
+ inputsToSign.push({
230
+ address: signature.address,
231
+ sigHash: isLegacySatsConnect ? getSigHashType({
232
+ input: psbt.data.inputs[index]
233
+ }) : request.allowedSighash[0],
234
+ signingIndexes: [
235
+ index
236
+ ]
237
+ });
238
+ }
239
+ }
240
+ }
241
+ return inputsToSign;
242
+ };
243
+
244
+ const getSatsConnectSigningProtocol = (protocol)=>{
245
+ if (!protocol) {
246
+ return undefined;
247
+ }
248
+ return protocol === 'ecdsa' ? satsConnect.MessageSigningProtocols.ECDSA : satsConnect.MessageSigningProtocols.BIP322;
249
+ };
250
+
251
+ const parseBitcoinConnectionResult = ({ connectedAddresses })=>{
252
+ // Xverse will return other addresses/types that we don't support
253
+ // so we filter them out
254
+ const filteredAddresses = connectedAddresses.filter((address)=>address.purpose === 'ordinals' || address.purpose === 'payment');
255
+ const addresses = filteredAddresses.map((account)=>({
256
+ address: account.address,
257
+ publicKey: account.publicKey,
258
+ type: account.purpose === 'payment' ? 'payment' : 'ordinals'
259
+ }));
260
+ // put ordinals addresses first, as they should be the main walletAccount address
261
+ addresses.sort((a)=>a.type === 'ordinals' ? -1 : 1);
262
+ return {
263
+ addresses
264
+ };
265
+ };
266
+
267
+ const MAGIC_EDEN_METADATA = {
268
+ displayName: 'Magic Eden',
269
+ icon: `${core.DYNAMIC_ICONIC_SPRITE_URL}#magiceden`
270
+ };
271
+ // https://docs-wallet.magiceden.io/bitcoin/detecting-the-provider
272
+ const createMagicEdenBitcoinWalletProvider = ({ dynamicClient, satsConnectProvider })=>{
273
+ const chain = 'BTC';
274
+ const walletProviderType = sdkApiCore.WalletProviderEnum.BrowserExtension;
275
+ const key = core.formatWalletProviderKey({
276
+ chain,
277
+ displayName: MAGIC_EDEN_METADATA.displayName,
278
+ walletProviderType
279
+ });
280
+ const getNetworkPayload = async ()=>{
281
+ const activeNetworkId = await getActiveNetworkId();
282
+ const networkType = convertNetworkIdToSatsConnectNetworkType(activeNetworkId.networkId);
283
+ return {
284
+ network: {
285
+ type: networkType
286
+ }
287
+ };
288
+ };
289
+ const connect = async ()=>{
290
+ const { network } = await getNetworkPayload();
291
+ return new Promise((resolve, reject)=>{
292
+ void satsConnect.getAddress({
293
+ getProvider: async ()=>satsConnectProvider,
294
+ onCancel: ()=>{
295
+ reject(new client.UserRejectedError({
296
+ action: 'connect'
297
+ }));
298
+ },
299
+ onFinish: async (response)=>{
300
+ const { addresses: connectedAddresses } = response;
301
+ const { addresses } = parseBitcoinConnectionResult({
302
+ connectedAddresses
303
+ });
304
+ resolve({
305
+ addresses
306
+ });
307
+ },
308
+ payload: {
309
+ message: 'Address for receiving Ordinals and payments',
310
+ network,
311
+ purposes: [
312
+ satsConnect.AddressPurpose.Ordinals,
313
+ satsConnect.AddressPurpose.Payment
314
+ ]
315
+ }
316
+ });
317
+ });
318
+ };
319
+ const getActiveNetworkId = async ()=>core.getActiveNetworkIdFromLastKnownRegistry({
320
+ client: dynamicClient,
321
+ walletProviderKey: key
322
+ });
323
+ // there's no specific method to get connected addresses in Magic Eden
324
+ // so we use the connect method to get the addresses
325
+ const getConnectedAddresses = async ()=>{
326
+ const { addresses } = await connect();
327
+ return {
328
+ addresses: addresses.map((address)=>address.address)
329
+ };
330
+ };
331
+ const sendBitcoin = async ({ transaction, walletAccount })=>{
332
+ await client.assertWalletAccountSigningAvailability({
333
+ walletAccount
334
+ }, dynamicClient);
335
+ var _getWalletAccountAddressByType;
336
+ // should use payment address if available
337
+ const senderAddress = (_getWalletAccountAddressByType = client.getWalletAccountAddressByType({
338
+ type: 'payment',
339
+ walletAccount
340
+ })) != null ? _getWalletAccountAddressByType : walletAccount.address;
341
+ const { network } = await getNetworkPayload();
342
+ return new Promise((resolve, reject)=>{
343
+ void satsConnect.sendBtcTransaction({
344
+ getProvider: async ()=>satsConnectProvider,
345
+ onCancel: ()=>{
346
+ reject(new client.UserRejectedError({
347
+ action: 'sendBitcoin'
348
+ }));
349
+ },
350
+ onFinish: (response)=>{
351
+ resolve({
352
+ transactionId: response
353
+ });
354
+ },
355
+ payload: {
356
+ network,
357
+ recipients: [
358
+ {
359
+ address: transaction.recipientAddress,
360
+ amountSats: BigInt(transaction.amount)
361
+ }
362
+ ],
363
+ senderAddress
364
+ }
365
+ });
366
+ });
367
+ };
368
+ const signMessage = async ({ message, walletAccount, protocol, addressType })=>{
369
+ core.assertDefined(walletAccount, 'Wallet account not found');
370
+ await client.assertWalletAccountSigningAvailability({
371
+ walletAccount
372
+ }, dynamicClient);
373
+ const { network } = await getNetworkPayload();
374
+ let addressToSignWith = walletAccount.address;
375
+ if (addressType) {
376
+ var _getWalletAccountAddressByType;
377
+ addressToSignWith = (_getWalletAccountAddressByType = client.getWalletAccountAddressByType({
378
+ type: addressType,
379
+ walletAccount
380
+ })) != null ? _getWalletAccountAddressByType : addressToSignWith;
381
+ }
382
+ return new Promise((resolve, reject)=>{
383
+ void satsConnect.signMessage({
384
+ getProvider: async ()=>satsConnectProvider,
385
+ onCancel: ()=>{
386
+ reject(new client.UserRejectedError({
387
+ action: 'signMessage'
388
+ }));
389
+ },
390
+ onFinish: async (response)=>{
391
+ resolve({
392
+ signature: response
393
+ });
394
+ },
395
+ payload: {
396
+ address: addressToSignWith,
397
+ message: message,
398
+ network,
399
+ protocol: getSatsConnectSigningProtocol(protocol)
400
+ }
401
+ });
402
+ });
403
+ };
404
+ const signPsbt = async ({ request, walletAccount })=>{
405
+ if (!request.allowedSighash.length) {
406
+ throw new InvalidPsbtError('allowedSighash cannot be an empty array');
407
+ }
408
+ await client.assertWalletAccountSigningAvailability({
409
+ walletAccount
410
+ }, dynamicClient);
411
+ const activeNetworkId = await getActiveNetworkId();
412
+ const network = convertNetworkIdForPsbt(activeNetworkId.networkId);
413
+ const { network: networkPayload } = await getNetworkPayload();
414
+ const psbtFromBase64 = bitcoinjsLib.Psbt.fromBase64(request.unsignedPsbtBase64, {
415
+ network
416
+ });
417
+ const inputsToSign = getPsbtInputsToSignForSatsConnect({
418
+ isLegacySatsConnect: true,
419
+ psbt: psbtFromBase64,
420
+ request
421
+ });
422
+ return new Promise((resolve, reject)=>{
423
+ void satsConnect.signTransaction({
424
+ getProvider: async ()=>satsConnectProvider,
425
+ onCancel: ()=>{
426
+ reject(new client.UserRejectedError({
427
+ action: 'signPsbt'
428
+ }));
429
+ },
430
+ onFinish: (response)=>{
431
+ resolve({
432
+ signedPsbt: response.psbtBase64
433
+ });
434
+ },
435
+ payload: {
436
+ broadcast: false,
437
+ inputsToSign,
438
+ message: 'Sign Pbst',
439
+ network: networkPayload,
440
+ psbtBase64: request.unsignedPsbtBase64
441
+ }
442
+ });
443
+ });
444
+ };
445
+ const signPsbts = async ({ requests, walletAccount })=>{
446
+ await client.assertWalletAccountSigningAvailability({
447
+ walletAccount
448
+ }, dynamicClient);
449
+ const activeNetworkId = await getActiveNetworkId();
450
+ const network = convertNetworkIdForPsbt(activeNetworkId.networkId);
451
+ const { network: networkPayload } = await getNetworkPayload();
452
+ const psbtsToSign = [];
453
+ for (const request of requests){
454
+ const psbtFromBase64 = bitcoinjsLib.Psbt.fromBase64(request.unsignedPsbtBase64, {
455
+ network
456
+ });
457
+ const inputsToSign = getPsbtInputsToSignForSatsConnect({
458
+ isLegacySatsConnect: true,
459
+ psbt: psbtFromBase64,
460
+ request
461
+ });
462
+ psbtsToSign.push({
463
+ inputsToSign,
464
+ psbtBase64: request.unsignedPsbtBase64
465
+ });
466
+ }
467
+ const signMultipleTransactionPayload = {
468
+ message: 'Sign Pbsts',
469
+ network: networkPayload,
470
+ psbts: psbtsToSign
471
+ };
472
+ // Magic Eden has implemented their own signTransactions feature, and have requested us
473
+ // to ensure we use it rather than the general Sats Connect API for this method
474
+ const request = jsontokens.createUnsecuredToken(signMultipleTransactionPayload);
475
+ const response = await satsConnectProvider.signMultipleTransactions(request);
476
+ return {
477
+ signedPsbts: response.map((response)=>response.psbtBase64)
478
+ };
479
+ };
480
+ const { getEventEmitter, cleanupEventEmitter } = core.createWalletProviderEventEmitter({
481
+ removeEventListeners: ({ setupReturnValue })=>{
482
+ core.assertDefined(setupReturnValue, 'Setup return value not defined');
483
+ setupReturnValue.removeAccountChangeListener();
484
+ },
485
+ setupEventListeners: ({ handleAccountsChanged })=>{
486
+ const removeAccountChangeListener = satsConnect.addListener('accountsChanged', (accounts)=>{
487
+ if (!accounts) {
488
+ return;
489
+ }
490
+ handleAccountsChanged({
491
+ addresses: accounts.map((account)=>account.address)
492
+ });
493
+ });
494
+ return {
495
+ removeAccountChangeListener
496
+ };
497
+ },
498
+ supportedEvents: [
499
+ 'accountsChanged'
500
+ ]
501
+ });
502
+ const terminate = async ()=>{
503
+ cleanupEventEmitter();
504
+ };
505
+ return {
506
+ chain,
507
+ connect,
508
+ get events () {
509
+ return getEventEmitter();
510
+ },
511
+ getActiveNetworkId,
512
+ getConnectedAddresses,
513
+ groupKey: core.formatWalletProviderGroupKey(MAGIC_EDEN_METADATA.displayName),
514
+ key,
515
+ metadata: MAGIC_EDEN_METADATA,
516
+ sendBitcoin,
517
+ signMessage,
518
+ signPsbt,
519
+ signPsbts,
520
+ terminate,
521
+ walletProviderType
522
+ };
523
+ };
524
+
525
+ const MAGIC_EDEN_BITCOIN_PROVIDER_LOCATOR = 'magicEden.bitcoin';
526
+ const getMagicEdenInjectedProvider = ()=>{
527
+ return core.getInjectedProviderFromWindow(MAGIC_EDEN_BITCOIN_PROVIDER_LOCATOR);
528
+ };
529
+
67
530
  const PHANTOM_METADATA = {
68
531
  displayName: 'Phantom',
69
532
  icon: `${core.DYNAMIC_ICONIC_SPRITE_URL}#phantom`
@@ -169,7 +632,10 @@ const createPhantomBitcoinWalletProvider = ({ dynamicClient, injectedProvider })
169
632
  addresses: accounts.map((account)=>account.address)
170
633
  });
171
634
  });
172
- }
635
+ },
636
+ supportedEvents: [
637
+ 'accountsChanged'
638
+ ]
173
639
  });
174
640
  const terminate = async ()=>{
175
641
  cleanupEventEmitter();
@@ -198,131 +664,6 @@ const getPhantomInjectedProvider = ()=>{
198
664
  return core.getInjectedProviderFromWindow(PHANTOM_BITCOIN_PROVIDER_LOCATOR);
199
665
  };
200
666
 
201
- class InvalidPsbtError extends client.BaseError {
202
- constructor(message){
203
- super({
204
- cause: null,
205
- code: 'invalid_psbt_error',
206
- docsUrl: null,
207
- name: 'InvalidPsbtError',
208
- shortMessage: message
209
- });
210
- }
211
- }
212
-
213
- /**
214
- * This method will return the signature hash type for the current input.
215
- * If there is a sighashType, it will return that
216
- * If there is a witnessUtxo AND it is a taproot address, then it will return SIGHASH_DEFAULT
217
- * Otherwise, it will return SIGHASH_ALL
218
- */ const getSigHashType = ({ input })=>{
219
- var _input_witnessUtxo;
220
- if (input == null ? void 0 : input.sighashType) {
221
- return input.sighashType;
222
- }
223
- let isTaprootAddress = false;
224
- if ((_input_witnessUtxo = input.witnessUtxo) == null ? void 0 : _input_witnessUtxo.script) {
225
- try {
226
- bitcoinjsLib.payments.p2tr({
227
- output: input.witnessUtxo.script
228
- });
229
- isTaprootAddress = true;
230
- } catch (e) {
231
- // do nothing - address is not taproot
232
- }
233
- }
234
- return isTaprootAddress ? bitcoinjsLib.Transaction.SIGHASH_DEFAULT : bitcoinjsLib.Transaction.SIGHASH_ALL;
235
- };
236
-
237
- const validateSigHash = ({ allowedSigHashTypes, input })=>{
238
- const sigHashType = getSigHashType({
239
- input
240
- });
241
- // if the request has allowedSigHashTypes, then we need to make sure that the sigHashType
242
- // is a member of that array before continuing
243
- if ((allowedSigHashTypes == null ? void 0 : allowedSigHashTypes.length) && !allowedSigHashTypes.includes(sigHashType)) {
244
- throw new InvalidPsbtError(`sigHashType ${sigHashType} not in allowed list`);
245
- }
246
- };
247
-
248
- /**
249
- * This method extracts the address from the input data of the psbt.
250
- * The address is stored as script (Buffer) in either the witnessUtxo or nonWitnessUtxo as an output
251
- */ const extractAddressFromInput = ({ index, input, psbt })=>{
252
- let extractedAddress;
253
- try {
254
- var _input_witnessUtxo;
255
- if ((_input_witnessUtxo = input.witnessUtxo) == null ? void 0 : _input_witnessUtxo.script) {
256
- extractedAddress = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script);
257
- }
258
- if (input.nonWitnessUtxo) {
259
- const nonWitnessTxn = bitcoinjsLib.Transaction.fromBuffer(input.nonWitnessUtxo);
260
- const txOut = nonWitnessTxn.outs[psbt.txInputs[index].index];
261
- extractedAddress = bitcoinjsLib.address.fromOutputScript(txOut.script);
262
- }
263
- return extractedAddress;
264
- } catch (e) {
265
- return extractedAddress;
266
- }
267
- };
268
-
269
- const validateSigningAddress = ({ index, inputAtIndex, psbt, signingAddress })=>{
270
- // we need to extract the address from the input at the current signing index
271
- // to be able to compare it to the address provided in the request for the current index
272
- const extractedAddress = extractAddressFromInput({
273
- index,
274
- input: inputAtIndex,
275
- psbt
276
- });
277
- if (!extractedAddress) {
278
- throw new InvalidPsbtError(`Could not extract address from input at index ${index}`);
279
- }
280
- if (extractedAddress !== signingAddress) {
281
- throw new InvalidPsbtError(`Signing address does not match with address extracted from input at index ${index}`);
282
- }
283
- };
284
-
285
- /**
286
- * This method will validate the psbt against the signature data provided in the request
287
- * It checks 3 things:
288
- * - That the signing index exists in the input
289
- * - That the address provided in the request matches the address in the input,
290
- * unless the disableAddressValidation flag is set
291
- * - That the sigHashType of the input is a member of the allowedSigHashTypes array
292
- */ const validatePsbt = ({ allowedSigHashTypes, psbt, signatureData })=>{
293
- if (!(signatureData == null ? void 0 : signatureData.length)) {
294
- return;
295
- }
296
- for (const input of signatureData){
297
- const { address: signingAddress, signingIndexes, // request from ME in cases of multi-sig. Steven wanted this defaulted to true
298
- disableAddressValidation = true } = input;
299
- if (!(signingIndexes == null ? void 0 : signingIndexes.length)) {
300
- return;
301
- }
302
- if (!signingAddress) {
303
- throw new InvalidPsbtError('Missing signing address');
304
- }
305
- for (const index of signingIndexes){
306
- const inputAtIndex = psbt.data.inputs[index];
307
- if (!inputAtIndex) {
308
- throw new InvalidPsbtError(`Missing input for index ${index}`);
309
- }
310
- if (!disableAddressValidation) {
311
- validateSigningAddress({
312
- index,
313
- inputAtIndex,
314
- psbt,
315
- signingAddress
316
- });
317
- }
318
- validateSigHash({
319
- allowedSigHashTypes,
320
- input: inputAtIndex
321
- });
322
- }
323
- }
324
- };
325
-
326
667
  /**
327
668
  * This method will create the psbt sign options for the given request
328
669
  * It will validate the psbt against the signature data provided in the request
@@ -456,7 +797,11 @@ const createUnisatWalletProvider = ({ dynamicClient, injectedProvider })=>{
456
797
  networkId: network
457
798
  });
458
799
  });
459
- }
800
+ },
801
+ supportedEvents: [
802
+ 'accountsChanged',
803
+ 'networkChanged'
804
+ ]
460
805
  });
461
806
  const terminate = async ()=>{
462
807
  cleanupEventEmitter();
@@ -487,64 +832,6 @@ const getUnisatInjectedProvider = ()=>{
487
832
  return core.getInjectedProviderFromWindow(UNISAT_PROVIDER_LOCATOR);
488
833
  };
489
834
 
490
- const convertNetworkIdForPsbt = (networkId)=>{
491
- if (networkId === '1') {
492
- return bitcoinjsLib.networks.bitcoin;
493
- }
494
- if (networkId === '2') {
495
- return bitcoinjsLib.networks.testnet;
496
- }
497
- return undefined;
498
- };
499
-
500
- const convertNetworkIdToSatsConnectNetworkType = (networkId)=>{
501
- if (networkId === '2') {
502
- return satsConnect.BitcoinNetworkType.Testnet;
503
- }
504
- // fallback to mainnet
505
- return satsConnect.BitcoinNetworkType.Mainnet;
506
- };
507
-
508
- /**
509
- * This method will create the psbt sign options for SatsConnect for the given request
510
- * It will validate the psbt against the signature data provided in the request
511
- * It will return the inputs to sign if the signature data is provided
512
- */ const getPsbtInputsToSignForSatsConnect = ({ psbt, request, isLegacySatsConnect })=>{
513
- if (!request.signature) {
514
- return [];
515
- }
516
- validatePsbt({
517
- allowedSigHashTypes: request.allowedSighash,
518
- psbt,
519
- signatureData: request.signature
520
- });
521
- const inputsToSign = [];
522
- for (const signature of request.signature){
523
- var _signature_signingIndexes;
524
- if ((_signature_signingIndexes = signature.signingIndexes) == null ? void 0 : _signature_signingIndexes.length) {
525
- for (const index of signature.signingIndexes){
526
- inputsToSign.push({
527
- address: signature.address,
528
- sigHash: isLegacySatsConnect ? getSigHashType({
529
- input: psbt.data.inputs[index]
530
- }) : request.allowedSighash[0],
531
- signingIndexes: [
532
- index
533
- ]
534
- });
535
- }
536
- }
537
- }
538
- return inputsToSign;
539
- };
540
-
541
- const getSatsConnectSigningProtocol = (protocol)=>{
542
- if (!protocol) {
543
- return undefined;
544
- }
545
- return protocol === 'ecdsa' ? satsConnect.MessageSigningProtocols.ECDSA : satsConnect.MessageSigningProtocols.BIP322;
546
- };
547
-
548
835
  const signMultipleTransactionsWithSatsConnect = async ({ network, psbts, provider })=>{
549
836
  const response = await new Promise((resolve, reject)=>{
550
837
  void satsConnect.signMultipleTransactions({
@@ -598,16 +885,9 @@ const createXverseBitcoinWalletProvider = ({ dynamicClient, satsConnectProvider
598
885
  throw response.error;
599
886
  }
600
887
  const { addresses: connectedAddresses } = response.result;
601
- // Xverse will return other addresses/types that we don't support
602
- // so we filter them out
603
- const filteredAddresses = connectedAddresses.filter((address)=>address.purpose === 'ordinals' || address.purpose === 'payment');
604
- const addresses = filteredAddresses.map((account)=>({
605
- address: account.address,
606
- publicKey: account.publicKey,
607
- type: account.purpose === 'payment' ? 'payment' : 'ordinals'
608
- }));
609
- // put ordinals addresses first, as they should be the main walletAccount address
610
- addresses.sort((a)=>a.type === 'ordinals' ? -1 : 1);
888
+ const { addresses } = parseBitcoinConnectionResult({
889
+ connectedAddresses
890
+ });
611
891
  return {
612
892
  addresses
613
893
  };
@@ -769,7 +1049,11 @@ const createXverseBitcoinWalletProvider = ({ dynamicClient, satsConnectProvider
769
1049
  accountDisconnectedListener,
770
1050
  removeAccountChangeListener
771
1051
  };
772
- }
1052
+ },
1053
+ supportedEvents: [
1054
+ 'accountsChanged',
1055
+ 'disconnected'
1056
+ ]
773
1057
  });
774
1058
  const terminate = async ()=>{
775
1059
  cleanupEventEmitter();
@@ -846,7 +1130,15 @@ const BITCOIN_INJECTED_WALLETS_EXTENSION_KEY = 'bitcoinInjectedWallets';
846
1130
  });
847
1131
  injectedWalletProviders.push(xverseWalletProvider);
848
1132
  }
849
- // TODO: create and register MagicEden wallet provider
1133
+ // Create and register MagicEden wallet provider
1134
+ const magicEdenInjectedProvider = getMagicEdenInjectedProvider();
1135
+ if (magicEdenInjectedProvider) {
1136
+ const magicEdenWalletProvider = createMagicEdenBitcoinWalletProvider({
1137
+ dynamicClient: client,
1138
+ satsConnectProvider: magicEdenInjectedProvider
1139
+ });
1140
+ injectedWalletProviders.push(magicEdenWalletProvider);
1141
+ }
850
1142
  // TODO: create and register OKX wallet provider
851
1143
  // TODO: create and register Bitget wallet provider
852
1144
  // TODO: create and register OneKey wallet provider