Skip to main content

Why On-Chain?

The Mnemom Trust Rating is computed and stored on centralized infrastructure. While the scoring methodology is transparent and cryptographically verifiable via Merkle proofs, the data ultimately lives on Mnemom servers. On-chain verification adds a decentralized trust anchor that eliminates single-point-of-failure concerns:
  • Immutable — Once a reputation score or Merkle root is published to the blockchain, it cannot be altered or deleted by anyone, including Mnemom
  • Tamper-evident — Any discrepancy between on-chain and off-chain data is immediately detectable by any observer
  • Independently verifiable — Anyone with an Ethereum-compatible client can verify scores without relying on Mnemom’s API or infrastructure
  • Composable — On-chain scores can be consumed by other smart contracts, dApps, and protocols directly, enabling trust-gated interactions in DeFi, DAOs, and agent marketplaces
On-chain verification does not replace the off-chain scoring system. It complements it by anchoring the most critical data points — Merkle roots and reputation scores — to an immutable ledger that survives even if Mnemom’s infrastructure is unavailable.

ERC-8004 Reputation Registry

Mnemom’s on-chain verification is built on ERC-8004, a standard for on-chain reputation registries. ERC-8004 defines a common interface for publishing, querying, and verifying reputation scores on EVM-compatible chains, enabling any contract or dApp to:
  • Query an agent’s current reputation score and grade
  • Retrieve historical score records
  • Verify Merkle root anchors for tamper-evidence
  • Gate interactions based on minimum reputation thresholds
By building on a standard rather than a proprietary interface, Mnemom enables interoperability with other reputation systems, agent marketplaces, and smart contracts that adopt ERC-8004.

Base L2 Rationale

Mnemom deploys its reputation contracts on Base, Coinbase’s Layer 2 network built on the OP Stack. The choice of Base is driven by:
FactorBase L2 Advantage
Gas costsTransactions cost $0.01-0.05, making frequent score publishing economical
Ethereum securityBase settles to Ethereum L1, inheriting its security guarantees
EVM compatibilityStandard Solidity contracts and tooling work without modification
Ecosystem alignmentCoinbase’s agent and crypto infrastructure provides natural distribution
Finality speed2-second block times enable near-instant score confirmation
Base’s low transaction costs are critical for the anchoring model. Publishing reputation scores for hundreds of agents would cost thousands of dollars per batch on Ethereum L1 but only a few dollars on Base.

Smart Contracts Overview

MnemoReputationRegistry

The primary contract for publishing and querying individual agent reputation scores. Constants:
ConstantValueDescription
MAX_SCORE1000Maximum possible reputation score
MAX_BATCH_SIZE200Maximum agents per batch publication
Key Functions:
FunctionDescription
publishScore(bytes32 agentId, uint16 score, bytes3 grade, bytes32 metadataHash)Publish a single agent’s reputation score
publishBatch(ScoreRecord[] records)Publish scores for up to 200 agents in a single transaction
getScore(bytes32 agentId)Retrieve the latest on-chain score for an agent
getScoreHistory(bytes32 agentId)Retrieve all historical score records for an agent
getLatestBatchRoot()Get the Merkle root of the most recent batch publication
getTotalPublishedAgents()Count of unique agents with on-chain scores
ScoreRecord Struct:
struct ScoreRecord {
    uint16  score;         // 0-1000 composite score
    bytes3  grade;         // ASCII grade (e.g., "A", "AA", "BBB")
    uint64  publishedAt;   // Unix timestamp of publication
    uint64  blockNumber;   // Block number at publication
    bytes32 metadataHash;  // keccak256 hash of off-chain metadata
}
Events:
EventEmitted When
ScorePublished(bytes32 indexed agentId, uint16 score, bytes3 grade, uint64 publishedAt)A single score is published
BatchPublished(bytes32 batchRoot, uint32 agentCount, uint64 publishedAt)A batch of scores is published

MnemoMerkleAnchor

The anchoring contract for publishing Merkle tree roots from the off-chain integrity checkpoint system. Key Functions:
FunctionDescription
anchorRoot(bytes32 merkleRoot, uint32 leafCount, uint16 treeDepth)Anchor a new Merkle root on-chain
getLatestRoot()Retrieve the most recently anchored root
getRootByIndex(uint256 index)Retrieve a specific historical root by index
getRootCount()Total number of anchored roots
isRootAnchored(bytes32 merkleRoot)Check whether a specific Merkle root has been anchored
AnchorRecord Struct:
struct AnchorRecord {
    bytes32 merkleRoot;    // Root hash of the Merkle tree
    uint64  anchoredAt;    // Unix timestamp of anchoring
    uint64  blockNumber;   // Block number at anchoring
    uint32  leafCount;     // Number of leaves (checkpoints) in the tree
    uint16  treeDepth;     // Depth of the Merkle tree
}
Events:
EventEmitted When
RootAnchored(bytes32 indexed merkleRoot, uint32 leafCount, uint16 treeDepth, uint64 anchoredAt)A new Merkle root is anchored

Merkle Root Anchoring Flow

Mnemom anchors Merkle roots on-chain as tamper-evidence checkpoints for the off-chain integrity system. The anchoring flow works as follows:
Off-Chain                                      On-Chain (Base L2)
─────────                                      ──────────────────

Agent integrity checkpoints


Per-agent Merkle trees
(each agent's checkpoints
 form a tree)


Agent-level Merkle roots
aggregated into global root


Global Merkle root ──────────────────────────→ MnemoMerkleAnchor.anchorRoot()


                                               AnchorRecord stored on-chain
                                               RootAnchored event emitted
Anchoring cadence: Global Merkle roots are anchored periodically (typically every few hours) to Base L2. The frequency balances cost efficiency against freshness — more frequent anchoring provides tighter tamper-evidence windows but costs more gas. Verification: Anyone can call isRootAnchored(root) with a Merkle root obtained from the off-chain API to confirm it has been anchored on-chain. If the root exists on-chain, the underlying checkpoint data has not been tampered with since anchoring. Inclusion proofs: Individual checkpoints can be verified for inclusion in an anchored root using standard Merkle inclusion proofs. The off-chain API provides the proof path, and the on-chain root serves as the trusted reference.

Score Publishing and Verification

Publishing

Reputation scores are published to MnemoReputationRegistry either individually or in batches: Agent ID encoding: Human-readable agent IDs (e.g., smolt-a4c12709) are converted to bytes32 via keccak256(abi.encodePacked(agentId)) before on-chain storage. This provides a fixed-size identifier suitable for mapping keys. Grade encoding: Letter grades are stored as bytes3 ASCII values. For example, "A" becomes 0x410000, "AA" becomes 0x414100, and "BBB" becomes 0x424242. Batch publishing: When multiple scores are published in a single transaction via publishBatch(), a batch Merkle root is computed from the individual score records and stored alongside the batch. This enables efficient verification that a specific score was included in a particular batch without replaying the entire batch.

Verification

Anyone can verify an agent’s on-chain reputation:
  1. Query the score — Call getScore(agentId) on the MnemoReputationRegistry contract to retrieve the latest on-chain ScoreRecord
  2. Compare with off-chain — Fetch the same agent’s score from the Mnemom API (GET /v1/reputation/{agent_id}) and compare. Matching scores confirm consistency
  3. Verify the anchor — Call isRootAnchored(root) on MnemoMerkleAnchor with the Merkle root from the off-chain verification endpoint to confirm the underlying data is tamper-evident
  4. Check history — Call getScoreHistory(agentId) to see how the on-chain score has evolved over time
Verifier                     Base L2                     Mnemom API
────────                     ───────                     ──────────

getScore(agentId) ─────────→ ScoreRecord
                              (score: 782,
                               grade: "A")

                                                 GET /v1/reputation/{agent_id}
                                                 ◄────── score: 782, grade: "A"

Compare: on-chain == off-chain ✓

isRootAnchored(root) ──────→ true ✓

Verification complete: score is authentic and tamper-evident

Cost Estimates

On-chain operations consume gas, but Base L2’s low fees make frequent anchoring and publishing economical:
OperationApproximate GasApproximate Cost (Base L2)
Anchor single Merkle root~50,000 gas0.010.01 - 0.02
Publish single score~80,000 gas0.020.02 - 0.03
Batch publish (50 agents)~200,000 gas0.030.03 - 0.05
Batch publish (200 agents)~600,000 gas0.080.08 - 0.15
Read score (view call)0 gasFree
Check if root anchored (view call)0 gasFree
Gas costs fluctuate with Base L2 network activity and Ethereum L1 blob fees. The estimates above reflect typical conditions. Read operations (view calls) are always free.
For comparison, the same batch publish of 50 agents on Ethereum L1 would cost approximately $5-15 depending on gas prices — 100-300x more expensive than Base L2.

See Also