-
-
Paste a company's offset claim. On the Climate Action Reserve, 32% of retired credits don't say who they were retired for.
-
GPT-5.5 lists each claim with the document's own words; plain code checks every quote, name and number against the text.
-
Matched to the registry's retirement records: a claim is backed only when the registry's own note names the claimant.
-
A second company citing the same serial numbers: the registry names Microsoft, and the ledger already holds those tonnes.
-
Retired with no note on whose behalf: anyone could claim these tonnes, so Claimcheck won't record the claim on the registry's word.
-
The ledger is read straight from the Soroban contract on Stellar testnet; anyone can re-hash the published evidence.
-
Look up any serial number or range: the registry's retirement, and which ledger claim uses it.
Track
Carbon Markets & Emissions Transparency. Claimcheck is a smart contract that prevents double counting of carbon credit claims, plus blockchain-based verification of each claim against the registry's own records.
Inspiration
A carbon credit is one tonne of CO₂ kept out of the air. When a company uses one, the registry retires it, once. But the claim built on it ("we offset 60,000 tonnes") is just text in a press release or a sustainability report, and nothing stops the same tonnes from backing two claims.
The registry's own data shows how wide that gap is. In the Climate Action Reserve's public report of 11,375 retirements (85.8 million credits), 27.4 million credits (32%) have no note saying who they were retired for, and 21.5 million were retired "on behalf of a third party" that is never named. Any company could claim those tonnes, and two companies could claim the same ones.
What it does
Claimcheck checks a company's offset claim against the registry, then records it once.
- Read. Paste a press release or a report section, or give a link. GPT-5.5 lists each claim: who, how many credits, which project, which serial numbers. Every claim must quote the document word for word, and plain code checks each quote, name and number against the text. Anything the document doesn't say is dropped.
- Match. The claim is matched against the registry's retirement records. It counts as backed only when the registry's own note names the claimant. The account that did the retiring doesn't count, and neither does "a third party". Verdicts: backed, partly backed, registry doesn't say for whom, registry names someone else, not in the registry.
- Record once. A backed claim is written to a Soroban smart contract on Stellar with its exact serial range, the claimant, and the SHA-256 of an evidence bundle (the registry record and the claim's own words). The contract refuses any later claim that shares even one serial number.
- Audit. The ledger page reads every claim straight from the contract and re-hashes the published evidence. Any serial number can be looked up: the registry's retirement, and who claimed it.
In the demo, a real Indigo Ag press release (Microsoft buying 60,000 soil carbon credits) is matched to two retirements on May 27, 2025 "on behalf of Microsoft Corporation" and recorded. A made-up second company citing the same serial numbers is refused.
Who it's for
- Companies buying credits: check that their tonnes were retired in their name, and record the claim so no one else can make it.
- Auditors, journalists and watchdogs: verify a net-zero claim in a minute, from public data.
- Registries and marketplaces: run the same check before issuing a retirement certificate.
- Regulators: California's AB 1305 already requires companies that buy offsets and claim net zero or carbon neutrality to disclose the registry and project behind them. Claimcheck makes that disclosure checkable.
Scale and adoption
- Free to run: a static registry snapshot, one Cloudflare Worker (free plan) and one contract. Recording a claim takes about 25 ms of Worker CPU. Pages read the ledger straight from the chain.
- Cheap to check: the contract keeps each issuance's claimed ranges sorted, so one binary search checks a new range against every earlier claim.
- Any registry with serial numbers: adding one means loading its public retirement report. The serial parser already reads Climate Action Reserve, ACR, Verra and Gold Standard formats.
- Nothing to sign up for: no account, wallet or token is needed to check a claim or audit the ledger. Claimcheck never tokenizes or trades credits; it records claims about credits already retired.
How we built it
- Contract: Rust and soroban-sdk. Claims are stored by issuance as sorted serial ranges;
recordchecks the neighbours of the new range and fails withOverlapif any serial is taken. Only an approved recorder can write. 11 tests, including a randomized check against a simple model. Deployed on Stellar testnet. - Registry data: the Climate Action Reserve's public "Retired Offset Credits" report, cleaned (text encodings, HTML entities) into a compact snapshot and one file per project.
- AI reading: GPT-5.5 through the OpenAI Responses API with a strict JSON schema; readings are cached in Workers KV.
- Checks: plain TypeScript shared by the page and the Worker. Before signing anything, the Worker re-checks the registry record and the name itself; it never takes the page's word for it.
- Front end: React and Vite, set in IBM Plex. Each recorded claim is drawn as a numbered ticket for its serial numbers.
- Tests: Vitest, 32 tests on serial parsing, name matching, quote grounding and matching against the real snapshot.
Challenges we ran into
- Names. "Retired by Cool Effect on behalf of Salesforce" names Salesforce, not Cool Effect. Matching reads only what follows the last "on behalf of", by whole words in order, and is strict on purpose: a loose match would let one organization claim another's retirement.
- Brokers. "HubSpot, which purchased via Watershed": the registry lists Watershed as the account that retired the credits, so a claim has to fit both the project and the broker.
- Free-plan CPU. Recording first took about 75 ms of CPU. Building the Soroban transaction by hand, signing with WebCrypto Ed25519 and letting the page wait for confirmation brought it to about 25 ms.
- The model's wording. The live reading described the project as "the company's fourth and largest carbon crop", which named no project but still had to fit one. Descriptive words now count as generic, with a test from that reading.
Accomplishments that we're proud of
- A real press release goes from text to a recorded, auditable claim in under a minute, and a second claim on the same tonnes is refused by the contract itself.
- The evidence behind every ledger entry can be fetched and re-hashed by anyone.
What we learned
- For most claims the registry already holds the answer. What's missing is one public place that says "these tonnes are taken".
- Make the AI quote its source, then check the quote with code you can read.
What's next
- Verra and Gold Standard snapshots.
- Holder-assigned claims: the account that retired unattributed credits assigns them on the record (the contract already has the basis field for it).
- Mainnet, with registries or auditors as recorders.
Try it: https://claimcheck.mikey9220.workers.dev (press one of the examples) Demo video: https://youtu.be/3ktqykzq4pM Code (MIT): https://github.com/mikey92/claimcheck
Built With
- cloudflare-workers
- openai
- react
- rust
- soroban
- stellar
- typescript
- vite
- vitest
Log in or sign up for Devpost to join the conversation.