220 lines
6.5 KiB
Markdown
220 lines
6.5 KiB
Markdown
# Web of Trust (WoT) Integration
|
|
|
|
This document describes the Web of Trust trust scoring system in SkateSpots, inspired by ContextVM's Relatr approach.
|
|
|
|
## Overview
|
|
|
|
**Web of Trust (WoT)** is a decentralized trust system that computes personalized trust scores by analyzing social graph connections on Nostr.
|
|
|
|
SkateSpots uses Web of Trust to:
|
|
1. **Display trust badges** on spot cards to help users identify trusted contributors
|
|
2. **Show trust scores** in Pyramid rankings to highlight quality contributors
|
|
3. **Future: Gate bounty claims** to prevent spam (when bounty system is implemented)
|
|
|
|
## What is a Trust Score?
|
|
|
|
Trust scores (0-100) are calculated using Nostr social graph analysis:
|
|
|
|
- **100**: Self (your own content)
|
|
- **90**: Direct follow (you follow them)
|
|
- **60**: Friend-of-friend (you follow someone who follows them, 2 hops)
|
|
- **30**: Has NIP-05 verification (basic credibility)
|
|
- **0**: No connection or verification
|
|
|
|
**Trust is personalized** - scores are calculated from the viewer's perspective. If a user is logged in, trust is based on who THEY follow. If not logged in, trust is based on a default admin pubkey.
|
|
|
|
## Implementation
|
|
|
|
### 1. Trust Score Hook (`src/hooks/useTrustScore.ts`)
|
|
|
|
The `useTrustScore` hook calculates trust scores client-side using Nostr follow lists:
|
|
|
|
```typescript
|
|
import { useTrustScore } from '@/hooks/useTrustScore';
|
|
|
|
function MyComponent({ pubkey }: { pubkey: string }) {
|
|
const { data: trustScore } = useTrustScore(pubkey);
|
|
|
|
// trustScore is 0-100, or undefined if not available
|
|
console.log('Trust score:', trustScore);
|
|
}
|
|
```
|
|
|
|
**How it works:**
|
|
1. Fetches viewer's follow list (kind 3 event)
|
|
2. Checks if target is directly followed → Score: 90
|
|
3. Fetches friends' follow lists (kind 3 events)
|
|
4. Checks if target is followed by a friend → Score: 60
|
|
5. Checks if target has NIP-05 verification → Score: 30
|
|
6. Otherwise → Score: 0
|
|
|
|
**Features:**
|
|
- Client-side calculation (no external API required)
|
|
- Personalized to current user (or admin if logged out)
|
|
- Caches scores for 1 hour (trust changes slowly)
|
|
- Graceful error handling (returns undefined on failure)
|
|
|
|
### 2. Spot Card Trust Badges
|
|
|
|
Trust badges appear next to the creator's name on spot cards:
|
|
|
|
- **VERIFIED** (green): Trust score 80-100
|
|
- **TRUSTED** (yellow): Trust score 50-79
|
|
- **No badge**: Trust score below 50
|
|
|
|
### 3. Pyramid Rankings
|
|
|
|
Trust scores appear as a new column in the Pyramid leaderboard:
|
|
|
|
- **Green**: 80-100 (Highly trusted)
|
|
- **Yellow**: 50-79 (Trusted)
|
|
- **Gray**: Below 50 or unknown
|
|
|
|
## Configuration
|
|
|
|
### Default Trust Source
|
|
|
|
When users are not logged in, trust scores are calculated from a default admin pubkey:
|
|
|
|
```typescript
|
|
const DEFAULT_SOURCE_PUBKEY = '20e7c953439e66f3882ab96fe0faa8ba246d6fb12c03b0cb4e2dc4623b8bcb21';
|
|
```
|
|
|
|
When users ARE logged in, trust scores are calculated from **their own perspective** (using their follow list).
|
|
|
|
### No External Dependencies
|
|
|
|
Trust calculation happens entirely client-side using:
|
|
- Kind 3 events (follow lists) from Nostr relays
|
|
- Kind 0 events (profile metadata) for NIP-05 verification
|
|
- No external APIs required
|
|
|
|
## Future: Advanced Trust with ContextVM Relatr
|
|
|
|
For more sophisticated trust calculations, you could integrate ContextVM's Relatr service:
|
|
|
|
### Benefits of Full Relatr Integration:
|
|
|
|
- **Deeper graph analysis** (3+ hops instead of 2)
|
|
- **Profile validation metrics** (Lightning addresses, event activity)
|
|
- **Reciprocity checking** (mutual follows weighted higher)
|
|
- **Configurable scoring weights**
|
|
- **Pre-computed trust database** (faster queries)
|
|
|
|
### Implementation:
|
|
|
|
Relatr is an **MCP (Model Context Protocol) server**, designed for AI agents. To use it from a web app, you would need to:
|
|
|
|
1. **Self-host Relatr** with a custom HTTP wrapper
|
|
2. **Use ContextVM SDK** over Nostr transport
|
|
3. **Build a proxy service** that exposes HTTP endpoints
|
|
|
|
For most use cases, the **current client-side WoT calculation is sufficient** and requires no infrastructure.
|
|
|
|
## Performance
|
|
|
|
### Caching Strategy
|
|
|
|
Trust scores are cached aggressively since they change slowly:
|
|
|
|
```typescript
|
|
staleTime: 3600000, // 1 hour
|
|
gcTime: 86400000, // 24 hours in cache
|
|
```
|
|
|
|
### Lazy Loading
|
|
|
|
Trust scores are only fetched when the component using them is rendered. For optimal performance, consider using intersection observers for large lists.
|
|
|
|
## Future Enhancements
|
|
|
|
### 1. Bounty Spam Prevention
|
|
|
|
When the bounty system is implemented, trust scores can gate bounty claims:
|
|
|
|
```typescript
|
|
function BountyClaimButton({ bounty }) {
|
|
const { user } = useCurrentUser();
|
|
const { data: trustScore } = useTrustScore(user?.pubkey);
|
|
const MIN_TRUST = 30;
|
|
|
|
if (!trustScore || trustScore < MIN_TRUST) {
|
|
return <div>Trust score too low to claim bounties</div>;
|
|
}
|
|
|
|
return <Button onClick={handleClaim}>Claim Bounty</Button>;
|
|
}
|
|
```
|
|
|
|
### 2. Trust-Weighted Sorting
|
|
|
|
Rankings can be weighted by trust score:
|
|
|
|
```typescript
|
|
const trustWeighted = (spots + events) * (trustScore / 100);
|
|
```
|
|
|
|
This would prioritize quality over quantity in leaderboards.
|
|
|
|
### 3. Trust Filters
|
|
|
|
Add filters to map/list views:
|
|
|
|
```typescript
|
|
// Show only verified spots
|
|
const verifiedSpots = spots.filter(spot => spot.trustScore >= 80);
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### `useTrustScore(pubkey: string | undefined)`
|
|
|
|
Fetch trust score for a Nostr pubkey.
|
|
|
|
**Parameters:**
|
|
- `pubkey` - Hex-encoded Nostr pubkey (or undefined)
|
|
|
|
**Returns:**
|
|
- `data: number | undefined` - Trust score (0-100) or undefined
|
|
- Standard React Query properties (`isLoading`, `error`, etc.)
|
|
|
|
**Example:**
|
|
```typescript
|
|
const { data: trustScore, isLoading } = useTrustScore(userPubkey);
|
|
```
|
|
|
|
### `getTrustBadgeConfig(score: number | undefined)`
|
|
|
|
Get badge configuration based on trust score.
|
|
|
|
**Parameters:**
|
|
- `score` - Trust score (0-100) or undefined
|
|
|
|
**Returns:**
|
|
```typescript
|
|
{
|
|
show: boolean; // Whether to show badge
|
|
variant: 'default' | 'outline';
|
|
className: string; // Tailwind classes
|
|
label: string; // 'VERIFIED', 'TRUSTED', or 'UNVERIFIED'
|
|
icon: 'check' | 'shield' | null;
|
|
}
|
|
```
|
|
|
|
## Resources
|
|
|
|
- [ContextVM GitHub](https://github.com/ContextVM)
|
|
- [Relatr Repository](https://github.com/ContextVM/relatr)
|
|
- [ContextVM Documentation](https://docs.contextvm.org)
|
|
- [Public Relatr Instance](https://relatr.xyz)
|
|
|
|
## Support
|
|
|
|
For issues with Relatr integration:
|
|
1. Check browser console for API errors
|
|
2. Verify Relatr API is accessible: `curl https://relatr.xyz/api/health`
|
|
3. Review trust score calculation in Relatr docs
|
|
|
|
For SkateSpots integration issues:
|
|
- File an issue on the repository
|
|
- Check `useTrustScore` hook for error handling
|