Skip to content

Commit

Permalink
fix: use account session and fix errors when the session is invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
Jadapema committed Jan 22, 2025
1 parent 40e1359 commit 1a9de20
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 141 deletions.
5 changes: 2 additions & 3 deletions src/auth/context/web3Auth/config/web3AuthSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,11 @@ export function web3AuthFactory(): Web3Auth {
});

const web3AuthOptions: Web3AuthOptions = {
// sessionTime: 60 * 60 * 24 * 30, // 30 days
sessionTime: 10, // 10 seconds
sessionTime: 60 * 60 * 24 * 30, // 30 days
privateKeyProvider,
accountAbstractionProvider,
chainConfig: chain.polygonAmoy,
// storageKey: 'local',
storageKey: 'local',
clientId: GLOBAL_CONSTANTS.WEB3_CLIENT_ID,
uiConfig: {
appName: 'Watchit',
Expand Down
3 changes: 1 addition & 2 deletions src/components/activate-subscription-profile-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ export const ActivateSubscriptionProfileModal = ({

onClose?.();
} catch (err) {
console.error('err');
console.error(err);
notifyError(ERRORS.ACTIVATE_SUBSCRIPTION_FAILED_ERROR);
}
};

Expand Down
115 changes: 82 additions & 33 deletions src/hooks/use-account-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,27 @@ import { useWeb3Session } from '@src/hooks/use-web3-session';

// ----------------------------------------------------------------------

interface UseAccountSessionProps {
/**
* Whether to automatically run the expiration checks
* on mount + every interval (default: true).
*/
autoCheck?: boolean;
}

interface UseAccountSessionHook {
/**
* Combined logout for Lens + Web3Auth
*/
logout: () => Promise<void>;

/**
* Check session validity on demand:
* - Verifies Web3Auth is fully connected (or still connecting)
* - Verifies localStorage expiration
* - Logs out + notifies error if invalid
*/
checkSessionValidity: () => void;
}

// ----------------------------------------------------------------------
Expand All @@ -28,76 +47,94 @@ interface UseAccountSessionHook {
* This hook consolidates:
* 1. Lens session fetching & Redux updates.
* 2. Web3Auth session validation (connected, bundler, smartAccount).
* 3. LocalStorage expiration checks + auto-logout.
* 3. LocalStorage expiration checks + auto-logout (optionally).
*
* If `autoCheck` is false, the hook won't run the checks automatically,
* but you can still call `checkSessionValidity()` manually.
*/
export const useAccountSession = (): UseAccountSessionHook => {
export const useAccountSession = (
{ autoCheck = true }: UseAccountSessionProps = {}
): UseAccountSessionHook => {
const dispatch = useDispatch();
const { execute: lensLogout } = useLogout();
const { web3Auth } = useWeb3Auth();
const { data, loading } = useSession();
const isUpdatingMetadata: boolean = useSelector(
(state: any) => state.auth.isUpdatingMetadata
);
const { bundlerClient, smartAccount } = useWeb3Session();

// Update Redux with the current session loading status from Lens
const parsedSessionConnected = JSON.stringify(web3Auth.connected);
const parsedSessionData = JSON.stringify(data);

// Keep Redux in sync with Lens loading state
useEffect(() => {
// If autoCheck is disabled, skip
if (!autoCheck) return;
dispatch(setAuthLoading({ isSessionLoading: loading }));
}, [loading]);

// Convert session data to string so that changes in the object trigger this effect
const parsedSessionData = JSON.stringify(data);
}, [loading, autoCheck]);

// Update Redux session whenever Lens session data changes (unless updating metadata)
// Keep Redux in sync with actual Lens session data
useEffect(() => {
// If autoCheck is disabled, skip
if (!autoCheck) return;
if (!isUpdatingMetadata) {
dispatch(setSession({ session: data }));
}
}, [parsedSessionData, isUpdatingMetadata]);
}, [parsedSessionData, isUpdatingMetadata, autoCheck]);

// logout (Lens + Web3Auth)
// LOGOUT (Lens + Web3Auth)
const logout = useCallback(async () => {
try {
// 1) Logout from Lens
await lensLogout();
// 2) Logout from Web3Auth
await web3Auth?.logout();
// 3) Clear Redux states or local
// 3) Clear Redux state & localStorage
dispatch(setBalance({ balance: 0 }));
dispatch(setAuthLoading({ isSessionLoading: false }));
localStorage.removeItem('sessionExpiration');
} catch (err) {
console.error('Error during logout:', err);
localStorage.removeItem('sessionExpiration');
}
}, [lensLogout, web3Auth, dispatch]);

// Validate Web3Auth Session
const { bundlerClient, smartAccount } = useWeb3Session();

// Decide if Web3Auth is in a valid/connecting state
const isValidWeb3AuthSession = useCallback((): boolean => {
// Check that user is connected, status is 'connected', and bundler + smartAccount are available
return (
const isConnecting =
web3Auth.status === 'connecting' ||
web3Auth.status === 'not_ready';

const isFullyValid =
web3Auth.connected &&
web3Auth.status === 'connected' &&
!!bundlerClient &&
!!smartAccount
);
!!smartAccount;

console.log('isValidWeb3AuthSession')
console.log(isConnecting)
console.log(isFullyValid)
console.log(isConnecting || isFullyValid)

// Return true if either "still connecting" or "fully valid"
return isConnecting || isFullyValid;
}, [web3Auth.connected, web3Auth.status, bundlerClient, smartAccount]);

// Expiration Checks
// If session is invalid or expired, do logout + show error
const handleSessionExpired = useCallback(() => {
logout();
notifyError(ERRORS.BUNDLER_UNAVAILABLE);
}, [logout]);

const checkSessionValidity = useCallback(() => {
console.log('checkSessionValidity')
// If Web3Auth isn't fully valid, consider session expired
// 1) If Web3Auth isn't valid (and not just connecting), expire
if (!isValidWeb3AuthSession()) {
handleSessionExpired();
return;
}

// Otherwise, check localStorage for expiration
// 2) Otherwise, check localStorage for expiration
const expirationStr = localStorage.getItem('sessionExpiration');
if (!expirationStr) return;

Expand All @@ -107,33 +144,45 @@ export const useAccountSession = (): UseAccountSessionHook => {
}
}, [isValidWeb3AuthSession, handleSessionExpired]);

const parsedSessionConnected = JSON.stringify(web3Auth.connected);
const parsedData = JSON.stringify(data);

// Interval to Check Expiration
// Automatic checks on mount + interval
useEffect(() => {
// Only run the expiration checks if the user is connected
if (!web3Auth.connected) {
// If autoCheck is disabled, skip
if (!autoCheck) return;

// If Lens or Web3Auth is still loading, skip checks until loaded
if (loading || web3Auth.status === 'connecting' || web3Auth.status === 'not_ready') return;

// If user is not authenticated in Lens, skip
if (!data?.authenticated) {
return;
}

// If Web3Auth is in "ready" state but not connected, log out
// (meaning: it's done with any connecting state, but the user is not actually connected)
if (!web3Auth.connected && web3Auth.status === 'ready') {
logout();
return;
}
// if (!web3Auth.connected && data?.authenticated) return handleSessionExpired();
if (!data?.authenticated) return;

// Check once immediately
checkSessionValidity();

// Then check every 60 seconds
const intervalId = setInterval(() => {
checkSessionValidity();
// }, 60 * 1000);
}, 5 * 1000);
}, 60 * 1000);

// Cleanup
return () => clearInterval(intervalId);
}, [parsedSessionConnected, parsedData]);
}, [
autoCheck,
loading,
parsedSessionConnected,
parsedSessionData
]);

return {
logout,
checkSessionValidity,
};
};
29 changes: 15 additions & 14 deletions src/hooks/use-authorize-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { GLOBAL_CONSTANTS } from '@src/config-global.ts';
import { useSelector } from 'react-redux';
import { useWeb3Session } from '@src/hooks/use-web3-session.ts';
import { ERRORS } from '@notifications/errors.ts';
import { useAccountSession } from '@src/hooks/use-account-session.ts';

// ----------------------------------------------------------------------
// Define the return type of the useAuthorizePolicy hook
Expand All @@ -34,6 +35,7 @@ export const useAuthorizePolicy = (): useAuthorizePolicyHook => {
const [error, setError] = useState<keyof typeof ERRORS | null>(null);
const sessionData = useSelector((state: any) => state.auth.session);
const { bundlerClient, smartAccount } = useWeb3Session();
const { checkSessionValidity } = useAccountSession({ autoCheck: false });

/**
* Creates the flash policy agreement data.
Expand All @@ -57,19 +59,19 @@ export const useAuthorizePolicy = (): useAuthorizePolicyHook => {
setLoading(true);
setError(null);

try {
if (!sessionData?.authenticated) {
setError(ERRORS.AUTHORIZATION_POLICY_ERROR);
setLoading(false);
return;
}

if (!bundlerClient) {
setError(ERRORS.BUNDLER_UNAVAILABLE);
setLoading(false);
return;
}
if (!sessionData?.authenticated) {
setError(ERRORS.AUTHORIZATION_POLICY_ERROR);
setLoading(false);
return;
}

if (!bundlerClient) {
checkSessionValidity();
setLoading(false);
throw new Error('Invalid Web3Auth session');
}

try {
// Prepare the authorize policy data
const rightPolicyAuthorizerData = initializeAuthorizePolicy({
policyAddress,
Expand Down Expand Up @@ -100,8 +102,7 @@ export const useAuthorizePolicy = (): useAuthorizePolicyHook => {
setData(receipt);
setLoading(false);
} catch (err: any) {
console.log('err')
console.log(err)
console.error('USE AUTHORIZE POLICY ERR:', err);
setError(ERRORS.UNKNOWN_ERROR);
setLoading(false);
}
Expand Down
29 changes: 14 additions & 15 deletions src/hooks/use-deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import MMCAbi from '@src/config/abi/MMC.json';
import { GLOBAL_CONSTANTS } from '@src/config-global';
import { useWeb3Session } from '@src/hooks/use-web3-session.ts';
import { ERRORS } from '@notifications/errors.ts';
import { useAccountSession } from '@src/hooks/use-account-session.ts';

interface DepositParams {
recipient: string; // address
Expand All @@ -25,6 +26,7 @@ export const useDeposit = (): UseDepositHook => {
const [error, setError] = useState<keyof typeof ERRORS | null>(null);
const { bundlerClient, smartAccount } = useWeb3Session();
const sessionData = useSelector((state: any) => state.auth.session);
const { checkSessionValidity } = useAccountSession({ autoCheck: false });

const approveMMC = (amount: number): string => {
// Convert to Wei (assuming 18 decimals)
Expand Down Expand Up @@ -58,19 +60,19 @@ export const useDeposit = (): UseDepositHook => {
setLoading(true);
setError(null);

try {
if (!sessionData?.authenticated) {
setError(ERRORS.DEPOSIT_FAILED_ERROR);
setLoading(false);
return;
}
if (!sessionData?.authenticated) {
setError(ERRORS.DEPOSIT_FAILED_ERROR);
setLoading(false);
return;
}

if (!bundlerClient) {
setError(ERRORS.BUNDLER_UNAVAILABLE);
setLoading(false);
return;
}
if (!bundlerClient) {
checkSessionValidity();
setLoading(false);
throw new Error('Invalid Web3Auth session');
}

try {
const approveData = approveMMC(amount);
const depositData = initializeDeposit({ recipient, amount });

Expand Down Expand Up @@ -102,11 +104,8 @@ export const useDeposit = (): UseDepositHook => {
setData(receipt);
setLoading(false);
} catch (err: any) {

console.error('USE DEPOSIT ERR:', err);
setError(ERRORS.UNKNOWN_ERROR);

console.error('USE DEPOSIT:', err);

setLoading(false);
}
};
Expand Down
Loading

0 comments on commit 1a9de20

Please sign in to comment.