Inspiration
The idea for Credipro came from a simple observation: DeFi lending is broken for creditworthy borrowers. Overcollateralized protocols like Aave and Compound require locking up 150%+ of a loan's value — a borrower with an 820 FICO score and six-figure income still needs to mint \$15,000 in ETH to borrow \$10,000 USDC. Uncollateralized lending barely exists in Web3 because of the Sybil default paradox: on pseudonymous networks, malicious actors can take loans, default, abandon their wallet, and repeat infinitely — with zero real-world accountability.
We wanted to build a system where creditworthiness could be proven without being revealed, where identity could be committed without being exposed, and where default had real consequences through selective, cryptographic identity disclosure — not through trust, but through math.
What it does
Credipro is a privacy-preserving decentralized lending protocol on the Midnight Network that enables undercollateralized loans with ZK-proof credit verification and selective identity reveal upon default.
Borrowers generate a zero-knowledge proof that their credit score meets a pool's threshold — without ever revealing the actual score. Their identity is hashed and committed on-chain but remains encrypted off-chain. If the borrower defaults, a 2-of-3 oracle committee must reach consensus to decrypt and reveal their identity exclusively to the affected underwriter, backed by a signed Master Loan Agreement for legal recourse. The system includes a full Express API with JWT auth, a React frontend with a step-based ZK pipeline UI, and a runtime toggle between demo mode (mock circuits) and production mode (Lace Wallet + on-chain contracts).
How we built it
Smart contracts were written in Compact (Midnight's TypeScript-inspired ZK DSL), implementing two core circuits: requestLoan (underwriting with credit score threshold proofs) and triggerSlashing (default resolution with 2-of-3 oracle consensus). The backend is an Express TypeScript API with SQLite persistence, Poseidon-Goldilocks hashing (hashNoPad), and a three-tier circuit fallback (mock → compiled → on-chain). The prover layer maps each Compact witness declaration to a TypeScript implementation with synchronous compact-runtime wrappers. The oracle system tracks votes in SQLite with duplicate-vote prevention and AES-256-GCM identity encryption. The frontend is a React SPA (CRA + react-app-rewired for Midnight SDK polyfills) with an oracle voting panel, demo/production toggle, and a complete loan lifecycle UI. Everything is containerized with Docker Compose and tested with 54 passing tests (unit + integration + API).
Challenges we ran into
Midnight SDK volatility. Package names and APIs shifted across preview releases — midnight-js-contracts exported different factory functions depending on the build. We built adaptive imports that try multiple patterns and a three-tier fallback so the system never hard-fails. ESM/CJS module hell. The Midnight SDK ships as native ESM but our backend uses CommonJS, requiring fragile dynamic imports via new Function("return import(...)")(). Ledger state seeding. Executing the compiled Compact runtime required programmatically seeding Merkle-like ledger state using low-level queryLedgerState() operations — understanding cell encoding, alignment, and path indexing for pool TVL, risk parameters, and loan records was the single hardest technical challenge. Poseidon alignment. Ensuring hashNoPad in TypeScript produced identical results to persistentHash in Compact required careful 32-byte chunking, field element representation in the Goldilocks field ($p = 2^{64} - 2^{32} + 1$), and padding semantics. The 48-hour constraint. Real zkTLS, MPC threshold decryption, and NFC passport integration were impossible in a hackathon — every production component was mocked but architecturally replaceable.
Accomplishments that we're proud of
- A syntactically valid, structurally complete Compact smart contract with two working circuits and proper Kachina three-context separation (ledger/witness/circuit)
- 54 passing tests covering witness initialization, oracle voting, Sybil attack prevention, privacy preservation, API endpoints with auth, and a complete end-to-end loan-to-slashing lifecycle
- A three-tier circuit execution system (
mock → compiled → onchain) that gracefully degrades and enables development without testnet access - Runtime mode switching — toggling between demo and production without restarting the server
- A compiled contract runtime integration that loads the actual Compact contract, wires up TypeScript witness functions, seeds ledger state, and executes circuits via
@midnight-ntwrk/compact-runtime - Proper cryptographic foundations — Poseidon-Goldilocks hashing for circuit compatibility, AES-256-GCM for identity encryption, scrypt key derivation
What we learned
- Midnight's Kachina protocol enforces a clean separation of concerns: ledger state is public, witness data is private, and circuits prove constraints without revealing inputs. The
disclose()annotation forces deliberate thinking about every byte that becomes public. - Compact is deceptively familiar. It looks like TypeScript but has no loops, uses
persistentHashfor Poseidon hashing, and requires explicit map membership checks (map.member(key)) before lookups. - Zero-knowledge proof systems demand cryptographic discipline. Every hash, every commitment, every alignment choice must match across TypeScript prover and Compact circuit — even a single-byte mismatch breaks proof verification.
- Architectural mocking is an art. The key insight was mocking at the data source layer (credit bureau, passport reader, oracle MPC) while keeping the circuit logic real — the contract has real ZK semantics, the witness layer has real API signatures, and the runtime integration is real.
- Adaptive SDK handling is essential when building on a pre-release platform — try multiple import shapes, build fallback chains, and never let a third-party API change break your entire system.
What's next for Credipro
- zkTLS Integration — Replace mock credit scores with real zkPass or Reclaim Protocol oracles for cryptographic proof of FICO scores and income
- MPC Threshold Decryption — Replace the trusted 2-of-3 oracle committee with BLS threshold signatures for true N-party decentralized identity reveal
- On-Chain Deployment — Deploy the compiled contract to Midnight testnet with live ledger interactions via Lace Wallet
- Real ePassport Integration — Support ICAO 9303-compliant NFC passport chip reading for identity verification
- Zswap Private Transfers — Enable private loan disbursement and repayment via Midnight's native privacy-preserving DEX
- Loan Pool Secondary Market — Allow underwriters to trade loan positions while preserving borrower privacy
Built With
- compact
- docker
- express.js
- jest
- lace-wallet
- midnight-local-proof-server
- midnight-ntwrk/compact-runtime
- midnight-ntwrk/midnight-js-contracts
- node.js
- poseidon-goldilocks
- react-18
- sqlite
- supertest
- typescript
- winston

Log in or sign up for Devpost to join the conversation.