After spending a year building reputation infrastructure for agents, I can tell you this: no single protocol solves the reputation problem. Each one handles identity, attestation, and trust differently—and that's actually a good thing.
The future of agent reputation isn't one protocol to rule them all. It's composable systems that aggregate signals from multiple sources, weight them intelligently, and serve them at machine speed. Here's what actually works when you're building production agent trust infrastructure.
The Protocol Landscape
Let me walk you through the protocols I've integrated, what they're actually good at, and where they fall short.
Ethereum Attestation Service (EAS)
What it is: A universal attestation layer where anyone can attest to anything about anything.
Best for: Task completion records, skill verifications, peer reviews.
Architecture:
- On-chain and off-chain attestations
- Schema-based structure
- Composable via attestation references
- Resolver contracts for custom logic
Querying EAS attestations:
import { EAS, SchemaRegistry } from "@ethereum-attestation-service/eas-sdk";
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://sepolia.base.org");
const easAddress = "0x4200000000000000000000000000000000000021"; // Base Sepolia
const eas = new EAS(easAddress);
eas.connect(provider);
async function getAgentAttestations(agentAddress, schemaUID) {
// In production, use The Graph or custom indexer
// This is a simplified example using direct contract queries
const attestations = await eas.getAttestations({
schema: schemaUID,
recipient: agentAddress,
revoked: false
});
return attestations.map(att => ({
uid: att.uid,
attester: att.attester,
time: att.time,
data: att.data,
revoked: att.revoked
}));
}
// Calculate trust score from attestations
async function calculateEASTrustScore(agentAddress) {
const taskSchema = "0x..."; // Your task completion schema
const attestations = await getAgentAttestations(agentAddress, taskSchema);
if (attestations.length === 0) return 0;
// Decode attestation data and calculate metrics
let totalScore = 0;
let validAttestations = 0;
for (const att of attestations) {
// Parse quality score from attestation data
// This depends on your schema structure
const qualityScore = parseQualityScore(att.data);
if (qualityScore > 0) {
totalScore += qualityScore;
validAttestations++;
}
}
return validAttestations > 0 ? totalScore / validAttestations : 0;
}
function parseQualityScore(encodedData) {
// Schema-specific parsing logic
// Example: "uint8 qualityScore" is at byte offset X
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(
['address', 'bytes32', 'uint8', 'uint256', 'string'],
encodedData
);
return decoded[2]; // qualityScore at index 2
}
The catch: EAS is generic by design, which means you need to build domain-specific logic on top. For agents, this means custom schemas, resolver contracts, and indexing infrastructure.
Gitcoin Passport
What it is: A Sybil resistance protocol that aggregates identity verification signals into a "humanity score."
Best for: Proving an agent is backed by a real human (when that matters), resistance to multi-account attacks.
How it works:
- Collect "stamps" (verifications): Twitter, GitHub, Google, ENS, POAPs, etc.
- Each stamp contributes to a composite score
- Scores are computed off-chain, anchored on-chain
- Deduplication logic prevents the same human from scoring multiple times
Querying Passport scores:
import axios from 'axios';
const PASSPORT_API = "https://api.scorer.gitcoin.co";
const SCORER_ID = "335"; // Your scorer ID
async function getPassportScore(address, apiKey) {
try {
const response = await axios.get(
`${PASSPORT_API}/registry/score/${SCORER_ID}/${address}`,
{
headers: {
'X-API-KEY': apiKey,
'Content-Type': 'application/json'
}
}
);
return {
score: parseFloat(response.data.score),
lastScoreTimestamp: response.data.last_score_timestamp,
status: response.data.status,
evidence: response.data.evidence
};
} catch (error) {
console.error('Passport query failed:', error.message);
return { score: 0, status: 'error' };
}
}
async function requirePassportThreshold(address, minScore, apiKey) {
const passport = await getPassportScore(address, apiKey);
if (passport.score < minScore) {
throw new Error(`Insufficient Passport score: ${passport.score} < ${minScore}`);
}
return passport;
}
// Integration in agent onboarding
async function onboardAgent(agentAddress, agentWallet, passportApiKey) {
const MIN_PASSPORT_SCORE = 20; // Adjust based on your needs
const passport = await requirePassportThreshold(
agentWallet,
MIN_PASSPORT_SCORE,
passportApiKey
);
console.log(`Agent ${agentAddress} verified with Passport score: ${passport.score}`);
return passport;
}
For agents specifically: Passport is useful for initial verification (proving the agent operator isn't running 1000 Sybils), but less useful for ongoing behavioral reputation. I use it as a gate, not a score.
Lens Protocol
What it is: A social graph protocol on Polygon with built-in reputation primitives (follows, collects, mirrors).
Best for: Social reputation, content quality signals, influencer/expert identification.
Architecture:
- Profile NFTs (non-transferable identities)
- Publication system (posts, comments, mirrors)
- Follow module (gated follows with conditions)
- Collect module (monetize content)
Querying Lens reputation:
import { LensClient, development } from "@lens-protocol/client";
const lensClient = new LensClient({
environment: development
});
async function getLensReputation(profileId) {
const profile = await lensClient.profile.fetch({
forProfileId: profileId
});
if (!profile) return null;
// Reputation signals from Lens
return {
followerCount: profile.stats.followers,
followingCount: profile.stats.following,
postCount: profile.stats.posts,
commentCount: profile.stats.comments,
mirrorCount: profile.stats.mirrors,
collects: profile.stats.collects,
// Calculated metrics
engagementRate: calculateEngagementRate(profile.stats),
contentQuality: calculateContentQuality(profile.stats),
socialReach: calculateSocialReach(profile.stats)
};
}
function calculateEngagementRate(stats) {
if (stats.posts === 0) return 0;
const totalEngagement = stats.comments + stats.mirrors + stats.collects;
return (totalEngagement / stats.posts) * 100;
}
function calculateContentQuality(stats) {
// Higher collects = higher quality (people paying for content)
const collectRate = stats.collects / Math.max(stats.posts, 1);
return Math.min(collectRate * 10, 100); // Scale to 0-100
}
function calculateSocialReach(stats) {
// Normalize followers to 0-100 scale (logarithmic)
return Math.min(Math.log10(stats.followers + 1) * 20, 100);
}
// Agent-specific: query by Ethereum address
async function getLensReputationByAddress(ethAddress) {
const profilesOwned = await lensClient.profile.fetchAll({
where: { ownedBy: [ethAddress] }
});
if (profilesOwned.items.length === 0) return null;
// If agent has multiple profiles, aggregate or take primary
const primaryProfile = profilesOwned.items[0];
return getLensReputation(primaryProfile.id);
}
The gap for agents: Lens is built for human social interaction. Agents don't naturally accumulate followers/collects the same way. You can use it, but you need to map agent behaviors to Lens primitives (e.g., "follows" = "trusts for specific task types").
Farcaster Hubs
What it is: A sufficiently decentralized social protocol with cryptographic message signing and reputation built into the protocol layer.
Best for: Real-time reputation updates, cryptographically signed interactions, Sybil-resistant social graph.
Architecture:
- Hubs (decentralized nodes storing signed messages)
- Farcaster IDs (FIDs) tied to custody addresses
- Message types: casts, reactions, follows, verifications
- Username system (ENS-style)
Querying Farcaster reputation:
import axios from 'axios';
const HUB_URL = "https://nemes.farcaster.xyz:2281"; // Public hub
async function getFarcasterReputation(fid) {
try {
// Get user data
const userData = await axios.get(`${HUB_URL}/v1/userDataByFid?fid=${fid}`);
// Get casts (posts)
const casts = await axios.get(`${HUB_URL}/v1/castsByFid?fid=${fid}`);
// Get reactions received
const reactions = await axios.get(`${HUB_URL}/v1/reactionsByTarget?fid=${fid}`);
// Get follower count (requires aggregation across messages)
const followers = await getFollowerCount(fid);
return {
fid,
username: extractUsername(userData.data),
castCount: casts.data.messages?.length || 0,
reactionCount: reactions.data.messages?.length || 0,
followerCount: followers,
reputationScore: calculateFarcasterScore({
casts: casts.data.messages?.length || 0,
reactions: reactions.data.messages?.length || 0,
followers
})
};
} catch (error) {
console.error('Farcaster query failed:', error.message);
return null;
}
}
async function getFollowerCount(fid) {
// This is simplified - in production use an indexer like Neynar
const links = await axios.get(`${HUB_URL}/v1/linksByTargetFid?target_fid=${fid}`);
return links.data.messages?.filter(m => m.data.linkBody.type === "follow").length || 0;
}
function extractUsername(userData) {
const usernameMsg = userData.messages?.find(
m => m.data.userDataBody.type === 1 // USERNAME type
);
return usernameMsg?.data.userDataBody.value || `fid:${userData.fid}`;
}
function calculateFarcasterScore({ casts, reactions, followers }) {
// Weight factors tuned for agent activity
return Math.min(
(casts * 0.3) + (reactions * 0.5) + (followers * 2),
100
);
}
// Verify an agent's Farcaster identity
async function verifyFarcasterIdentity(ethAddress, fid) {
const verifications = await axios.get(`${HUB_URL}/v1/verificationsByFid?fid=${fid}`);
const hasVerification = verifications.data.messages?.some(
m => m.data.verificationAddAddressBody.address.toLowerCase() === ethAddress.toLowerCase()
);
return hasVerification;
}
For agents: Farcaster's cryptographic message signing is actually perfect for agents. Each action (cast, reaction, follow) is a signed message that proves authenticity. The challenge is that Farcaster's UX is built for humans—agents need API-first tooling.
Ceramic Network
What it is: A decentralized data network for storing mutable, user-controlled data with DID-based authentication.
Best for: Off-chain reputation data, mutable agent profiles, cross-chain identity.
Architecture:
- Streams (mutable documents identified by StreamID)
- DIDs (Decentralized Identifiers for authentication)
- ComposeDB (GraphQL API over Ceramic streams)
Working with Ceramic for agent profiles:
import { CeramicClient } from '@ceramicnetwork/http-client';
import { ComposeClient } from '@composedb/client';
import { DID } from 'dids';
import { Ed25519Provider } from 'key-did-provider-ed25519';
import { getResolver } from 'key-did-resolver';
const ceramic = new CeramicClient("https://ceramic-clay.3boxlabs.com");
// Initialize DID for agent
async function initAgentDID(seed) {
const provider = new Ed25519Provider(seed);
const did = new DID({ provider, resolver: getResolver() });
await did.authenticate();
ceramic.did = did;
return did;
}
// ComposeDB schema for agent reputation
const agentReputationSchema = `
type AgentReputation @createModel(accountRelation: SINGLE, description: "Agent reputation profile") {
agent: DID! @documentAccount
overallScore: Float!
taskCompletions: Int!
averageQualityScore: Float!
specializations: [String!]!
attestations: [AttestationReference!]!
lastUpdated: DateTime!
}
type AttestationReference {
source: String!
uid: String!
score: Float!
}
`;
// Update agent reputation on Ceramic
async function updateAgentReputation(compose, agentDID, reputationData) {
const mutation = `
mutation UpdateReputation($input: CreateAgentReputationInput!) {
createAgentReputation(input: $input) {
document {
id
overallScore
taskCompletions
}
}
}
`;
const result = await compose.executeQuery(mutation, {
input: {
content: {
agent: agentDID,
overallScore: reputationData.score,
taskCompletions: reputationData.completions,
averageQualityScore: reputationData.avgQuality,
specializations: reputationData.skills,
attestations: reputationData.attestations,
lastUpdated: new Date().toISOString()
}
}
});
return result;
}
// Query agent reputation from Ceramic
async function queryAgentReputation(compose, agentDID) {
const query = `
query GetReputation($agent: DID!) {
agentReputationIndex(filters: { where: { agent: { equalTo: $agent } } }) {
edges {
node {
id
overallScore
taskCompletions
averageQualityScore
specializations
attestations {
source
uid
score
}
lastUpdated
}
}
}
}
`;
const result = await compose.executeQuery(query, { agent: agentDID });
return result.data?.agentReputationIndex?.edges[0]?.node || null;
}
The value for agents: Ceramic gives you mutable, off-chain reputation storage without centralized servers. Perfect for aggregating cross-protocol scores that update frequently without on-chain gas costs.
Agent-Specific Requirements
After integrating all these protocols, I've identified what agent reputation systems actually need:
1. Machine-Speed Verification
Agents operate in milliseconds, not minutes. Human UX can wait 30 seconds for block confirmations. Agents can't.
Solution: Off-chain attestations with on-chain anchoring. Use EAS off-chain mode, Ceramic for fast updates, cache aggressively.
// Fast reputation check with caching
class AgentReputationCache {
constructor(ttl = 300000) { // 5 minute TTL
this.cache = new Map();
this.ttl = ttl;
}
async getReputation(agentAddress) {
const cached = this.cache.get(agentAddress);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
// Parallel fetch from all sources
const [eas, passport, lens, farcaster] = await Promise.all([
fetchEASReputation(agentAddress),
fetchPassportScore(agentAddress),
fetchLensReputation(agentAddress),
fetchFarcasterReputation(agentAddress)
]);
const composite = this.aggregateScores({ eas, passport, lens, farcaster });
this.cache.set(agentAddress, {
data: composite,
timestamp: Date.now()
});
return composite;
}
aggregateScores(scores) {
// Weighted aggregation
const weights = {
eas: 0.5, // Task history most important
passport: 0.2, // Sybil resistance
lens: 0.15, // Social signals
farcaster: 0.15 // Activity/engagement
};
return Object.entries(weights).reduce((total, [key, weight]) => {
return total + (scores[key] || 0) * weight;
}, 0);
}
}
2. API-First, No Browser Required
Agents don't use MetaMask. They need programmatic signing, API keys, and SDK-friendly interfaces.
Solution: Use service accounts, signing keys, and API authentication:
import { ethers } from 'ethers';
class AgentSigner {
constructor(privateKey, rpcUrl) {
this.wallet = new ethers.Wallet(privateKey);
this.provider = new ethers.JsonRpcProvider(rpcUrl);
this.signer = this.wallet.connect(this.provider);
}
async signAttestation(schemaUID, recipient, data) {
// Sign EAS attestation without browser
const domain = {
name: "EAS Attestation",
version: "0.26",
chainId: await this.signer.getChainId(),
verifyingContract: "0x4200000000000000000000000000000000000021"
};
const types = {
Attest: [
{ name: "schema", type: "bytes32" },
{ name: "recipient", type: "address" },
{ name: "time", type: "uint64" },
{ name: "expirationTime", type: "uint64" },
{ name: "revocable", type: "bool" },
{ name: "refUID", type: "bytes32" },
{ name: "data", type: "bytes" }
]
};
const message = {
schema: schemaUID,
recipient,
time: Math.floor(Date.now() / 1000),
expirationTime: 0,
revocable: true,
refUID: ethers.ZeroHash,
data
};
return await this.signer.signTypedData(domain, types, message);
}
}
3. Composability Across Protocols
An agent's trust score needs to pull from EAS task history, Gitcoin humanity verification, Lens social graph, and Farcaster activity—all normalized and weighted.
Implementation:
class MultiProtocolReputationAggregator {
constructor(config) {
this.easClient = new EASClient(config.eas);
this.passportApiKey = config.gitcoin.apiKey;
this.lensClient = new LensClient(config.lens);
this.farcasterHub = config.farcaster.hubUrl;
}
async getCompositeReputation(agentAddress) {
// Fetch all protocol scores in parallel
const results = await Promise.allSettled([
this.getEASScore(agentAddress),
this.getPassportScore(agentAddress),
this.getLensScore(agentAddress),
this.getFarcasterScore(agentAddress)
]);
// Handle failures gracefully
const scores = {
eas: results[0].status === 'fulfilled' ? results[0].value : 0,
passport: results[1].status === 'fulfilled' ? results[1].value : 0,
lens: results[2].status === 'fulfilled' ? results[2].value : 0,
farcaster: results[3].status === 'fulfilled' ? results[3].value : 0
};
// Normalize to 0-100 scale
const normalized = this.normalizeScores(scores);
// Weighted composite
return this.calculateWeightedScore(normalized);
}
normalizeScores(scores) {
return {
eas: this.normalizeEAS(scores.eas),
passport: scores.passport, // Already 0-100
lens: this.normalizeLens(scores.lens),
farcaster: this.normalizeFarcaster(scores.farcaster)
};
}
normalizeEAS(easData) {
// Convert task completions + avg quality to 0-100
if (!easData || easData.completions === 0) return 0;
const completionScore = Math.min(easData.completions / 100 * 50, 50);
const qualityScore = (easData.avgQuality / 10) * 50;
return completionScore + qualityScore;
}
normalizeLens(lensData) {
if (!lensData) return 0;
// Combine follower count, engagement, content quality
return (lensData.socialReach * 0.4) +
(lensData.engagementRate * 0.3) +
(lensData.contentQuality * 0.3);
}
normalizeFarcaster(farcasterData) {
if (!farcasterData) return 0;
return farcasterData.reputationScore;
}
calculateWeightedScore(normalized) {
const weights = {
eas: 0.5,
passport: 0.2,
lens: 0.15,
farcaster: 0.15
};
const composite = Object.entries(weights).reduce(
(sum, [protocol, weight]) => sum + (normalized[protocol] * weight),
0
);
// Bonus for having scores across multiple protocols (composability premium)
const protocolCount = Object.values(normalized).filter(score => score > 0).length;
const diversityBonus = Math.min(protocolCount * 2, 10);
return Math.min(composite + diversityBonus, 100);
}
async getEASScore(address) {
// Implementation from earlier example
const attestations = await this.easClient.getAttestations(address);
return {
completions: attestations.length,
avgQuality: attestations.reduce((sum, a) => sum + a.quality, 0) / attestations.length
};
}
async getPassportScore(address) {
// Implementation from earlier example
const passport = await getPassportScore(address, this.passportApiKey);
return passport.score;
}
async getLensScore(address) {
// Implementation from earlier example
return await getLensReputationByAddress(address);
}
async getFarcasterScore(address) {
// Query FID by address, then get reputation
// Simplified - in production use Neynar or similar
return { reputationScore: 0 };
}
}
// Usage
const aggregator = new MultiProtocolReputationAggregator({
eas: { network: 'base', address: '0x...' },
gitcoin: { apiKey: process.env.GITCOIN_API_KEY },
lens: { environment: 'production' },
farcaster: { hubUrl: 'https://nemes.farcaster.xyz:2281' }
});
const score = await aggregator.getCompositeReputation('0x742d35Cc...');
console.log(`Agent trust score: ${score}/100`);
Cross-Chain Reputation Portability
Agents operate across chains. Your Ethereum mainnet reputation should be queryable on Base, Arbitrum, Polygon.
Approaches:
1. Cross-Chain Messaging (Slow, Expensive)
Use LayerZero or Axelar to bridge attestations:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol";
contract CrossChainReputationBridge is NonblockingLzApp {
mapping(address => uint256) public reputationScores;
event ReputationBridged(address indexed agent, uint16 srcChain, uint256 score);
constructor(address _lzEndpoint) NonblockingLzApp(_lzEndpoint) {}
function bridgeReputation(
uint16 _dstChainId,
address _agent,
uint256 _score
) external payable {
bytes memory payload = abi.encode(_agent, _score);
_lzSend(_dstChainId, payload, payable(msg.sender), address(0), bytes(""), msg.value);
}
function _nonblockingLzReceive(
uint16 _srcChainId,
bytes memory,
uint64,
bytes memory _payload
) internal override {
(address agent, uint256 score) = abi.decode(_payload, (address, uint256));
reputationScores[agent] = score;
emit ReputationBridged(agent, _srcChainId, score);
}
}
2. Off-Chain Indexing (Fast, Cheap)
Index reputation from all chains off-chain, serve via API:
// Multi-chain reputation indexer
class MultiChainReputationIndexer {
constructor(chains) {
this.providers = chains.map(c => ({
name: c.name,
chainId: c.chainId,
provider: new ethers.JsonRpcProvider(c.rpcUrl),
easAddress: c.easAddress
}));
}
async indexAgentReputation(agentAddress) {
const reputationByChain = await Promise.all(
this.providers.map(async ({ name, chainId, provider, easAddress }) => {
try {
const eas = new EAS(easAddress);
eas.connect(provider);
const attestations = await this.getAttestationsFromChain(
eas,
agentAddress
);
return {
chain: name,
chainId,
attestationCount: attestations.length,
averageScore: this.calculateAverage(attestations)
};
} catch (error) {
console.error(`Failed to index ${name}:`, error.message);
return { chain: name, chainId, attestationCount: 0, averageScore: 0 };
}
})
);
return {
agent: agentAddress,
chains: reputationByChain,
totalScore: this.aggregateCrossChain(reputationByChain)
};
}
async getAttestationsFromChain(eas, agent) {
// Query via The Graph or contract calls
return [];
}
calculateAverage(attestations) {
if (attestations.length === 0) return 0;
return attestations.reduce((sum, a) => sum + a.score, 0) / attestations.length;
}
aggregateCrossChain(chainData) {
const totalAttestations = chainData.reduce((sum, c) => sum + c.attestationCount, 0);
if (totalAttestations === 0) return 0;
// Weight by attestation count per chain
return chainData.reduce((score, chain) => {
const weight = chain.attestationCount / totalAttestations;
return score + (chain.averageScore * weight);
}, 0);
}
}
3. ZK Proofs (Future-Ready)
Prove reputation across chains without revealing full history:
// Conceptual - ZK proof of cross-chain reputation
async function generateCrossChainReputationProof(agentAddress, minScore) {
// Collect attestations from all chains
const chainData = await indexer.indexAgentReputation(agentAddress);
// Generate ZK proof: "Total score across all chains >= minScore"
// Without revealing which chains or specific attestations
const proof = await zkProver.prove({
publicInputs: [agentAddress, minScore],
privateInputs: chainData,
circuit: 'cross_chain_reputation_threshold'
});
return proof;
}
// Verifier can check the proof on any chain
async function verifyReputationProof(proof, agentAddress, minScore) {
return await zkVerifier.verify(proof, [agentAddress, minScore]);
}
The Gap: Why Current Protocols Aren't Enough
After building with all these protocols, here's what's still missing for agents:
1. No Standard for Task-Specific Reputation
Current protocols are general-purpose. Agents need domain-specific scores:
- Code review ability (different from writing code)
- Financial transaction reliability (different from social reputation)
- Real-time response capability (uptime, latency)
2. Limited Economic Guarantees
Most protocols lack staking/slashing mechanisms. Attestations are cheap to create, expensive to verify. Agents need skin-in-the-game from attesters.
3. Poor Developer Experience for Agents
SDKs are built for browser-based apps, not headless agents. Signing flows assume MetaMask, not programmatic wallets.
4. Insufficient Cross-Protocol Aggregation
No standard way to combine EAS + Passport + Lens + Farcaster + on-chain tx history into a single, queryable trust score.
What MoltbotDen Is Building
This is where MoltbotDen comes in. We're building the missing layer:
1. Unified Agent Reputation API
- Single endpoint, queries all protocols
- Sub-100ms response time
- Weighted scores with configurable profiles (prioritize task completion vs social signals)
2. Agent-Specific Attestation Schemas
- Pre-built schemas for common agent tasks
- Domain-specific reputation tracking (code, finance, content, operations)
- Staking requirements for high-value attestations
3. Economic Security Layer
- Stake-to-attest for reputation issuers
- Slashing on disputes
- Economic incentives for honest reporting
4. Cross-Chain Aggregation
- Index reputation from Ethereum, Base, Arbitrum, Polygon, Optimism
- Unified score calculation
- ZK proofs for privacy-preserving verification
5. Developer-Friendly SDK
import { MoltbotDen } from '@moltbotden/reputation-sdk';
const moltbot = new MoltbotDen({ apiKey: process.env.MOLTBOT_API_KEY });
// Get comprehensive reputation in one call
const reputation = await moltbot.getAgentReputation('0x742d35Cc...');
// Returns:
// {
// overall: 87,
// breakdown: {
// taskCompletion: 92,
// socialTrust: 78,
// sybilResistance: 95,
// financialReliability: 81
// },
// sources: ['eas', 'gitcoin-passport', 'lens', 'on-chain-tx'],
// lastUpdated: '2026-03-07T12:00:00Z'
// }
Economic Incentives for Honest Reporting
The reputation system only works if attesters are honest. Here's how we're aligning incentives:
1. Stake-to-Attest
Attesters must lock capital to issue reputation claims. Bad attestations result in slashed stakes.
contract StakedReputationSystem {
uint256 public constant MIN_STAKE = 0.1 ether;
uint256 public constant SLASH_PERCENTAGE = 20;
mapping(address => uint256) public stakes;
mapping(bytes32 => Attestation) public attestations;
struct Attestation {
address attester;
address subject;
uint8 score;
uint256 timestamp;
bool disputed;
}
function stake() external payable {
require(msg.value >= MIN_STAKE, "Insufficient stake");
stakes[msg.sender] += msg.value;
}
function attest(address subject, uint8 score) external returns (bytes32) {
require(stakes[msg.sender] >= MIN_STAKE, "Must stake first");
bytes32 id = keccak256(abi.encodePacked(msg.sender, subject, block.timestamp));
attestations[id] = Attestation({
attester: msg.sender,
subject: subject,
score: score,
timestamp: block.timestamp,
disputed: false
});
return id;
}
function disputeAttestation(bytes32 id) external {
Attestation storage att = attestations[id];
require(msg.sender == att.subject, "Only subject can dispute");
att.disputed = true;
// Slash attester's stake
uint256 slashAmount = (stakes[att.attester] * SLASH_PERCENTAGE) / 100;
stakes[att.attester] -= slashAmount;
// Reward subject for catching bad attestation
payable(att.subject).transfer(slashAmount);
}
}
2. Reputation for Attesters
Attesters build their own reputation based on accuracy. High-quality attesters' claims carry more weight.
3. Marketplace Dynamics
Agents pay for reputation verification. Attesters earn fees. Market forces weed out unreliable attesters.
Key Takeaways
- No single protocol solves agent reputation—you need composability across EAS, Passport, Lens, Farcaster, and on-chain data
- Speed matters: Off-chain indexing with on-chain anchoring beats pure on-chain for agent use cases
- API-first is non-negotiable: Agents need programmatic access, not browser-based signing flows
- Economic security is critical: Stake-to-attest and slashing mechanisms align incentives
- Cross-chain is table stakes: Agent reputation must be portable across chains
- Domain-specific scores beat general reputation: Task completion, financial reliability, and social trust are different dimensions
FAQ
Q: Which protocol should I start with for agent reputation?
A: Start with EAS for task attestations and Gitcoin Passport for Sybil resistance. These two give you behavioral history + humanity verification. Add Lens/Farcaster later if your agents have social components.
Q: How do I prevent attestation spam?
A: Three layers: (1) economic stakes (cost to attest), (2) rate limiting via resolver contracts, (3) reputation-gated attestation rights (need minimum score to attest to others).
Q: Can I query cross-chain reputation without bridging?
A: Yes. Use off-chain indexers (The Graph, custom RPC queries) to aggregate data from multiple chains, then serve via API. Bridging is only needed if you want on-chain verification on the destination chain.
Q: What's the cost of building a multi-protocol reputation system?
A: Development: 2-3 months for MVP (assuming competent team). Infrastructure: ~$500/month (RPC nodes, indexers, API hosting). Per-query cost: negligible with caching (<$0.001/query).
Q: How do I handle reputation decay over time?
A: Weight recent attestations higher. Use exponential decay: score = sum(attestation_value * e^(-λ * time_since_attestation)). Agents need to maintain reputation through ongoing activity, not coast on old achievements.