Inspiration
DeFi lending is stuck at 150%+ collateralization because lenders have no way to evaluate a borrower's creditworthiness without seeing their entire wallet history — every balance, every trade, every liquidation, exposed forever on a public ledger. That's a privacy problem masquerading as a risk-management requirement. Midnight's zero-knowledge circuits let us separate the two: prove the fact ("this borrower clears the bar") without disclosing the data behind it.
What it does
Ghost Credit lets a borrower prove "my credit score is above 700, I've never been liquidated, and my wallet is at least 6 months old" as a zero-knowledge circuit. The lending pool contract verifies the proof on-chain and approves the loan — the score, liquidation history, and account age never touch the public ledger. A lender sees a checkmark and a loan amount. Nothing else.
How we built it
- Contract: a Compact smart contract (
ghost-credit.compact) with two witnesses —localSecretKeyandcreditData— that never leave the borrower's device. Borrower identity on-chain is apersistentHashof a witness-held secret, never a wallet address, and deliberately neverownPublicKey()(which is prover-claimed and unverifiable, so it can't be trusted for access control). - Deploy/test harness: a real local Midnight devnet (node + indexer +
proof server via Docker) with a full deploy-and-exercise test suite —
requestLoan,repayLoan, andgetLoanStatusall verified against actual ZK proofs, not mocks. - Frontend: a two-screen React app (borrower / lender view) wired to a real deployed contract, showing the same request side-by-side with what a normal DeFi dashboard exposes today vs. what Ghost Credit's lender actually sees.
Challenges we ran into
- The Compact compiler's disclosure analysis treats circuit parameters as
potential witness leaks by default — even public loan amounts needed an
explicit
disclose()before touching the ledger. - A duplicate-module-instance bug: having the contract package and the deploy
harness as separate npm packages meant two copies of
compact-jsin the dependency tree, which broke class-identity checks deep in the deploy path with an opaqueCannot read properties of undefined (ctor)error. Fixed by converting to an npm workspace so dependencies dedupe. - DUST (Midnight's fee-generation token) doesn't accrue automatically — NIGHT has to be explicitly registered for DUST generation via its own on-chain transaction, and the wallet's own sync-progress signal for DUST never resolves until after that registration succeeds. That's a chicken-and-egg trap if you naively wait on it.
What's next
- Wire the frontend to a real wallet connection via the Midnight DApp Connector (Lace), so proof generation happens client-side instead of through our dev bridge server.
- Replace the seeded wallet-history fixture with a real Solana/EVM indexer.
- Push past local devnet to a live Preprod deployment.
Built With
- compact
- defi
- docker
- midnight
- node.js
- react
- smart-contracts
- typescript
- vite
- vitest
- zero-knowledge-proofs
- zk-proofs
Log in or sign up for Devpost to join the conversation.