Skip to content

Dami904/ShieldPass

 
 

Repository files navigation

ShieldPass Banner

🛡️ ShieldPass

Ultimate Privacy: Trustless Crypto → Fiat Off-Ramp + Private Payments on Stellar

ShieldPass is a private cross-border remittance corridor. It lets anyone swap crypto for Nigerian naira instantly, paid straight to their bank account — without ever exposing their identity or banking data on-chain — and send funds privately to other users, where the amount, sender, and receiver stay hidden.

Your crypto lives in a Shielded Pool, not a standard escrow. You prove ownership and compliance with zero-knowledge proofs generated locally on your device, and the smart contract verifies every proof on-chain using Stellar's native BN254 pairing functions. The chain only ever sees mathematics — never your BVN, name, or bank details.

Built for the Stellar Hacks: ZK hackathon. The ZK proof is load-bearing: no valid proof ⇒ no swap, no transfer, no payout. Verification happens on Soroban itself, not off-chain.

Shielded PoolOn-chain Groth16 (BN254)Private P2P TransfersMulti-Asset (XLM + USDC)Zero-Storage BackendPasskey Smart WalletsGasless

shieldpass.demo.mp4

🧭 The Ultimate Privacy Architecture (Old vs New Way)

Traditional off-ramps force you to upload your identity, trust a custodian with your funds, and publicly broadcast your transactions. ShieldPass eliminates all three — and adds fully private peer-to-peer payments on top.

1. The Shielded Pool (The "Dark Pool")

Shielded Pool Concept

  • Old Way: When you sent money, everyone could see it sitting in an escrow account.
  • New Way: All user funds of a given asset are mixed in one pool. Each balance is a secret note (Poseidon(amount, owner, randomness, …)) owned by your shielded key. Nobody scanning the chain can tell which note is yours. ShieldPass currently runs two live pools — XLM and USDC — each a separate contract instance (same audited wasm/circuits, bound to a different token at init).

2. On-Chain ZK Verification (No Trusted Verifier)

  • Old Way: Proofs were checked off-chain by a backend you had to trust.
  • New Way: The Soroban contract verifies every Groth16 proof itself, on-chain, via the native bn254 pairing-check host function (~37.5M instructions — well within budget). The math is the only authority.

3. Trustless Append-Only Tree (No Trusted Root)

  • Old Way: The pool would have to trust a relayer to publish the correct Merkle root.
  • New Way: A dedicated merkle_insert ZK circuit proves every old_root → new_root transition. The contract verifies each append, so the commitment tree advances trustlessly — no party can forge a root.

4. Private Payments (Hidden Amounts)

  • Old Way: Sending money revealed who, to whom, and how much.
  • New Way: A shielded_transfer proof spends your note and mints one note for the recipient + a change note for you — entirely inside the pool. The amount, sender, and receiver are all hidden; only the recipient learns the amount (from an encrypted blob).

5. Zero-Storage Banking (Hack-Proof Database)

Zero Storage Concept

  • Old Way: We saved your bank account in our database. A breach leaked your banking info.
  • New Way: We don't save your bank account at all. It lives in your browser; at swap time your phone flashes the details to the backend, we pay the bank, and the details are dropped from memory.

6. Trustless Refunds (Math-Enforced Escape Hatch)

Trustless Payout Concept

  • Old Way: If the off-ramp took your crypto but never paid the fiat, your funds were gone.
  • New Way: A withdrawal pre-commits a refund note on-chain. If the naira never settles, after a 1-hour time-lock you reclaim your value trustlessly — the platform can never simply keep the crypto. (A future zkTLS fiat_payout proof will make the claim itself fully trustless; today the claim is admin-gated and the refund is your guarantee.)

🔄 How the App Works (Step-by-Step)

Meet Tobi, who wants to use ShieldPass:

1. Onboard (invisible funding). Tobi signs up with a Passkey (Face ID). His shielded identity (spending + encryption keys) is derived from the passkey itself. ShieldPass mints him a secret note worth 500 XLM — no public transaction happens. To the outside world, his wallet holds $0.

2. Shield / Unshield. Tobi can move his own crypto — XLM or USDCinto the private pool (Shield) or pull it back out to his wallet (Unshield) at any time.

3. Withdraw to Naira. Tobi cashes out 100 XLM. On his phone a ZK proof spends his note, mints a 400 XLM change note, and authorizes the contract. The backend pays his bank via Paystack/Lenco; the change stays private.

4. Send privately. Tobi sends 50 XLM to a friend by email or shp_ address. A shielded_transfer proof moves the value inside the pool — fully private. His friend's app scans, decrypts the note, and their shielded balance just goes up. A 🔔 notification fires.

5. Stay informed. Every action — faucet, shield, unshield, withdraw, send, and received payments — lands in an in-app Activity feed with an unread badge.


🔐 Cryptographic Pipeline

Three Circom/Groth16 circuits over BN254, all verified on-chain:

  1. confidential_swap (browser): proves you own a valid note, derives the spend nullifier, and computes the change. Used by Withdraw and Unshield. swap_amount is public here (real value leaves the pool).
  2. shielded_transfer (browser): spends one note → two output notes (recipient + change). Amounts are private; the recipient's owner tag is bound into the proof. Powers private P2P payments.
  3. merkle_insert (backend): proves each old_root → new_root tree append so the pool's commitment tree advances trustlessly — no on-chain hashing needed.
flowchart LR
    subgraph Device["📱 Your Device"]
        SK["Shielded key (from passkey PRF)"]
        PROOF["confidential_swap / shielded_transfer proof"]
        ENC["x25519 note encryption"]
    end
    subgraph Chain["⛓️ Soroban Shielded Pool"]
        VERIFY["bn254 pairing_check (on-chain Groth16)"]
        TREE["Poseidon commitment tree"]
        NULL["Spent nullifiers"]
    end
    subgraph Backend["⚙️ ShieldPass Relayer"]
        IDX["Tree indexer + merkle_insert prover"]
        PAY["Paystack / Lenco"]
        BLOB["Encrypted note blobs"]
    end

    SK -->|"prove locally"| PROOF
    PROOF -->|"verified on-chain"| VERIFY
    VERIFY --> TREE
    VERIFY --> NULL
    IDX -->|"advance root trustlessly"| TREE
    ENC -->|"deliver to recipient"| BLOB
    Backend -->|"naira"| PAY
Loading

🤝 Private Payments (How It Stays Private)

Sending to another ShieldPass user keeps everything hidden, like a locked mailbox with no names:

  1. You encrypt the note details to the recipient's published encryption key (x25519 ECDH + XChaCha20-Poly1305) and submit the shielded_transfer.
  2. The funds never leave the pool — your note is nullified; the recipient gets a new note; nothing public is revealed.
  3. The recipient's app scans new encrypted blobs, trial-decrypts with their key, finds the ones meant for them, and updates their shielded balance — automatically, with a notification.

Sending to an external G…/C… wallet instead unshields (the funds become public on arrival). Sending to a ShieldPass user stays fully shielded.


🪜 Progressive KYC — Programmable Privacy

A tiered compliance model so small swaps stay frictionless while large ones stay regulated:

Tier Gate Unlocks
Tier 1 Passkey hardware attestation (hardware_attested) Everyday swaps
Tier 2 BVN verification (bvn_verified) High-value swaps (> ₦1,000,000)

The same circuit enforces both. A public input require_bvn is set by the backend from the swap's naira value; the contract rejects a high-value withdrawal that didn't use a Tier-2 proof. Compliance attributes are bound into the note.


🔑 Passkey Smart Wallets + Shielded Identity

No seed phrases, no extensions, no XLM required. Each user gets an OpenZeppelin Smart Account secured by a WebAuthn passkey; transactions are submitted gaslessly via the relayer. Your shielded key (which owns your private notes) is derived from the passkey's PRF — so resetting your login PIN never touches your private funds.


🛠️ Tech Stack

Layer Tech
ZK Circuits Circom + snarkjs Groth16, Poseidon (BN254)
On-chain verification Soroban native bn254 pairing-check (Rust contract)
Smart Contract Rust / Soroban — Shielded Pool (deposit · insert · confidential_swap · unshield · shielded_transfer · claim · refund), one instance per supported asset
Note encryption x25519 + XChaCha20-Poly1305 (@noble)
Wallets OpenZeppelin Smart Accounts (WebAuthn passkeys / secp256r1)
Gasless Relay OpenZeppelin Channels
Backend Node, Express, Prisma 7 + Neon Postgres
Frontend React, Vite, Tailwind, Framer Motion
Fiat Payouts Paystack + Lenco (stateless / zero-storage)

📡 Deployment


🚀 Local Development

Prerequisites: Node 20+ (Prisma 7 requires ≥ 20.19), Rust + stellar CLI (for the contract), circom (only to regenerate circuits), a backend .env, and a frontend .env.

# Backend — prisma generate is required (the v7 client is gitignored)
cd backend && npm install && npx prisma generate && npm run dev   # http://localhost:3001

# Frontend
cd frontend && npm install && npm run dev                          # http://localhost:5173

Build & test the Soroban Shielded Pool:

cd SDK/contracts/shielded_pool && cargo test           # contract tests (real proofs)
stellar contract build                                  # wasm for deploy

Regenerate circuits + proving keys (only if you change a circuit):

cd SDK/circom && npm install
bash scripts/build.sh confidential_swap
bash scripts/build.sh merkle_insert
bash scripts/build.sh shielded_transfer

Key environment variables:

File Var Purpose
backend/.env NEON_CONNECTION_STRING Neon Postgres direct URL (?sslmode=require, no channel_binding)
backend/.env STELLAR_CONTRACT_ID / USDC_POOL_CONTRACT_ID XLM / USDC Shielded Pool contract ids
backend/.env XLM_SAC_ADDRESS / USDC_SAC_ADDRESS Stellar Asset Contract addresses backing each pool
backend/.env STELLAR_RELAYER_SECRET Admin/relayer keypair (pool init, faucet seeding)
backend/.env CHANNELS_URL / CHANNELS_API_KEY OpenZeppelin Channels — required for gasless smart-account submission
backend/.env CORS_ORIGIN Comma-separated allowed frontend origin(s); unset = allow all (dev only)
backend/.env PAYSTACK_SECRET_KEY / LENCO_* Naira payout providers
backend/.env FAUCET_NOTE_AMOUNT / FAUCET_NOTE_ASSET Onboarding seed note (defaults 500 / XLM)
backend/.env SEED_TOKENS Fallback public-funding for brand-new smart wallets (comma-separated contractId:amount)
frontend/.env VITE_API_URL Backend URL (powers swaps, transfers, scanning, notifications)
frontend/.env VITE_ACCOUNT_WASM_HASH / VITE_WEBAUTHN_VERIFIER_ADDRESS smart-account-kit account wasm + WebAuthn verifier contract
frontend/.env VITE_XLM_POOL_CONTRACT_ID / VITE_USDC_POOL_CONTRACT_ID Per-asset Shielded Pool contract ids
frontend/.env VITE_XLM_SAC / VITE_USDC_SAC Per-asset SAC addresses (drives which assets show up in the UI)

📜 License

See LICENSE.

About

Stellar native P2P for Nigerians

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 72.4%
  • Rust 15.5%
  • MDX 4.9%
  • JavaScript 2.7%
  • CSS 2.5%
  • Circom 1.5%
  • Other 0.5%