Reputation that follows you, backed by proof.
Portable, cryptographically proven on-chain credit history — derived from real Ethereum mainnet lending activity via the Attestcoin Protocol — used to unlock collateral efficiency in a Creditcoin lending market.
Built for BUIDL CTC 2026 Fall · Track: DeFi Deployed and verified on Creditcoin CC3 Testnet (chainId
102031)
DeFi today demands 150–200% over-collateralization from everyone. A borrower who has repaid 40 Aave loans over two years is treated exactly like a wallet created five minutes ago.
Reputation has no economic value — not because it doesn't exist, but because that history is locked on another chain and can't be proven where you're standing.
Corolary proves that history cryptographically, then prices it.
Borrower repays a loan on Aave V3 (Ethereum mainnet)
↓ real event, real transaction
Attestcoin Protocol — decentralized attestors reach consensus on the block
↓ Merkle proof + continuity proof
FactRegistry on Creditcoin — synchronous verification via precompile 0x0FD2
↓ permanent fact, auditable by anyone
CreditGraph — score 0..1000, every component points to specific evidence
↓
EfficiencyMarket — collateral ratio 150% → 110%
We are not selling uncollateralized lending. Every loan stays over-collateralized. Borrowers with proven reputation simply lock far less capital. The protocol remains solvent without identity and without legal recourse — and that is what separates Corolary from earlier on-chain credit-scoring attempts that never reached adoption.
Attestcoin is not bolted onto this project — it is the product.
| Usage | Detail |
|---|---|
| Core data source | Every credit fact originates from an Ethereum mainnet transaction proven through the Block Prover Precompile 0x…0FD2 |
| Price oracle | Collateral prices are proven from Chainlink AnswerUpdated events on Ethereum — zero centralized oracles anywhere in the system |
| Eager proving | Proofs are bought inside the <24h window (2.59×10⁻⁵ CTC vs 3.13×10⁻⁴ lazy — ~12× cheaper) and the resulting fact is stored permanently |
| Batch proving | Up to 10 transactions share one continuity proof; measured 4,198,654 gas for a batch of 10 against ~13.1M for ten singles (~3× cheaper) |
| Selective extraction | SDK QueryBuilder for partial decoding instead of decoding whole receipts |
| ChainInfo registry | Precompile 0x…0fd3 to track attestation status before attempting a proof |
A ZK-coprocessor answers a query and charges per read. Corolary pays for a proof once, then the fact is readable for free, forever, by any Creditcoin dApp. Cost scales with the number of facts, not the number of reads.
That turns Attestcoin from a per-query oracle into a persistent proven-data layer.
FactRegistry is deliberately built as infrastructure: the scoring and market layers on
top of it are consumers, not owners.
- Watcher follows
Borrow/Repay/LiquidationCall/Supply/Withdraw/SupplyCollateral/WithdrawCollateral/AbsorbDebton Ethereum mainnet. - Attestation wait — the system waits for the containing block to be attested (~38 blocks, ≈8 minutes), checked via ChainInfo, instead of guessing.
- Eager proving — as soon as it is attested, proofs are bought while still inside the cheap window, batched up to 10 transactions within a ≤999-block span.
- On-chain verification —
FactRegistry.recordFactcalls the precompile synchronously, then applies the gates below before anything is stored. - Permanent facts — replay-protected by a
queryIdderived from(chainKey, blockHeight, txIndex, logIndex).
| Gate | Why it exists |
|---|---|
| Proof verification | The precompile proves inclusion in a block |
receiptStatus == 1 |
Inclusion is not success. Without this check, an Ethereum transaction that reverted still produces a fact and poisons the registry. The precompile does not check this for you. |
| Emitter → adapter | Proving "a log exists in this transaction" is not "this log is from Aave". The adapter is selected by the emitting address, so a mismatched adapter cannot even be expressed. A copycat contract emitting fake Aave events has no registered adapter and is skipped. |
subject != 0 |
A zero subject means a broken adapter. Stored facts use subject != 0 as the existence marker, so a zero-subject fact would be written yet read back as absent — then silently overwritten. Hard failure instead. |
| Batch is all-or-nothing | Verified against the live precompile: corrupting one byte of one member's encodedTx in a batch of 7 reverts the entire batch with Error("Merkle proof validation failed"). No member is ever silently skipped. |
The hackathon requires deploying on testnet. We refused to use fake data. Those look contradictory — they aren't.
Creditcoin CC3 Testnet supports Ethereum Mainnet as a source chain
(chainKey = 3, verified directly against the precompile). Corolary runs on testnet as
required, while consuming genuine Aave V3, SparkLend, Morpho Blue, Compound V3 and
Chainlink events from Ethereum mainnet.
We state the exception up front rather than waiting to be asked: CC3 Testnet has no real USDC or WETH to lend, so the demo market uses testnet ERC20s.
| Layer | Source | Real? |
|---|---|---|
| Credit facts (Aave V3, SparkLend, Morpho Blue, Compound V3) | Ethereum mainnet, cryptographically proven via Attestcoin | Yes |
Prices (Chainlink AnswerUpdated) |
Ethereum mainnet, cryptographically proven | Yes |
| Scores and collateral tiers | Derived on-chain from the facts above | Yes |
Tokens lent in EfficiencyMarket |
Testnet ERC20 (tUSDC, tWETH) |
No — unavoidable |
The market tokens are testnet tokens. The credit history, the prices, and the scores come from real Ethereum mainnet.
The distinction matters: a testnet token is a container, not data. tUSDC is
even priced using genuinely proven mainnet USDC, through PriceRegistry.setPriceAlias —
the token is a stand-in, the price is not. What this project forbids is invented numbers,
and there are none.
All contracts are verified on Blockscout — source is readable, not just bytecode.
Network: Creditcoin CC3 Testnet · chainId 102031 (0x18e8f)
RPC: https://rpc.cc3-testnet.creditcoin.network
Explorer: https://creditcoin-testnet.blockscout.com
| Contract | Address |
|---|---|
FactRegistry |
0xF7283aDefb2801db75160A49dA2F7E5e8fDc36c5 |
PriceRegistry |
0x1fC6c2CFB9e339012B70D45977737B9e411efdc9 |
CreditGraph |
0x896E283FB7213650f2C65c239168fEd89F57e952 |
EfficiencyMarket |
0xd97657E361928298A342D8e5049b7aD440b167d4 |
Each adapter decodes one mainnet protocol's events and is bound to that protocol's mainnet address.
| Adapter | Decodes (Ethereum mainnet) | Address |
|---|---|---|
AaveV3Adapter |
Aave V3 Pool 0x8787…4fA4E2 |
0x3175390d1c019E043CEB7a31D22C8eFE334f2EFB |
SparkAdapter |
SparkLend Pool 0xC13e…BE987 |
0x87601b6aB6c4B0eDd5556DdBAeDda6eb7EE243b5 |
MorphoBlueAdapter |
Morpho Blue 0xBBBB…EFFCb |
0x0f13a8A29251a0B62F5cd9e547f19F8Ccf938b27 |
CompoundV3Adapter |
Compound V3 Comet 0xc3d6…4cdc3 |
0xA841835736aA0a4F1ce8EEb45538583fb74A8192 |
| Token | Address |
|---|---|
tUSDC (6 decimals, open faucet) |
0x66f5F2C577ec38CE5bb7BCb7054a531a72004d19 |
tWETH (18 decimals, open faucet) |
0x886E3d92314c037206bB789Ee3A9016EE67b661E |
Read from the live registry on 2026-08-26. Every number below is verifiable on-chain by anyone.
| Facts recorded from Ethereum mainnet | 5,123 |
| Distinct wallets with proven history | 1,206 |
| Mainnet protocols indexed | 4 |
0x94963B928498bE7f06637C3D57ea1E74D7f73423 — score 813 · tier 4 · 110% collateral
ratio, down from the 150% baseline.
| Component | Points | Max | Backed by |
|---|---|---|---|
| Repayment volume | 297 | 300 | 72 facts |
| Repayment count | 171 | 200 | 72 facts |
| History duration | 95 | 200 | first proven fact |
| Liquidation penalty | 0 | −300 | no liquidations |
| Protocol diversity | 50 | 100 | 2 of 4 protocols |
| Active standing | 200 | 200 | 130 facts |
Every component points back to specific facts, and every fact points back to a specific Ethereum mainnet transaction. Nothing here is a black box — which is precisely the failure mode of previous on-chain credit scores.
Deterministic and fully on-chain. No off-chain model, no proprietary weights.
| Component | Max | Shape |
|---|---|---|
| Repayment volume | 300 | half-saturating at $50,000 |
| Repayment count | 200 | half-saturating at 12 repayments |
| History duration | 200 | half-saturating at 365 days |
| Protocol diversity | 100 | linear, 25 points per protocol |
| Active standing | 200 | recency-weighted over a 365-day lookback |
| Liquidation penalty | −300 | severity-weighted, capped |
| Score | Tier | Required collateral |
|---|---|---|
| ≥ 800 | 4 | 110% |
| ≥ 600 | 3 | 120% |
| ≥ 400 | 2 | 130% |
| ≥ 200 | 1 | 140% |
| < 200 | 0 | 150% (baseline) |
The ratio is locked at borrow time. A later score drop cannot retroactively make a healthy position liquidatable — it only applies to new borrows.
packages/contracts/ Solidity — FactRegistry, CreditGraph, EfficiencyMarket, adapters
packages/shared/ TypeScript types + ABIs (the contract between developers)
services/indexer/ Eager-proving worker (watcher → attestation → prover → submitter)
services/api/ REST API (Hono)
apps/web/ Frontend (Next.js) — separate workstream, lands before submission
Three layers: FactRegistry (infrastructure — usable by any other Creditcoin dApp) → CreditGraph (scoring) → EfficiencyMarket (the market).
The indexer is a single process on purpose. Its queue is Postgres, not Redis or Kafka: at this scale one process removes cross-process coordination and, more importantly, makes the submitter the only writer of the submitter key — so nonce management needs no distributed lock.
Requires Node 24, pnpm, Docker, and Foundry.
pnpm install
docker compose up -d # local Postgres
cp .env.example .env # then fill in the values below
pnpm db:migrate
pnpm dev:indexer # watcher → prover → submitter
pnpm dev:api # http://localhost:8080ETHEREUM_RPC_URL must satisfy two separate requirements: archive-capable and
able to serve eth_getLogs over wide block ranges. Verified working: https://eth.drpc.org
(no signup). Alchemy's free tier is archive-capable but caps eth_getLogs at 10 blocks,
which makes the indexer's chunking impossible.
Contracts and quality gates:
forge build && forge test -vvv # 128 Solidity tests
pnpm typecheck
pnpm test # 183 tests total across all packages
pnpm check:no-mocks # the zero-mock-data gatecheck:no-mocks is a real gate, not a slogan. It fails the build on seed data,
hardcoded figures, and non-functional UI affordances. Development fixtures are confined
to a single file behind NEXT_PUBLIC_USE_FIXTURES, which defaults to false.
Live: https://corolary-production.up.railway.app
curl https://corolary-production.up.railway.app/v1/score/0x94963B928498bE7f06637C3D57ea1E74D7f73423Base path: /v1. Every response — success or failure — uses the same envelope.
| Method | Path | Returns |
|---|---|---|
GET |
/health |
Liveness and version |
GET |
/chains |
Source chain and attestation status |
GET |
/indexer/status |
Cursors, lag, queue depth |
GET |
/facts |
Proven facts, cursor-paginated |
GET |
/facts/:factId |
One fact with its proof reference |
GET |
/score/:address |
Current score with per-component evidence |
GET |
/score/:address/history |
Score over time |
GET |
/market/summary |
TVL, utilization, average ratio |
GET |
/market/reserves |
Assets and market parameters |
GET |
/market/positions/:address |
Collateral, debt, health factor |
GET |
/prices |
Latest proven price per asset |
POST |
/prove |
Queue an eager proof for one transaction |
POST |
/backfill |
Scan a wallet's mainnet history ("claim your history") |
POST endpoints queue work for the indexer and return 202. The API never calls the
prover or signs a transaction itself — the submitter must remain the only writer of the
submitter key.
| Role | Scope |
|---|---|
| Dev A | Smart contracts, indexer, API, infrastructure |
| Dev B | Frontend, design, wallet integration |
The docs/ directory holds internal working documents — design records, measured
findings, open questions, and decisions taken during the build. They are written for the
team, in Indonesian, and are excluded from the submitted repository.
This README is therefore self-contained: everything needed to understand, verify, and run Corolary is here, and every claim in it is checkable against a verified contract, a Blockscout page, or a command you can run.
MIT