@satoshai/kit 0.1.1 → 0.3.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WalletConnect, setSelectedProviderId, request, getSelectedProvider, clearSelectedProviderId } from '@stacks/connect';
2
- import { createContext, useState, useEffect, useCallback, useMemo, useContext } from 'react';
2
+ import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
  import { PostConditionMode, postConditionToHex, cvToHex } from '@stacks/transactions';
5
5
  import { getPrimaryName } from 'bns-v2-sdk';
@@ -160,15 +160,18 @@ var useXverse = ({
160
160
  }, [provider]);
161
161
  useEffect(() => {
162
162
  if (provider !== "xverse" || !address || !isProviderReady) return;
163
+ let cancelled = false;
163
164
  let removeListener;
164
165
  const setupXverse = async () => {
165
166
  try {
166
167
  const productInfo = await getXverseProductInfo();
168
+ if (cancelled) return;
167
169
  if (!shouldSupportAccountChange(productInfo?.version)) return;
168
170
  const response = await getSelectedProvider()?.request(
169
171
  "wallet_connect",
170
172
  null
171
173
  );
174
+ if (cancelled) return;
172
175
  extractAndValidateStacksAddress(
173
176
  response?.result?.addresses,
174
177
  address,
@@ -192,6 +195,7 @@ var useXverse = ({
192
195
  };
193
196
  void setupXverse();
194
197
  return () => {
198
+ cancelled = true;
195
199
  if (!removeListener) return;
196
200
  try {
197
201
  removeListener();
@@ -222,6 +226,7 @@ var StacksWalletContext = createContext(
222
226
  );
223
227
  var StacksWalletProvider = ({
224
228
  children,
229
+ wallets,
225
230
  walletConnect,
226
231
  onConnect,
227
232
  onAddressChange,
@@ -230,6 +235,16 @@ var StacksWalletProvider = ({
230
235
  const [address, setAddress] = useState();
231
236
  const [provider, setProvider] = useState();
232
237
  const [isConnecting, setIsConnecting] = useState(false);
238
+ const connectGenRef = useRef(0);
239
+ const wcInitRef = useRef(null);
240
+ const walletsKey = wallets?.join(",");
241
+ useEffect(() => {
242
+ if (wallets?.includes("wallet-connect") && !walletConnect?.projectId) {
243
+ throw new Error(
244
+ 'StacksWalletProvider: "wallet-connect" is listed in wallets but no walletConnect.projectId was provided.'
245
+ );
246
+ }
247
+ }, [walletsKey, walletConnect?.projectId]);
233
248
  useEffect(() => {
234
249
  const loadPersistedWallet = async () => {
235
250
  const persisted = getLocalStorageWallet();
@@ -242,6 +257,18 @@ var StacksWalletProvider = ({
242
257
  setProvider(data.provider);
243
258
  return;
244
259
  }
260
+ if (persisted.provider === "wallet-connect" && walletConnect?.projectId) {
261
+ const initPromise = WalletConnect.initializeProvider(
262
+ buildWalletConnectConfig(
263
+ walletConnect.projectId,
264
+ walletConnect.metadata,
265
+ walletConnect.chains
266
+ )
267
+ );
268
+ wcInitRef.current = initPromise;
269
+ await initPromise;
270
+ wcInitRef.current = null;
271
+ }
245
272
  setAddress(persisted.address);
246
273
  setProvider(persisted.provider);
247
274
  setSelectedProviderId(
@@ -254,7 +281,7 @@ var StacksWalletProvider = ({
254
281
  }
255
282
  };
256
283
  void loadPersistedWallet();
257
- }, []);
284
+ }, [walletConnect?.projectId]);
258
285
  const connect = useCallback(
259
286
  async (providerId, options) => {
260
287
  const typedProvider = SUPPORTED_STACKS_WALLETS.find(
@@ -284,10 +311,12 @@ var StacksWalletProvider = ({
284
311
  options?.onError?.(error);
285
312
  return;
286
313
  }
314
+ const gen = ++connectGenRef.current;
287
315
  setIsConnecting(true);
288
316
  try {
289
317
  if (typedProvider === "okx") {
290
318
  const data2 = await getOKXStacksAddress();
319
+ if (connectGenRef.current !== gen) return;
291
320
  setAddress(data2.address);
292
321
  setProvider(data2.provider);
293
322
  options?.onSuccess?.(data2.address, data2.provider);
@@ -296,17 +325,25 @@ var StacksWalletProvider = ({
296
325
  setSelectedProviderId(
297
326
  STACKS_TO_STACKS_CONNECT_PROVIDERS[typedProvider]
298
327
  );
299
- const data = walletConnect ? await request(
300
- {
301
- walletConnect: buildWalletConnectConfig(
302
- walletConnect.projectId,
303
- walletConnect.metadata,
304
- walletConnect.chains
305
- )
306
- },
328
+ const wcConfig = typedProvider === "wallet-connect" && walletConnect ? buildWalletConnectConfig(
329
+ walletConnect.projectId,
330
+ walletConnect.metadata,
331
+ walletConnect.chains
332
+ ) : void 0;
333
+ if (wcConfig) {
334
+ if (wcInitRef.current) await wcInitRef.current;
335
+ const initPromise = WalletConnect.initializeProvider(wcConfig);
336
+ wcInitRef.current = initPromise;
337
+ await initPromise;
338
+ wcInitRef.current = null;
339
+ }
340
+ if (connectGenRef.current !== gen) return;
341
+ const data = wcConfig ? await request(
342
+ { walletConnect: wcConfig },
307
343
  "getAddresses",
308
344
  {}
309
345
  ) : await request("getAddresses");
346
+ if (connectGenRef.current !== gen) return;
310
347
  const extractedAddress = extractStacksAddress(
311
348
  typedProvider,
312
349
  data.addresses
@@ -315,16 +352,26 @@ var StacksWalletProvider = ({
315
352
  setProvider(typedProvider);
316
353
  options?.onSuccess?.(extractedAddress, typedProvider);
317
354
  } catch (error) {
355
+ if (connectGenRef.current !== gen) return;
318
356
  console.error("Failed to connect wallet:", error);
319
- getSelectedProvider()?.disconnect?.();
320
- clearSelectedProviderId();
357
+ if (typedProvider !== "okx") {
358
+ getSelectedProvider()?.disconnect?.();
359
+ clearSelectedProviderId();
360
+ }
321
361
  options?.onError?.(error);
322
362
  } finally {
323
- setIsConnecting(false);
363
+ if (connectGenRef.current === gen) {
364
+ setIsConnecting(false);
365
+ }
324
366
  }
325
367
  },
326
368
  [walletConnect]
327
369
  );
370
+ const reset = useCallback(() => {
371
+ connectGenRef.current++;
372
+ setIsConnecting(false);
373
+ clearSelectedProviderId();
374
+ }, []);
328
375
  const disconnect = useCallback(
329
376
  (callback) => {
330
377
  localStorage.removeItem(LOCAL_STORAGE_STACKS);
@@ -357,6 +404,14 @@ var StacksWalletProvider = ({
357
404
  },
358
405
  connect
359
406
  });
407
+ const walletInfos = useMemo(() => {
408
+ const { installed } = getStacksWallets();
409
+ const configured = wallets ?? [...SUPPORTED_STACKS_WALLETS];
410
+ return configured.map((w) => ({
411
+ id: w,
412
+ available: w === "wallet-connect" ? !!walletConnect?.projectId : installed.includes(w)
413
+ }));
414
+ }, [walletsKey, walletConnect?.projectId]);
360
415
  const value = useMemo(() => {
361
416
  const walletState = isConnecting ? { status: "connecting", address: void 0, provider: void 0 } : address && provider ? { status: "connected", address, provider } : {
362
417
  status: "disconnected",
@@ -366,9 +421,11 @@ var StacksWalletProvider = ({
366
421
  return {
367
422
  ...walletState,
368
423
  connect,
369
- disconnect
424
+ disconnect,
425
+ reset,
426
+ wallets: walletInfos
370
427
  };
371
- }, [address, provider, isConnecting, connect, disconnect]);
428
+ }, [address, provider, isConnecting, connect, disconnect, reset, walletInfos]);
372
429
  return /* @__PURE__ */ jsx(StacksWalletContext.Provider, { value, children });
373
430
  };
374
431
  var useStacksWalletContext = () => {
@@ -402,37 +459,108 @@ var useAddress = () => {
402
459
  }, [address, status, provider]);
403
460
  };
404
461
  var useConnect = () => {
405
- const { connect, status } = useStacksWalletContext();
462
+ const {
463
+ connect: contextConnect,
464
+ reset: contextReset,
465
+ status: walletStatus
466
+ } = useStacksWalletContext();
467
+ const [error, setError] = useState(null);
468
+ const [mutationStatus, setMutationStatus] = useState("idle");
469
+ const connect = useCallback(
470
+ async (providerId, options) => {
471
+ setError(null);
472
+ setMutationStatus("pending");
473
+ let settled = false;
474
+ try {
475
+ await contextConnect(providerId, {
476
+ onSuccess: (address, provider) => {
477
+ settled = true;
478
+ setMutationStatus("success");
479
+ options?.onSuccess?.(address, provider);
480
+ },
481
+ onError: (err) => {
482
+ settled = true;
483
+ setError(err);
484
+ setMutationStatus("error");
485
+ options?.onError?.(err);
486
+ }
487
+ });
488
+ } finally {
489
+ if (!settled) {
490
+ setMutationStatus("idle");
491
+ }
492
+ }
493
+ },
494
+ [contextConnect]
495
+ );
496
+ const reset = useCallback(() => {
497
+ setError(null);
498
+ setMutationStatus("idle");
499
+ contextReset();
500
+ }, [contextReset]);
406
501
  const value = useMemo(
407
502
  () => ({
408
503
  connect,
409
- connectors: SUPPORTED_STACKS_WALLETS,
410
- isPending: status === "connecting"
504
+ reset,
505
+ error,
506
+ isError: mutationStatus === "error",
507
+ isIdle: mutationStatus === "idle",
508
+ isPending: mutationStatus === "pending" || walletStatus === "connecting",
509
+ isSuccess: mutationStatus === "success",
510
+ status: mutationStatus
411
511
  }),
412
- [connect, status]
512
+ [connect, reset, error, mutationStatus, walletStatus]
413
513
  );
414
514
  return value;
415
515
  };
416
516
  var useDisconnect = () => {
417
- const { disconnect } = useStacksWalletContext();
418
- return useMemo(
517
+ const { disconnect: contextDisconnect } = useStacksWalletContext();
518
+ const [error, setError] = useState(null);
519
+ const [mutationStatus, setMutationStatus] = useState("idle");
520
+ const disconnect = useCallback(
521
+ (callback) => {
522
+ setError(null);
523
+ try {
524
+ contextDisconnect(callback);
525
+ setMutationStatus("success");
526
+ } catch (err) {
527
+ const normalizedError = err instanceof Error ? err : new Error(String(err));
528
+ setError(normalizedError);
529
+ setMutationStatus("error");
530
+ }
531
+ },
532
+ [contextDisconnect]
533
+ );
534
+ const reset = useCallback(() => {
535
+ setError(null);
536
+ setMutationStatus("idle");
537
+ }, []);
538
+ const value = useMemo(
419
539
  () => ({
420
- disconnect
540
+ disconnect,
541
+ reset,
542
+ error,
543
+ isError: mutationStatus === "error",
544
+ isIdle: mutationStatus === "idle",
545
+ isPending: mutationStatus === "pending",
546
+ isSuccess: mutationStatus === "success",
547
+ status: mutationStatus
421
548
  }),
422
- [disconnect]
549
+ [disconnect, reset, error, mutationStatus]
423
550
  );
551
+ return value;
424
552
  };
425
553
  var useSignMessage = () => {
426
554
  const { isConnected, provider } = useAddress();
427
555
  const [data, setData] = useState(void 0);
428
556
  const [error, setError] = useState(null);
429
- const [isPending, setIsPending] = useState(false);
557
+ const [status, setStatus] = useState("idle");
430
558
  const signMessageAsync = useCallback(
431
559
  async (variables) => {
432
560
  if (!isConnected) {
433
561
  throw new Error("Wallet is not connected");
434
562
  }
435
- setIsPending(true);
563
+ setStatus("pending");
436
564
  setError(null);
437
565
  setData(void 0);
438
566
  try {
@@ -453,12 +581,12 @@ var useSignMessage = () => {
453
581
  });
454
582
  }
455
583
  setData(result);
456
- setIsPending(false);
584
+ setStatus("success");
457
585
  return result;
458
586
  } catch (err) {
459
587
  const error2 = err instanceof Error ? err : new Error(String(err));
460
588
  setError(error2);
461
- setIsPending(false);
589
+ setStatus("error");
462
590
  throw error2;
463
591
  }
464
592
  },
@@ -476,13 +604,26 @@ var useSignMessage = () => {
476
604
  },
477
605
  [signMessageAsync]
478
606
  );
479
- return {
480
- signMessage,
481
- signMessageAsync,
482
- data,
483
- error,
484
- isPending
485
- };
607
+ const reset = useCallback(() => {
608
+ setData(void 0);
609
+ setError(null);
610
+ setStatus("idle");
611
+ }, []);
612
+ return useMemo(
613
+ () => ({
614
+ signMessage,
615
+ signMessageAsync,
616
+ reset,
617
+ data,
618
+ error,
619
+ isError: status === "error",
620
+ isIdle: status === "idle",
621
+ isPending: status === "pending",
622
+ isSuccess: status === "success",
623
+ status
624
+ }),
625
+ [signMessage, signMessageAsync, reset, data, error, status]
626
+ );
486
627
  };
487
628
 
488
629
  // src/utils/get-network-from-address.ts
@@ -503,13 +644,13 @@ var useWriteContract = () => {
503
644
  const { isConnected, address, provider } = useAddress();
504
645
  const [data, setData] = useState(void 0);
505
646
  const [error, setError] = useState(null);
506
- const [isPending, setIsPending] = useState(false);
647
+ const [status, setStatus] = useState("idle");
507
648
  const writeContractAsync = useCallback(
508
649
  async (variables) => {
509
650
  if (!isConnected || !address) {
510
651
  throw new Error("Wallet is not connected");
511
652
  }
512
- setIsPending(true);
653
+ setStatus("pending");
513
654
  setError(null);
514
655
  setData(void 0);
515
656
  try {
@@ -531,7 +672,7 @@ var useWriteContract = () => {
531
672
  anchorMode: 3
532
673
  });
533
674
  setData(response2.txHash);
534
- setIsPending(false);
675
+ setStatus("success");
535
676
  return response2.txHash;
536
677
  }
537
678
  const response = await request("stx_callContract", {
@@ -547,12 +688,12 @@ var useWriteContract = () => {
547
688
  throw new Error("No transaction ID returned");
548
689
  }
549
690
  setData(response.txid);
550
- setIsPending(false);
691
+ setStatus("success");
551
692
  return response.txid;
552
693
  } catch (err) {
553
694
  const error2 = err instanceof Error ? err : new Error(String(err));
554
695
  setError(error2);
555
- setIsPending(false);
696
+ setStatus("error");
556
697
  throw error2;
557
698
  }
558
699
  },
@@ -570,13 +711,26 @@ var useWriteContract = () => {
570
711
  },
571
712
  [writeContractAsync]
572
713
  );
573
- return {
574
- writeContract,
575
- writeContractAsync,
576
- data,
577
- error,
578
- isPending
579
- };
714
+ const reset = useCallback(() => {
715
+ setData(void 0);
716
+ setError(null);
717
+ setStatus("idle");
718
+ }, []);
719
+ return useMemo(
720
+ () => ({
721
+ writeContract,
722
+ writeContractAsync,
723
+ reset,
724
+ data,
725
+ error,
726
+ isError: status === "error",
727
+ isIdle: status === "idle",
728
+ isPending: status === "pending",
729
+ isSuccess: status === "success",
730
+ status
731
+ }),
732
+ [writeContract, writeContractAsync, reset, data, error, status]
733
+ );
580
734
  };
581
735
  var useBnsName = (address) => {
582
736
  const [bnsName, setBnsName] = useState(null);
@@ -604,7 +758,11 @@ var useBnsName = (address) => {
604
758
  }, [address]);
605
759
  return { bnsName, isLoading };
606
760
  };
761
+ var useWallets = () => {
762
+ const { wallets } = useStacksWalletContext();
763
+ return useMemo(() => ({ wallets }), [wallets]);
764
+ };
607
765
 
608
- export { SUPPORTED_STACKS_WALLETS, StacksWalletProvider, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useWriteContract };
766
+ export { SUPPORTED_STACKS_WALLETS, StacksWalletProvider, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useWallets, useWriteContract };
609
767
  //# sourceMappingURL=index.js.map
610
768
  //# sourceMappingURL=index.js.map