chore: restructure contexts and hooks for readability

This commit is contained in:
Danish Arora 2025-03-27 14:12:19 +05:30
parent ba2f640eea
commit f8671dc2c0
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
21 changed files with 215 additions and 465 deletions

View File

@ -39,3 +39,7 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.giga/
.cursor/*
.cursorrules

View File

@ -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 (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className={`${inter.variable} antialiased`}
>
<WalletProvider>
<RLNImplementationProvider>
<KeystoreProvider>
<RLNUnifiedProvider>
<RLNProvider>
<div className="flex flex-col min-h-screen">
<Header />
<main className="flex-grow">
{children}
</main>
</div>
</RLNUnifiedProvider>
</RLNProvider>
</KeystoreProvider>
</RLNImplementationProvider>
</WalletProvider>

View File

@ -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() {

View File

@ -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();

View File

@ -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();

View File

@ -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';

View File

@ -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' ? (
<StandardRLNProvider>{children}</StandardRLNProvider>
) : (
<LightRLNProvider>{children}</LightRLNProvider>
)}
</>
);
}

View File

@ -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<void>;
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<RLNContextType>(dummyRLNContext);
// Create a provider component that will fetch the appropriate implementation
export function UnifiedRLNProvider({ children }: { children: ReactNode }) {
const { implementation } = useRLNImplementation();
const [contextValue, setContextValue] = useState<RLNContextType>(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 <RLNProvider><TempComponent /></RLNProvider>;
} 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 <RLNProvider><TempComponent /></RLNProvider>;
}
} catch (error) {
console.error('Error loading RLN context:', error);
}
};
fetchContext();
}, [implementation]);
return (
<UnifiedRLNContext.Provider value={contextValue}>
{children}
</UnifiedRLNContext.Provider>
);
}
// Create a hook to use the unified RLN context
export function useRLN() {
return useContext(UnifiedRLNContext);
}

View File

@ -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';

View File

@ -0,0 +1 @@
export { KeystoreProvider, useKeystore } from './KeystoreContext';

View File

@ -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<RLNContextType | undefined>(undefined);
const RLNContext = createContext<RLNContextType | undefined>(undefined);
// Create the provider component
export function RLNUnifiedProvider({ children }: { children: ReactNode }) {
export function RLNProvider({ children }: { children: ReactNode }) {
const { implementation } = useRLNImplementation();
const [rln, setRln] = useState<UnifiedRLNInstance | null>(null);
const [isInitialized, setIsInitialized] = useState(false);
@ -109,53 +96,6 @@ export function RLNUnifiedProvider({ children }: { children: ReactNode }) {
setError(null);
}, [implementation]);
const ensureLineaSepoliaNetwork = async (): Promise<boolean> => {
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<unknown>;
}
// 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<string> => {
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 (
<RLNUnifiedContext.Provider value={contextValue}>
<RLNContext.Provider
value={{
rln,
isInitialized,
isStarted,
error,
initializeRLN,
registerMembership,
rateMinLimit,
rateMaxLimit,
getCurrentRateLimit,
getRateLimitsBounds,
saveCredentialsToKeystore
}}
>
{children}
</RLNUnifiedContext.Provider>
</RLNContext.Provider>
);
}
// 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;
}
}

View File

@ -32,4 +32,4 @@ export function useRLNImplementation() {
throw new Error('useRLNImplementation must be used within a RLNImplementationProvider');
}
return context;
}
}

View File

@ -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;
}
}
}

View File

@ -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';

View File

@ -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<boolean> => {
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<unknown>;
}
// 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 (
<RLNContext.Provider
@ -294,7 +222,7 @@ export function RLNProvider({ children }: { children: ReactNode }) {
export function useRLN() {
const context = useContext(RLNContext);
if (context === undefined) {
throw new Error('useRLN must be used within an RLNProvider');
throw new Error('useRLN must be used within a RLNProvider');
}
return context;
}

View File

@ -2,18 +2,9 @@
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { createRLN, DecryptedCredentials, LINEA_CONTRACT, RLNInstance } from '@waku/rln';
import { useWallet } from './WalletContext';
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)"
];
import { ensureLineaSepoliaNetwork, ERC20_ABI, SIGNATURE_MESSAGE } from '../utils/network';
interface RLNContextType {
rln: RLNInstance | null;
@ -37,53 +28,6 @@ export function RLNProvider({ children }: { children: ReactNode }) {
const [rateMinLimit, setRateMinLimit] = useState(0);
const [rateMaxLimit, setRateMaxLimit] = useState(0);
const ensureLineaSepoliaNetwork = async (): Promise<boolean> => {
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<unknown>;
}
// 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 (
<RLNContext.Provider
value={{
@ -285,7 +217,7 @@ export function RLNProvider({ children }: { children: ReactNode }) {
export function useRLN() {
const context = useContext(RLNContext);
if (context === undefined) {
throw new Error('useRLN must be used within an RLNProvider');
throw new Error('useRLN must be used within a RLNProvider');
}
return context;
}

View File

@ -0,0 +1,3 @@
export { RLNProvider, useRLN } from './RLNContext';
export { RLNImplementationProvider, useRLNImplementation, type RLNImplementationType } from './RLNImplementationContext';
export type { UnifiedRLNInstance } from './implementations';

View File

@ -0,0 +1,68 @@
"use client";
import { ethers } from 'ethers';
// Linea Sepolia configuration
export const LINEA_SEPOLIA_CONFIG = {
chainId: 59141,
tokenAddress: '0x185A0015aC462a0aECb81beCc0497b649a64B9ea'
};
// Type for Ethereum provider in window
export interface EthereumProvider {
request: (args: {
method: string;
params?: unknown[]
}) => Promise<unknown>;
}
// Function to ensure the wallet is connected to Linea Sepolia network
export const ensureLineaSepoliaNetwork = async (signer?: ethers.Signer): Promise<boolean> => {
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";

View File

@ -0,0 +1 @@
export { WalletProvider, useWallet } from './WalletContext';