@solana/react-hooks 0.3.0 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import { createClient, toAddress, toAddressString, stableStringify, createSolTransferController, createSplTransferController, getWalletStandardConnectors, watchWalletStandardConnectors, createTransactionPoolController, createInitialAsyncState, createAsyncState, normalizeSignature, SIGNATURE_STATUS_TIMEOUT_MS, deriveConfirmationStatus, confirmationMeetsCommitment, deserializeSolanaState, subscribeSolanaState, serializeSolanaState } from '@solana/client';
1
+ import { createClient, toAddress, toAddressString, stableStringify, createSolTransferController, createSplTransferController, createTransactionPoolController, createInitialAsyncState, createAsyncState, normalizeSignature, SIGNATURE_STATUS_TIMEOUT_MS, deriveConfirmationStatus, confirmationMeetsCommitment, deserializeSolanaState, subscribeSolanaState, serializeSolanaState } from '@solana/client';
2
2
  import { createContext, useMemo, useEffect, useContext, useCallback, useRef, useSyncExternalStore, useState } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import useSWR, { SWRConfig } from 'swr';
@@ -56,11 +56,11 @@ var QUERY_NAMESPACE = "@solana/react-hooks";
56
56
  function useSolanaRpcQuery(scope, args, fetcher, options = {}) {
57
57
  const client = useSolanaClient();
58
58
  const cluster = useClientStore((state) => state.cluster);
59
- const { disabled = false, ...restOptions } = options;
59
+ const { disabled = false, swr } = options;
60
60
  const providerSuspensePreference = useQuerySuspensePreference();
61
61
  const suspenseEnabled = !disabled && Boolean(providerSuspensePreference);
62
62
  const swrOptions = {
63
- ...restOptions,
63
+ ...swr ?? {},
64
64
  suspense: suspenseEnabled
65
65
  };
66
66
  const key = useMemo(() => {
@@ -69,59 +69,105 @@ function useSolanaRpcQuery(scope, args, fetcher, options = {}) {
69
69
  }
70
70
  return [QUERY_NAMESPACE, scope, cluster.endpoint, cluster.commitment, ...args];
71
71
  }, [cluster.commitment, cluster.endpoint, args, scope, disabled]);
72
- const swr = useSWR(key, () => fetcher(client), swrOptions);
72
+ const swrResponse = useSWR(key, () => fetcher(client), swrOptions);
73
73
  const [dataUpdatedAt, setDataUpdatedAt] = useState(
74
- () => swr.data !== void 0 ? Date.now() : void 0
74
+ () => swrResponse.data !== void 0 ? Date.now() : void 0
75
75
  );
76
76
  useEffect(() => {
77
- if (swr.data !== void 0) {
77
+ if (swrResponse.data !== void 0) {
78
78
  setDataUpdatedAt(Date.now());
79
79
  }
80
- }, [swr.data]);
81
- const status = swr.error ? "error" : swr.isLoading ? "loading" : swr.data !== void 0 ? "success" : "idle";
82
- const refresh = useCallback(() => swr.mutate(void 0, { revalidate: true }), [swr.mutate]);
80
+ }, [swrResponse.data]);
81
+ const status = swrResponse.error ? "error" : swrResponse.isLoading ? "loading" : swrResponse.data !== void 0 ? "success" : "idle";
82
+ const refresh = useCallback(() => swrResponse.mutate(void 0, { revalidate: true }), [swrResponse.mutate]);
83
83
  return {
84
- data: swr.data,
84
+ data: swrResponse.data,
85
85
  dataUpdatedAt,
86
- error: swr.error ?? null,
86
+ error: swrResponse.error ?? null,
87
87
  isError: status === "error",
88
- isLoading: swr.isLoading,
88
+ isLoading: swrResponse.isLoading,
89
89
  isSuccess: status === "success",
90
- isValidating: swr.isValidating,
91
- mutate: swr.mutate,
90
+ isValidating: swrResponse.isValidating,
91
+ mutate: swrResponse.mutate,
92
92
  refresh,
93
93
  status
94
94
  };
95
95
  }
96
96
  __name(useSolanaRpcQuery, "useSolanaRpcQuery");
97
+ function getLatestBlockhashKey(params = {}) {
98
+ const { commitment = null, minContextSlot = null } = params;
99
+ return ["latestBlockhash", commitment, normalizeBigint(minContextSlot)];
100
+ }
101
+ __name(getLatestBlockhashKey, "getLatestBlockhashKey");
102
+ function getProgramAccountsKey(params = {}) {
103
+ const { programAddress, config } = params;
104
+ const address = programAddress ? toAddress(programAddress) : void 0;
105
+ const addressKey = address ? toAddressString(address) : null;
106
+ const configKey = stableStringify(config ?? null);
107
+ return ["programAccounts", addressKey, configKey];
108
+ }
109
+ __name(getProgramAccountsKey, "getProgramAccountsKey");
110
+ function getSimulateTransactionKey(params = {}) {
111
+ const { transaction, config } = params;
112
+ const wire = transaction ? normalizeWire(transaction) : null;
113
+ const configKey = stableStringify(config ?? null);
114
+ return ["simulateTransaction", wire, configKey];
115
+ }
116
+ __name(getSimulateTransactionKey, "getSimulateTransactionKey");
117
+ function getSignatureStatusKey(params = {}) {
118
+ const { config, signature } = params;
119
+ const signatureKey = signature?.toString() ?? null;
120
+ const configKey = JSON.stringify(config ?? null);
121
+ return ["signatureStatus", signatureKey, configKey];
122
+ }
123
+ __name(getSignatureStatusKey, "getSignatureStatusKey");
124
+ function normalizeBigint(value) {
125
+ if (value === void 0 || value === null) return null;
126
+ return typeof value === "bigint" ? value : BigInt(Math.floor(value));
127
+ }
128
+ __name(normalizeBigint, "normalizeBigint");
129
+ function normalizeWire(input) {
130
+ if (!input) return null;
131
+ if (typeof input === "string") {
132
+ return input;
133
+ }
134
+ return getBase64EncodedWireTransaction(input);
135
+ }
136
+ __name(normalizeWire, "normalizeWire");
137
+
138
+ // src/queryHooks.ts
97
139
  var DEFAULT_BLOCKHASH_REFRESH_INTERVAL = 3e4;
98
- function useLatestBlockhash(options) {
99
- const { commitment, minContextSlot, refreshInterval = DEFAULT_BLOCKHASH_REFRESH_INTERVAL, ...rest } = options ?? {};
100
- const normalizedMinContextSlot = useMemo(() => {
101
- if (minContextSlot === void 0) {
102
- return void 0;
103
- }
104
- return typeof minContextSlot === "bigint" ? minContextSlot : BigInt(Math.floor(minContextSlot));
105
- }, [minContextSlot]);
106
- const keyArgs = useMemo(
107
- () => [commitment ?? null, normalizedMinContextSlot ?? null],
108
- [commitment, normalizedMinContextSlot]
109
- );
140
+ function useLatestBlockhash(options = {}) {
141
+ const {
142
+ commitment,
143
+ minContextSlot,
144
+ refreshInterval = DEFAULT_BLOCKHASH_REFRESH_INTERVAL,
145
+ disabled = false,
146
+ swr
147
+ } = options;
110
148
  const fetcher = useCallback(
111
149
  async (client) => {
112
150
  const fallbackCommitment = commitment ?? client.store.getState().cluster.commitment;
113
151
  const plan = client.runtime.rpc.getLatestBlockhash({
114
152
  commitment: fallbackCommitment,
115
- minContextSlot: normalizedMinContextSlot
153
+ minContextSlot: normalizeMinContextSlot(minContextSlot)
116
154
  });
117
155
  return plan.send({ abortSignal: AbortSignal.timeout(15e3) });
118
156
  },
119
- [commitment, normalizedMinContextSlot]
157
+ [commitment, minContextSlot]
158
+ );
159
+ const query = useSolanaRpcQuery(
160
+ "latestBlockhash",
161
+ getLatestBlockhashKey(options),
162
+ fetcher,
163
+ {
164
+ disabled,
165
+ swr: {
166
+ refreshInterval,
167
+ ...swr
168
+ }
169
+ }
120
170
  );
121
- const query = useSolanaRpcQuery("latestBlockhash", keyArgs, fetcher, {
122
- refreshInterval,
123
- ...rest
124
- });
125
171
  return {
126
172
  ...query,
127
173
  blockhash: query.data?.value.blockhash ?? null,
@@ -131,13 +177,10 @@ function useLatestBlockhash(options) {
131
177
  }
132
178
  __name(useLatestBlockhash, "useLatestBlockhash");
133
179
  function useProgramAccounts(programAddress, options) {
134
- const { commitment, config, ...queryOptions } = options ?? {};
135
- const { disabled: disabledOption, ...restQueryOptions } = queryOptions;
136
- const address = useMemo(() => programAddress ? toAddress(programAddress) : void 0, [programAddress]);
137
- const addressKey = useMemo(() => address ? toAddressString(address) : null, [address]);
138
- const configKey = useMemo(() => stableStringify(config ?? null), [config]);
180
+ const { commitment, config, swr, disabled: disabledOption } = options ?? {};
139
181
  const fetcher = useCallback(
140
182
  async (client) => {
183
+ const address = programAddress ? toAddress(programAddress) : void 0;
141
184
  if (!address) {
142
185
  throw new Error("Provide a program address before querying program accounts.");
143
186
  }
@@ -149,13 +192,18 @@ function useProgramAccounts(programAddress, options) {
149
192
  const plan = client.runtime.rpc.getProgramAccounts(address, mergedConfig);
150
193
  return plan.send({ abortSignal: AbortSignal.timeout(2e4) });
151
194
  },
152
- [address, commitment, config]
195
+ [commitment, config, programAddress]
196
+ );
197
+ const disabled = disabledOption ?? !programAddress;
198
+ const query = useSolanaRpcQuery(
199
+ "programAccounts",
200
+ getProgramAccountsKey({ programAddress, config }),
201
+ fetcher,
202
+ {
203
+ disabled,
204
+ swr
205
+ }
153
206
  );
154
- const disabled = disabledOption ?? !address;
155
- const query = useSolanaRpcQuery("programAccounts", [addressKey, configKey], fetcher, {
156
- ...restQueryOptions,
157
- disabled
158
- });
159
207
  return {
160
208
  ...query,
161
209
  accounts: query.data ?? []
@@ -163,8 +211,7 @@ function useProgramAccounts(programAddress, options) {
163
211
  }
164
212
  __name(useProgramAccounts, "useProgramAccounts");
165
213
  function useSimulateTransaction(transaction, options) {
166
- const { commitment, config, refreshInterval, ...rest } = options ?? {};
167
- const { disabled: disabledOption, revalidateIfStale, revalidateOnFocus, ...queryOptions } = rest;
214
+ const { commitment, config, refreshInterval, disabled: disabledOption, swr } = options ?? {};
168
215
  const wire = useMemo(() => {
169
216
  if (!transaction) {
170
217
  return null;
@@ -174,7 +221,6 @@ function useSimulateTransaction(transaction, options) {
174
221
  }
175
222
  return getBase64EncodedWireTransaction(transaction);
176
223
  }, [transaction]);
177
- const configKey = useMemo(() => stableStringify(config ?? null), [config]);
178
224
  const fetcher = useCallback(
179
225
  async (client) => {
180
226
  if (!wire) {
@@ -190,19 +236,31 @@ function useSimulateTransaction(transaction, options) {
190
236
  [commitment, config, wire]
191
237
  );
192
238
  const disabled = disabledOption ?? !wire;
193
- const query = useSolanaRpcQuery("simulateTransaction", [wire, configKey], fetcher, {
194
- ...queryOptions,
195
- refreshInterval,
196
- disabled,
197
- revalidateIfStale: revalidateIfStale ?? false,
198
- revalidateOnFocus: revalidateOnFocus ?? false
199
- });
239
+ const query = useSolanaRpcQuery(
240
+ "simulateTransaction",
241
+ getSimulateTransactionKey({ transaction, config }),
242
+ fetcher,
243
+ {
244
+ disabled,
245
+ swr: {
246
+ refreshInterval,
247
+ revalidateIfStale: false,
248
+ revalidateOnFocus: false,
249
+ ...swr
250
+ }
251
+ }
252
+ );
200
253
  return {
201
254
  ...query,
202
255
  logs: query.data?.value.logs ?? []
203
256
  };
204
257
  }
205
258
  __name(useSimulateTransaction, "useSimulateTransaction");
259
+ function normalizeMinContextSlot(minContextSlot) {
260
+ if (minContextSlot === void 0) return void 0;
261
+ return typeof minContextSlot === "bigint" ? minContextSlot : BigInt(Math.floor(minContextSlot));
262
+ }
263
+ __name(normalizeMinContextSlot, "normalizeMinContextSlot");
206
264
 
207
265
  // src/hooks.ts
208
266
  function createClusterSelector() {
@@ -352,10 +410,19 @@ function useSplToken(mint, options = {}) {
352
410
  }
353
411
  return helper.fetchBalance(owner, options.commitment);
354
412
  }, [helper, owner, options.commitment]);
355
- const { data, error, isLoading, isValidating, mutate } = useSWR(balanceKey, fetchBalance, {
356
- revalidateOnFocus: options.revalidateOnFocus ?? false,
357
- suspense
358
- });
413
+ const swrOptions = useMemo(
414
+ () => ({
415
+ revalidateOnFocus: options.revalidateOnFocus ?? false,
416
+ suspense,
417
+ ...options.swr ?? {}
418
+ }),
419
+ [options.revalidateOnFocus, options.swr, suspense]
420
+ );
421
+ const { data, error, isLoading, isValidating, mutate } = useSWR(
422
+ balanceKey,
423
+ fetchBalance,
424
+ swrOptions
425
+ );
359
426
  const sessionRef = useRef(session);
360
427
  useEffect(() => {
361
428
  sessionRef.current = session;
@@ -521,24 +588,6 @@ function useBalance(addressLike, options = {}) {
521
588
  );
522
589
  }
523
590
  __name(useBalance, "useBalance");
524
- function useWalletStandardConnectors(options) {
525
- const overrides = options?.overrides;
526
- const disabled = options?.disabled ?? false;
527
- const memoisedOptions = useMemo(() => overrides ? { overrides } : void 0, [overrides]);
528
- const [connectors, setConnectors] = useState(
529
- () => disabled ? [] : getWalletStandardConnectors(memoisedOptions ?? {})
530
- );
531
- useEffect(() => {
532
- if (disabled) return;
533
- setConnectors(getWalletStandardConnectors(memoisedOptions ?? {}));
534
- const unwatch = watchWalletStandardConnectors(setConnectors, memoisedOptions ?? {});
535
- return () => {
536
- unwatch();
537
- };
538
- }, [disabled, memoisedOptions]);
539
- return connectors;
540
- }
541
- __name(useWalletStandardConnectors, "useWalletStandardConnectors");
542
591
  function useTransactionPool(config = {}) {
543
592
  const initialInstructions = useMemo(
544
593
  () => config.instructions ?? [],
@@ -672,10 +721,9 @@ function useSendTransaction() {
672
721
  }
673
722
  __name(useSendTransaction, "useSendTransaction");
674
723
  function useSignatureStatus(signatureInput, options = {}) {
675
- const { config, ...queryOptions } = options;
724
+ const { config, disabled: disabledOption, swr } = options;
676
725
  const signature = useMemo(() => normalizeSignature(signatureInput), [signatureInput]);
677
726
  const signatureKey = signature?.toString() ?? null;
678
- const configKey = useMemo(() => JSON.stringify(config ?? null), [config]);
679
727
  const fetcher = useCallback(
680
728
  async (client) => {
681
729
  if (!signatureKey) {
@@ -690,14 +738,14 @@ function useSignatureStatus(signatureInput, options = {}) {
690
738
  },
691
739
  [config, signature, signatureKey]
692
740
  );
693
- const disabled = queryOptions.disabled ?? !signatureKey;
741
+ const disabled = disabledOption ?? !signatureKey;
694
742
  const query = useSolanaRpcQuery(
695
743
  "signatureStatus",
696
- [signatureKey, configKey],
744
+ getSignatureStatusKey({ signature: signatureInput, config }),
697
745
  fetcher,
698
746
  {
699
- ...queryOptions,
700
- disabled
747
+ disabled,
748
+ swr
701
749
  }
702
750
  );
703
751
  const confirmationStatus = deriveConfirmationStatus(query.data ?? null);
@@ -716,14 +764,17 @@ function useWaitForSignature(signatureInput, options = {}) {
716
764
  watchCommitment,
717
765
  ...signatureStatusOptions
718
766
  } = options;
719
- const { refreshInterval, ...restStatusOptions } = signatureStatusOptions;
767
+ const { swr, ...restStatusOptions } = signatureStatusOptions;
720
768
  const subscribeCommitment = watchCommitment ?? commitment;
721
769
  const client = useSolanaClient();
722
770
  const normalizedSignature = useMemo(() => normalizeSignature(signatureInput), [signatureInput]);
723
771
  const disabled = disabledOption ?? !normalizedSignature;
724
772
  const statusQuery = useSignatureStatus(signatureInput, {
725
773
  ...restStatusOptions,
726
- refreshInterval: refreshInterval ?? 2e3,
774
+ swr: {
775
+ refreshInterval: 2e3,
776
+ ...swr
777
+ },
727
778
  disabled
728
779
  });
729
780
  const [subscriptionSettled, setSubscriptionSettled] = useState(false);
@@ -779,10 +830,11 @@ function useWaitForSignature(signatureInput, options = {}) {
779
830
  __name(useWaitForSignature, "useWaitForSignature");
780
831
  var createCache = /* @__PURE__ */ __name(() => /* @__PURE__ */ new Map(), "createCache");
781
832
  var DEFAULT_QUERY_CONFIG = Object.freeze({
782
- dedupingInterval: 1e3,
783
- focusThrottleInterval: 1e3,
833
+ dedupingInterval: 2e3,
834
+ focusThrottleInterval: 5e3,
784
835
  provider: /* @__PURE__ */ __name(() => createCache(), "provider"),
785
- revalidateOnFocus: false,
836
+ revalidateIfStale: true,
837
+ revalidateOnFocus: true,
786
838
  revalidateOnReconnect: true
787
839
  });
788
840
  function SolanaQueryProvider({
@@ -970,12 +1022,7 @@ function useWalletConnection(options = {}) {
970
1022
  const connectWallet = useConnectWallet();
971
1023
  const disconnectWallet = useDisconnectWallet();
972
1024
  const client = useSolanaClient();
973
- const shouldDiscover = !options.connectors && client.connectors.all.length === 0;
974
- const discovered = useWalletStandardConnectors({
975
- ...options.discoveryOptions,
976
- disabled: !shouldDiscover
977
- });
978
- const connectors = options.connectors ?? (client.connectors.all.length > 0 ? client.connectors.all : discovered);
1025
+ const connectors = options.connectors ?? client.connectors.all;
979
1026
  const connect = useCallback(
980
1027
  (connectorId, connectOptions) => connectWallet(connectorId, connectOptions),
981
1028
  [connectWallet]
@@ -983,6 +1030,7 @@ function useWalletConnection(options = {}) {
983
1030
  const disconnect = useCallback(() => disconnectWallet(), [disconnectWallet]);
984
1031
  const state = useMemo(() => {
985
1032
  const connectorId = "connectorId" in wallet ? wallet.connectorId : void 0;
1033
+ const currentConnector = connectorId ? connectors.find((connector) => connector.id === connectorId) : void 0;
986
1034
  const session = wallet.status === "connected" ? wallet.session : void 0;
987
1035
  const error = wallet.status === "error" ? wallet.error ?? null : null;
988
1036
  return {
@@ -991,6 +1039,7 @@ function useWalletConnection(options = {}) {
991
1039
  connecting: wallet.status === "connecting",
992
1040
  connectors,
993
1041
  connectorId,
1042
+ currentConnector,
994
1043
  disconnect,
995
1044
  error,
996
1045
  status: wallet.status,
@@ -1000,8 +1049,8 @@ function useWalletConnection(options = {}) {
1000
1049
  return state;
1001
1050
  }
1002
1051
  __name(useWalletConnection, "useWalletConnection");
1003
- function WalletConnectionManager({ children, connectors, discoveryOptions }) {
1004
- const state = useWalletConnection({ connectors, discoveryOptions });
1052
+ function WalletConnectionManager({ children, connectors }) {
1053
+ const state = useWalletConnection({ connectors });
1005
1054
  return /* @__PURE__ */ jsx(Fragment, { children: children(state) });
1006
1055
  }
1007
1056
  __name(WalletConnectionManager, "WalletConnectionManager");
@@ -1037,6 +1086,6 @@ function useWalletModalState(options = {}) {
1037
1086
  }
1038
1087
  __name(useWalletModalState, "useWalletModalState");
1039
1088
 
1040
- export { SolanaClientProvider, SolanaProvider, SolanaQueryProvider, WalletConnectionManager, useAccount, useBalance, useClientStore, useClusterState, useClusterStatus, useConnectWallet, useDisconnectWallet, useLatestBlockhash, useProgramAccounts, useSendTransaction, useSignatureStatus, useSimulateTransaction, useSolTransfer, useSolanaClient, useSplToken, useTransactionPool, useWaitForSignature, useWallet, useWalletActions, useWalletConnection, useWalletModalState, useWalletSession, useWalletStandardConnectors };
1089
+ export { SolanaClientProvider, SolanaProvider, SolanaQueryProvider, WalletConnectionManager, getLatestBlockhashKey, getProgramAccountsKey, getSignatureStatusKey, getSimulateTransactionKey, useAccount, useBalance, useClientStore, useClusterState, useClusterStatus, useConnectWallet, useDisconnectWallet, useLatestBlockhash, useProgramAccounts, useSendTransaction, useSignatureStatus, useSimulateTransaction, useSolTransfer, useSolanaClient, useSplToken, useTransactionPool, useWaitForSignature, useWallet, useWalletActions, useWalletConnection, useWalletModalState, useWalletSession };
1041
1090
  //# sourceMappingURL=index.browser.mjs.map
1042
1091
  //# sourceMappingURL=index.browser.mjs.map