Verify Vera yourself
Recover the signer of any recorded plan and check it against the live agentSigner().
You can prove Vera authored a plan’s risk assessment without trusting Monvera. Read agentSigner() live from the VeraRecord contract, fetch the signed RiskInference payload, ECDSA-recover its signer, and assert the two match. Then confirm the same planId appears in an on-chain RecommendationCommitted log. Every value below is on-chain or on a public endpoint.
This proves authorship, not performance. It says Vera’s key signed that exact risk call before the trade, nothing about whether the plan makes money. What she signs versus what the user signs is covered in accountable AI.
Vera’s two identities
Section titled “Vera’s two identities”| Identity | Chain | Registry | Agent id | Role |
|---|---|---|---|---|
| Canonical ERC-8004 | Base (8453) | 0x8004a169fb4a3325136eb29fa0ceb6d2e539a432 |
58228 |
Portable identity, registered via Virtuals ACP |
| Monvera IdentityRegistry | Robinhood Chain (4663) | 0x751ae640cfa816404b017fbb8234dd21abafbbdc |
1 |
The agent id recorded with every plan on 4663 |
The signature you recover on this page is checked against agentSigner() on VeraRecord, chain 4663. The Base entry is declared in registrations[0] of her agent card and is the one the card labels canonical; do not label the 4663 registry canonical unless the published card changes.
The agent card
Section titled “The agent card”GET /.well-known/agent-card.json is Vera’s discovery document, cached s-maxage=3600. It is a custom shape, not the generic A2A schema.
curl https://monvera.best/.well-known/agent-card.jsonconst card = await fetch( 'https://monvera.best/.well-known/agent-card.json',).then((r) => r.json());Top-level fields, in order:
| Field | Type or value | What it holds |
|---|---|---|
name |
"Vera" |
The agent name |
description |
string | Human-readable summary |
image |
"https://monvera.best/icon-512.png" |
Avatar |
active |
true |
Whether the agent is live |
persona |
{ role, blurb } |
Role and blurb |
services |
{ web: { url } } |
The web app URL |
endpoints |
{ app, agent, strategies } |
App, agent-card, and strategies URLs |
supportedTrust |
["reputation"] |
The trust model Vera declares |
skills |
5 slugs | portfolio-allocation, plain-language-allocation, dca-autopilot, trading-strategy, risk-management |
domains |
["finance","investing","real-world-assets"] |
Subject domains |
x402 |
false |
No x402 payment gating on this deployment |
registrations |
array | On-chain identity registrations |
metadata |
object | Chain, contracts, and the current signer |
metadata carries what you need to verify a record on 4663:
{ "version": "2.3", "chain": "robinhood-chain", "chainId": 4663, "app": "https://monvera.best/app", "explorer": "https://robinhoodchain.blockscout.com", "identityRegistry": "0x751ae640cfa816404b017fbb8234dd21abafbbdc", "agentId": 1, "agentSigner": "0xe532105523d4eD559c3a53E3E82D616bE1a085c5"}The struct she signs
Section titled “The struct she signs”Vera signs an EIP-712 RiskInference typed message. The type and domain are fixed by the deployed contract:
keccak256("RiskInference(bytes32 planId,uint16 assessedRisk,uint16 maxRisk,uint256 expiry)")Fields in order: bytes32 planId, uint16 assessedRisk, uint16 maxRisk, uint256 expiry. The domain:
{ "name": "VeraRecord", "version": "1", "chainId": 4663, "verifyingContract": "0x7ff1a5ee19330c165146488a7ad8af6cb41da1df"}VeraRecord.record(...) recovers the signer of this payload on-chain and reverts if anything is wrong, so a plan cannot be recorded with a forged or stale assessment, and the same planId cannot be recorded twice. The record lands in the same transaction as the buys, which is what makes the track record uneditable after the fact. The revert order is in conventions.
Recover the signer
Section titled “Recover the signer”-
Read
agentSigner()live.import {createPublicClient,http,parseAbiItem,recoverTypedDataAddress,} from 'viem';const VERA_RECORD = '0x7ff1a5ee19330c165146488a7ad8af6cb41da1df';const client = createPublicClient({transport: http('https://rpc.mainnet.chain.robinhood.com'),});const agentSigner = await client.readContract({address: VERA_RECORD,abi: [parseAbiItem('function agentSigner() view returns (address)')],functionName: 'agentSigner',}); -
Fetch the signed payload and signature.
GET /api/vera-record?user=<address>returns each recorded plan with itsRiskInferencefields and Vera’s signature. It is a public read.Terminal window ACCOUNT=0xYourAccountAddresscurl "https://monvera.best/api/vera-record?user=$ACCOUNT"const res = await fetch(`https://monvera.best/api/vera-record?user=${account}`,).then((r) => r.json());const record = res.records[0];const { planId, assessedRisk, maxRisk, expiry, signature } = record; -
Confirm the plan is on-chain. Pull
RecommendationCommittedlogs from the deploy block. Public RPC capseth_getLogsat 10,000 blocks, so scan in chunks of 9,999.const event = parseAbiItem('event RecommendationCommitted(bytes32 indexed planId, address indexed user, bytes32 recHash, uint16 riskScore, uint256 agentId)',);const DEPLOY_BLOCK = 2429508n;const STEP = 9999n;const latest = await client.getBlockNumber();let logs = [];for (let from = DEPLOY_BLOCK; from <= latest; from += STEP + 1n) {const to = from + STEP > latest ? latest : from + STEP;logs = logs.concat(await client.getLogs({ address: VERA_RECORD, event, fromBlock: from, toBlock: to }),);}const onChain = logs.find((l) => l.args.planId === planId);// onChain.args.riskScore equals assessedRisk; onChain.args.agentId is 1n -
Recover and assert.
const recovered = await recoverTypedDataAddress({domain: {name: 'VeraRecord',version: '1',chainId: 4663,verifyingContract: VERA_RECORD,},types: {RiskInference: [{ name: 'planId', type: 'bytes32' },{ name: 'assessedRisk', type: 'uint16' },{ name: 'maxRisk', type: 'uint16' },{ name: 'expiry', type: 'uint256' },],},primaryType: 'RiskInference',message: { planId, assessedRisk, maxRisk, expiry: BigInt(expiry) },signature,});const authored = recovered.toLowerCase() === agentSigner.toLowerCase();// true means Vera's agentSigner authored this exact risk assessment
When authored is true and the same planId appears in a RecommendationCommitted log, you have confirmed two things without trusting anyone: Vera’s signer authored that risk assessment, and it was recorded in the transaction that ran the trades. Browse the same records for any address on Blockscout at 0x7ff1a5ee19330c165146488a7ad8af6cb41da1df.
Reputation reads zero for now
Section titled “Reputation reads zero for now”reputationScore(agentId) on the IdentityRegistry returns 0 until feedback is written — the score is owner-updated through feedback, not computed live. Do not read a nonzero score as proof of anything yet.
const IDENTITY_REGISTRY = '0x751ae640cfa816404b017fbb8234dd21abafbbdc';
const score = await client.readContract({ address: IDENTITY_REGISTRY, abi: [parseAbiItem('function reputationScore(uint256 agentId) view returns (uint256)')], functionName: 'reputationScore', args: [1n],});// 0n until feedback is written for agent #1/api/vera-record returns that same live score alongside the recovered signer, the agent id, and Vera’s recent recommendations, so you do not have to reassemble history from log chunks yourself. Its full response shape is at /api/vera-record.
© 2026 Aibora · Documentation interface. Original Monvera materials retain their upstream attribution andMIT license.