Identity System
Horizon uses an EVM-first identity system with multi-wallet support and name resolution.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ User Identity │
├─────────────────────────────────────────────────────────────┤
│ Primary: EVM Address (Base L2) │
│ └── Missions, guilds, reputation, XP │
├─────────────────────────────────────────────────────────────┤
│ Linked Wallets: Additional EVM addresses │
│ └── Multi-wallet support with labels │
├─────────────────────────────────────────────────────────────┤
│ Name Resolution: Basename / ENS │
│ └── Human-readable names and avatars │
├─────────────────────────────────────────────────────────────┤
│ Off-chain: Display name, avatar, bio │
└─────────────────────────────────────────────────────────────┘
Wallet Integration
CDP Embedded Wallets (Primary)
Coinbase Developer Platform embedded wallets for seamless onboarding:
- Email OTP - Sign up with email verification
- Social Login - Google, Apple authentication
- Non-custodial - Users own their keys
- No seed phrase - Simplified UX
External Wallets
Also supported via WalletConnect:
- Coinbase Wallet - Native Base integration
- MetaMask - Popular browser wallet
- Rainbow - Mobile-first wallet
- Other WalletConnect-compatible wallets
Authentication (SIWE)
Horizon uses Sign-In With Ethereum (EIP-4361) for authentication:
// SIWE message format
const message = `
horizon.app wants you to sign in with your Ethereum account:
${address}
Sign in to Horizon
URI: https://horizon.app
Version: 1
Chain ID: ${chainId}
Nonce: ${nonce}
Issued At: ${issuedAt}
`;
Flow
- User connects wallet
- Backend generates SIWE challenge with nonce
- User signs message with wallet
- Backend verifies signature
- JWT token issued for session
Name Resolution
Basenames (.base.eth)
Native Base name resolution:
// Reverse resolution: address → name
const result = await basenameService.resolveAddress('0x...');
// { name: 'alice.base.eth', avatar: 'https://...' }
// Forward resolution: name → address
const address = await basenameService.resolveName('alice.base.eth');
// '0x...'
ENS (.eth)
Fallback to Ethereum Name Service:
const result = await ensService.resolveAddress('0x...');
// { name: 'vitalik.eth', avatar: 'https://...' }
Priority
- Check Basename first (Base-native)
- Fall back to ENS if no Basename
- Display address if neither found
Multi-Wallet Support
Users can link multiple wallets to their account:
Link Wallet
// Generate link message
const message = generateLinkMessage(userId, address);
// "Link wallet to Horizon\nUser: ...\nWallet: ...\nTimestamp: ..."
// User signs message
const signature = await wallet.signMessage(message);
// Backend verifies and links
await identityService.linkWallet(userId, 'evm', address, signature, message);
Wallet Management
| Feature | Description |
|---|---|
| Primary wallet | Main address for missions |
| Labels | Custom names for wallets |
| Unlink | Remove linked wallets (except primary) |
User Data
On-chain (Immutable)
- Wallet addresses
- Reputation attestations (EAS)
- Achievement NFTs
- Guild memberships
Off-chain (Mutable)
- Display name
- Avatar URL
- Bio
- Notification preferences
- Location history (30-day retention)
Privacy Controls
Users can:
- Export all data (GDPR compliance)
- Delete off-chain data
- Control location sharing
- Manage notification preferences
- Revoke linked wallets---## Future: Device AttestationPlanned for high-security operations:| Platform | Technology | |----------|------------| | Android | Play Integrity API | | iOS | DeviceCheck | | Web | WebAuthn/Passkeys |This will enable:
- Anti-fraud protection
- Bot prevention
- Location verification enhancement