Last updated 2026-05-05
Submit feedback for an ERC-8004 agent
One transaction. Call giveFeedback on the Reputation Registry with the agent’s tokenId, a primary tag, a score-like value, and optional evidence URI/hash fields. The sending wallet becomes the clientAddress on the event. Confirmed in a block, shows up on the explorer within seconds. See Reputation Registry deep-dive for how that record factors into the score.
Prerequisites
New to ERC-8004? Start with Read onchain with viem first; it sets up the TypeScript client and project structure used across all tutorials.
- An RPC endpoint on the chain where the agent lives. This tutorial targets Base; the Reputation Registry address is identical on every supported chain. (Get one →)
- An Ethereum wallet with enough native token to cover gas
- The agent’s
(network, tokenId)pair, from any agent’s detail page under/agents/:network/:id
The RPC connects to the chain. The wallet signs and sends the transaction, and msg.sender becomes the clientAddress on the feedback record. The tokenId is how the contract routes the feedback to the right agent.
The feedback record
giveFeedback takes eight arguments:
agentId(uint256): the agent’s token identifier from the Identity Registryvalue(int128) andvalueDecimals(uint8): the numeric value and decimal scale. For a 0-100 score, pass85and0.tag1(string): the primary rating dimension, such asquality,safety,cost,speed, oraccuracytag2(string, optional): a secondary label if your workflow needs oneendpoint(string, optional): the service endpoint or interaction surface being ratedfeedbackURI(string, optional): URI for a longer rationale; use an IPFS URI if you want it to outlast your serverfeedbackHash(bytes32, optional): content hash for the off-chain evidence, or0x00...00if you have no evidence document
The contract stores tags as strings and indexes tag1 as a hashed topic for efficient filtering. The ones this explorer tracks are quality, safety, cost, speed, and accuracy; each maps to a per-tag sub-score on the agent’s detail page. Use a conventional tag and your score gets rolled into the cross-client aggregate. Use a custom tag and the explorer surfaces it, but nobody else’s feedback matches until other clients adopt the same label.
Code: TypeScript + viem
npm install viem@^2.21.0
// src/submit-feedback.ts
// ABI derived from the ERC-8004 reference contracts:
// https://github.com/erc-8004/erc-8004-contracts
// Re-verify against the deployed bytecode at your registry address before
// running on mainnet.
import {
createWalletClient,
createPublicClient,
http,
parseAbi,
zeroHash,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
chain: base,
transport: http(process.env.QUICKNODE_RPC_URL!), // https://example.quiknode.pro/YOUR_KEY/
});
const publicClient = createPublicClient({
chain: base,
transport: http(process.env.QUICKNODE_RPC_URL!),
});
// Mainnet address. Testnet deployments may differ (e.g. Base Sepolia: 0x8004B663056A597Dffe9eCcC1965A193B7388713).
// Confirm at /docs/contracts before running.
const REPUTATION_REGISTRY = "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63";
const abi = parseAbi([
"function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)",
]);
// Target agent: find the tokenId by searching the agents index at /agents, then reading the number from the URL (e.g. /agents/base/42 means tokenId 42).
const agentId = 42n;
// value=85 and valueDecimals=0 means "85 / 10^0", a score of 85 out of 100.
async function main() {
const hash = await walletClient.writeContract({
address: REPUTATION_REGISTRY,
abi,
functionName: "giveFeedback",
args: [
agentId,
85n,
0,
"quality",
"",
"https://researcher.example.com/api",
"ipfs://YOUR_FEEDBACK_REPORT_CID",
zeroHash,
],
});
console.log("feedback tx:", hash); // e.g. 0xabc...
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") {
throw new Error("feedback transaction reverted");
}
console.log("confirmed in block", receipt.blockNumber);
// Decode the NewFeedback event to get your feedbackIndex (needed to revoke later).
const { parseEventLogs, parseAbiItem } = await import("viem");
const feedbackEvent = parseAbiItem(
"event NewFeedback(uint256 indexed agentId, address indexed clientAddress, uint64 feedbackIndex, int128 value, uint8 valueDecimals, string indexed indexedTag1, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)"
);
const [decoded] = parseEventLogs({ abi: [feedbackEvent], logs: receipt.logs, eventName: "NewFeedback" });
if (decoded) console.log("feedbackIndex =", decoded.args.feedbackIndex);
}
main();
When the transaction lands, the contract emits NewFeedback with the agentId, clientAddress, feedbackIndex, value, valueDecimals, tag1, tag2, endpoint, feedbackURI, and feedbackHash. To hook a dashboard update on confirmation, listen for NewFeedback filtered by agentId using publicClient.getLogs or publicClient.watchContractEvent. The viem docs cover the watch pattern.
On tag encoding: the contract stores tag1 as a string and Solidity places keccak256(tag1) in the indexed topic. If you use viem’s ABI event parser, pass the human-readable tag string in filters and let viem handle the topic encoding. Check the ABI at your target address before running on mainnet; non-canonical deployments may differ.
Verify
After the transaction confirms, open /agents/:network/:tokenId for the agent. The feedback row shows up within one block: about two seconds on Base, around twelve on Ethereum mainnet. Each row shows client address, tag, value, timestamp, endpoint, and feedback URI where provided. The reputation score refreshes on the next indexer pass, which tracks block cadence.
To find any agent, search the agents index by name or address, or build the URL directly from the network slug and tokenId.
Revoke a feedback you submitted
The original submitter can retract. You reference the record by feedbackIndex: the per-client index emitted in the original NewFeedback event.
// src/revoke-feedback.ts
const revokeAbi = parseAbi([
"function revokeFeedback(uint256 agentId, uint64 feedbackIndex)",
]);
async function main() {
const revokeHash = await walletClient.writeContract({
address: REPUTATION_REGISTRY,
abi: revokeAbi,
functionName: "revokeFeedback",
args: [agentId, 0n], // replace 0n with the feedbackIndex logged by giveFeedback
});
console.log("revoke tx:", revokeHash);
}
main();
Revoking drops the record from the feedback sub-score numerator and from the unique-clients count. The history stays. The revocation itself is a public event, and indexers count it toward the reliability sub-score. An agent with heavy revocation churn looks less reliable, not just cleaned up. Formula details at /learn/registries/reputation.
Run it
PRIVATE_KEY=0x... QUICKNODE_RPC_URL=https://... npx tsx src/submit-feedback.ts
The script logs the transaction hash, confirms the block, and prints the feedbackIndex you’ll need if you ever want to revoke.
Common errors
self feedback rejected: reference deployments reject feedback from the agent owner or an approved operator. Connect a different wallet.agent not found: wrongtokenId, or the wrong chain. Confirm both from the agent’s URL on this explorer.wrong feedbackIndex: revocation keys off the per-clientfeedbackIndex, not the global log index. Pull it from the originalNewFeedbackevent.out-of-range value: the contract can carry arbitraryint128values, but this explorer only aggregates non-revoked score-like rows whose normalized value is in[0, 100].
Next steps
- What is ERC-8004?: the standard, end to end
- Become a validator: the heavier-weight reputation primitive
- Reputation Registry deep-dive: how scores are calculated
- Browse live feedback: see what other clients are submitting
- viem docs: https://viem.sh
- The canonical EIP: https://eips.ethereum.org/EIPS/eip-8004
FAQ
Can I submit feedback for myself?
Reference deployments reject feedback from the agent owner or an approved operator. Even where a non-canonical deployment allows it, onchain self-feedback is publicly visible and easy to detect, so it does not improve an agent’s score in any aggregator that tracks unique clients.
How are tags chosen?
Tags are free-form strings. Conventional tags this explorer recognizes are quality, safety, cost, speed, and accuracy. Other tags work too; the explorer surfaces all tags an agent has received feedback under. Pick a tag that matches what you actually evaluated; the more specific the better.
Can I edit feedback I already submitted?
Not directly. The Reputation Registry supports revoking a feedback record (which removes it from the score) and submitting a new one. Edit-as-revoke-plus-resubmit is the pattern.
Does this cost gas?
Yes. Submitting feedback is an onchain transaction, so it consumes gas in the chain’s native token. Mainnet is the most expensive; L2s like Base and Mantle are dramatically cheaper.
Can the agent owner block feedback?
No. There is no allowlist or block mechanism in the Reputation Registry. Any address can submit a signed feedback event for any registered agent.