export class MessageVerifier {
private evmClient: any;
private nonceStore: Map<string, number> = new Map();
constructor() {
this.evmClient = await authenticatedEvmClient();
}
// Generate a nonce for a user
generateNonce(userId: string): string {
const nonce = Date.now();
this.nonceStore.set(userId, nonce);
return nonce.toString();
}
// Verify user authentication
async verifyUser({
walletAddress,
userId,
signature,
}: {
walletAddress: string;
userId: string;
signature: string;
}): Promise<boolean> {
const expectedNonce = this.nonceStore.get(userId);
if (!expectedNonce) {
throw new Error('No nonce found for user');
}
const message = `Sign this message to authenticate user ${userId}: nonce: ${expectedNonce}`;
const isValid = await this.evmClient.verifyMessageSignature({
accountAddress: walletAddress,
message,
signature,
});
if (isValid) {
// Clear the used nonce
this.nonceStore.delete(userId);
}
return isValid;
}
// Verify transaction approval
async verifyTransactionApproval({
walletAddress,
transactionHash,
signature,
}: {
walletAddress: string;
transactionHash: string;
signature: string;
}): Promise<boolean> {
const message = `I approve transaction: ${transactionHash}`;
return await this.evmClient.verifyMessageSignature({
accountAddress: walletAddress,
message,
signature,
});
}
}
// Usage
const verifier = new MessageVerifier();
// Step 1: Generate nonce for user
const nonce = verifier.generateNonce('user123');
console.log('Nonce generated:', nonce);
// Step 2: User signs message with nonce (on frontend)
// const message = `Sign this message to authenticate user user123: nonce: ${nonce}`;
// const signature = await wallet.signMessage(message);
// Step 3: Verify signature
const isValid = await verifier.verifyUser({
walletAddress: '0xUserWalletAddress',
userId: 'user123',
signature: '0xUserSignature',
});
if (isValid) {
console.log('User authenticated successfully');
} else {
console.log('Authentication failed');
}