mirror of
https://github.com/logos-messaging/lab.waku.org.git
synced 2026-08-08 09:03:33 +00:00
chore: restructure contexts and hooks for readability
This commit is contained in:
parent
ba2f640eea
commit
f8671dc2c0
4
examples/keystore-management/.gitignore
vendored
4
examples/keystore-management/.gitignore
vendored
@ -39,3 +39,7 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.giga/
|
||||
.cursor/*
|
||||
.cursorrules
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
15
examples/keystore-management/src/contexts/index.ts
Normal file
15
examples/keystore-management/src/contexts/index.ts
Normal 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';
|
||||
@ -0,0 +1 @@
|
||||
export { KeystoreProvider, useKeystore } from './KeystoreContext';
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -32,4 +32,4 @@ export function useRLNImplementation() {
|
||||
throw new Error('useRLNImplementation must be used within a RLNImplementationProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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';
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
3
examples/keystore-management/src/contexts/rln/index.ts
Normal file
3
examples/keystore-management/src/contexts/rln/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { RLNProvider, useRLN } from './RLNContext';
|
||||
export { RLNImplementationProvider, useRLNImplementation, type RLNImplementationType } from './RLNImplementationContext';
|
||||
export type { UnifiedRLNInstance } from './implementations';
|
||||
@ -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";
|
||||
@ -0,0 +1 @@
|
||||
export { WalletProvider, useWallet } from './WalletContext';
|
||||
Loading…
x
Reference in New Issue
Block a user