1. Frontend: User clicks “Connect Wallet” (MetaMask, WalletConnect, etc.).
2. Nonce Generation: The backend creates a one-time nonce (e.g., random string) stored in the user’s DB row or Redis.
3. Signature: The frontend requests the user to sign the nonce with their wallet’s private key.
4. Verification: The backend verifies the signature using ethers.js or web3.js. If valid, it associates the wallet address with the user’s account.
// backend/src/controllers/walletController.js
const { ethers } = require('ethers');
const User = require('../models/User');
const crypto = require('crypto');
exports.generateNonce = async (req, res) => {
try {
const nonce = crypto.randomBytes(16).toString('hex');
// Store in DB or Redis for user
// ...
return res.json({ nonce });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
};
exports.verifySignature = async (req, res) => {
try {
const { address, signature, nonce } = req.body;
// Retrieve the expected nonce from DB
// ...
// Recreate the message and verify
const message = `Welcome to SUM+1. Nonce: ${nonce}`;
const signingAddress = ethers.utils.verifyMessage(message, signature);
if (signingAddress.toLowerCase() === address.toLowerCase()) {
// Link wallet to user account
// ...
return res.json({ success: true });
}
return res.status(400).json({ error: 'Invalid signature' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
};