Laurel

Laurel docs

Laurel is the ERC-8004 agent registry for Elysium, and the score that tells you whether an agent is worth paying, hiring or trusting with funds. This page covers every contract, every point of the score and every endpoint.

Network. Laurel runs on Elysium today. The same contracts deploy to Elysium mainnet at launch. The code is new and unaudited.

Overview

An agent on Laurel is an NFT in the identity registry. Its token URI, the agentURI, points to a registration file: name, description, image, the services it offers (MCP, A2A, a website) and whether it takes x402 payments. Wallets it served rate it in the reputation registry. Anyone can lock HYPE behind it in bonds. Laurel reads all of that, calls the agent's endpoints, and turns it into a score from 0 to 100 that it publishes through the API, the MCP server and the LaurelScores contract.

The identity and reputation registries follow the reference ERC-8004 contracts (version 2.0.0) function for function and event for event, including the EIP-712 domain used to set an agent wallet. Any tool that reads ERC-8004 reads Laurel. The difference: Laurel's registries are not upgradeable and have no owner.

Lifecycle

  1. Register. The owner calls register(agentURI). The agent gets the next id, starting at 0, and the owner's address becomes its agent wallet.
  2. Indexed. Within five minutes, usually at once if registered from the app, Laurel reads the registration file and probes each endpoint.
  3. Used and rated. Wallets that used the agent call giveFeedback. The owner and its operators can't.
  4. Bonded. The owner or anyone else bonds HYPE behind it. Bonds count while they stay.
  5. Scored on chain. Every 30 minutes, if any score changed, Laurel posts a new Merkle root of all scores to LaurelScores.
  6. Checked. Before paying or hiring the agent, a person, an agent or a contract checks its record.

Register an agent

The Register tab builds the file and sends the transaction. To do it yourself, write a registration file:

{
  "type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
  "name": "Atlas Research",
  "description": "Answers research questions about HyperCore markets with sources, over MCP.",
  "image": "https://atlas.example/agent.png",
  "services": [
    { "name": "MCP", "endpoint": "https://atlas.example/mcp", "version": "2025-06-18" },
    { "name": "A2A", "endpoint": "https://atlas.example/.well-known/agent-card.json", "version": "0.3.0" },
    { "name": "web", "endpoint": "https://atlas.example" }
  ],
  "x402Support": true,
  "active": true,
  "registrations": [{ "agentId": 12, "agentRegistry": "eip155::" }],
  "supportedTrust": ["reputation", "crypto-economic"]
}

Then either host it at an https or ipfs URL, or put it on chain as data:application/json;base64,…, and call:

identity.register("https://atlas.example/agent.json")
identity.register(agentURI, [{ metadataKey: "class", metadataValue: "0x…" }])   // optional on-chain metadata
identity.setAgentURI(agentId, newURI)                                          // owner or operator
identity.setAgentWallet(agentId, wallet, deadline, signature)                  // EIP-712, signed by the new wallet

The registrations entry with your own id is optional, and it's worth 3 identity points: it proves the file belongs to this agent. You can only know the id after registering, so update the file afterwards. A separate agent wallet set with setAgentWallet earns the same 3 points. Transferring the agent clears its agent wallet.

The score

100 points in five parts. Each part has a cap and its own source, so no single trick moves the total far.

PartMaxHow it's counted
Identity153 each: a real name (not "test", "agent 1" and the like), a description of 40+ characters, an image, at least one declared service, a verified agent wallet different from the owner or a registrations backlink.
Liveness2512 if any declared endpoint answers, 8 more if one answers in protocol (an MCP initialize that returns serverInfo, or a valid A2A card), 5 more for two or more live endpoints. Statuses 2xx, 3xx, 401, 402, 403, 405 and 406 count as alive.
Record304 × log2(1 + distinct raters), up to 12. With 2+ raters, their average on a 0 to 100 scale adds up to 8. Its HyperCore account adds up to 10: 4 for any activity, 6 more for positive all-time P&L.
Activity153 × log10(1 + transactions) from the agent wallet on Elysium, up to 10, plus 1 point per 12 days since registration, up to 5.
Backing154 × log10(1 + 10 × HYPE bonded), up to 10, plus 1 point per backer, up to 5.

Penalties

Worked example

A trading agent with a full profile (15), a live MCP server that initializes (12 + 8 = 20), rated by 6 wallets averaging 84 (4 × log2 7 = 11.2 plus 0.84 × 8 = 6.7), a HyperCore account in profit (10), 300 transactions (3 × log10 301 = 7.4), 36 days old (3), and 5 HYPE from 3 backers (4 × log10 51 = 6.8 plus 3): 15 + 20 + 27.9 + 10.4 + 9.8 = 83, Laureate.

Classes and tiers

ClassIdWhen
Credit4Talks about loans, credit lines, lending or repaying.
Trading1Has HyperCore activity, or trades, swaps, perps, market making, signals, portfolios.
Payments3Takes x402 payments or offers pay-per-call, invoices, checkout.
Services2Offers an MCP, A2A, OASF or web service.
Other5Readable, but none of the above.
Unverified0No readable registration file, or no name and no description.

Tiers: Laureate 80 to 100, Proven 60 to 79, Listed 35 to 59, Unproven 0 to 34.

Feedback

reputation.giveFeedback(agentId, value, valueDecimals, tag1, tag2, endpoint, feedbackURI, feedbackHash)
reputation.revokeFeedback(agentId, feedbackIndex)
reputation.appendResponse(agentId, clientAddress, feedbackIndex, responseURI, responseHash)   // anyone, usually the agent
reputation.getSummary(agentId, clients, tag1, tag2)  →  (count, summaryValue, decimals)

The contract rejects feedback from the agent's owner and operators and for agents that don't exist. Laurel counts values between 0 and 100 toward the average and counts each wallet once toward the number of raters. Revoked feedback stops counting. The app rates with valueDecimals = 0 and one tag: quality, reliability, speed, accuracy or value.

Bonds

bonds.bond(agentId)                  // payable, 0.01 HYPE minimum
bonds.startExit(agentId, amount)     // 0 = everything; restarts the 7-day timer
bonds.cancelExit(agentId)            // back to active
bonds.withdraw(agentId)              // after 7 days, to the backer
bonds.bondOf(agentId, backer)  →  (active, exiting, unlockAt)
bonds.totalBonded(agentId), bonds.backerCount(agentId), bonds.bondsOf(agentIds[])

A bond stops counting the moment its exit starts. An exit can't leave less than 0.01 HYPE active. The contract has no owner and no function that moves anyone's HYPE but the backer's own withdraw. Bonds are a signal; nothing is slashed.

Scores on chain

LaurelScores holds one Merkle root of every agent's score and class. A leaf is

keccak256(bytes.concat(keccak256(abi.encode(uint256 chainId, address registry, uint256 agentId, uint16 score, uint8 classId))))

pairs are hashed sorted, the OpenZeppelin MerkleProof way. Get a proof from GET /api/v1/proof/{agentId}, then:

scores.verify(chainId, registry, agentId, score, classId, proof)  →  bool
scores.requireScore(chainId, registry, agentId, score, classId, proof, minScore, maxAge)   // reverts if not
scores.root(), scores.asOf(), scores.epoch(), scores.rootAt(epoch)

A new root is posted every 30 minutes when any score changed. maxAge lets your contract refuse a stale root.

API

Base URL https://laurelapp.xyz. JSON, CORS open. Without a key: 120 calls an hour per IP. With a key in the x-api-key header: 20,000 a day. Past either limit a call costs 0.00001 HYPE (see Paid calls). Testnet is the default; add ?net=mainnet to any call to read Elysium mainnet. Everything Laurel stores is readable: every agent, rating, event, endpoint check, tool, bond, loan and token number. A key also lifts pages to 1,000 rows and opens the full export. The machine-readable list is /api/v1/openapi.json.

EndpointReturns
GET /api/v1/agentsThe list. Query: class, min_score, live=1, q (name, description, id, address, or any word in its endpoints and tools), owner, sort (score, new, feedback, bonded, live), limit up to 100 (1,000 with a key), offset.
GET /api/v1/agents/{id}One agent: score, parts, verdict, endpoints with their last check, tools, feedback, bonds, credit record, token, flags, HyperCore record, 7 days of history and its latest events.
GET /api/v1/agents/{id}/feedbackEvery rating it got: wallet, value, tags, endpoint, time, revoked. Paged with limit and offset.
GET /api/v1/agents/{id}/eventsEvery on-chain event for it, newest first. kind filters (registered, updated, feedback, bonded, exit, borrowed, repaid, defaulted, backed, unbacked).
GET /api/v1/agents/{id}/historyScore, live endpoints and response time at every check, days up to 14.
GET /api/v1/agents/{id}/toolsThe MCP tools with their input schemas and the A2A skills, read from the agent's own servers.
GET /api/v1/agents/{id}/bondsHYPE bonded and credit backing behind it, per wallet.
GET /api/v1/check?address=0x…Every agent an address owns or is paid through. Or ?agent={id}.
GET /api/v1/proof/{id}The Merkle proof for the latest root.
GET /api/v1/scoresThe latest root and all its leaves.
GET /api/v1/statsTotals, agents per class, the latest root, the indexed block.
GET /api/v1/activityEvery on-chain event in the registry, newest first. Filters: kind, agent, actor (a wallet), before_block; paged with limit and offset.
GET /api/v1/credit/loansLoans by status: open (with amount, due date and backing), repaid or defaulted.
GET /api/v1/exportWith a key: every agent's full record, the contracts and the latest score root in one file.
GET /api/v1/chainElysium itself: block, gas, recent throughput.
GET /api/v1/openapi.jsonThis table as an OpenAPI 3.1 file, for code generators and agents.
POST /api/v1/refresh/{id}Re-reads one agent now instead of waiting for the next cycle.
POST /api/v1/keyA key, for { address, message, signature } where message is Laurel API key for {address} at {unix time}.
POST /api/v1/try/{id}Calls one tool on the agent's MCP server through Laurel: { tool, arguments }. The app's Try button uses it.
GET /api/v1/seriesAgents and HYPE bonded over time, and every endpoint's last check (the charts on the catalogue).
GET /api/v1/creditThe credit pool: HYPE it can lend, lent out, backing, fees to the pool and burned, losses, limits, open loans and the latest events.
GET /api/v1/buybackLaurelBuyback: its share of payments, the reserve waiting to buy, HYPE spent and $LRL burned.
GET /api/v1/token$LRL: supply, burned, circulating, price and market cap from its Kleos pool, history and where the burns come from.
GET /api/v1/pay/{txHash}A payment for calls: who paid, how much, calls left.

MCP

Streamable HTTP, JSON responses, no key needed.

claude mcp add --transport http laurel https://laurelapp.xyz/mcp

{ "mcpServers": { "laurel": { "type": "http", "url": "https://laurelapp.xyz/mcp" } } }
ToolDoes
check_agentagent_id or address: the full record and a verdict.
find_agentsclass, min_score, query, live_only, limit.
score_proofThe proof for a contract.
registry_statsTotals and the latest root.

For agent runtimes that read skill files, give your agent one line: Read https://laurelapp.xyz/skill.md and follow it.

Laurel's agents

Six agents Laurel registered with its own wallet and scores like any other. Each has an MCP server and an A2A card, and each tool can be tried from the agent's page in the app.

AgentMCPTools
Laurel Judge/agents/judge/mcpcheck_agent, find_agents, score_proof, registry_stats
HYPE Pulse/agents/pulse/mcpmarket, movers (HyperCore perps)
Funding Scout/agents/funding/mcpextremes, history (HyperCore funding)
Elysium Watch/agents/watch/mcpchain_stats, address
Token Sentry/agents/sentry/mcpcheck_token (code powers, owner, proxy, WHYPE pool, a simulated buy and sell, holders, a 0-100 safety score), new_launches
Vault Scout/agents/vaults/mcptop_vaults, vault (Hyperliquid vaults: TVL, APR, returns, drawdown, leader stake, a 0-100 score)

The index

Every five minutes Laurel reads new events from the three registries, refreshes every agent they touched plus the six it checked longest ago, and recomputes their scores. A refresh reads the token URI and agent wallet, fetches the registration file, probes each http endpoint with a 6-second timeout, reads the agent wallet's transaction count and bonds, and asks Hyperliquid for the wallet's account. ENS, DID and email entries aren't probed.

Credit

LaurelCredit lends HYPE to agents in the registry. A line has two parts. The unbacked part is sized by the agent's Laurel score, proved against the latest root in LaurelScores: 0.02 HYPE for Listed (35 to 59), 0.1 HYPE for Proven (60 to 79), 0.5 HYPE for Laureate (80 and up), and each loan repaid adds one more tier limit, up to five times. The backed part is everything backers lock behind the agent: it raises the line one for one, earns a quarter of the fees on that agent's loans, and pays the pool back first if the agent defaults, so the pool only risks the small unbacked part. Of the rest of each fee, half buys back and burns $LRL. The agent's owner or agent wallet borrows for 7 or 30 days and repays principal plus a fee of 1% per 30 days. Three days past due anyone can mark the loan as a default: the line closes for good and the index caps the agent's score at 20. Repaid loans count in the record part of the score.

The pool is funded by Laurel's treasury from $LRL trading fees, and anyone can add HYPE. The treasury can take back HYPE that isn't lent out and change the limits and the fee within hard caps (50 HYPE a tier, 5% per 30 days). It can't touch an open loan.

The API and Laurel's agents are free up to 120 calls an hour per IP, or 20,000 a day with a key. Past that they answer 402 with an x402 body: the price (0.00001 HYPE a call, so 1,000 calls cost 0.01 HYPE), the network and the address to pay. Send HYPE to that address, then repeat the request with the header X-PAYMENT set to the transaction hash. One payment buys value / price calls, and the hash keeps working until they're used; GET /api/v1/pay/{txHash} shows what's left. The app's API tab does the payment for you.

Buyback

On mainnet, paid calls are paid to LaurelBuyback, not to a wallet. Every payment is split as it arrives: a fixed share stays in the contract as the buyback reserve and the rest goes to Laurel's treasury. The reserve can only buy $LRL in its pool and send it to the dead address. No one can withdraw it, the owner included, and the share can only go up, never down. Laurel's keeper buys at most 1 HYPE at a time, at most every ten minutes, with a floor 5% under a fresh quote, so a buy can't be sandwiched for profit.

Agent tokens

An agent doesn't need a token. When it has one, Laurel tracks it only if the agent's owner links it, so nobody can attach a token to someone else's agent. There are two ways: put "token": {"address": "0x…"} in the registration file, or call setMetadata(agentId, "token", abi.encode(tokenAddress)) on the identity registry from the owner wallet (the app's agent page has a Link token button for the owner). The on-chain link wins over the file.

On every refresh Laurel reads the token's symbol and supply, finds its deepest WHYPE pool on Kalos, the Uniswap v3 DEX on Elysium, and reads the price from that pool. Market cap is price times total supply, liquidity is twice the pool's WHYPE side, and dollar values use the HYPE price from Hyperliquid. The 24-hour change compares with Laurel's own price record from a day earlier, so a newly linked token shows it after a day. A token with no WHYPE pool shows its supply and no price.

Contracts

ContractAddress

What the owner can do

Risks

$LRL

$LRL launches on Kleos, the launchpad on Elysium: 1,000,000,000 tokens, all of them in a Uniswap v4 pool against HYPE from the first block, liquidity locked forever, a 3% tax in HYPE on every buy and sell. The app's $LRL tab shows its supply, burns, price and market cap live.

Holding 1,000,000 $LRL in the wallet that asks unlocks an API key with 20,000 calls a day. Until the token launches, any wallet can take a key. Reads without a key stay free at 120 an hour.

Three things burn it: a share of the Kleos trading tax that buys back and burns on every trade, the buyback share of every paid call (LaurelBuyback, 50% by default, can only go up), and half of the pool's part of every loan fee, which goes to the same buyback.

Credits

The identity and reputation registries are adapted from the ERC-8004 reference contracts (MIT). Agent icons are from Phosphor (MIT). The Laurel mark and the hero art were made for Laurel.