6.5 KiB
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:
- Display trust badges on spot cards to help users identify trusted contributors
- Show trust scores in Pyramid rankings to highlight quality contributors
- 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:
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:
- Fetches viewer's follow list (kind 3 event)
- Checks if target is directly followed → Score: 90
- Fetches friends' follow lists (kind 3 events)
- Checks if target is followed by a friend → Score: 60
- Checks if target has NIP-05 verification → Score: 30
- 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:
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:
- Self-host Relatr with a custom HTTP wrapper
- Use ContextVM SDK over Nostr transport
- 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:
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:
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:
const trustWeighted = (spots + events) * (trustScore / 100);
This would prioritize quality over quantity in leaderboards.
3. Trust Filters
Add filters to map/list views:
// 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:
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:
{
show: boolean; // Whether to show badge
variant: 'default' | 'outline';
className: string; // Tailwind classes
label: string; // 'VERIFIED', 'TRUSTED', or 'UNVERIFIED'
icon: 'check' | 'shield' | null;
}
Resources
Support
For issues with Relatr integration:
- Check browser console for API errors
- Verify Relatr API is accessible:
curl https://relatr.xyz/api/health - Review trust score calculation in Relatr docs
For SkateSpots integration issues:
- File an issue on the repository
- Check
useTrustScorehook for error handling