From f8671dc2c0a623234ff16ce1ed7431ff9c436126 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Thu, 27 Mar 2025 14:12:19 +0530 Subject: [PATCH] chore: restructure contexts and hooks for readability --- examples/keystore-management/.gitignore | 4 + .../keystore-management/src/app/layout.tsx | 22 +- .../src/components/KeystoreManager.tsx | 2 +- .../components/RLNImplementationToggle.tsx | 2 +- .../components/RLNMembershipRegistration.tsx | 4 +- .../src/components/WalletInfo.tsx | 2 +- .../src/contexts/RLNUnifiedContext.tsx | 23 -- .../src/contexts/RLNUnifiedHook.tsx | 93 ------ .../keystore-management/src/contexts/index.ts | 15 + .../{ => keystore}/KeystoreContext.tsx | 0 .../src/contexts/keystore/index.ts | 1 + .../RLNContext.tsx} | 271 ++++++------------ .../{ => rln}/RLNImplementationContext.tsx | 2 +- .../implementations/factory.tsx} | 2 +- .../src/contexts/rln/implementations/index.ts | 3 + .../implementations/light.tsx} | 86 +----- .../implementations/standard.tsx} | 76 +---- .../src/contexts/rln/index.ts | 3 + .../src/contexts/rln/utils/network.ts | 68 +++++ .../contexts/{ => wallet}/WalletContext.tsx | 0 .../src/contexts/wallet/index.ts | 1 + 21 files changed, 215 insertions(+), 465 deletions(-) delete mode 100644 examples/keystore-management/src/contexts/RLNUnifiedContext.tsx delete mode 100644 examples/keystore-management/src/contexts/RLNUnifiedHook.tsx create mode 100644 examples/keystore-management/src/contexts/index.ts rename examples/keystore-management/src/contexts/{ => keystore}/KeystoreContext.tsx (100%) create mode 100644 examples/keystore-management/src/contexts/keystore/index.ts rename examples/keystore-management/src/contexts/{RLNUnifiedContext2.tsx => rln/RLNContext.tsx} (58%) rename examples/keystore-management/src/contexts/{ => rln}/RLNImplementationContext.tsx (99%) rename examples/keystore-management/src/contexts/{RLNFactory.tsx => rln/implementations/factory.tsx} (99%) create mode 100644 examples/keystore-management/src/contexts/rln/implementations/index.ts rename examples/keystore-management/src/contexts/{RLNLightContext.tsx => rln/implementations/light.tsx} (73%) rename examples/keystore-management/src/contexts/{RLNZerokitContext.tsx => rln/implementations/standard.tsx} (76%) create mode 100644 examples/keystore-management/src/contexts/rln/index.ts create mode 100644 examples/keystore-management/src/contexts/rln/utils/network.ts rename examples/keystore-management/src/contexts/{ => wallet}/WalletContext.tsx (100%) create mode 100644 examples/keystore-management/src/contexts/wallet/index.ts diff --git a/examples/keystore-management/.gitignore b/examples/keystore-management/.gitignore index 5ef6a52..b85cbcd 100644 --- a/examples/keystore-management/.gitignore +++ b/examples/keystore-management/.gitignore @@ -39,3 +39,7 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +.giga/ +.cursor/* +.cursorrules diff --git a/examples/keystore-management/src/app/layout.tsx b/examples/keystore-management/src/app/layout.tsx index b9a21d5..c760e7e 100644 --- a/examples/keystore-management/src/app/layout.tsx +++ b/examples/keystore-management/src/app/layout.tsx @@ -1,19 +1,11 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Inter } from 'next/font/google' import "./globals.css"; -import { WalletProvider } from "../contexts/WalletContext"; -import { RLNUnifiedProvider } from "../contexts/RLNUnifiedContext2"; -import { RLNImplementationProvider } from "../contexts/RLNImplementationContext"; -import { KeystoreProvider } from "../contexts/KeystoreContext"; +import { WalletProvider, RLNImplementationProvider, KeystoreProvider, RLNProvider } from "../contexts/index"; import { Header } from "../components/Header"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const inter = Inter({ + variable: "--font-inter", subsets: ["latin"], }); @@ -30,19 +22,19 @@ export default function RootLayout({ return ( - +
{children}
-
+
diff --git a/examples/keystore-management/src/components/KeystoreManager.tsx b/examples/keystore-management/src/components/KeystoreManager.tsx index 2ef1bc8..33db7de 100644 --- a/examples/keystore-management/src/components/KeystoreManager.tsx +++ b/examples/keystore-management/src/components/KeystoreManager.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from 'react'; -import { useKeystore } from '../contexts/KeystoreContext'; +import { useKeystore } from '../contexts/index'; import { saveKeystoreToFile, readKeystoreFromFile } from '../utils/fileUtils'; export default function KeystoreManager() { diff --git a/examples/keystore-management/src/components/RLNImplementationToggle.tsx b/examples/keystore-management/src/components/RLNImplementationToggle.tsx index 5c730d5..6250093 100644 --- a/examples/keystore-management/src/components/RLNImplementationToggle.tsx +++ b/examples/keystore-management/src/components/RLNImplementationToggle.tsx @@ -1,6 +1,6 @@ "use client"; -import { useRLNImplementation, RLNImplementationType } from '../contexts/RLNImplementationContext'; +import { useRLNImplementation, type RLNImplementationType } from '../contexts/index'; export function RLNImplementationToggle() { const { implementation, setImplementation } = useRLNImplementation(); diff --git a/examples/keystore-management/src/components/RLNMembershipRegistration.tsx b/examples/keystore-management/src/components/RLNMembershipRegistration.tsx index 57d2a15..8a8ba82 100644 --- a/examples/keystore-management/src/components/RLNMembershipRegistration.tsx +++ b/examples/keystore-management/src/components/RLNMembershipRegistration.tsx @@ -1,9 +1,9 @@ "use client"; import { useState } from 'react'; -import { useRLN } from '../contexts/RLNUnifiedContext2'; -import { useWallet } from '../contexts/WalletContext'; +import { useWallet } from '../contexts/index'; import { KeystoreEntity } from '@waku/rln'; +import { useRLN } from '../contexts/rln'; export default function RLNMembershipRegistration() { const { registerMembership, isInitialized, isStarted, rateMinLimit, rateMaxLimit, error, initializeRLN } = useRLN(); diff --git a/examples/keystore-management/src/components/WalletInfo.tsx b/examples/keystore-management/src/components/WalletInfo.tsx index 3b81d89..aa9444e 100644 --- a/examples/keystore-management/src/components/WalletInfo.tsx +++ b/examples/keystore-management/src/components/WalletInfo.tsx @@ -1,7 +1,7 @@ "use client"; import React from 'react'; -import { useWallet } from '../contexts/WalletContext'; +import { useWallet } from '../contexts/index'; function getNetworkName(chainId: number | null): string { if (!chainId) return 'Unknown'; diff --git a/examples/keystore-management/src/contexts/RLNUnifiedContext.tsx b/examples/keystore-management/src/contexts/RLNUnifiedContext.tsx deleted file mode 100644 index 6c96150..0000000 --- a/examples/keystore-management/src/contexts/RLNUnifiedContext.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; - -import { ReactNode } from 'react'; -import { RLNProvider as StandardRLNProvider } from './RLNZerokitContext'; -import { RLNProvider as LightRLNProvider } from './RLNLightContext'; -import { useRLNImplementation } from './RLNImplementationContext'; - -// Create a unified provider that conditionally renders the appropriate provider -export function RLNUnifiedProvider({ children }: { children: ReactNode }) { - const { implementation } = useRLNImplementation(); - - // Render the appropriate provider based on the implementation - return ( - <> - {implementation === 'standard' ? ( - {children} - ) : ( - {children} - )} - - ); -} - diff --git a/examples/keystore-management/src/contexts/RLNUnifiedHook.tsx b/examples/keystore-management/src/contexts/RLNUnifiedHook.tsx deleted file mode 100644 index 7449120..0000000 --- a/examples/keystore-management/src/contexts/RLNUnifiedHook.tsx +++ /dev/null @@ -1,93 +0,0 @@ -"use client"; - -import { createContext, useContext, useState, useEffect, ReactNode } from 'react'; -import { DecryptedCredentials, RLNInstance, RLNLightInstance } from '@waku/rln'; -import { useRLNImplementation } from './RLNImplementationContext'; - -// Define a dummy context for when neither implementation is available -interface RLNContextType { - rln: RLNInstance | RLNLightInstance | null; - isInitialized: boolean; - isStarted: boolean; - error: string | null; - initializeRLN: () => Promise; - registerMembership: (rateLimit: number) => Promise<{ success: boolean; error?: string; credentials?: DecryptedCredentials }>; - rateMinLimit: number; - rateMaxLimit: number; -} - -// Create a dummy context with default values -const dummyRLNContext: RLNContextType = { - rln: null, - isInitialized: false, - isStarted: false, - error: 'RLN context not initialized', - initializeRLN: async () => { throw new Error('RLN context not initialized'); }, - registerMembership: async () => ({ success: false, error: 'RLN context not initialized' }), - rateMinLimit: 20, - rateMaxLimit: 600 -}; - -// Create a context to store the selected RLN implementation -const UnifiedRLNContext = createContext(dummyRLNContext); - -// Create a provider component that will fetch the appropriate implementation -export function UnifiedRLNProvider({ children }: { children: ReactNode }) { - const { implementation } = useRLNImplementation(); - const [contextValue, setContextValue] = useState(dummyRLNContext); - - useEffect(() => { - // This effect will run when the implementation changes - // We'll dynamically import the appropriate context module - const fetchContext = async () => { - try { - if (implementation === 'standard') { - // Import the standard RLN hook - const standardModule = await import('./RLNZerokitContext'); - const { useRLN: useStandardRLN } = standardModule; - - // Create a temporary component to access the context - function TempComponent() { - const context = useStandardRLN(); - setContextValue(context); - return null; - } - - // Render the component within the provider - const { RLNProvider } = standardModule; - return ; - } else { - // Import the light RLN hook - const lightModule = await import('./RLNLightContext'); - const { useRLN: useLightRLN } = lightModule; - - // Create a temporary component to access the context - function TempComponent() { - const context = useLightRLN(); - setContextValue(context); - return null; - } - - // Render the component within the provider - const { RLNProvider } = lightModule; - return ; - } - } catch (error) { - console.error('Error loading RLN context:', error); - } - }; - - fetchContext(); - }, [implementation]); - - return ( - - {children} - - ); -} - -// Create a hook to use the unified RLN context -export function useRLN() { - return useContext(UnifiedRLNContext); -} diff --git a/examples/keystore-management/src/contexts/index.ts b/examples/keystore-management/src/contexts/index.ts new file mode 100644 index 0000000..cac44a5 --- /dev/null +++ b/examples/keystore-management/src/contexts/index.ts @@ -0,0 +1,15 @@ +// Re-export wallet context +export { WalletProvider, useWallet } from './wallet'; + +// Re-export keystore context +export { KeystoreProvider, useKeystore } from './keystore'; + +// Re-export RLN contexts +export { + RLNImplementationProvider, + useRLNImplementation, + type RLNImplementationType, + RLNProvider, + type UnifiedRLNInstance, + useRLN +} from './rln'; \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/KeystoreContext.tsx b/examples/keystore-management/src/contexts/keystore/KeystoreContext.tsx similarity index 100% rename from examples/keystore-management/src/contexts/KeystoreContext.tsx rename to examples/keystore-management/src/contexts/keystore/KeystoreContext.tsx diff --git a/examples/keystore-management/src/contexts/keystore/index.ts b/examples/keystore-management/src/contexts/keystore/index.ts new file mode 100644 index 0000000..b92e7da --- /dev/null +++ b/examples/keystore-management/src/contexts/keystore/index.ts @@ -0,0 +1 @@ +export { KeystoreProvider, useKeystore } from './KeystoreContext'; \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/RLNUnifiedContext2.tsx b/examples/keystore-management/src/contexts/rln/RLNContext.tsx similarity index 58% rename from examples/keystore-management/src/contexts/RLNUnifiedContext2.tsx rename to examples/keystore-management/src/contexts/rln/RLNContext.tsx index c7e2141..36ed21b 100644 --- a/examples/keystore-management/src/contexts/RLNUnifiedContext2.tsx +++ b/examples/keystore-management/src/contexts/rln/RLNContext.tsx @@ -2,24 +2,11 @@ import { createContext, useContext, useState, useEffect, ReactNode } from 'react'; import { KeystoreEntity } from '@waku/rln'; -import { UnifiedRLNInstance } from './RLNFactory'; +import { createRLNImplementation, UnifiedRLNInstance } from './implementations'; import { useRLNImplementation } from './RLNImplementationContext'; -import { createRLNImplementation } from './RLNFactory'; import { ethers } from 'ethers'; -import { useKeystore } from './KeystoreContext'; - -// Constants for RLN membership registration -const ERC20_ABI = [ - "function allowance(address owner, address spender) view returns (uint256)", - "function approve(address spender, uint256 amount) returns (bool)", - "function balanceOf(address account) view returns (uint256)" -]; - -// Linea Sepolia configuration -const LINEA_SEPOLIA_CONFIG = { - chainId: 59141, - tokenAddress: '0x185A0015aC462a0aECb81beCc0497b649a64B9ea' -}; +import { useKeystore } from '../keystore'; +import { ERC20_ABI, LINEA_SEPOLIA_CONFIG, ensureLineaSepoliaNetwork } from './utils/network'; // Define the context type interface RLNContextType { @@ -42,10 +29,10 @@ interface RLNContextType { } // Create the context -const RLNUnifiedContext = createContext(undefined); +const RLNContext = createContext(undefined); // Create the provider component -export function RLNUnifiedProvider({ children }: { children: ReactNode }) { +export function RLNProvider({ children }: { children: ReactNode }) { const { implementation } = useRLNImplementation(); const [rln, setRln] = useState(null); const [isInitialized, setIsInitialized] = useState(false); @@ -109,53 +96,6 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { setError(null); }, [implementation]); - const ensureLineaSepoliaNetwork = async (): Promise => { - try { - console.log("Current network: unknown", await signer?.getChainId()); - - // Check if already on Linea Sepolia - if (await signer?.getChainId() === LINEA_SEPOLIA_CONFIG.chainId) { - console.log("Already on Linea Sepolia network"); - return true; - } - - // If not on Linea Sepolia, try to switch - console.log("Not on Linea Sepolia, attempting to switch..."); - - interface EthereumProvider { - request: (args: { - method: string; - params?: unknown[] - }) => Promise; - } - - // Get the provider from window.ethereum - const provider = window.ethereum as EthereumProvider | undefined; - - if (!provider) { - console.warn("No Ethereum provider found"); - return false; - } - - try { - // Request network switch - await provider.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: `0x${LINEA_SEPOLIA_CONFIG.chainId.toString(16)}` }], - }); - - console.log("Successfully switched to Linea Sepolia"); - return true; - } catch (switchError: unknown) { - console.error("Error switching network:", switchError); - return false; - } - } catch (err) { - console.error("Error checking or switching network:", err); - return false; - } - }; - const initializeRLN = async () => { console.log("InitializeRLN called. Connected:", isConnected, "Signer available:", !!signer); @@ -251,23 +191,21 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { setRateMinLimit(minLimit); setRateMaxLimit(maxLimit); - return { - success: true, - rateMinLimit: minLimit, - rateMaxLimit: maxLimit + return { + success: true, + rateMinLimit: minLimit, + rateMaxLimit: maxLimit }; - } catch (error) { - console.error("Error getting rate limits bounds:", error); + } catch (err) { return { success: false, - rateMinLimit: 0, - rateMaxLimit: 0, - error: 'Failed to get rate limits bounds' + rateMinLimit: rateMinLimit, + rateMaxLimit: rateMaxLimit, + error: err instanceof Error ? err.message : 'Failed to get rate limits' }; } - } + }; - // Save credentials to keystore const saveCredentialsToKeystore = async (credentials: KeystoreEntity, password: string): Promise => { try { return await saveToKeystore(credentials, password); @@ -277,13 +215,7 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { } }; - // Update registerMembership to optionally save credentials to keystore - const registerMembership = async (rateLimit: number, saveOptions?: { password: string }): Promise<{ - success: boolean; - error?: string; - credentials?: KeystoreEntity; - keystoreHash?: string; - }> => { + const registerMembership = async (rateLimit: number, saveOptions?: { password: string }) => { console.log("registerMembership called with rate limit:", rateLimit); if (!rln || !isStarted) { @@ -295,13 +227,6 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { } try { - console.log("im here") - const rateMinLimit = await rln.contract.getMinRateLimit(); - const rateMaxLimit = await rln.contract.getMaxRateLimit(); - console.log({ - rateMinLimit, - rateMaxLimit - }) // Validate rate limit if (rateLimit < rateMinLimit || rateLimit > rateMaxLimit) { return { @@ -309,11 +234,10 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { error: `Rate limit must be between ${rateMinLimit} and ${rateMaxLimit}` }; } - rln.contract.setRateLimit(rateLimit); - console.log("Rate limit set to:", rateLimit); + await rln.contract.setRateLimit(rateLimit); // Ensure we're on the correct network - const isOnLineaSepolia = await ensureLineaSepoliaNetwork(); + const isOnLineaSepolia = await ensureLineaSepoliaNetwork(signer); if (!isOnLineaSepolia) { console.warn("Could not switch to Linea Sepolia network. Registration may fail."); } @@ -343,111 +267,106 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) { // Check and approve token allowance if needed const currentAllowance = await tokenContract.allowance(userAddress, contractAddress); - // Get membership fee - implementation may differ between standard and light - const membershipFee = await rln.contract.membershipFee?.() || ethers.utils.parseEther("0.01"); - - if (currentAllowance.lt(membershipFee)) { - console.log("Approving token allowance..."); + if (currentAllowance.eq(0)) { + console.log("Requesting token approval..."); + + // Approve a large amount (max uint256) + const maxUint256 = ethers.constants.MaxUint256; try { - const approveTx = await tokenContract.approve(contractAddress, membershipFee); - await approveTx.wait(); - console.log("Token allowance approved"); - } catch (approveErr) { - console.error("Error approving token allowance:", approveErr); - return { success: false, error: "Failed to approve token allowance for membership registration." }; + const approveTx = await tokenContract.approve(contractAddress, maxUint256); + console.log("Approval transaction submitted:", approveTx.hash); + + // Wait for the transaction to be mined + await approveTx.wait(1); + console.log("Token approval confirmed"); + } catch (approvalErr) { + console.error("Error during token approval:", approvalErr); + return { + success: false, + error: `Failed to approve token: ${approvalErr instanceof Error ? approvalErr.message : String(approvalErr)}` + }; } } else { console.log("Token allowance already sufficient"); } - // Register membership - console.log("Registering membership with rate limit:", rateLimit); + // Generate signature for identity + const timestamp = Date.now(); + const message = `Sign this message to generate your RLN credentials ${timestamp}`; + const signature = await signer.signMessage(message); - try { - // Both implementations use registerMembership with a signature - // Generate signature for identity - const message = `Sign this message to generate your RLN credentials ${Date.now()}`; - const signature = await signer.signMessage(message); - - // Call registerMembership with the signature - const credentials = await rln.registerMembership({ - signature: signature - }) as unknown as KeystoreEntity; - - // Validate credentials - if (!credentials) { - throw new Error("Failed to register membership: No credentials returned"); + // Register membership + console.log("Registering membership..."); + const credentials = await rln.registerMembership({ + signature: signature + }); + + // If we have save options, save to keystore + let keystoreHash: string | undefined; + if (saveOptions && saveOptions.password && credentials) { + try { + keystoreHash = await saveCredentialsToKeystore(credentials as KeystoreEntity, saveOptions.password); + console.log("Credentials saved to keystore with hash:", keystoreHash); + } catch (saveErr) { + console.error("Error saving credentials to keystore:", saveErr); + // Continue without failing the overall registration } - if (!credentials.identity) { - throw new Error("Failed to register membership: Missing identity information"); - } - if (!credentials.membership) { - throw new Error("Failed to register membership: Missing membership information"); - } - - console.log("Membership registered successfully"); - - // If saveOptions provided, save to keystore - let keystoreHash: string | undefined; - if (saveOptions?.password) { - try { - keystoreHash = await saveCredentialsToKeystore(credentials, saveOptions.password); - console.log("Credentials saved to keystore with hash:", keystoreHash); - } catch (keystoreErr) { - console.warn("Could not save credentials to keystore:", keystoreErr); - } - } - - return { - success: true, - credentials, - keystoreHash - }; - } catch (registerErr) { - console.error("Error registering membership:", registerErr); - return { - success: false, - error: registerErr instanceof Error ? registerErr.message : "Failed to register membership" - }; } - } catch (err) { - console.error("Error in registerMembership:", err); + return { - success: false, - error: err instanceof Error ? err.message : "An unknown error occurred during registration" + success: true, + credentials: credentials as KeystoreEntity, + keystoreHash }; + } catch (err) { + console.error("Error registering membership:", err); + + let errorMsg = "Failed to register membership"; + if (err instanceof Error) { + errorMsg = err.message; + } + + return { success: false, error: errorMsg }; } }; - // Create the context value - const contextValue: RLNContextType = { - rln, - isInitialized, - isStarted, - error, - initializeRLN, - registerMembership, - getCurrentRateLimit, - getRateLimitsBounds, - rateMinLimit, - rateMaxLimit, - saveCredentialsToKeystore, - }; + // Initialize RLN when wallet connects + useEffect(() => { + console.log("Wallet connection state changed:", { isConnected, hasSigner: !!signer }); + + if (isConnected && signer) { + console.log("Wallet connected, attempting to initialize RLN"); + initializeRLN(); + } + }, [isConnected, signer]); return ( - + {children} - + ); } -// Create a hook to use the context +// Hook to use the RLN context export function useRLN() { - const context = useContext(RLNUnifiedContext); + const context = useContext(RLNContext); if (context === undefined) { - throw new Error('useRLN must be used within a RLNUnifiedProvider'); + throw new Error('useRLN must be used within a RLNProvider'); } return context; -} - +} \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/RLNImplementationContext.tsx b/examples/keystore-management/src/contexts/rln/RLNImplementationContext.tsx similarity index 99% rename from examples/keystore-management/src/contexts/RLNImplementationContext.tsx rename to examples/keystore-management/src/contexts/rln/RLNImplementationContext.tsx index 8f1c367..fc78203 100644 --- a/examples/keystore-management/src/contexts/RLNImplementationContext.tsx +++ b/examples/keystore-management/src/contexts/rln/RLNImplementationContext.tsx @@ -32,4 +32,4 @@ export function useRLNImplementation() { throw new Error('useRLNImplementation must be used within a RLNImplementationProvider'); } return context; -} +} \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/RLNFactory.tsx b/examples/keystore-management/src/contexts/rln/implementations/factory.tsx similarity index 99% rename from examples/keystore-management/src/contexts/RLNFactory.tsx rename to examples/keystore-management/src/contexts/rln/implementations/factory.tsx index 48a689f..8c63f56 100644 --- a/examples/keystore-management/src/contexts/RLNFactory.tsx +++ b/examples/keystore-management/src/contexts/rln/implementations/factory.tsx @@ -35,4 +35,4 @@ export async function createRLNImplementation(type: 'standard' | 'light'): Promi // Create and return the light RLN implementation return new RLNLightInstance() as unknown as UnifiedRLNInstance; } -} +} \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/rln/implementations/index.ts b/examples/keystore-management/src/contexts/rln/implementations/index.ts new file mode 100644 index 0000000..0a033cd --- /dev/null +++ b/examples/keystore-management/src/contexts/rln/implementations/index.ts @@ -0,0 +1,3 @@ +export { RLNProvider as StandardRLNProvider, useRLN as useStandardRLN } from './standard'; +export { RLNProvider as LightRLNProvider, useRLN as useLightRLN } from './light'; +export { createRLNImplementation, type UnifiedRLNInstance } from './factory'; \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/RLNLightContext.tsx b/examples/keystore-management/src/contexts/rln/implementations/light.tsx similarity index 73% rename from examples/keystore-management/src/contexts/RLNLightContext.tsx rename to examples/keystore-management/src/contexts/rln/implementations/light.tsx index bd83846..b95c9ee 100644 --- a/examples/keystore-management/src/contexts/RLNLightContext.tsx +++ b/examples/keystore-management/src/contexts/rln/implementations/light.tsx @@ -1,23 +1,10 @@ "use client"; import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react'; -import { DecryptedCredentials, RLNInstance, RLNLightInstance } from '@waku/rln'; -import { useWallet } from './WalletContext'; +import { DecryptedCredentials, RLNInstance, RLNLightInstance } from '@waku/rln'; +import { useWallet } from '../../wallet'; import { ethers } from 'ethers'; - -// Constants -const SIGNATURE_MESSAGE = "Sign this message to generate your RLN credentials"; -const ERC20_ABI = [ - "function allowance(address owner, address spender) view returns (uint256)", - "function approve(address spender, uint256 amount) returns (bool)", - "function balanceOf(address account) view returns (uint256)" -]; - -// Linea Sepolia configuration -const LINEA_SEPOLIA_CONFIG = { - chainId: 59141, - tokenAddress: '0x185A0015aC462a0aECb81beCc0497b649a64B9ea' -}; +import { ensureLineaSepoliaNetwork, ERC20_ABI, SIGNATURE_MESSAGE } from '../utils/network'; interface RLNContextType { rln: RLNLightInstance | RLNInstance | null; @@ -41,53 +28,6 @@ export function RLNProvider({ children }: { children: ReactNode }) { const [rateMinLimit, setRateMinLimit] = useState(0); const [rateMaxLimit, setRateMaxLimit] = useState(0); - const ensureLineaSepoliaNetwork = async (): Promise => { - try { - console.log("Current network: unknown", await signer?.getChainId()); - - // Check if already on Linea Sepolia - if (await signer?.getChainId() === LINEA_SEPOLIA_CONFIG.chainId) { - console.log("Already on Linea Sepolia network"); - return true; - } - - // If not on Linea Sepolia, try to switch - console.log("Not on Linea Sepolia, attempting to switch..."); - - interface EthereumProvider { - request: (args: { - method: string; - params?: unknown[] - }) => Promise; - } - - // Get the provider from window.ethereum - const provider = window.ethereum as EthereumProvider | undefined; - - if (!provider) { - console.warn("No Ethereum provider found"); - return false; - } - - try { - // Request network switch - await provider.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: `0x${LINEA_SEPOLIA_CONFIG.chainId.toString(16)}` }], - }); - - console.log("Successfully switched to Linea Sepolia"); - return true; - } catch (switchError: unknown) { - console.error("Error switching network:", switchError); - return false; - } - } catch (err) { - console.error("Error checking or switching network:", err); - return false; - } - }; - const initializeRLN = useCallback(async () => { console.log("InitializeRLN called. Connected:", isConnected, "Signer available:", !!signer); @@ -172,7 +112,7 @@ export function RLNProvider({ children }: { children: ReactNode }) { await rln.contract?.setRateLimit(rateLimit); // Ensure we're on the correct network - const isOnLineaSepolia = await ensureLineaSepoliaNetwork(); + const isOnLineaSepolia = await ensureLineaSepoliaNetwork(signer); if (!isOnLineaSepolia) { console.warn("Could not switch to Linea Sepolia network. Registration may fail."); } @@ -185,7 +125,7 @@ export function RLNProvider({ children }: { children: ReactNode }) { } const contractAddress = rln.contract.address; - const tokenAddress = LINEA_SEPOLIA_CONFIG.tokenAddress; + const tokenAddress = '0x185A0015aC462a0aECb81beCc0497b649a64B9ea'; // Linea Sepolia token address // Create token contract instance const tokenContract = new ethers.Contract( @@ -258,20 +198,8 @@ export function RLNProvider({ children }: { children: ReactNode }) { if (isConnected && signer) { console.log("Wallet connected, attempting to initialize RLN"); initializeRLN(); - } else { - console.log("Wallet not connected or no signer available, skipping RLN initialization"); } - }, [initializeRLN, isConnected, signer]); - - // Debug log for state changes - useEffect(() => { - console.log("RLN Context state:", { - isInitialized, - isStarted, - hasRln: !!rln, - error - }); - }, [isInitialized, isStarted, rln, error]); + }, [isConnected, signer, initializeRLN]); return ( => { - try { - console.log("Current network: unknown", await signer?.getChainId()); - - // Check if already on Linea Sepolia - if (await signer?.getChainId() === LINEA_CONTRACT.chainId) { - console.log("Already on Linea Sepolia network"); - return true; - } - - // If not on Linea Sepolia, try to switch - console.log("Not on Linea Sepolia, attempting to switch..."); - - interface EthereumProvider { - request: (args: { - method: string; - params?: unknown[] - }) => Promise; - } - - // Get the provider from window.ethereum - const provider = window.ethereum as EthereumProvider | undefined; - - if (!provider) { - console.warn("No Ethereum provider found"); - return false; - } - - try { - // Request network switch - await provider.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: `0x${LINEA_CONTRACT.chainId.toString(16)}` }], - }); - - console.log("Successfully switched to Linea Sepolia"); - return true; - } catch (switchError: unknown) { - console.error("Error switching network:", switchError); - return false; - } - } catch (err) { - console.error("Error checking or switching network:", err); - return false; - } - }; - const initializeRLN = async () => { console.log("InitializeRLN called. Connected:", isConnected, "Signer available:", !!signer); @@ -163,7 +107,7 @@ export function RLNProvider({ children }: { children: ReactNode }) { rln.contract?.setRateLimit(rateLimit); // Ensure we're on the correct network - const isOnLineaSepolia = await ensureLineaSepoliaNetwork(); + const isOnLineaSepolia = await ensureLineaSepoliaNetwork(signer); if (!isOnLineaSepolia) { console.warn("Could not switch to Linea Sepolia network. Registration may fail."); } @@ -249,21 +193,9 @@ export function RLNProvider({ children }: { children: ReactNode }) { if (isConnected && signer) { console.log("Wallet connected, attempting to initialize RLN"); initializeRLN(); - } else { - console.log("Wallet not connected or no signer available, skipping RLN initialization"); } }, [isConnected, signer]); - // Debug log for state changes - useEffect(() => { - console.log("RLN Context state:", { - isInitialized, - isStarted, - hasRln: !!rln, - error - }); - }, [isInitialized, isStarted, rln, error]); - return ( Promise; +} + +// Function to ensure the wallet is connected to Linea Sepolia network +export const ensureLineaSepoliaNetwork = async (signer?: ethers.Signer): Promise => { + try { + console.log("Current network: unknown", await signer?.getChainId()); + + // Check if already on Linea Sepolia + if (await signer?.getChainId() === LINEA_SEPOLIA_CONFIG.chainId) { + console.log("Already on Linea Sepolia network"); + return true; + } + + // If not on Linea Sepolia, try to switch + console.log("Not on Linea Sepolia, attempting to switch..."); + + // Get the provider from window.ethereum + const provider = window.ethereum as EthereumProvider | undefined; + + if (!provider) { + console.warn("No Ethereum provider found"); + return false; + } + + try { + // Request network switch + await provider.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: `0x${LINEA_SEPOLIA_CONFIG.chainId.toString(16)}` }], + }); + + console.log("Successfully switched to Linea Sepolia"); + return true; + } catch (switchError: unknown) { + console.error("Error switching network:", switchError); + return false; + } + } catch (err) { + console.error("Error checking or switching network:", err); + return false; + } +}; + +// ERC20 ABI for token operations +export const ERC20_ABI = [ + "function allowance(address owner, address spender) view returns (uint256)", + "function approve(address spender, uint256 amount) returns (bool)", + "function balanceOf(address account) view returns (uint256)" +]; + +// Message for signing to generate identity +export const SIGNATURE_MESSAGE = "Sign this message to generate your RLN credentials"; \ No newline at end of file diff --git a/examples/keystore-management/src/contexts/WalletContext.tsx b/examples/keystore-management/src/contexts/wallet/WalletContext.tsx similarity index 100% rename from examples/keystore-management/src/contexts/WalletContext.tsx rename to examples/keystore-management/src/contexts/wallet/WalletContext.tsx diff --git a/examples/keystore-management/src/contexts/wallet/index.ts b/examples/keystore-management/src/contexts/wallet/index.ts new file mode 100644 index 0000000..7419613 --- /dev/null +++ b/examples/keystore-management/src/contexts/wallet/index.ts @@ -0,0 +1 @@ +export { WalletProvider, useWallet } from './WalletContext'; \ No newline at end of file