Compare commits
No commits in common. "95d7f9631ce987a309d60737855d7ac9bde8829d" and "f17d6dea17fd371bc00434d9f1e540696dab0cfd" have entirely different histories.
95d7f9631c
...
f17d6dea17
|
|
@ -1,665 +0,0 @@
|
||||||
---
|
|
||||||
id: doc-001
|
|
||||||
title: Web3 Wallet Integration Architecture
|
|
||||||
type: other
|
|
||||||
created_date: '2026-01-02 16:07'
|
|
||||||
---
|
|
||||||
# Web3 Wallet Integration Architecture
|
|
||||||
|
|
||||||
**Status:** Planning
|
|
||||||
**Created:** 2026-01-02
|
|
||||||
**Related Task:** task-007
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Overview
|
|
||||||
|
|
||||||
This document outlines the architecture for integrating Web3 wallet capabilities into the canvas-website, enabling CryptID users to link Ethereum wallets for on-chain transactions, voting, and token-gated features.
|
|
||||||
|
|
||||||
### Key Constraint: Cryptographic Curve Mismatch
|
|
||||||
|
|
||||||
| System | Curve | Usage |
|
|
||||||
|--------|-------|-------|
|
|
||||||
| **CryptID (WebCrypto)** | ECDSA P-256 (NIST) | Authentication, passwordless login |
|
|
||||||
| **Ethereum** | ECDSA secp256k1 | Transactions, message signing |
|
|
||||||
|
|
||||||
These curves are **incompatible**. A CryptID key cannot sign Ethereum transactions. Therefore, we use a **wallet linking** approach where:
|
|
||||||
1. CryptID handles authentication (who you are)
|
|
||||||
2. Linked wallet handles on-chain actions (what you can do)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Database Schema
|
|
||||||
|
|
||||||
### Migration: `002_linked_wallets.sql`
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- Migration: Add Linked Wallets for Web3 Integration
|
|
||||||
-- Date: 2026-01-02
|
|
||||||
-- Description: Enables CryptID users to link Ethereum wallets for
|
|
||||||
-- on-chain transactions, voting, and token-gated features.
|
|
||||||
|
|
||||||
-- =============================================================================
|
|
||||||
-- LINKED WALLETS TABLE
|
|
||||||
-- =============================================================================
|
|
||||||
-- Each CryptID user can link multiple Ethereum wallets (EOA, Safe, hardware)
|
|
||||||
-- Linking requires signature verification to prove wallet ownership
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS linked_wallets (
|
|
||||||
id TEXT PRIMARY KEY, -- UUID for the link record
|
|
||||||
user_id TEXT NOT NULL, -- References users.id (CryptID account)
|
|
||||||
wallet_address TEXT NOT NULL, -- Ethereum address (checksummed, 0x-prefixed)
|
|
||||||
|
|
||||||
-- Wallet metadata
|
|
||||||
wallet_type TEXT DEFAULT 'eoa' CHECK (wallet_type IN ('eoa', 'safe', 'hardware', 'contract')),
|
|
||||||
chain_id INTEGER DEFAULT 1, -- Primary chain (1 = Ethereum mainnet)
|
|
||||||
label TEXT, -- User-provided label (e.g., "Main Wallet")
|
|
||||||
|
|
||||||
-- Verification proof
|
|
||||||
signature_message TEXT NOT NULL, -- The message that was signed
|
|
||||||
signature TEXT NOT NULL, -- EIP-191 personal_sign signature
|
|
||||||
verified_at TEXT NOT NULL, -- When signature was verified
|
|
||||||
|
|
||||||
-- ENS integration
|
|
||||||
ens_name TEXT, -- Resolved ENS name (if any)
|
|
||||||
ens_avatar TEXT, -- ENS avatar URL (if any)
|
|
||||||
ens_resolved_at TEXT, -- When ENS was last resolved
|
|
||||||
|
|
||||||
-- Flags
|
|
||||||
is_primary INTEGER DEFAULT 0, -- 1 = primary wallet for this user
|
|
||||||
is_active INTEGER DEFAULT 1, -- 0 = soft-deleted
|
|
||||||
|
|
||||||
-- Timestamps
|
|
||||||
created_at TEXT DEFAULT (datetime('now')),
|
|
||||||
updated_at TEXT DEFAULT (datetime('now')),
|
|
||||||
last_used_at TEXT, -- Last time wallet was used for action
|
|
||||||
|
|
||||||
-- Constraints
|
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
UNIQUE(user_id, wallet_address) -- Can't link same wallet twice
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Indexes for efficient lookups
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_linked_wallets_user ON linked_wallets(user_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_linked_wallets_address ON linked_wallets(wallet_address);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_linked_wallets_active ON linked_wallets(is_active);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_linked_wallets_primary ON linked_wallets(user_id, is_primary);
|
|
||||||
|
|
||||||
-- =============================================================================
|
|
||||||
-- WALLET LINKING TOKENS TABLE (for Safe/multisig delayed verification)
|
|
||||||
-- =============================================================================
|
|
||||||
-- For contract wallets that require on-chain signature verification
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wallet_link_tokens (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
user_id TEXT NOT NULL,
|
|
||||||
wallet_address TEXT NOT NULL,
|
|
||||||
nonce TEXT NOT NULL, -- Random nonce for signature message
|
|
||||||
token TEXT NOT NULL UNIQUE, -- Secret token for verification callback
|
|
||||||
expires_at TEXT NOT NULL,
|
|
||||||
used INTEGER DEFAULT 0,
|
|
||||||
created_at TEXT DEFAULT (datetime('now')),
|
|
||||||
|
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_wallet_link_tokens_token ON wallet_link_tokens(token);
|
|
||||||
|
|
||||||
-- =============================================================================
|
|
||||||
-- TOKEN BALANCES CACHE (optional, for token-gating)
|
|
||||||
-- =============================================================================
|
|
||||||
-- Cache of token balances for faster permission checks
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wallet_token_balances (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
wallet_address TEXT NOT NULL,
|
|
||||||
token_address TEXT NOT NULL, -- ERC-20/721/1155 contract address
|
|
||||||
token_type TEXT CHECK (token_type IN ('erc20', 'erc721', 'erc1155')),
|
|
||||||
chain_id INTEGER NOT NULL,
|
|
||||||
balance TEXT NOT NULL, -- String to handle big numbers
|
|
||||||
last_updated TEXT DEFAULT (datetime('now')),
|
|
||||||
|
|
||||||
UNIQUE(wallet_address, token_address, chain_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_token_balances_wallet ON wallet_token_balances(wallet_address);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_token_balances_token ON wallet_token_balances(token_address);
|
|
||||||
```
|
|
||||||
|
|
||||||
### TypeScript Types
|
|
||||||
|
|
||||||
Add to `worker/types.ts`:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// =============================================================================
|
|
||||||
// Linked Wallet Types
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
export type WalletType = 'eoa' | 'safe' | 'hardware' | 'contract';
|
|
||||||
|
|
||||||
export interface LinkedWallet {
|
|
||||||
id: string;
|
|
||||||
user_id: string;
|
|
||||||
wallet_address: string;
|
|
||||||
wallet_type: WalletType;
|
|
||||||
chain_id: number;
|
|
||||||
label: string | null;
|
|
||||||
signature_message: string;
|
|
||||||
signature: string;
|
|
||||||
verified_at: string;
|
|
||||||
ens_name: string | null;
|
|
||||||
ens_avatar: string | null;
|
|
||||||
ens_resolved_at: string | null;
|
|
||||||
is_primary: number; // SQLite boolean
|
|
||||||
is_active: number; // SQLite boolean
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
last_used_at: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WalletLinkToken {
|
|
||||||
id: string;
|
|
||||||
user_id: string;
|
|
||||||
wallet_address: string;
|
|
||||||
nonce: string;
|
|
||||||
token: string;
|
|
||||||
expires_at: string;
|
|
||||||
used: number;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WalletTokenBalance {
|
|
||||||
id: string;
|
|
||||||
wallet_address: string;
|
|
||||||
token_address: string;
|
|
||||||
token_type: 'erc20' | 'erc721' | 'erc1155';
|
|
||||||
chain_id: number;
|
|
||||||
balance: string;
|
|
||||||
last_updated: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Response types
|
|
||||||
export interface LinkedWalletResponse {
|
|
||||||
id: string;
|
|
||||||
address: string;
|
|
||||||
type: WalletType;
|
|
||||||
chainId: number;
|
|
||||||
label: string | null;
|
|
||||||
ensName: string | null;
|
|
||||||
ensAvatar: string | null;
|
|
||||||
isPrimary: boolean;
|
|
||||||
linkedAt: string;
|
|
||||||
lastUsedAt: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WalletLinkRequest {
|
|
||||||
walletAddress: string;
|
|
||||||
signature: string;
|
|
||||||
message: string;
|
|
||||||
walletType?: WalletType;
|
|
||||||
chainId?: number;
|
|
||||||
label?: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. API Endpoints
|
|
||||||
|
|
||||||
### Base Path: `/api/wallet`
|
|
||||||
|
|
||||||
All endpoints require CryptID authentication via `X-CryptID-PublicKey` header.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `POST /api/wallet/link`
|
|
||||||
|
|
||||||
Link a new wallet to the authenticated CryptID account.
|
|
||||||
|
|
||||||
**Request:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
walletAddress: string; // 0x-prefixed Ethereum address
|
|
||||||
signature: string; // EIP-191 signature of the message
|
|
||||||
message: string; // Must match server-generated format
|
|
||||||
walletType?: 'eoa' | 'safe' | 'hardware' | 'contract';
|
|
||||||
chainId?: number; // Default: 1 (mainnet)
|
|
||||||
label?: string; // Optional user label
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Message Format (must be signed):**
|
|
||||||
```
|
|
||||||
Link wallet to CryptID
|
|
||||||
|
|
||||||
Account: ${cryptidUsername}
|
|
||||||
Wallet: ${walletAddress}
|
|
||||||
Timestamp: ${isoTimestamp}
|
|
||||||
Nonce: ${randomNonce}
|
|
||||||
|
|
||||||
This signature proves you own this wallet.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response (201 Created):**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
success: true;
|
|
||||||
wallet: LinkedWalletResponse;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Errors:**
|
|
||||||
- `400` - Invalid request body or signature
|
|
||||||
- `401` - Not authenticated
|
|
||||||
- `409` - Wallet already linked to this account
|
|
||||||
- `422` - Signature verification failed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /api/wallet/list`
|
|
||||||
|
|
||||||
Get all wallets linked to the authenticated user.
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
wallets: LinkedWalletResponse[];
|
|
||||||
count: number;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /api/wallet/:address`
|
|
||||||
|
|
||||||
Get details for a specific linked wallet.
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
wallet: LinkedWalletResponse;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `PATCH /api/wallet/:address`
|
|
||||||
|
|
||||||
Update a linked wallet (label, primary status).
|
|
||||||
|
|
||||||
**Request:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
label?: string;
|
|
||||||
isPrimary?: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
success: true;
|
|
||||||
wallet: LinkedWalletResponse;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `DELETE /api/wallet/:address`
|
|
||||||
|
|
||||||
Unlink a wallet from the account.
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
success: true;
|
|
||||||
message: 'Wallet unlinked';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /api/wallet/verify/:address`
|
|
||||||
|
|
||||||
Check if a wallet address is linked to any CryptID account.
|
|
||||||
(Public endpoint - no auth required)
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
linked: boolean;
|
|
||||||
cryptidUsername?: string; // Only if user allows public display
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `POST /api/wallet/refresh-ens`
|
|
||||||
|
|
||||||
Refresh ENS name resolution for a linked wallet.
|
|
||||||
|
|
||||||
**Request:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
walletAddress: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
ensName: string | null;
|
|
||||||
ensAvatar: string | null;
|
|
||||||
resolvedAt: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Signature Verification Implementation
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// worker/walletAuth.ts
|
|
||||||
|
|
||||||
import { verifyMessage, getAddress } from 'viem';
|
|
||||||
|
|
||||||
export function generateLinkMessage(
|
|
||||||
username: string,
|
|
||||||
address: string,
|
|
||||||
timestamp: string,
|
|
||||||
nonce: string
|
|
||||||
): string {
|
|
||||||
return `Link wallet to CryptID
|
|
||||||
|
|
||||||
Account: ${username}
|
|
||||||
Wallet: ${address}
|
|
||||||
Timestamp: ${timestamp}
|
|
||||||
Nonce: ${nonce}
|
|
||||||
|
|
||||||
This signature proves you own this wallet.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function verifyWalletSignature(
|
|
||||||
address: string,
|
|
||||||
message: string,
|
|
||||||
signature: `0x${string}`
|
|
||||||
): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
// Normalize address
|
|
||||||
const checksumAddress = getAddress(address);
|
|
||||||
|
|
||||||
// Verify EIP-191 personal_sign signature
|
|
||||||
const valid = await verifyMessage({
|
|
||||||
address: checksumAddress,
|
|
||||||
message,
|
|
||||||
signature,
|
|
||||||
});
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Signature verification error:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For ERC-1271 contract wallet verification (Safe, etc.)
|
|
||||||
export async function verifyContractSignature(
|
|
||||||
address: string,
|
|
||||||
message: string,
|
|
||||||
signature: string,
|
|
||||||
rpcUrl: string
|
|
||||||
): Promise<boolean> {
|
|
||||||
// ERC-1271 magic value: 0x1626ba7e
|
|
||||||
// Implementation needed for Safe/contract wallet support
|
|
||||||
// Uses eth_call to isValidSignature(bytes32,bytes)
|
|
||||||
throw new Error('Contract signature verification not yet implemented');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Library Comparison
|
|
||||||
|
|
||||||
### Recommendation: **wagmi v2 + viem**
|
|
||||||
|
|
||||||
| Library | Bundle Size | Type Safety | React Hooks | Maintenance | Recommendation |
|
|
||||||
|---------|-------------|-------------|-------------|-------------|----------------|
|
|
||||||
| **wagmi v2** | ~40KB | Excellent | Native | Active (wevm team) | ✅ **Best for React** |
|
|
||||||
| **viem** | ~25KB | Excellent | N/A | Active (wevm team) | ✅ **Best for worker** |
|
|
||||||
| **ethers v6** | ~120KB | Good | None | Active | ⚠️ Larger bundle |
|
|
||||||
| **web3.js** | ~400KB | Poor | None | Declining | ❌ Avoid |
|
|
||||||
|
|
||||||
### Why wagmi + viem?
|
|
||||||
|
|
||||||
1. **Same team** - wagmi and viem are both from wevm, designed to work together
|
|
||||||
2. **Tree-shakeable** - Only import what you use
|
|
||||||
3. **TypeScript-first** - Excellent type inference and autocomplete
|
|
||||||
4. **Modern React** - Hooks-based, works with React 18+ and Suspense
|
|
||||||
5. **WalletConnect v2** - Built-in support via Web3Modal
|
|
||||||
6. **No ethers dependency** - Pure viem underneath
|
|
||||||
|
|
||||||
### Package Configuration
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"wagmi": "^2.12.0",
|
|
||||||
"viem": "^2.19.0",
|
|
||||||
"@tanstack/react-query": "^5.45.0",
|
|
||||||
"@web3modal/wagmi": "^5.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Supported Wallets (via Web3Modal)
|
|
||||||
|
|
||||||
- MetaMask (injected)
|
|
||||||
- WalletConnect v2 (mobile wallets)
|
|
||||||
- Coinbase Wallet
|
|
||||||
- Rainbow
|
|
||||||
- Safe (via WalletConnect)
|
|
||||||
- Hardware wallets (via MetaMask bridge)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Frontend Architecture
|
|
||||||
|
|
||||||
### Provider Setup (`src/providers/Web3Provider.tsx`)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { WagmiProvider, createConfig, http } from 'wagmi';
|
|
||||||
import { mainnet, optimism, arbitrum, base } from 'wagmi/chains';
|
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
||||||
import { createWeb3Modal } from '@web3modal/wagmi/react';
|
|
||||||
|
|
||||||
// Configure chains
|
|
||||||
const chains = [mainnet, optimism, arbitrum, base] as const;
|
|
||||||
|
|
||||||
// Create wagmi config
|
|
||||||
const config = createConfig({
|
|
||||||
chains,
|
|
||||||
transports: {
|
|
||||||
[mainnet.id]: http(),
|
|
||||||
[optimism.id]: http(),
|
|
||||||
[arbitrum.id]: http(),
|
|
||||||
[base.id]: http(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create Web3Modal
|
|
||||||
const projectId = process.env.WALLETCONNECT_PROJECT_ID!;
|
|
||||||
|
|
||||||
createWeb3Modal({
|
|
||||||
wagmiConfig: config,
|
|
||||||
projectId,
|
|
||||||
chains,
|
|
||||||
themeMode: 'dark',
|
|
||||||
});
|
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
|
||||||
|
|
||||||
export function Web3Provider({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<WagmiProvider config={config}>
|
|
||||||
<QueryClientProvider client={queryClient}>
|
|
||||||
{children}
|
|
||||||
</QueryClientProvider>
|
|
||||||
</WagmiProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Wallet Link Hook (`src/hooks/useWalletLink.ts`)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { useAccount, useSignMessage, useDisconnect } from 'wagmi';
|
|
||||||
import { useAuth } from '../context/AuthContext';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
export function useWalletLink() {
|
|
||||||
const { address, isConnected } = useAccount();
|
|
||||||
const { signMessageAsync } = useSignMessage();
|
|
||||||
const { disconnect } = useDisconnect();
|
|
||||||
const { session } = useAuth();
|
|
||||||
const [isLinking, setIsLinking] = useState(false);
|
|
||||||
|
|
||||||
const linkWallet = async (label?: string) => {
|
|
||||||
if (!address || !session.username) return;
|
|
||||||
|
|
||||||
setIsLinking(true);
|
|
||||||
try {
|
|
||||||
// Generate link message
|
|
||||||
const timestamp = new Date().toISOString();
|
|
||||||
const nonce = crypto.randomUUID();
|
|
||||||
const message = generateLinkMessage(
|
|
||||||
session.username,
|
|
||||||
address,
|
|
||||||
timestamp,
|
|
||||||
nonce
|
|
||||||
);
|
|
||||||
|
|
||||||
// Request signature from wallet
|
|
||||||
const signature = await signMessageAsync({ message });
|
|
||||||
|
|
||||||
// Send to backend for verification
|
|
||||||
const response = await fetch('/api/wallet/link', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CryptID-PublicKey': session.publicKey,
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
walletAddress: address,
|
|
||||||
signature,
|
|
||||||
message,
|
|
||||||
label,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to link wallet');
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.json();
|
|
||||||
} finally {
|
|
||||||
setIsLinking(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
address,
|
|
||||||
isConnected,
|
|
||||||
isLinking,
|
|
||||||
linkWallet,
|
|
||||||
disconnect,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Integration Points
|
|
||||||
|
|
||||||
### A. AuthContext Extension
|
|
||||||
|
|
||||||
Add to `Session` type:
|
|
||||||
```typescript
|
|
||||||
interface Session {
|
|
||||||
// ... existing fields
|
|
||||||
linkedWallets?: LinkedWalletResponse[];
|
|
||||||
primaryWallet?: LinkedWalletResponse;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### B. Token-Gated Features
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Check if user holds specific tokens
|
|
||||||
async function checkTokenGate(
|
|
||||||
walletAddress: string,
|
|
||||||
requirement: {
|
|
||||||
tokenAddress: string;
|
|
||||||
minBalance: string;
|
|
||||||
chainId: number;
|
|
||||||
}
|
|
||||||
): Promise<boolean> {
|
|
||||||
// Query on-chain balance or use cached value
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### C. Snapshot Voting (Future)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Vote on Snapshot proposal
|
|
||||||
async function voteOnProposal(
|
|
||||||
space: string,
|
|
||||||
proposal: string,
|
|
||||||
choice: number,
|
|
||||||
walletAddress: string
|
|
||||||
): Promise<void> {
|
|
||||||
// Use Snapshot.js SDK with linked wallet
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Security Considerations
|
|
||||||
|
|
||||||
1. **Signature Replay Prevention**
|
|
||||||
- Include timestamp and nonce in message
|
|
||||||
- Server validates timestamp is recent (within 5 minutes)
|
|
||||||
- Nonces are single-use
|
|
||||||
|
|
||||||
2. **Address Validation**
|
|
||||||
- Always checksum addresses before storing/comparing
|
|
||||||
- Validate address format (0x + 40 hex chars)
|
|
||||||
|
|
||||||
3. **Rate Limiting**
|
|
||||||
- Limit link attempts per user (e.g., 5/hour)
|
|
||||||
- Limit total wallets per user (e.g., 10)
|
|
||||||
|
|
||||||
4. **Wallet Verification**
|
|
||||||
- EOA: EIP-191 personal_sign
|
|
||||||
- Safe: ERC-1271 isValidSignature
|
|
||||||
- Hardware: Same as EOA (via MetaMask bridge)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Next Steps
|
|
||||||
|
|
||||||
1. **Phase 1 (This Sprint)**
|
|
||||||
- [ ] Add migration file
|
|
||||||
- [ ] Install wagmi/viem dependencies
|
|
||||||
- [ ] Implement link/list/unlink endpoints
|
|
||||||
- [ ] Create WalletLinkPanel UI
|
|
||||||
- [ ] Add wallet section to settings
|
|
||||||
|
|
||||||
2. **Phase 2 (Next Sprint)**
|
|
||||||
- [ ] Snapshot.js integration
|
|
||||||
- [ ] VotingShape for canvas
|
|
||||||
- [ ] Token balance caching
|
|
||||||
|
|
||||||
3. **Phase 3 (Future)**
|
|
||||||
- [ ] Safe SDK integration
|
|
||||||
- [ ] TransactionBuilderShape
|
|
||||||
- [ ] Account Abstraction exploration
|
|
||||||
|
|
@ -1,182 +0,0 @@
|
||||||
---
|
|
||||||
id: task-007
|
|
||||||
title: Web3 Wallet Linking & Blockchain Integration
|
|
||||||
status: Done
|
|
||||||
assignee: []
|
|
||||||
created_date: '2025-12-03'
|
|
||||||
updated_date: '2026-01-02 17:05'
|
|
||||||
labels:
|
|
||||||
- feature
|
|
||||||
- web3
|
|
||||||
- blockchain
|
|
||||||
dependencies: []
|
|
||||||
priority: high
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
||||||
Integrate Web3 wallet capabilities to enable CryptID users to link EOA wallets and Safe multisigs for on-chain transactions, voting (Snapshot), and token-gated features.
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
CryptID uses ECDSA P-256 (WebCrypto), while Ethereum uses secp256k1. These curves are incompatible, so we use a **wallet linking** approach rather than key reuse.
|
|
||||||
|
|
||||||
### Core Concept
|
|
||||||
1. CryptID remains the primary authentication layer (passwordless)
|
|
||||||
2. Users can link one or more Ethereum wallets to their CryptID
|
|
||||||
3. Linking requires signing a verification message with the wallet
|
|
||||||
4. Linked wallets enable: transactions, voting, token-gating, NFT features
|
|
||||||
|
|
||||||
### Tech Stack
|
|
||||||
- **wagmi v2** + **viem** - Modern React hooks for wallet connection
|
|
||||||
- **WalletConnect v2** - Multi-wallet support (MetaMask, Rainbow, etc.)
|
|
||||||
- **Safe SDK** - Multisig wallet integration
|
|
||||||
- **Snapshot.js** - Off-chain governance voting
|
|
||||||
|
|
||||||
## Implementation Phases
|
|
||||||
|
|
||||||
### Phase 1: Wallet Linking Foundation (This Task)
|
|
||||||
- Add wagmi/viem/walletconnect dependencies
|
|
||||||
- Create linked_wallets D1 table
|
|
||||||
- Implement wallet linking API endpoints
|
|
||||||
- Build WalletLinkPanel UI component
|
|
||||||
- Display linked wallets in user settings
|
|
||||||
|
|
||||||
### Phase 2: Snapshot Voting (Future Task)
|
|
||||||
- Integrate Snapshot.js SDK
|
|
||||||
- Create VotingShape for canvas visualization
|
|
||||||
- Implement vote signing flow
|
|
||||||
|
|
||||||
### Phase 3: Safe Multisig (Future Task)
|
|
||||||
- Safe SDK integration
|
|
||||||
- TransactionBuilderShape for visual tx composition
|
|
||||||
- Collaborative signing UI
|
|
||||||
|
|
||||||
### Phase 4: Account Abstraction (Future Task)
|
|
||||||
- ERC-4337 smart wallet with P-256 signature validation
|
|
||||||
- Gasless transactions via paymaster
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
<!-- AC:BEGIN -->
|
|
||||||
- [x] #1 Install and configure wagmi v2, viem, and @walletconnect/web3modal
|
|
||||||
- [x] #2 Create linked_wallets table in Cloudflare D1 with proper schema
|
|
||||||
- [x] #3 Implement POST /api/wallet/link endpoint with signature verification
|
|
||||||
- [ ] #4 Implement GET /api/wallet/list endpoint to retrieve linked wallets
|
|
||||||
- [ ] #5 Implement DELETE /api/wallet/unlink endpoint to remove wallet links
|
|
||||||
- [ ] #6 Create WalletConnectButton component using wagmi hooks
|
|
||||||
- [ ] #7 Create WalletLinkPanel component for linking flow UI
|
|
||||||
- [ ] #8 Add wallet section to user settings/profile panel
|
|
||||||
- [ ] #9 Display linked wallet addresses with ENS resolution
|
|
||||||
- [ ] #10 Support multiple wallet types: EOA, Safe, Hardware
|
|
||||||
- [ ] #11 Add wallet connection state to AuthContext
|
|
||||||
- [ ] #12 Write tests for wallet linking flow
|
|
||||||
- [ ] #13 Update CLAUDE.md with Web3 architecture documentation
|
|
||||||
<!-- AC:END -->
|
|
||||||
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
### Step 1: Dependencies & Configuration
|
|
||||||
```bash
|
|
||||||
npm install wagmi viem @tanstack/react-query @walletconnect/web3modal
|
|
||||||
```
|
|
||||||
|
|
||||||
Configure wagmi with WalletConnect projectId and supported chains.
|
|
||||||
|
|
||||||
### Step 2: Database Schema
|
|
||||||
Add to D1 migration:
|
|
||||||
- linked_wallets table (user_id, wallet_address, wallet_type, chain_id, verified_at, signature_proof, ens_name, is_primary)
|
|
||||||
|
|
||||||
### Step 3: API Endpoints
|
|
||||||
Worker routes:
|
|
||||||
- POST /api/wallet/link - Verify signature, create link
|
|
||||||
- GET /api/wallet/list - List user's linked wallets
|
|
||||||
- DELETE /api/wallet/unlink - Remove a linked wallet
|
|
||||||
- GET /api/wallet/verify/:address - Check if address is linked to any CryptID
|
|
||||||
|
|
||||||
### Step 4: Frontend Components
|
|
||||||
- WagmiProvider wrapper in App.tsx
|
|
||||||
- WalletConnectButton - Connect/disconnect wallet
|
|
||||||
- WalletLinkPanel - Full linking flow with signature
|
|
||||||
- WalletBadge - Display linked wallet in UI
|
|
||||||
|
|
||||||
### Step 5: Integration
|
|
||||||
- Add linkedWallets to Session type
|
|
||||||
- Update AuthContext with wallet state
|
|
||||||
- Add wallet section to settings panel
|
|
||||||
|
|
||||||
### Step 6: Testing
|
|
||||||
- Unit tests for signature verification
|
|
||||||
- Integration tests for linking flow
|
|
||||||
- E2E test for full wallet link journey
|
|
||||||
<!-- SECTION:PLAN:END -->
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
|
||||||
## Planning Complete (2026-01-02)
|
|
||||||
|
|
||||||
Comprehensive planning phase completed:
|
|
||||||
|
|
||||||
### Created Architecture Document (doc-001)
|
|
||||||
- Full technical architecture for wallet linking
|
|
||||||
- Database schema design
|
|
||||||
- API endpoint specifications
|
|
||||||
- Library comparison (wagmi/viem recommended)
|
|
||||||
- Security considerations
|
|
||||||
- Frontend component designs
|
|
||||||
|
|
||||||
### Created Migration File
|
|
||||||
- `worker/migrations/002_linked_wallets.sql`
|
|
||||||
- Tables: linked_wallets, wallet_link_tokens, wallet_token_balances
|
|
||||||
- Proper indexes and foreign keys
|
|
||||||
|
|
||||||
### Created Follow-up Tasks
|
|
||||||
- task-060: Snapshot Voting Integration
|
|
||||||
- task-061: Safe Multisig Integration
|
|
||||||
- task-062: Account Abstraction Exploration
|
|
||||||
|
|
||||||
### Key Architecture Decisions
|
|
||||||
1. **Wallet Linking** approach (not key reuse) due to P-256/secp256k1 incompatibility
|
|
||||||
2. **wagmi v2 + viem** for frontend (React hooks, tree-shakeable)
|
|
||||||
3. **viem** for worker (signature verification)
|
|
||||||
4. **EIP-191 personal_sign** for EOA verification
|
|
||||||
5. **ERC-1271** for Safe/contract wallet verification (future)
|
|
||||||
|
|
||||||
### Next Steps
|
|
||||||
1. Install dependencies: wagmi, viem, @tanstack/react-query, @web3modal/wagmi
|
|
||||||
2. Run migration on D1
|
|
||||||
3. Implement API endpoints in worker
|
|
||||||
4. Build WalletLinkPanel UI component
|
|
||||||
|
|
||||||
## Implementation Complete (Phase 1: Wallet Linking)
|
|
||||||
|
|
||||||
### Files Created:
|
|
||||||
- `src/providers/Web3Provider.tsx` - Wagmi v2 config with WalletConnect
|
|
||||||
- `src/hooks/useWallet.ts` - React hooks for wallet connection/linking
|
|
||||||
- `src/components/WalletLinkPanel.tsx` - UI component for wallet management
|
|
||||||
- `worker/walletAuth.ts` - Backend signature verification and API handlers
|
|
||||||
- `worker/migrations/002_linked_wallets.sql` - Database schema
|
|
||||||
|
|
||||||
### Files Modified:
|
|
||||||
- `worker/types.ts` - Added wallet types
|
|
||||||
- `worker/worker.ts` - Added wallet API routes
|
|
||||||
- `src/App.tsx` - Integrated Web3Provider
|
|
||||||
- `src/ui/UserSettingsModal.tsx` - Added wallet section to Integrations tab
|
|
||||||
|
|
||||||
### Features:
|
|
||||||
- Connect wallets via MetaMask, WalletConnect, Coinbase Wallet
|
|
||||||
- Link wallets to CryptID accounts via EIP-191 signature
|
|
||||||
- View/manage linked wallets
|
|
||||||
- Set primary wallet, unlink wallets
|
|
||||||
- Supports mainnet, Optimism, Arbitrum, Base, Polygon
|
|
||||||
|
|
||||||
### Remaining Work:
|
|
||||||
- Add @noble/hashes for proper keccak256/ecrecover (placeholder functions)
|
|
||||||
- Run D1 migration on production
|
|
||||||
- Get WalletConnect Project ID from cloud.walletconnect.com
|
|
||||||
<!-- SECTION:NOTES:END -->
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
id: task-007
|
||||||
|
title: Web3 Integration
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2025-12-03'
|
||||||
|
labels: [feature, web3, blockchain]
|
||||||
|
priority: low
|
||||||
|
branch: web3-integration
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
Integrate Web3 capabilities for blockchain-based features (wallet connect, NFT canvas elements, etc.).
|
||||||
|
|
||||||
|
## Branch Info
|
||||||
|
- **Branch**: `web3-integration`
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [ ] Add wallet connection
|
||||||
|
- [ ] Enable NFT minting of canvas elements
|
||||||
|
- [ ] Blockchain-based ownership verification
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
id: task-060
|
|
||||||
title: Snapshot Voting Integration
|
|
||||||
status: To Do
|
|
||||||
assignee: []
|
|
||||||
created_date: '2026-01-02 16:08'
|
|
||||||
labels:
|
|
||||||
- feature
|
|
||||||
- web3
|
|
||||||
- governance
|
|
||||||
- voting
|
|
||||||
dependencies:
|
|
||||||
- task-007
|
|
||||||
priority: medium
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
||||||
Integrate Snapshot.js SDK for off-chain governance voting through the canvas interface.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
Enable CryptID users with linked wallets to participate in Snapshot governance votes directly from the canvas. Proposals and voting can be visualized as shapes on the canvas.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
- Requires task-007 (Web3 Wallet Linking) to be completed first
|
|
||||||
- User must have at least one linked wallet with voting power
|
|
||||||
|
|
||||||
## Technical Approach
|
|
||||||
- Use Snapshot.js SDK for proposal fetching and vote submission
|
|
||||||
- Create VotingShape to visualize proposals on canvas
|
|
||||||
- Support EIP-712 signature-based voting via linked wallet
|
|
||||||
- Cache voting power from linked wallets
|
|
||||||
|
|
||||||
## Features
|
|
||||||
1. **Proposal Browser** - List active proposals from configured spaces
|
|
||||||
2. **VotingShape** - Canvas shape to display proposal details and vote
|
|
||||||
3. **Vote Signing** - Use wagmi's signTypedData for EIP-712 votes
|
|
||||||
4. **Voting Power Display** - Show user's voting power per space
|
|
||||||
5. **Vote History** - Track user's past votes
|
|
||||||
|
|
||||||
## Spaces to Support Initially
|
|
||||||
- mycofi.eth (MycoFi DAO)
|
|
||||||
- Add configuration for additional spaces
|
|
||||||
|
|
||||||
## References
|
|
||||||
- Snapshot.js: https://docs.snapshot.org/tools/snapshot.js
|
|
||||||
- Snapshot API: https://docs.snapshot.org/tools/api
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
<!-- AC:BEGIN -->
|
|
||||||
- [ ] #1 Install and configure Snapshot.js SDK
|
|
||||||
- [ ] #2 Create VotingShape with proposal details display
|
|
||||||
- [ ] #3 Implement vote signing flow with EIP-712
|
|
||||||
- [ ] #4 Add proposal browser panel to canvas UI
|
|
||||||
- [ ] #5 Display voting power from linked wallets
|
|
||||||
- [ ] #6 Support multiple Snapshot spaces via configuration
|
|
||||||
- [ ] #7 Cache and display vote history
|
|
||||||
<!-- AC:END -->
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
---
|
|
||||||
id: task-061
|
|
||||||
title: Safe Multisig Integration for Collaborative Transactions
|
|
||||||
status: To Do
|
|
||||||
assignee: []
|
|
||||||
created_date: '2026-01-02 16:08'
|
|
||||||
labels:
|
|
||||||
- feature
|
|
||||||
- web3
|
|
||||||
- multisig
|
|
||||||
- safe
|
|
||||||
- governance
|
|
||||||
dependencies:
|
|
||||||
- task-007
|
|
||||||
priority: medium
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
||||||
Integrate Safe (Gnosis Safe) SDK to enable collaborative transaction building and signing through the canvas interface.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
Allow CryptID users to create, propose, and sign Safe multisig transactions visually on the canvas. Multiple signers can collaborate in real-time to approve transactions.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
- Requires task-007 (Web3 Wallet Linking) to be completed first
|
|
||||||
- Users must link their Safe wallet or EOA that is a Safe signer
|
|
||||||
|
|
||||||
## Technical Approach
|
|
||||||
- Use Safe{Core} SDK for transaction building and signing
|
|
||||||
- Create TransactionBuilderShape for visual tx composition
|
|
||||||
- Use Safe Transaction Service API for proposal queue
|
|
||||||
- Real-time signature collection via canvas collaboration
|
|
||||||
|
|
||||||
## Features
|
|
||||||
1. **Safe Linking** - Link Safe addresses (detect via ERC-1271)
|
|
||||||
2. **TransactionBuilderShape** - Visual transaction composer
|
|
||||||
3. **Signature Collection UI** - See who has signed, who is pending
|
|
||||||
4. **Transaction Queue** - View pending transactions for linked Safes
|
|
||||||
5. **Execution** - Execute transactions when threshold is met
|
|
||||||
|
|
||||||
## Visual Transaction Builder Capabilities
|
|
||||||
- Transfer ETH/tokens
|
|
||||||
- Contract interactions (with ABI import)
|
|
||||||
- Batch transactions
|
|
||||||
- Scheduled transactions (via delay module)
|
|
||||||
|
|
||||||
## Collaboration Features
|
|
||||||
- Real-time signature status on canvas
|
|
||||||
- Notifications when signatures are needed
|
|
||||||
- Discussion threads on pending transactions
|
|
||||||
|
|
||||||
## References
|
|
||||||
- Safe{Core} SDK: https://docs.safe.global/sdk/overview
|
|
||||||
- Safe Transaction Service API: https://docs.safe.global/core-api/transaction-service-overview
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
<!-- AC:BEGIN -->
|
|
||||||
- [ ] #1 Install and configure Safe{Core} SDK
|
|
||||||
- [ ] #2 Implement ERC-1271 signature verification for Safe linking
|
|
||||||
- [ ] #3 Create TransactionBuilderShape for visual tx composition
|
|
||||||
- [ ] #4 Build signature collection UI with real-time updates
|
|
||||||
- [ ] #5 Display pending transaction queue for linked Safes
|
|
||||||
- [ ] #6 Enable transaction execution when threshold is met
|
|
||||||
- [ ] #7 Support basic transfer and contract interaction transactions
|
|
||||||
<!-- AC:END -->
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
---
|
|
||||||
id: task-062
|
|
||||||
title: Account Abstraction (ERC-4337) Exploration
|
|
||||||
status: To Do
|
|
||||||
assignee: []
|
|
||||||
created_date: '2026-01-02 16:08'
|
|
||||||
labels:
|
|
||||||
- research
|
|
||||||
- web3
|
|
||||||
- account-abstraction
|
|
||||||
- erc-4337
|
|
||||||
dependencies:
|
|
||||||
- task-007
|
|
||||||
priority: low
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
||||||
Research and prototype using ERC-4337 Account Abstraction to enable CryptID's P-256 keys to directly control smart contract wallets.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
Explore the possibility of using Account Abstraction (ERC-4337) to bridge CryptID's WebCrypto P-256 keys with Ethereum transactions. This would eliminate the need for wallet linking by allowing CryptID keys to directly sign UserOperations that control a smart wallet.
|
|
||||||
|
|
||||||
## Background
|
|
||||||
- CryptID uses ECDSA P-256 (NIST curve) via WebCrypto API
|
|
||||||
- Ethereum uses ECDSA secp256k1
|
|
||||||
- These curves are incompatible for direct signing
|
|
||||||
- ERC-4337 allows any signature scheme via custom validation logic
|
|
||||||
|
|
||||||
## Research Questions
|
|
||||||
1. Is P-256 signature verification gas-efficient on-chain?
|
|
||||||
2. What existing implementations exist? (Clave, Daimo)
|
|
||||||
3. What are the wallet deployment costs per user?
|
|
||||||
4. How do we handle gas sponsorship (paymaster)?
|
|
||||||
5. Which bundler/paymaster providers support this?
|
|
||||||
|
|
||||||
## Potential Benefits
|
|
||||||
- Single key for auth AND transactions
|
|
||||||
- Gasless transactions via paymaster
|
|
||||||
- Social recovery using CryptID email
|
|
||||||
- No MetaMask/wallet app needed
|
|
||||||
- True passwordless Web3
|
|
||||||
|
|
||||||
## Risks & Challenges
|
|
||||||
- Complex implementation
|
|
||||||
- Gas costs for P-256 verification (~100k gas)
|
|
||||||
- Not all L2s support ERC-4337 yet
|
|
||||||
- User education on new paradigm
|
|
||||||
|
|
||||||
## Providers to Evaluate
|
|
||||||
- Pimlico (bundler + paymaster)
|
|
||||||
- Alchemy Account Kit
|
|
||||||
- Stackup
|
|
||||||
- Biconomy
|
|
||||||
|
|
||||||
## References
|
|
||||||
- ERC-4337 Spec: https://eips.ethereum.org/EIPS/eip-4337
|
|
||||||
- Clave (P-256 wallet): https://getclave.io/
|
|
||||||
- Daimo (P-256 wallet): https://daimo.com/
|
|
||||||
- viem Account Abstraction: https://viem.sh/account-abstraction
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
<!-- AC:BEGIN -->
|
|
||||||
- [ ] #1 Research P-256 on-chain verification gas costs
|
|
||||||
- [ ] #2 Evaluate existing P-256 wallet implementations (Clave, Daimo)
|
|
||||||
- [ ] #3 Prototype UserOperation signing with CryptID keys
|
|
||||||
- [ ] #4 Evaluate bundler/paymaster providers
|
|
||||||
- [ ] #5 Document architecture proposal if viable
|
|
||||||
- [ ] #6 Estimate implementation timeline and costs
|
|
||||||
<!-- AC:END -->
|
|
||||||
40
src/App.tsx
40
src/App.tsx
|
|
@ -28,9 +28,6 @@ import { ErrorBoundary } from './components/ErrorBoundary';
|
||||||
import CryptID from './components/auth/CryptID';
|
import CryptID from './components/auth/CryptID';
|
||||||
import CryptoDebug from './components/auth/CryptoDebug';
|
import CryptoDebug from './components/auth/CryptoDebug';
|
||||||
|
|
||||||
// Import Web3 provider for wallet integration
|
|
||||||
import { Web3Provider } from './providers/Web3Provider';
|
|
||||||
|
|
||||||
// Import Google Data test component
|
// Import Google Data test component
|
||||||
import { GoogleDataTest } from './components/GoogleDataTest';
|
import { GoogleDataTest } from './components/GoogleDataTest';
|
||||||
|
|
||||||
|
|
@ -119,15 +116,6 @@ const RedirectBoardSlug = () => {
|
||||||
return <Navigate to={`/board/${slug}/`} replace />;
|
return <Navigate to={`/board/${slug}/`} replace />;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Component to redirect direct slug URLs to board URLs
|
|
||||||
* Handles canvas.jeffemmett.com/ccc → /board/ccc/
|
|
||||||
*/
|
|
||||||
const RedirectDirectSlug = () => {
|
|
||||||
const { slug } = useParams<{ slug: string }>();
|
|
||||||
return <Navigate to={`/board/${slug}/`} replace />;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main App with context providers
|
* Main App with context providers
|
||||||
*/
|
*/
|
||||||
|
|
@ -154,12 +142,11 @@ const AppWithProviders = () => {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<Web3Provider>
|
<FileSystemProvider>
|
||||||
<FileSystemProvider>
|
<NotificationProvider>
|
||||||
<NotificationProvider>
|
<Suspense fallback={<LoadingSpinner />}>
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
<DailyProvider callObject={null}>
|
||||||
<DailyProvider callObject={null}>
|
<BrowserRouter>
|
||||||
<BrowserRouter>
|
|
||||||
{/* Display notifications */}
|
{/* Display notifications */}
|
||||||
<NotificationsDisplay />
|
<NotificationsDisplay />
|
||||||
|
|
||||||
|
|
@ -222,20 +209,13 @@ const AppWithProviders = () => {
|
||||||
{/* Google Data routes */}
|
{/* Google Data routes */}
|
||||||
<Route path="/google" element={<GoogleDataTest />} />
|
<Route path="/google" element={<GoogleDataTest />} />
|
||||||
<Route path="/oauth/google/callback" element={<GoogleDataTest />} />
|
<Route path="/oauth/google/callback" element={<GoogleDataTest />} />
|
||||||
|
|
||||||
{/* Catch-all: Direct slug URLs redirect to board URLs */}
|
|
||||||
{/* e.g., canvas.jeffemmett.com/ccc → /board/ccc/ */}
|
|
||||||
{/* Must be LAST to not interfere with other routes */}
|
|
||||||
<Route path="/:slug" element={<RedirectDirectSlug />} />
|
|
||||||
<Route path="/:slug/" element={<RedirectDirectSlug />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</DailyProvider>
|
</DailyProvider>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</NotificationProvider>
|
</NotificationProvider>
|
||||||
</FileSystemProvider>
|
</FileSystemProvider>
|
||||||
</Web3Provider>
|
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue