@pear-protocol/symmio-client 0.3.2 → 0.3.5

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.
@@ -2,7 +2,7 @@
2
2
  import { createContext, useContext, useMemo, useCallback, useRef, useEffect } from 'react';
3
3
  import { createSymmSDK, isAuthExpiredError, isNetworkError, isInsufficientMarginError, isRateLimitedError, isTimeoutError } from '@pear-protocol/symm-core';
4
4
  import { create } from 'zustand';
5
- import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
5
+ import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
  import { SiweMessage } from 'siwe';
8
8
  import { isAddress, encodeFunctionData } from 'viem';
@@ -675,6 +675,9 @@ function useSymmWs(params = {}) {
675
675
  }, [symmCoreClient, accountAddress, chainId, queryClient, setConnected]);
676
676
  return { isConnected };
677
677
  }
678
+ function trimTrailingSlashes(value) {
679
+ return value.replace(/\/+$/, "");
680
+ }
678
681
  function SymmProvider({
679
682
  chainId = 42161,
680
683
  address,
@@ -686,13 +689,21 @@ function SymmProvider({
686
689
  symmioConfig,
687
690
  children
688
691
  }) {
692
+ const normalizedApiUrl = useMemo(
693
+ () => trimTrailingSlashes(symmCoreConfig.apiUrl),
694
+ [symmCoreConfig.apiUrl]
695
+ );
696
+ const normalizedWsUrl = useMemo(
697
+ () => symmCoreConfig.wsUrl ? trimTrailingSlashes(symmCoreConfig.wsUrl) : void 0,
698
+ [symmCoreConfig.wsUrl]
699
+ );
689
700
  const symmCoreClient = useMemo(() => {
690
701
  return createSymmSDK({
691
- apiUrl: symmCoreConfig.apiUrl,
692
- wsUrl: symmCoreConfig.wsUrl,
702
+ apiUrl: normalizedApiUrl,
703
+ wsUrl: normalizedWsUrl,
693
704
  defaultChainId: chainId
694
705
  });
695
- }, [chainId, symmCoreConfig.apiUrl, symmCoreConfig.wsUrl]);
706
+ }, [chainId, normalizedApiUrl, normalizedWsUrl]);
696
707
  const value = useMemo(
697
708
  () => ({
698
709
  symmCoreClient,
@@ -893,27 +904,116 @@ async function fetchAccessTokenEntry(walletClient, signerAddress, accountAddress
893
904
  writeStoredToken(accountAddress, chainId, cachedToken);
894
905
  return cachedToken;
895
906
  }
907
+ function authStoreKey(accountAddress, chainId, signerAddress) {
908
+ return `${accountAddress}:${chainId}:${signerAddress ?? ""}`;
909
+ }
910
+ function getEntryFromSnapshot(state, accountAddress, chainId, signerAddress) {
911
+ const signerScoped = state.entries[authStoreKey(accountAddress, chainId, signerAddress)];
912
+ if (signerScoped) {
913
+ return signerScoped;
914
+ }
915
+ return state.entries[authStoreKey(accountAddress, chainId)] ?? null;
916
+ }
917
+ function getStatusFromSnapshot(state, accountAddress, chainId, signerAddress) {
918
+ const signerScoped = state.status[authStoreKey(accountAddress, chainId, signerAddress)];
919
+ if (signerScoped) {
920
+ return signerScoped;
921
+ }
922
+ return state.status[authStoreKey(accountAddress, chainId)] ?? {
923
+ error: null,
924
+ isLoading: false
925
+ };
926
+ }
927
+ var useSymmAuthStore = create((set) => ({
928
+ entries: {},
929
+ status: {},
930
+ setEntry: (accountAddress, chainId, signerAddress, entry) => set((state) => ({
931
+ entries: {
932
+ ...state.entries,
933
+ [authStoreKey(accountAddress, chainId, signerAddress)]: entry
934
+ },
935
+ status: {
936
+ ...state.status,
937
+ [authStoreKey(accountAddress, chainId, signerAddress)]: {
938
+ error: null,
939
+ isLoading: false
940
+ }
941
+ }
942
+ })),
943
+ clearEntry: (accountAddress, chainId, signerAddress) => set((state) => {
944
+ const nextEntries = { ...state.entries };
945
+ const nextStatus = { ...state.status };
946
+ delete nextEntries[authStoreKey(accountAddress, chainId, signerAddress)];
947
+ delete nextStatus[authStoreKey(accountAddress, chainId, signerAddress)];
948
+ return {
949
+ entries: nextEntries,
950
+ status: nextStatus
951
+ };
952
+ }),
953
+ setStatus: (accountAddress, chainId, signerAddress, status) => set((state) => ({
954
+ status: {
955
+ ...state.status,
956
+ [authStoreKey(accountAddress, chainId, signerAddress)]: {
957
+ error: null,
958
+ isLoading: false,
959
+ ...state.status[authStoreKey(accountAddress, chainId, signerAddress)],
960
+ ...status
961
+ }
962
+ }
963
+ })),
964
+ reset: () => set({
965
+ entries: {},
966
+ status: {}
967
+ })
968
+ }));
969
+ function getAuthStoreEntry(accountAddress, chainId, signerAddress) {
970
+ return getEntryFromSnapshot(
971
+ useSymmAuthStore.getState(),
972
+ accountAddress,
973
+ chainId,
974
+ signerAddress
975
+ );
976
+ }
977
+ function selectAuthStoreEntry(state, accountAddress, chainId, signerAddress) {
978
+ if (!accountAddress || chainId == null) {
979
+ return null;
980
+ }
981
+ return getEntryFromSnapshot(state, accountAddress, chainId, signerAddress);
982
+ }
983
+ function selectAuthStoreStatus(state, accountAddress, chainId, signerAddress) {
984
+ if (!accountAddress || chainId == null) {
985
+ return {
986
+ error: null,
987
+ isLoading: false
988
+ };
989
+ }
990
+ return getStatusFromSnapshot(state, accountAddress, chainId, signerAddress);
991
+ }
992
+ function setAuthStoreEntry(accountAddress, chainId, signerAddress, entry) {
993
+ useSymmAuthStore.getState().setEntry(accountAddress, chainId, signerAddress, entry);
994
+ }
995
+ function setAuthStoreStatus(accountAddress, chainId, signerAddress, status) {
996
+ useSymmAuthStore.getState().setStatus(accountAddress, chainId, signerAddress, status);
997
+ }
998
+ function clearAuthStoreEntry(accountAddress, chainId, signerAddress) {
999
+ useSymmAuthStore.getState().clearEntry(accountAddress, chainId, signerAddress);
1000
+ }
896
1001
 
897
1002
  // src/react/auth-cache.ts
898
- function getAuthQueryData(queryClient, accountAddress, chainId, signerAddress) {
899
- return queryClient.getQueryData(
900
- symmKeys.auth(accountAddress, chainId, signerAddress)
901
- ) ?? null;
1003
+ function getAuthQueryData(accountAddress, chainId, signerAddress) {
1004
+ return getAuthStoreEntry(accountAddress, chainId, signerAddress);
902
1005
  }
903
- function setAuthQueryData(queryClient, accountAddress, chainId, signerAddress, entry) {
904
- queryClient.setQueryData(symmKeys.auth(accountAddress, chainId, signerAddress), entry);
1006
+ function setAuthQueryData(accountAddress, chainId, signerAddress, entry) {
1007
+ setAuthStoreEntry(accountAddress, chainId, signerAddress, entry);
905
1008
  }
906
- function clearAuthQueryData(queryClient, accountAddress, chainId, signerAddress) {
907
- queryClient.removeQueries({
908
- queryKey: symmKeys.auth(accountAddress, chainId, signerAddress),
909
- exact: true
910
- });
1009
+ function clearAuthQueryData(accountAddress, chainId, signerAddress) {
1010
+ clearAuthStoreEntry(accountAddress, chainId, signerAddress);
911
1011
  }
912
1012
  function clearPersistedAuthState(accountAddress, chainId) {
913
1013
  clearCachedToken(accountAddress, chainId);
914
1014
  }
915
- function getAuthTokenFromRuntimeCache(queryClient, accountAddress, chainId, signerAddress) {
916
- const inQuery = getAuthQueryData(queryClient, accountAddress, chainId, signerAddress) ?? getAuthQueryData(queryClient, accountAddress, chainId);
1015
+ function getAuthTokenFromRuntimeCache(accountAddress, chainId, signerAddress) {
1016
+ const inQuery = getAuthQueryData(accountAddress, chainId, signerAddress) ?? getAuthQueryData(accountAddress, chainId);
917
1017
  if (inQuery && inQuery.expiresAt > Date.now()) {
918
1018
  return inQuery.token;
919
1019
  }
@@ -921,11 +1021,10 @@ function getAuthTokenFromRuntimeCache(queryClient, accountAddress, chainId, sign
921
1021
  if (!persisted) {
922
1022
  return null;
923
1023
  }
924
- setAuthQueryData(queryClient, accountAddress, chainId, signerAddress, persisted);
1024
+ setAuthQueryData(accountAddress, chainId, signerAddress, persisted);
925
1025
  return persisted.token;
926
1026
  }
927
1027
  async function resolveAuthTokenEntry({
928
- queryClient,
929
1028
  walletClient,
930
1029
  signerAddress,
931
1030
  accountAddress,
@@ -937,13 +1036,13 @@ async function resolveAuthTokenEntry({
937
1036
  return null;
938
1037
  }
939
1038
  if (!force) {
940
- const inQuery = getAuthQueryData(queryClient, accountAddress, chainId, signerAddress);
1039
+ const inQuery = getAuthQueryData(accountAddress, chainId, signerAddress);
941
1040
  if (inQuery && inQuery.expiresAt > Date.now()) {
942
1041
  return inQuery;
943
1042
  }
944
1043
  const persisted = getCachedTokenEntry(accountAddress, chainId);
945
1044
  if (persisted) {
946
- setAuthQueryData(queryClient, accountAddress, chainId, signerAddress, persisted);
1045
+ setAuthQueryData(accountAddress, chainId, signerAddress, persisted);
947
1046
  return persisted;
948
1047
  }
949
1048
  }
@@ -954,25 +1053,33 @@ async function resolveAuthTokenEntry({
954
1053
  chainId,
955
1054
  siweDomain
956
1055
  );
957
- setAuthQueryData(queryClient, accountAddress, chainId, signerAddress, fresh);
1056
+ setAuthQueryData(accountAddress, chainId, signerAddress, fresh);
958
1057
  return fresh;
959
1058
  }
960
- function clearAuthState(queryClient, accountAddress, chainId, signerAddress) {
1059
+ function clearAuthState(accountAddress, chainId, signerAddress) {
961
1060
  clearPersistedAuthState(accountAddress, chainId);
962
- clearAuthQueryData(queryClient, accountAddress, chainId, signerAddress);
1061
+ clearAuthQueryData(accountAddress, chainId, signerAddress);
963
1062
  }
964
1063
 
965
1064
  // src/react/hooks/use-symm-auth.ts
966
1065
  function useSymmAuth(params) {
967
1066
  const context = useSymmContext();
968
- const queryClient = useQueryClient();
969
1067
  const address = params?.address ?? context.address;
970
1068
  const chainId = params?.chainId ?? context.chainId ?? 42161;
971
1069
  const walletClient = params?.walletClient ?? context.walletClient;
972
1070
  const siweDomain = params?.siweDomain;
973
1071
  const activeAccountAddress = params?.activeAccountAddress;
974
- const canBootstrap = !!walletClient && !!address && !!activeAccountAddress;
975
- const refreshAuth = useCallback(
1072
+ const authEntry = useSymmAuthStore(
1073
+ (state) => selectAuthStoreEntry(state, activeAccountAddress, chainId, address)
1074
+ );
1075
+ useSymmAuthStore(
1076
+ (state) => selectAuthStoreStatus(state, activeAccountAddress, chainId, address).isLoading
1077
+ );
1078
+ const error = useSymmAuthStore(
1079
+ (state) => selectAuthStoreStatus(state, activeAccountAddress, chainId, address).error
1080
+ );
1081
+ const persistedEntry = !authEntry && activeAccountAddress ? getCachedTokenEntry(activeAccountAddress, chainId) : null;
1082
+ const signIn = useCallback(
976
1083
  async (accountAddress, options) => {
977
1084
  const resolvedAccountAddress = accountAddress ?? activeAccountAddress;
978
1085
  if (!resolvedAccountAddress) {
@@ -980,8 +1087,11 @@ function useSymmAuth(params) {
980
1087
  }
981
1088
  if (!walletClient || !address) return null;
982
1089
  try {
983
- const tokenEntry = await resolveAuthTokenEntry({
984
- queryClient,
1090
+ setAuthStoreStatus(resolvedAccountAddress, chainId, address, {
1091
+ error: null,
1092
+ isLoading: true
1093
+ });
1094
+ const tokenEntry2 = await resolveAuthTokenEntry({
985
1095
  walletClient,
986
1096
  signerAddress: address,
987
1097
  accountAddress: resolvedAccountAddress,
@@ -989,10 +1099,16 @@ function useSymmAuth(params) {
989
1099
  siweDomain,
990
1100
  force: options?.force
991
1101
  });
992
- const token2 = tokenEntry?.token ?? null;
993
- return token2;
994
- } catch (error) {
995
- clearPersistedAuthState(resolvedAccountAddress, chainId);
1102
+ setAuthStoreStatus(resolvedAccountAddress, chainId, address, {
1103
+ error: null,
1104
+ isLoading: false
1105
+ });
1106
+ return tokenEntry2?.token ?? null;
1107
+ } catch (error2) {
1108
+ clearAuthState(resolvedAccountAddress, chainId, address);
1109
+ setAuthStoreStatus(resolvedAccountAddress, chainId, address, {
1110
+ error: error2 instanceof Error ? error2 : new Error("failed to sign in")
1111
+ });
996
1112
  return null;
997
1113
  }
998
1114
  },
@@ -1001,46 +1117,22 @@ function useSymmAuth(params) {
1001
1117
  address,
1002
1118
  activeAccountAddress,
1003
1119
  chainId,
1004
- siweDomain,
1005
- queryClient
1120
+ siweDomain
1006
1121
  ]
1007
1122
  );
1008
- const authQuery = useQuery({
1009
- queryKey: symmKeys.auth(activeAccountAddress, chainId, address),
1010
- queryFn: async () => {
1011
- const tokenEntry = await resolveAuthTokenEntry({
1012
- queryClient,
1013
- walletClient,
1014
- signerAddress: address,
1015
- accountAddress: activeAccountAddress,
1016
- chainId,
1017
- siweDomain
1018
- });
1019
- if (!tokenEntry) {
1020
- return null;
1021
- }
1022
- return tokenEntry;
1023
- },
1024
- enabled: canBootstrap,
1025
- retry: false,
1026
- refetchOnWindowFocus: false,
1027
- refetchOnReconnect: false
1028
- });
1029
1123
  const clearAuth = useCallback(() => {
1030
1124
  if (activeAccountAddress) {
1031
- clearAuthState(queryClient, activeAccountAddress, chainId, address);
1125
+ clearAuthState(activeAccountAddress, chainId, address);
1032
1126
  }
1033
- }, [activeAccountAddress, address, chainId, queryClient]);
1034
- const token = authQuery.data?.token ?? null;
1127
+ }, [activeAccountAddress, address, chainId]);
1128
+ const tokenEntry = authEntry ?? persistedEntry;
1129
+ const token = tokenEntry?.token ?? null;
1035
1130
  return {
1036
1131
  accessToken: token,
1037
- authToken: token,
1038
1132
  isAuthenticated: !!token,
1039
- isLoading: authQuery.isLoading,
1040
- isFetching: authQuery.isFetching,
1041
- error: authQuery.error,
1042
- refresh: refreshAuth,
1043
- refreshAuth,
1133
+ error,
1134
+ signIn,
1135
+ refreshAuth: signIn,
1044
1136
  clear: clearAuth
1045
1137
  };
1046
1138
  }
@@ -1844,7 +1936,6 @@ async function ensureInstantTradeReady(deps, queryClient, request) {
1844
1936
  throw new Error("at least one delegation selector is required");
1845
1937
  }
1846
1938
  const accessToken = getAuthTokenFromRuntimeCache(
1847
- queryClient,
1848
1939
  accountAddress,
1849
1940
  chainId,
1850
1941
  signerAddress
@@ -2254,7 +2345,6 @@ function splitTradeHookArgs(paramsOrOptions, options) {
2254
2345
  }
2255
2346
  function useResolveTradeAuthToken(params = {}) {
2256
2347
  const context = useSymmContext();
2257
- const queryClient = useQueryClient();
2258
2348
  const address = params.address ?? context.address;
2259
2349
  const chainId = params.chainId ?? context.chainId;
2260
2350
  return useCallback(
@@ -2268,7 +2358,6 @@ function useResolveTradeAuthToken(params = {}) {
2268
2358
  return null;
2269
2359
  }
2270
2360
  const inMemoryToken = getAuthTokenFromRuntimeCache(
2271
- queryClient,
2272
2361
  resolvedAccountAddress,
2273
2362
  resolvedChainId,
2274
2363
  address
@@ -2278,7 +2367,7 @@ function useResolveTradeAuthToken(params = {}) {
2278
2367
  }
2279
2368
  return null;
2280
2369
  },
2281
- [address, chainId, queryClient]
2370
+ [address, chainId]
2282
2371
  );
2283
2372
  }
2284
2373
 
@@ -26240,7 +26329,6 @@ function useSymmPendingInstantOpens(params) {
26240
26329
  chainId: ctxChainId,
26241
26330
  address
26242
26331
  } = useSymmContext();
26243
- const queryClient = useQueryClient();
26244
26332
  const { accountAddress, authToken: providedAuthToken } = params;
26245
26333
  const chainId = params.chainId ?? ctxChainId;
26246
26334
  const internalEnabled = !!symmCoreClient && !!accountAddress;
@@ -26249,7 +26337,6 @@ function useSymmPendingInstantOpens(params) {
26249
26337
  queryKey: symmKeys.pendingInstantOpens(accountAddress, chainId),
26250
26338
  queryFn: async () => {
26251
26339
  const authToken = providedAuthToken ?? getAuthTokenFromRuntimeCache(
26252
- queryClient,
26253
26340
  accountAddress,
26254
26341
  chainId,
26255
26342
  address