@satoshai/kit 0.6.0 → 0.8.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
@@ -4,6 +4,79 @@ import { jsx } from 'react/jsx-runtime';
4
4
  import { PostConditionMode, postConditionToHex, cvToHex, noneCV, contractPrincipalCV, standardPrincipalCV, boolCV, intCV, uintCV, bufferCV, stringAsciiCV, stringUtf8CV, someCV, listCV, tupleCV } from '@stacks/transactions';
5
5
  import { getPrimaryName } from 'bns-v2-sdk';
6
6
 
7
+ // src/errors.ts
8
+ var BaseError = class extends Error {
9
+ name = "StacksKitError";
10
+ /** Short, human-readable error summary without details or cause chain. */
11
+ shortMessage;
12
+ constructor(shortMessage, options) {
13
+ const message = [
14
+ shortMessage,
15
+ options?.details && `Details: ${options.details}`
16
+ ].filter(Boolean).join("\n\n");
17
+ super(message, options?.cause ? { cause: options.cause } : void 0);
18
+ this.shortMessage = shortMessage;
19
+ }
20
+ /**
21
+ * Walk the error cause chain. If `fn` is provided, returns the first error
22
+ * where `fn` returns `true`; otherwise returns the root cause.
23
+ */
24
+ walk(fn) {
25
+ return walk(this, fn);
26
+ }
27
+ };
28
+ function walk(err, fn) {
29
+ if (fn?.(err)) return err;
30
+ if (err && typeof err === "object" && "cause" in err) {
31
+ return walk(err.cause, fn);
32
+ }
33
+ return err;
34
+ }
35
+ var WalletNotConnectedError = class extends BaseError {
36
+ name = "WalletNotConnectedError";
37
+ constructor() {
38
+ super("Wallet is not connected");
39
+ }
40
+ };
41
+ var WalletNotFoundError = class extends BaseError {
42
+ name = "WalletNotFoundError";
43
+ /** The wallet ID that was not found. */
44
+ wallet;
45
+ constructor({ wallet }) {
46
+ super(`${wallet} wallet not found`, {
47
+ details: "The wallet extension may not be installed."
48
+ });
49
+ this.wallet = wallet;
50
+ }
51
+ };
52
+ var UnsupportedMethodError = class extends BaseError {
53
+ name = "UnsupportedMethodError";
54
+ /** The SIP-030 method name that is not supported. */
55
+ method;
56
+ /** The wallet that does not support the method. */
57
+ wallet;
58
+ constructor({ method, wallet }) {
59
+ super(`${method} is not supported by ${wallet} wallet`);
60
+ this.method = method;
61
+ this.wallet = wallet;
62
+ }
63
+ };
64
+ var WalletRequestError = class extends BaseError {
65
+ name = "WalletRequestError";
66
+ /** The SIP-030 method name that failed. */
67
+ method;
68
+ /** The wallet that returned the error. */
69
+ wallet;
70
+ constructor({ method, wallet, cause }) {
71
+ super(`${wallet} wallet request failed`, {
72
+ cause,
73
+ details: cause.message
74
+ });
75
+ this.method = method;
76
+ this.wallet = wallet;
77
+ }
78
+ };
79
+
7
80
  // src/constants/stacks-provider-mapping.ts
8
81
  var STACKS_TO_STACKS_CONNECT_PROVIDERS = {
9
82
  xverse: "XverseProviders.BitcoinProvider",
@@ -149,6 +222,102 @@ var extractStacksAddress = (typedProvider, addresses) => {
149
222
  `No valid Stacks address found for ${typedProvider} wallet`
150
223
  );
151
224
  };
225
+
226
+ // src/hooks/use-wallet-connect/use-wallet-connect.helpers.ts
227
+ var getWcUniversalProvider = () => window.WalletConnectProvider?.connector?.provider ?? null;
228
+ var extractStacksAddress2 = (accounts) => {
229
+ for (const entry of accounts) {
230
+ if (typeof entry === "object" && entry !== null && "address" in entry) {
231
+ return entry.address;
232
+ }
233
+ if (typeof entry === "string") {
234
+ if (entry.startsWith("S")) return entry;
235
+ if (entry.startsWith("stacks:")) return entry.split(":")[2] ?? null;
236
+ }
237
+ }
238
+ return null;
239
+ };
240
+ var PING_TIMEOUT_MS = 1e4;
241
+ var pingSession = async () => {
242
+ const wcProvider = getWcUniversalProvider();
243
+ const client = wcProvider?.client;
244
+ const session = wcProvider?.session;
245
+ if (!client || !session) return false;
246
+ try {
247
+ await Promise.race([
248
+ client.ping({ topic: session.topic }),
249
+ new Promise(
250
+ (_, reject) => setTimeout(() => reject(new Error("Ping timeout")), PING_TIMEOUT_MS)
251
+ )
252
+ ]);
253
+ return true;
254
+ } catch {
255
+ return false;
256
+ }
257
+ };
258
+
259
+ // src/hooks/use-wallet-connect/use-wallet-connect.ts
260
+ var useWalletConnect = ({
261
+ address,
262
+ provider,
263
+ onAddressChange,
264
+ onDisconnect
265
+ }) => {
266
+ useEffect(() => {
267
+ if (provider !== "wallet-connect" || !address) return;
268
+ let cancelled = false;
269
+ const validateSession = async () => {
270
+ const alive = await pingSession();
271
+ if (cancelled) return;
272
+ if (!alive) {
273
+ const wcProvider = getWcUniversalProvider();
274
+ try {
275
+ await wcProvider?.disconnect();
276
+ } catch {
277
+ }
278
+ clearSelectedProviderId();
279
+ onDisconnect();
280
+ }
281
+ };
282
+ void validateSession();
283
+ return () => {
284
+ cancelled = true;
285
+ };
286
+ }, [provider, address, onDisconnect]);
287
+ useEffect(() => {
288
+ if (provider !== "wallet-connect" || !address) return;
289
+ const wcProvider = getWcUniversalProvider();
290
+ if (!wcProvider) return;
291
+ const handleDisconnect = () => {
292
+ clearSelectedProviderId();
293
+ onDisconnect();
294
+ };
295
+ const handleAccountsChanged = (...args) => {
296
+ const accounts = args[0];
297
+ const newAddress = extractStacksAddress2(accounts);
298
+ if (newAddress && newAddress !== address) {
299
+ onAddressChange(newAddress);
300
+ }
301
+ };
302
+ wcProvider.on("disconnect", handleDisconnect);
303
+ wcProvider.on("accountsChanged", handleAccountsChanged);
304
+ wcProvider.on("stx_accountChange", handleAccountsChanged);
305
+ wcProvider.on("stx_accountsChanged", handleAccountsChanged);
306
+ return () => {
307
+ try {
308
+ wcProvider.off("disconnect", handleDisconnect);
309
+ wcProvider.off("accountsChanged", handleAccountsChanged);
310
+ wcProvider.off("stx_accountChange", handleAccountsChanged);
311
+ wcProvider.off("stx_accountsChanged", handleAccountsChanged);
312
+ } catch (error) {
313
+ console.error(
314
+ "Failed to remove WalletConnect listeners:",
315
+ error
316
+ );
317
+ }
318
+ };
319
+ }, [address, provider, onAddressChange, onDisconnect]);
320
+ };
152
321
  var getXverseProductInfo = async () => await window.XverseProviders?.StacksProvider?.getProductInfo?.() ?? null;
153
322
  var shouldSupportAccountChange = (version) => version !== void 0 && version !== "1.0.0";
154
323
  var waitForXverseProvider = async (maxAttempts = 10, initialDelay = 200) => {
@@ -527,6 +696,18 @@ var StacksWalletProvider = ({
527
696
  onAddressChange: handleAddressChange,
528
697
  connect
529
698
  });
699
+ const handleWcDisconnect = useCallback(() => {
700
+ localStorage.removeItem(LOCAL_STORAGE_STACKS);
701
+ setAddress(void 0);
702
+ setProvider(void 0);
703
+ onDisconnect?.();
704
+ }, [onDisconnect]);
705
+ useWalletConnect({
706
+ address,
707
+ provider,
708
+ onAddressChange: handleAddressChange,
709
+ onDisconnect: handleWcDisconnect
710
+ });
530
711
  const { installed } = getStacksWallets();
531
712
  const configured = wallets ?? [...SUPPORTED_STACKS_WALLETS];
532
713
  const walletInfos = configured.map((w) => ({
@@ -683,7 +864,7 @@ var useSignMessage = () => {
683
864
  const signMessageAsync = useCallback(
684
865
  async (variables) => {
685
866
  if (!isConnected) {
686
- throw new Error("Wallet is not connected");
867
+ throw new WalletNotConnectedError();
687
868
  }
688
869
  setStatus("pending");
689
870
  setError(null);
@@ -692,7 +873,7 @@ var useSignMessage = () => {
692
873
  let result;
693
874
  if (provider === "okx") {
694
875
  if (!window.okxwallet) {
695
- throw new Error("OKX wallet not found");
876
+ throw new WalletNotFoundError({ wallet: "OKX" });
696
877
  }
697
878
  result = await window.okxwallet.stacks.signMessage({
698
879
  message: variables.message
@@ -709,7 +890,11 @@ var useSignMessage = () => {
709
890
  setStatus("success");
710
891
  return result;
711
892
  } catch (err) {
712
- const error2 = err instanceof Error ? err : new Error(String(err));
893
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
894
+ method: "stx_signMessage",
895
+ wallet: provider ?? "unknown",
896
+ cause: err instanceof Error ? err : new Error(String(err))
897
+ });
713
898
  setError(error2);
714
899
  setStatus("error");
715
900
  throw error2;
@@ -760,12 +945,13 @@ var useSignStructuredMessage = () => {
760
945
  const signStructuredMessageAsync = useCallback(
761
946
  async (variables) => {
762
947
  if (!isConnected) {
763
- throw new Error("Wallet is not connected");
948
+ throw new WalletNotConnectedError();
764
949
  }
765
950
  if (provider === "okx") {
766
- throw new Error(
767
- "Structured message signing is not supported by OKX wallet"
768
- );
951
+ throw new UnsupportedMethodError({
952
+ method: "stx_signStructuredMessage",
953
+ wallet: "OKX"
954
+ });
769
955
  }
770
956
  setStatus("pending");
771
957
  setError(null);
@@ -779,7 +965,11 @@ var useSignStructuredMessage = () => {
779
965
  setStatus("success");
780
966
  return result;
781
967
  } catch (err) {
782
- const error2 = err instanceof Error ? err : new Error(String(err));
968
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
969
+ method: "stx_signStructuredMessage",
970
+ wallet: provider ?? "unknown",
971
+ cause: err instanceof Error ? err : new Error(String(err))
972
+ });
783
973
  setError(error2);
784
974
  setStatus("error");
785
975
  throw error2;
@@ -835,12 +1025,13 @@ var useSignTransaction = () => {
835
1025
  const signTransactionAsync = useCallback(
836
1026
  async (variables) => {
837
1027
  if (!isConnected) {
838
- throw new Error("Wallet is not connected");
1028
+ throw new WalletNotConnectedError();
839
1029
  }
840
1030
  if (provider === "okx") {
841
- throw new Error(
842
- "Transaction signing is not supported by OKX wallet"
843
- );
1031
+ throw new UnsupportedMethodError({
1032
+ method: "stx_signTransaction",
1033
+ wallet: "OKX"
1034
+ });
844
1035
  }
845
1036
  setStatus("pending");
846
1037
  setError(null);
@@ -856,7 +1047,11 @@ var useSignTransaction = () => {
856
1047
  setStatus("success");
857
1048
  return result;
858
1049
  } catch (err) {
859
- const error2 = err instanceof Error ? err : new Error(String(err));
1050
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1051
+ method: "stx_signTransaction",
1052
+ wallet: provider ?? "unknown",
1053
+ cause: err instanceof Error ? err : new Error(String(err))
1054
+ });
860
1055
  setError(error2);
861
1056
  setStatus("error");
862
1057
  throw error2;
@@ -918,7 +1113,7 @@ var useTransferSTX = () => {
918
1113
  const transferSTXAsync = useCallback(
919
1114
  async (variables) => {
920
1115
  if (!isConnected || !address) {
921
- throw new Error("Wallet is not connected");
1116
+ throw new WalletNotConnectedError();
922
1117
  }
923
1118
  setStatus("pending");
924
1119
  setError(null);
@@ -926,7 +1121,7 @@ var useTransferSTX = () => {
926
1121
  try {
927
1122
  if (provider === "okx") {
928
1123
  if (!window.okxwallet) {
929
- throw new Error("OKX wallet not found");
1124
+ throw new WalletNotFoundError({ wallet: "OKX" });
930
1125
  }
931
1126
  const response2 = await window.okxwallet.stacks.signTransaction({
932
1127
  txType: "token_transfer",
@@ -961,7 +1156,11 @@ var useTransferSTX = () => {
961
1156
  setStatus("success");
962
1157
  return response.txid;
963
1158
  } catch (err) {
964
- const error2 = err instanceof Error ? err : new Error(String(err));
1159
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1160
+ method: "stx_transferStx",
1161
+ wallet: provider ?? "unknown",
1162
+ cause: err instanceof Error ? err : new Error(String(err))
1163
+ });
965
1164
  setError(error2);
966
1165
  setStatus("error");
967
1166
  throw error2;
@@ -1149,7 +1348,7 @@ var useWriteContract = () => {
1149
1348
  const writeContractAsync = useCallback(
1150
1349
  async (variables) => {
1151
1350
  if (!isConnected || !address) {
1152
- throw new Error("Wallet is not connected");
1351
+ throw new WalletNotConnectedError();
1153
1352
  }
1154
1353
  setStatus("pending");
1155
1354
  setError(null);
@@ -1158,7 +1357,7 @@ var useWriteContract = () => {
1158
1357
  try {
1159
1358
  if (provider === "okx") {
1160
1359
  if (!window.okxwallet) {
1161
- throw new Error("OKX wallet not found");
1360
+ throw new WalletNotFoundError({ wallet: "OKX" });
1162
1361
  }
1163
1362
  const response2 = await window.okxwallet.stacks.signTransaction({
1164
1363
  contractAddress: variables.address,
@@ -1193,7 +1392,11 @@ var useWriteContract = () => {
1193
1392
  setStatus("success");
1194
1393
  return response.txid;
1195
1394
  } catch (err) {
1196
- const error2 = err instanceof Error ? err : new Error(String(err));
1395
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1396
+ method: "stx_callContract",
1397
+ wallet: provider ?? "unknown",
1398
+ cause: err instanceof Error ? err : new Error(String(err))
1399
+ });
1197
1400
  setError(error2);
1198
1401
  setStatus("error");
1199
1402
  throw error2;
@@ -1278,6 +1481,6 @@ function createContractConfig(config) {
1278
1481
  return config;
1279
1482
  }
1280
1483
 
1281
- export { SUPPORTED_STACKS_WALLETS, StacksWalletProvider, createContractConfig, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useSignStructuredMessage, useSignTransaction, useTransferSTX, useWallets, useWriteContract };
1484
+ export { BaseError, SUPPORTED_STACKS_WALLETS, StacksWalletProvider, UnsupportedMethodError, WalletNotConnectedError, WalletNotFoundError, WalletRequestError, createContractConfig, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useSignStructuredMessage, useSignTransaction, useTransferSTX, useWallets, useWriteContract };
1282
1485
  //# sourceMappingURL=index.js.map
1283
1486
  //# sourceMappingURL=index.js.map