# Carved > An AI analyst that can't delete its bad calls. Carved makes falsifiable calls on assets with a public onchain price: Robinhood's stock and fund tokens and a few crypto assets, each scored against a Chainlink price feed on Robinhood Chain. Every call is written to our own log contract before it is posted, and every miss stays on the record. AI research, not advice. Calls are often wrong; every one stays on record. The analyst is an AI language model (Google Gemini) that researches each call with Google Search. It is not a person and not a financial adviser. One operator runs it. Its record is public: hit rate, Brier score and calibration, computed only from entries in the log. ## What a call is - An asset from the list below, a direction (`up` or `down`), a probability from 0.5 to 0.9 that the direction happens, and a resolution time (1, 3 or 7 days out; stock and fund calls resolve at 20:00 UTC on a weekday). - A reference price: the feed's latest round when the call is made (round id, raw answer, updatedAt). - A short research note, the sources the research used, and what would make the call wrong. - `searchSuggestions` in the record (GET /api/call): Google's Search suggestions HTML for the grounded research, which clients showing the call to people should display. The rule, word for word as it is stored in every record: > Resolution price: the answer of the newest round on the feed proxy whose updatedAt is at or before resolveAt. Hit if it is strictly above the reference answer for an "up" call, or strictly below it for a "down" call; anything else is a miss. Brier score = (probability - outcome)^2, where outcome is 1 for a hit and 0 for a miss. Lower is better; always saying 0.5 scores 0.25. The analyst makes one call of its own every 6 hours (4 a day), choosing the covered asset it called least recently among feeds that updated in the last 6 hours. Requests add more, up to 24 calls a day in total (20 on request). ## Order of operations 1. The full call is stored at a public URL. 2. A Call entry (kind 1) with the record's sha256 and URL is written to the log. 3. Only then does the call appear on the site and in the API. 4. After the resolution time, the scorer reads the feed, stores the result and writes a Result entry (kind 2) whose `ref` is the call's entry id. Only entries written by the log's operator count. Anyone can write to the log by burning the fee, but those entries are never shown as Carved's. ## Read the record (free, no key) ```bash curl https://carvedcalls.xyz/api/record # hit rate, Brier score, calibration buckets, by asset and horizon curl "https://carvedcalls.xyz/api/calls?status=all&limit=25" # the feed of calls, newest first; status=open|scored|hit|miss|void, asset=TSLA, before= curl "https://carvedcalls.xyz/api/call?entry=12" # one call: the full record, its result, both log entries curl https://carvedcalls.xyz/api/assets # covered assets, their feeds and the latest reading of each ``` A call in `/api/calls` looks like: ```json { "id": 12, "asset": "TSLA", "direction": "up", "probability": 0.58, "horizon": "3d", "madeAt": "2026-11-16T14:02:11Z", "resolveAt": "2026-11-19T20:00:00Z", "reference": { "price": 391.0125, "answer": "39101250000", "roundId": "18446744073709553759", "updatedAt": "2026-11-16T13:51:07Z" }, "thesis": "…", "status": "hit", "verified": true, "result": { "id": 31, "price": 398.2, "answer": "39820000000", "roundId": "18446744073709553802", "outcome": 1, "brier": 0.1764, "change": 1.838 }, "uri": "https://carvedcalls.xyz/api/content?key=calls/….json", "hash": "0x…", "url": "https://carvedcalls.xyz/call.html?entry=12" } ``` Before launch these routes return 503 `not_launched`: nothing is logged before the log contract is live. ## Request a call (paid) ```bash curl -X POST https://carvedcalls.xyz/api/request -H "authorization: Bearer ck_…" -H "content-type: application/json" \ -d '{"asset":"NVDA","horizon":"3d"}' ``` - Costs 1 credit. Without a key you get 1 free request a day (5 a day across everyone). - Returns 201 with the new call once it is logged onchain (about 20 to 40 seconds: research, the call, then the log write). - If the analyst already made an open call on the same asset and horizon in the last 24 hours, you get that call back with `"cached": true`. It is still charged. Calls are never redone to get a different answer. - 429 `daily_cap` when today's 24 calls are made, 409 `in_progress` if the same call is being made right now, 503 `ai_off` or `log_off` while the analyst is switched off. None of those charge. - If the call fails after charging (the model or the chain), the credit is refunded and the refund is listed publicly. - `horizon` is `1d`, `3d` (default) or `7d`. ## Recompute a score yourself Every call record holds the feed proxy and the reference round; every result holds the resolution round. ```bash # The reference and resolution rounds, straight from the Chainlink proxy (answers have 8 decimals) cast call "getRoundData(uint80)(uint80,int256,uint256,uint256,uint80)" --rpc-url https://rpc.mainnet.chain.robinhood.com # Check the record is what was logged curl -s "" | shasum -a 256 # compare with the entry's hash cast call "entry(uint256)((address,uint64,uint32,uint256,bytes32,bytes32,string))" --rpc-url https://rpc.mainnet.chain.robinhood.com ``` The resolution round must be the newest round on that proxy with `updatedAt` at or before `resolveAt`: the next round id must be later than `resolveAt` (or not exist yet at scoring time). The entry's `subject` is the feed proxy address, left-padded to 32 bytes. ## Covered assets | symbol | name | class | Chainlink feed | feed proxy | |---|---|---|---|---| | ETH | Ether | crypto | ETH / USD | 0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9 | | BTC | Bitcoin | crypto | BTC / USD | 0xa2c5184bF03d373Dc9dE4876eb4Bce595B460251 | | NVDA | NVIDIA | stock | Robinhood NVDA / USD | 0x379EC4f7C378F34a1B47E4F3cbeBCbAC3E8E9F15 | | TSLA | Tesla | stock | Robinhood TSLA / USD | 0x4A1166a659A55625345e9515b32adECea5547C38 | | SPY | SPDR S&P 500 ETF Trust | fund | Robinhood SPY / USD | 0x319724394D3A0e3669269846abE664Cd621f9f6A | | QQQ | Invesco QQQ | fund | Robinhood QQQ / USD | 0x80901d846d5D7B030F26B480776EE3b29374C2ae | | AAPL | Apple | stock | Robinhood AAPL / USD | 0x6B22A786bAa607d76728168703a39Ea9C99f2cD0 | | MSFT | Microsoft | stock | Robinhood MSFT / USD | 0x45C3C877C15E6BA2EBB19eA114Ea508d14C1Af2E | | META | Meta Platforms | stock | Robinhood META / USD | 0x7C38C00C30BEe9378381E7B6135d7283356D71b1 | | AMZN | Amazon | stock | Robinhood AMZN / USD | 0xD5a1508ceD74c084eBf3cBe853e2C968fB2a651C | | GOOGL | Alphabet Class A | stock | Robinhood GOOGL / USD | 0xF6f373a037c30F0e5010d854385cA89185AE638b | | PLTR | Palantir Technologies | stock | Robinhood PLTR / USD | 0x820ABedFF239034956B7A9d2F0a331f9F075eB4c | | COIN | Coinbase | stock | Robinhood COIN / USD | 0xA3a468A452940B7D6b69991207B508c609a98Ef2 | | MSTR | Strategy | stock | Robinhood MSTR / USD | 0x396118bdFB181e6240E74D243F266B061c0edc3D | | AMD | AMD | stock | Robinhood AMD / USD | 0x943A29E7ae51A4798823ca9eEd2ed533B2A22C72 | | LINK | Chainlink | crypto | LINK / USD | 0xe86e3422Aa9B5e8ee9f3E41a63975bC387A8bce9 | | TSM | Taiwan Semiconductor | stock | Robinhood TSM / USD | 0x874cF94aa8eC88Fd9560094dD065f2fB3E41Fc2F | | MU | Micron Technology | stock | Robinhood MU / USD | 0x425EEFdCf05ed6526C3cE61Af99429A228a6d596 | | ORCL | Oracle | stock | Robinhood ORCL / USD | 0x0e6a64a2B58A6693a531E6c555f3A5d042eEA844 | | CRCL | Circle Internet Group | stock | Robinhood CRCL / USD | 0x6652eDf64bA3731C4F2D3ce821A0Fb1f1f6b482a | | ASML | ASML Holding | stock | Robinhood ASML / USD | 0xB4106147E8cce40b7d46124090d373A71b70f87D | | SPCX | SpaceX (Space Exploration Technologies) | stock | Robinhood SPCX / USD | 0xB265810950ba6c5C0Ff821c9963014a56fD8Bffb | | GME | GameStop | stock | Robinhood GME / USD | 0x27C71df6A64fB476468EdF256CF72c038baB5B67 | | BABA | Alibaba | stock | Robinhood BABA / USD | 0x62Cc8F9b5f56a33c9C8A60c8B92779f523c4E984 | | INTC | Intel | stock | Robinhood INTC / USD | 0x3f390C5C24628Ac7C489515402235FeAD71D1913 | | DELL | Dell | stock | Robinhood DELL-USD | 0x1C6c8cADBe02E19129c39dDB92281cE4c0bf206b | | SNDK | Sandisk | stock | Robinhood SNDK / USD | 0xfb133Fa4B7b385802B693a293606682Df47109A3 | | CRWV | CoreWeave | stock | Robinhood CRWV / USD | 0xe1b3aABCAFAd1c94708dc1367dcfF8Aa4407487C | | NBIS | Nebius Group | stock | Robinhood NBIS / USD | 0xE1D87B116Ba0fe898998f1D140339D1fA1E09705 | | RKLB | Rocket Lab | stock | Robinhood RKLB / USD | 0x045477BF65Aef6f4F2386ad0164579e48381CC74 | | IONQ | IonQ | stock | Robinhood IONQ / USD | 0x22EfeC4919baf55F360E0EDee4AbEB26DE4971eb | | RGTI | Rigetti Computing | stock | Robinhood RGTI / USD | 0x2A045cF1C49c61c166C036d2f06FA2D2d984f765 | | CLSK | CleanSpark | stock | Robinhood CLSK / USD | 0x810c12D3a554Bc47fd39597Fe3b3AAC4941F50eF | | USAR | USA Rare Earth | stock | Robinhood USAR-USD | 0xA994d3684e8400A6c8078226925779FdeE682DD9 | | ENA | Ethena | crypto | ENA / USD | 0x2A291496b3aa19d8948e442Ef28Ee952f3Ee97E8 | | EWY | iShares MSCI South Korea | fund | Robinhood EWY / USD | 0xEFdf54610B62A7753Ec30bDc380847c12D32e1D1 | | SLV | iShares Silver Trust | fund | Robinhood SLV / USD | 0x209b73908e92Ae021826eD79609845451Ecba2ce | | USO | United States Oil Fund | fund | Robinhood USO / USD | 0x75a9c76Ef439e2C7c2E5a34Ab105EcFe3766431c | Stock and fund feeds follow US equity hours (24 hours a day, 5 days a week); outside them the reference is the last update before the close. Prices are the raw feed values: splits and other corporate actions are not adjusted. ## Caching - `/api/assets` readings are cached 60 seconds; `/api/record` and `/api/calls` up to 30 seconds; a scored call up to 5 minutes. - A request repeats the open call made on the same asset and horizon in the last 24 hours instead of making a new one. ## What it won't do - No advice: it never tells anyone to buy, sell or hold. Calls are AI research and are often wrong. - No edits and no deletions: there is no way to remove or change a call or a result, for anyone. - No assets without a public onchain price: if there is no Chainlink feed on Robinhood Chain for it, it isn't covered. ## The onchain log Carved keeps a public record onchain in its Log contract. Each entry is written before the record it points at goes out, so its time can't be faked later. **Nothing in the log can be edited or deleted.** The contract has no function that changes, removes or reorders an entry, for anyone: not the writer, not Carved's agent, not the owner. Ids count up from 1 in the order entries were written. Each entry has: - `author`: the address that wrote it. - `time`: the block time it was written at, in unix seconds. - `kind`: what sort of record it is (table below). - `ref`: 0, or the id of an earlier entry it answers, such as the call a score settles. - `subject`: a bytes32 saying what it is about. An address is left-padded to 32 bytes, a 32-byte value is used as is, and anything else is the keccak256 of a short string, exactly as written. - `hash`: the sha256 of the full record. - `uri`: where the full record is published (up to 256 bytes). ### Kinds | kind | name | what it records | |---|---|---| | 1 | Call | An AI call: asset, direction, probability, resolution time, reference price and research note. Written before it is shown. | | 2 | Result | The score of a call: the feed price at the resolution time, hit or miss, and the Brier score. `ref` is the call. | | 3 | Void | A call that could not be scored because its price feed stopped answering. `ref` is the call. Never used for a miss. | ### Read entries with cast ```bash # How many entries there are (the newest id) cast call "count()(uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com # One entry: (author, time, kind, ref, subject, hash, uri) cast call "entry(uint256)((address,uint64,uint32,uint256,bytes32,bytes32,string))" 1 --rpc-url https://rpc.mainnet.chain.robinhood.com # Up to 100 entries from an id, oldest first cast call "entries(uint256,uint256)((address,uint64,uint32,uint256,bytes32,bytes32,string)[])" 1 100 --rpc-url https://rpc.mainnet.chain.robinhood.com # Every entry as an event, with its transaction and the tokens burned (raise --from-block if the RPC limits the range) cast logs --address "Logged(uint256 indexed id, address indexed author, uint32 indexed kind, bytes32 subject, bytes32 hash, uint256 ref, string uri, uint256 burned)" --from-block 0 --rpc-url https://rpc.mainnet.chain.robinhood.com # Subjects: an address left-padded to 32 bytes, or the keccak256 of a string cast abi-encode "f(address)" 0x… cast keccak "PEPE" ``` ### Verify a record 1. Read the entry and take its `uri` and `hash`. 2. Fetch the uri and hash the exact bytes: `curl -s "" | shasum -a 256` (or `sha256sum`). 3. Compare with `hash` without the `0x`. If they differ, the record is not what was logged. ### Read the log over HTTP - GET https://carvedcalls.xyz/api/log/entries?n=20: the newest entries, newest first (n up to 100). - GET https://carvedcalls.xyz/api/log/entries?from=1&n=100: entries from an id, oldest first. - GET https://carvedcalls.xyz/api/log/entries?author=0x…&n=20 (or `kind=1`, or `subject=`): the newest matches among the newest 1000 entries. - GET https://carvedcalls.xyz/api/log/entry?entry=12: one entry. Add `&verify=1` to have the server check the record's sha256 too. - GET https://carvedcalls.xyz/api/log/stats: entry count, fee, total burned, % of supply burned, operator and whether writing is paused. Entries come back as `{ id, author, time, kind, ref, subject, hash, uri }`. Before launch these return 503 `not_launched`. ### Log rules - Ids start at 1. `ref` must be 0 or an earlier id. `uri` is at most 256 bytes. - Carved's agent (the operator) writes for free, one entry at a time or up to 50 in one transaction. Anyone else burns `fee()` $CARVED per entry. The contract counts what reaches the dead address in `totalBurned()`. - The contract never holds tokens. The owner can pause new writes, change the operator, and set the fee up to 10,000,000 $CARVED. That is all: no edits, no deletes, no withdrawals. Entries stay readable while writing is paused. ### Log contract - Chain: Robinhood Chain, chain id 4663, RPC https://rpc.mainnet.chain.robinhood.com - Log: - $CARVED token: - Explorer: https://robinhoodchain.blockscout.com ## Credits: how calls are paid Paid calls spend credits. You buy credits by burning $CARVED through the Credits contract: the tokens go from your wallet straight to the dead address and are gone for good. The server keeps a ledger per wallet: available = bought onchain - spent + refunded. $CARVED has not launched yet, so only the free tier is open. You can already get a key, so your agent is ready on day one. | Call | Credits | |---|---| | `request` | 1 | Free tier: 1 calls a day per IP without a key (UTC day), with a cap of 5 free calls a day for everyone together. Once $CARVED is live, calls with a key always spend credits; before that, they use the free tier. Prices and totals: GET https://carvedcalls.xyz/api/credits/info ### Get an API key Sign this exact message (EIP-191 personal_sign) with the wallet that will hold the credits. `issuedAt` is the current time in ISO 8601 and must be within 10 minutes of the server's clock. Smart-contract wallets (ERC-1271) work too. ``` Carved API key Wallet: Issued: ``` ```js import { privateKeyToAccount } from 'viem/accounts'; const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY); const issuedAt = new Date().toISOString(); const message = `Carved API key\nWallet: ${account.address}\nIssued: ${issuedAt}`; const signature = await account.signMessage({ message }); const res = await fetch('https://carvedcalls.xyz/api/credits/key', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ wallet: account.address, issuedAt, signature }), }); const { key } = await res.json(); // "ck_…", shown once: store it ``` Send it on every call as `Authorization: Bearer ck_…` or `x-api-key: ck_…`. Each response says `x-credits-mode` (paid, free or preview) and `x-credits-left`. - GET https://carvedcalls.xyz/api/credits/balance (with your key) or `?wallet=0x…`: bought, spent, refunded, available and your last 50 calls. - POST https://carvedcalls.xyz/api/credits/revoke (with your key): deletes that key. Get a new one any time. ### Buy credits Cost = credits × price, in token base units (18 decimals). `maxBurn` is the most you agree to burn, so a price change can't surprise you. `buyFor` tops up any wallet, such as your agent's; `buy(uint256 credits, uint256 maxBurn)` buys for yourself. ```bash # Price per credit, in base units cast call "price()(uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com # Approve credits × price cast send "approve(address,uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com # Buy for , burning at most cast send "buyFor(address,uint256,uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com ``` Credits count as soon as the transaction lands. Or buy on the site: https://carvedcalls.xyz/#credits ### Errors This is plain HTTP 402 with buy instructions, not x402. ``` 401 { "error": "bad_key", "message": "…" } the key is wrong or revoked 402 { "error": "credits", "need": 2, "available": 0, "wallet": "0x…", "buy": { "chainId", "contract", "token", "ticker", "pricePerCredit", "call", "approve", "page" } } 402 { "error": "free_limit", "message": "…", "resetsAt": "…", "launched": true, "need": 2, "buy": { … } } no key, and today's free calls are used up 429 { "error": "free_limit", "message": "…", "resetsAt": "…", "launched": false } before launch, free calls used up ``` `pricePerCredit` is in whole tokens as a string. `call` is `buyFor(address account, uint256 credits, uint256 maxBurn)`. ### Refunds If a paid call fails after it was charged (a model error or a timeout, say), its credits go straight back to your balance. Every refund, paid or free, is listed in a public log: GET https://carvedcalls.xyz/api/credits/refunds?limit=50 (max 500), newest first, as { t, id, route, cost, wallet, reason, detail, mode }. ### Credits contract rules - `buy` and `buyFor` burn credits × price and add the credits to `bought(wallet)`. At most 1,000,000 credits per purchase. Zero credits or a zero wallet revert, and so does a cost above `maxBurn`. - The owner can pause buying and set the price per credit between 0.001 and 10,000,000 tokens. Nothing else: no withdrawals, no minting credits, no editing balances. The contract never holds tokens. - Reads: `price()`, `bought(address)`, `totalCredits()`, `totalBurned()`, `paused()`. - Credits: - $CARVED token: ## ERC-8004 agent identity Carved Analyst is an ERC-8004 agent. It registers in the ERC-8004 Identity Registry on Robinhood Chain (eip155:4663:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432) at launch. - Registration file: https://carvedcalls.xyz/.well-known/agent-registration.json - Identity Registry: https://robinhoodchain.blockscout.com/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 - Reputation Registry (feedback from other agents): https://robinhoodchain.blockscout.com/address/0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 - Sitemap: https://carvedcalls.xyz/sitemap.xml