-
-
Double sale blocked: serials 800–1,000 were already retired, so nothing is recorded and the buyer gets a refund.
-
Solus holds the payment and only pays if the serial numbers have never been retired before.
-
Try your own sale: touching ranges are allowed, overlapping ones are rejected.
-
What to trust: the contract, the auditor, and what isn't covered yet.
Inspiration
Imagine selling one concert ticket to two different people. Both tickets look real, but only one person gets in.
Carbon credits can be sold twice in the same way. Each credit is one tonne of CO2 saved and has its own serial number. A buyer gets a certificate listing those numbers, but a seller can later sell some of the same numbers to someone else. INTERPOL describes this as "selling the same carbon credits over and over to multiple parties" (Guide to Carbon Trading Crime, section 4.2). When it happens, one tonne of climate benefit gets claimed twice.
What it does
Solus is an escrow account with a memory.
- The buyer pays into a smart contract. The money is held, and nobody can touch it yet.
- The certificate is read and checked for obvious mistakes.
- The contract looks at the serial numbers already used for that project.
- If none are used, the seller is paid and those numbers are locked forever. If even one is used, nothing is recorded and the buyer gets a full refund.
Our demo shows exactly this. One sale of serials 1 to 1,000 goes through. A second sale of serials 800 to 1,500 is blocked, because 800 to 1,000 were already used, and the buyer is refunded.
What to trust: the contract guarantees a used serial number can never be used again, and nobody can edit that, not even us. A trusted auditor confirms the certificate is real. AI only reads the certificate text, and fixed rules check it.
How we built it
- A Solidity smart contract on Ethereum Sepolia, verified on Blockscout and Sourcify:
0xdd0985a0b634a8e50ff122431f435184ba5259cf. - Ten contract tests, including a fuzz test and a stateful check that retired ranges never overlap, run in a Node EVM harness. Seven more tests cover the ledger logic.
- A live end-to-end script ran the honest sale and the blocked double sale on Sepolia. Seven transactions are confirmed on the explorer.
- A Next.js web app shows the serial numbers as a ledger, with the overlap in red.
- The public site replays that confirmed run and labels it "Replay of a real run". The demo uses saved extractions of sample certificates.
Challenges we ran into
- Checking overlap, not equality. Storing a hash of each certificate only catches an exact resale. Real double counting reuses part of a range, so the contract compares ranges.
- Keeping the demo honest. A shared live demo would have wallets colliding with each other, so the public site replays a real run and says so. The e2e script is the live proof.
- Making every claim checkable. We checked our citations against the original reports and removed things the sources didn't say.
Accomplishments that we're proud of
- A rule that holds on-chain: overlapping serials can't be retired twice, and a blocked sale leaves a permanent event,
DoubleCountDetected. - A refund path for the buyer that is tested and was run live.
- An interface that shows the problem at a glance: used serial numbers in teal, the clashing range in red.
What we learned
- A document check can't catch this. Only a shared record of serial ranges, tied to the payment, can.
- Showing the limits plainly makes a project more believable than hiding them.
What's next for Solus: every tonne counts once
- Check across registries. Today Solus checks the ranges inside the registries it sees, so the same forest registered twice in different registries isn't caught. That needs registries to share their retirements.
- A faster structure for projects with very many retired ranges.
- Registries and auditors plugging in as the trusted attestation role.
Built With
- blockscout
- ethereum
- ethereumjs-vm.
- nextjs
- react
- sepolia
- solc
- solidity
- sourcify
- tailwindcss
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.