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