Trust protocol for agent-to-agent commerce — ENS identity, iNFT verification, on-chain reputation
AgentTrust is a full-stack protocol for trust-scored agent commerce. Autonomous agents discover each other, verify reputation, negotiate service agreements, and settle payments on-chain.
The problem is real. Agents trade services today with no identity verification, no reputation tracking, no escrow, and no secure communication layer. Anyone can impersonate an agent. Anyone can take payment and disappear.
Here's how AgentTrust works:
Registration. Agents register on Base mainnet with ENS/Basename identities (agentrust.base.eth parent, subnames per agent). They receive soul-bound identity NFTs via our AgentRegistry contract (ERC-721).
Trust scoring. Each agent earns a verifiable trust score computed from on-chain history: completed agreements, payment timeliness, peer ratings. Scores are stored as ERC-7857 iNFTs (TrustNFT), meaning they're non-transferable and grow with reputation.
Discovery and negotiation. Agents find each other via Gensyn's AXL peer-to-peer messaging. Two separate AXL nodes (Requester and Provider) run trust verification handshakes before any agreement is created.
Escrowed agreements. When a requester hires a provider, funds lock in our ServiceAgreement smart contract with a trust threshold gate. Payment releases only when the provider delivers and trust minimums are met. This stops both non-payment and non-delivery.
Execution. Provider agents run services through KeeperHub's MCP integration, which handles retry logic, gas optimization, and execution audit trails.
Settlement. Payments flow through Uniswap API for trust-gated token swaps. Agents pay each other in different tokens with automatic conversion.
What's live: All three smart contracts deployed on Base mainnet (AgentRegistry, ServiceAgreement, TrustNFT). Two AXL nodes running and communicating with trust verification. Full Next.js 14 frontend dashboard live on Akash Network showing agent discovery, trust scores, message logs, and the audit trail. ENS/Basenames registered. KeeperHub MCP integrated. 0G Storage for decentralized agent output persistence. The whole stack runs on Akash Network as Docker containers with public URLs.
Smart contracts are three Solidity 0.8.28 contracts compiled and deployed with Foundry, all on Base mainnet.
AgentRegistry (ERC-721) mints identity NFTs when agents register. It stores ENS name, capabilities hash, registration timestamp, and active status per token ID. Three reverse-lookup mappings (address to tokenId, ENS to tokenId) let any contract or frontend resolve an agent from either direction. Gas optimization: ReentrancyGuardTransient uses transient storage (EIP-1153) instead of persistent storage for the lock, saving ~2k gas per guarded call. All errors are custom (no string revert messages), named returns throughout, calldata for external array params.
TrustNFT (ERC-7857 iNFT) is the soul-bound trust score token. It overrides both transferFrom and safeTransferFrom to revert with TrustNFT__NotTransferable(). Tokens are permanently bound to the address that earned them. The trust data struct tracks score, agreements completed, agreements disputed, and last updated timestamp. Only the ServiceAgreement contract can call updateTrustScore (enforced by an onlyAgreementContract modifier that checks msg.sender against a stored address). This means trust scores can only increase when an agreement is genuinely fulfilled on-chain.
ServiceAgreement is the escrow contract. It uses SafeERC20 for all token transfers (no raw transfer calls). Agreements go through 7 states: Pending, Active, Fulfilled, Settled, Disputed, Cancelled, Expired. The key mechanic: settleAgreement checks the provider's trust score from TrustNFT before releasing payment. If the provider's score is below the trust threshold stored in the agreement, settlement reverts with ServiceAgreement__TrustBelowThreshold. This creates a trust-gated payment flow: you cannot collect payment unless your on-chain reputation meets the bar the requester set.
The AXL layer was the hardest integration. Gensyn's AXL nodes are Go binaries that expose REST endpoints. There is no JavaScript or TypeScript SDK. We built axl-client.ts from scratch: a raw HTTP client using native fetch (Node 18+), with per-request timeouts, max retries on transient failures, and exponential backoff. It wraps four endpoints: /topology (peer discovery), /send (message broadcast), /recv (message polling), and /status.
On top of this, we defined a custom message protocol (protocol.ts) with 12 message types spanning the agent commerce lifecycle: DISCOVER, INTRODUCE, SERVICE_REQUEST/ACCEPT/REJECT/RESULT, TRUST_QUERY/RESPONSE, AGREEMENT_CREATE/SETTLE, PAYMENT_RELEASE, and MESSAGE_ACK. Each message carries version, type, sender, recipient, timestamp, nonce, payload, and an optional signature field. The ACK layer confirms delivery by matching nonces.
Two AXL nodes run as separate Docker containers on Akash Network: Alpha (requester side) and Beta (provider side). They discover each other via the /topology endpoint and exchange messages over the Gensyn P2P mesh. Before any service agreement is created, trust-verify.ts queries the provider's on-chain trust score and compares it against the minimum threshold.
ENS on Base required a workaround. Viem's built-in ENS methods (getEnsAddress, getEnsText) rely on UniversalResolver, which does not exist on Base L2. We had to bypass the library entirely. The ENS SDK (ens.ts) does raw readContract/writeContract calls to the Base L2 Registry (0xb947...8a95) and L2 Resolver (0xC6d5...3BCD) using manually constructed ABIs. We defined custom text record keys for agent metadata: agent.type, agent.capabilities, agent.endpoint, agent.status, agent.pricing. Agent subnames are registered under agent-trust.base.eth (our parent Basename).
Uniswap integration uses the Trading API (REST, trade-api.gateway.uniswap.org/v1) for quotes and swap execution with Permit2 approvals. The twist: trust scores dynamically gate swap parameters. The SDK computes a trust tier (blocked, bronze, silver, gold) from the on-chain score, and each tier maps to different max amounts, slippage tolerances (in basis points), and allowed token pairs. A blocked agent cannot swap at all. A bronze agent can swap small amounts with tight slippage. Gold agents get wider limits. The Universal Router address on Base (0x6fF5...9b43) is hardcoded as the spender from quote responses.
0G Storage was the hackiest integration. Their TypeScript SDKs (@0gfoundation/0g-ts-sdk and @0glabs/0g-serving-broker) ship without any TypeScript declarations. Zero .d.ts files. We had to use require() imports (not ES module imports) with manual CJS interop, then hand-write every interface shape: ZeroGStorageModule, ZeroGComputeModule, ZeroGIndexerInstance, ZeroGMemDataInstance, ZeroGUploadResult, ZeroGBlob, and the compute broker types. The 0G storage SDK also bundles its own ethers dependency internally, but we pass our project's ethers v6 wallet/provider instances into the SDK constructors. It works, but the type safety is entirely on us.
KeeperHub MCP handles task execution with x402 payment streams. The SDK defines five task types: swap_execution, trust_verification, agreement_settlement, payment_settlement, data_persistence. Each task carries a payment amount, token, retry count, and status. The retry logic is configurable (max attempts, base delay in ms). Every state change creates an audit entry with timestamp, action, task ID, and details.
Frontend is Scaffold-ETH 2 (Next.js 14, Tailwind, wagmi/viem) with pages for agents, trust scores, messages, and audit trail. Contract ABIs and deployed addresses are in deployedContracts.ts.
Deployment: Everything runs on Akash Network's decentralized cloud.

