zk-VEILRWA
VeilRWA is a Zero-knowledge privacy layer for RWA yield on Mantle. Institutions earn verified returns without revealing portfolio balances using Groth16 ZK proofs.
视频
技术栈
描述
VeilRWA - Zero-Knowledge Privacy Layer for Real-World Asset Yields
🔗 Links:
GitHub Repository: https://github.com/Rohitamalraj/zk-veilRWA
Live Demo: https://zk-veilrwa.vercel.app
Network: Mantle Sepolia Testnet (Chain ID: 5003)
🔴 The Problem
Institutional investors face a critical privacy dilemma in DeFi RWA markets. When depositing tokenized real-world assets (T-Bills, bonds, treasuries) on-chain, their entire portfolio balance becomes publicly visible. A $100M fund depositing treasury tokens reveals exact holdings to competitors, enabling front-running and market manipulation. Traditional DeFi protocols force investors to choose between transparency and yield—compromising institutional privacy requirements and regulatory compliance.
Current solutions fail:
Mixing protocols sacrifice auditability
Private chains lack composability
Centralized custodians reintroduce counterparty risk
Institutions need cryptographic privacy that preserves verifiable compliance.
✅ Our Solution
VeilRWA enables institutions to earn verified yields on tokenized RWAs without revealing portfolio balances on-chain. Using zero-knowledge proofs on Mantle's L2, investors deposit assets behind cryptographic commitments—the blockchain stores only a hash, never the amount.
When claiming accrued yield, users generate ZK proofs that cryptographically verify:
✅ They own the commitment
✅ Yield calculations are correct
✅ Time-based accrual is valid
All without exposing the principal balance.
🔧 How It Works
User Workflow
1. Connect Wallet & KYC Verification
User → Connect Wallet → Generate KYC Proof (off-chain)
→ Submit ZK-KYC Proof → Registry verifies → Status: VERIFIED
Users prove regulatory credentials using ZK proofs
No personal data stored on-chain, only cryptographic proof of eligibility
KYC status linked to wallet address via
KYCRegistrycontract
2. Deposit RWA Tokens (Private)
User selects amount → Generates random salt → Computes commitment
→ commitment = Poseidon(balance, salt)
→ Transfers TBILL tokens to vault
→ Submits commitment hash on-chain
→ Blockchain stores: commitment hash (not balance!)
What's stored on-chain:
Commitment: 0x2a5c8b... (32-byte Poseidon hash)
Balance: HIDDEN ❌ (Never leaves user's browser)
Owner: 0xYourAddress
Timestamp: 1736985600
Privacy guarantee: Even with full blockchain access, balance is computationally infeasible to reverse from the commitment hash.
3. Earn Yield (Off-Chain Accrual)
Time passes → Yield accrues based on APY (e.g., 5% annual)
→ User tracks: balance, salt, deposit time (client-side)
→ No on-chain updates = Zero gas costs
Example:
Deposit: 100 TBILL at 5% APY
After 1 year: 105 TBILL claimable
Blockchain shows: Same commitment hash (balance still hidden)
4. Claim Yield (ZK-Verified)
User requests claim → Computes yield locally
→ Generates ZK proof in browser (SnarkJS):
• Proves ownership of commitment
• Proves yield = balance × rate × time
• Proves time elapsed since deposit
→ Submits proof + nullifier to vault
→ Vault verifies proof via YieldVerifier contract
→ If valid: Transfers yield tokens
→ Nullifier prevents double-claims
On-chain verification (200K gas):
YieldVerifier.verifyProof(
proof, // Groth16 proof (200 bytes)
publicInputs // [commitment, nullifier, yield, timestamp]
) → returns true/false
Result:
User receives 5 TBILL yield
Balance remains private (commitment unchanged)
Transaction shows yield amount, not principal
🏗️ System Architecture
┌─────────────────────────────────────────────────────────────────┐
│ USER (Browser) │
│ • Generates proofs with SnarkJS (client-side, 2-3 sec) │
│ • Stores: balance, salt, witness data (never leaves device) │
└──────────────────────┬──────────────────────────────────────────┘
│ ZK Proof + Public Inputs
▼
┌─────────────────────────────────────────────────────────────────┐
│ MANTLE L2 BLOCKCHAIN │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ VeilRWAVault │◄──►│ Verifiers │◄──►│ KYCRegistry │ │
│ │ │ │ • Deposit │ │ │ │
│ │ - Commitments│ │ • Yield │ │ - KYC Status │ │
│ │ - Nullifiers │ │ • KYC │ │ │ │
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ TBILL Token │ (ERC20 RWA) │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Smart Contract Flow
// 1. DEPOSIT
function depositPrivate(bytes32 commitment) external {
require(kycRegistry.isVerified(msg.sender)); // KYC check
commitments[commitment] = CommitmentData({
owner: msg.sender,
timestamp: block.timestamp,
claimed: false
});
rwaToken.transferFrom(msg.sender, address(this), amount);
// ⚠️ 'amount' never stored on-chain!
}
// 2. CLAIM YIELD
function claimYield(
uint256[2] memory a, // Proof component A
uint256[2][2] memory b, // Proof component B
uint256[2] memory c, // Proof component C
uint256[4] memory input // [commitment, nullifier, yield, time]
) external {
require(
yieldVerifier.verifyProof(a, b, c, input),
"Invalid ZK proof"
);
require(!nullifiers[input[1]], "Already claimed");
nullifiers[input[1]] = true; // Prevent double-claim
rwaToken.transfer(msg.sender, input[2]); // Transfer yield
}
🔐 Zero-Knowledge Architecture
Circom Circuits (Groth16 SNARKs)
1. Deposit Circuit (250 constraints)
template DepositCircuit() {
signal input balance; // Private: user's deposit amount
signal input salt; // Private: random 32-byte value
signal output commitment; // Public: Poseidon(balance, salt)
component hasher = Poseidon(2);
hasher.inputs[0] <== balance;
hasher.inputs[1] <== salt;
commitment <== hasher.out;
}
Purpose: Generate commitment hash for private deposits
2. Yield Claim Circuit (2500 constraints)
Purpose: Prove valid yield calculation without revealing balance
template YieldClaimCircuit() {
signal input balance; // Private: original deposit
signal input salt; // Private: commitment salt
signal input rate; // Private: yield rate (e.g., 5%)
signal input depositTime; // Private: deposit timestamp
signal input claimTime; // Private: current timestamp
signal output commitment; // Public: verify ownership
signal output nullifier; // Public: prevent double-claim
signal output yieldAmount; // Public: calculated yield
// Verify commitment ownership
commitment <== Poseidon(balance, salt);
// Calculate yield: balance × rate × timeElapsed / 365 days
signal timeElapsed <== claimTime - depositTime;
yieldAmount <== (balance rate timeElapsed) / 31536000;
// Generate nullifier: Poseidon(commitment, claimTime)
nullifier <== Poseidon(commitment, claimTime);
}
3. KYC Circuit (1800 constraints)
template KYCCircuit() {
signal input credentialHash; // Private: user's KYC credentials
signal input walletAddress; // Public: user's ETH address
signal input kycProvider; // Private: trusted issuer ID
signal output isValid; // Public: 1 if valid, 0 otherwise
// Verify credential matches registered provider
// Prove user owns wallet without revealing identity
isValid <== verifyCredential(credentialHash, kycProvider);
}
Purpose: Prove regulatory compliance without exposing identity
Cryptographic Components
Component | Purpose | Security Level |
|---|---|---|
Groth16 | ZK proving system | 128-bit security |
Poseidon Hash | ZK-friendly commitment | Collision-resistant |
BN254 Curve | Pairing-friendly elliptic curve | 128-bit security |
Nullifiers | Prevent double-claims | Hash-based uniqueness |
Random Salt | Commitment hiding | 256-bit entropy |
Gas Costs (Mantle Sepolia)
Operation | Gas Used | Cost (Est.) | Ethereum L1 Equivalent |
|---|---|---|---|
Deposit (Private) | ~150K gas | $0.03 | $90 (3000x cheaper) |
Yield Claim (ZK Verify) | ~200K gas | $0.05 | $120 (2400x cheaper) |
KYC Proof Verify | ~180K gas | $0.04 | $108 (2700x cheaper) |
Total cost for full workflow: $0.12 on Mantle vs $318 on Ethereum L1
🚀 Key Differentiators
vs. Tornado Cash / Privacy Pools
✅ Privacy for yield, not transfers
✅ Maintains institutional auditability via selective disclosure
✅ Regulatory-compliant (KYC-gated)
❌ Tornado: Mixing-based privacy, sanctioned by OFAC
vs. Aztec / Aleo / ZK-VMs
✅ Purpose-built for RWA compliance
✅ Circuit constraints optimized for yield (60% less gas)
✅ Works on existing Mantle L2 (no new VM deployment)
❌ General ZK-VMs: Higher overhead for specialized use cases
vs. Private Chains (Hyperledger, Corda)
✅ Full DeFi composability on public Mantle L2
✅ Interacts with AMMs, lending, oracles while maintaining privacy
✅ Censorship-resistant (permissionless blockchain)
❌ Private chains: Isolated networks, no public DeFi access
vs. Centralized Custodians (Fireblocks, Copper)
✅ Self-custody + cryptographic verification
✅ Smart contracts enforce rules (no trusted intermediaries)
✅ Permissionless: Anyone with KYC can participate
❌ Custodians: Counterparty risk, centralized control
vs. ZK-Rollups (zkSync, StarkNet)
✅ Provides privacy, not just scalability
✅ Balances hidden via commitments (rollups show balances publicly)
✅ Selective disclosure for auditors
❌ Rollups: Focus on scaling, balances remain transparent
📦 Deployed Contracts (Mantle Sepolia)
Core Protocol
Contract | Address | Explorer Link |
|---|---|---|
VeilRWAVault (V3) |
| |
MockRWAToken (TBILL) |
| |
KYCRegistry |
|
ZK Verifier Contracts (Groth16)
Verifier | Address | Circuit | Explorer |
|---|---|---|---|
DepositVerifier |
| 250 constraints | |
YieldVerifier |
| 2500 constraints | |
KYCVerifier |
| 1800 constraints |
📊 Live Demo Walkthrough
Try it yourself: https://zk-veilrwa.vercel.app
Step-by-step demo:
Connect Wallet (MetaMask/Coinbase/WalletConnect)
Switch to Mantle Sepolia network (auto-prompt)
Get test TBILL tokens from faucet
Complete KYC (Mock verification for demo)
Navigate to KYC page
Generate ZK-KYC proof (off-chain)
Submit proof → Status: ✅ VERIFIED
Deposit Assets (Private)
Enter amount: 100 TBILL
System generates commitment hash
Approve + Deposit transaction
Result: Commitment stored, balance hidden
Check Balance (On-chain Explorer)
Visit Mantle Explorer
See: Commitment hash only
Privacy preserved ✅
Claim Yield (ZK-Verified)
Navigate to Claim page
Generate ZK proof (2-3 seconds)
Submit proof → Receive 5 TBILL yield
Result: Principal still hidden
🌐 Use Cases
Institutional Treasury Management
Problem: Fortune 500 companies don't want competitors seeing cash reserves
Solution: Deposit treasury tokens privately, earn yield, maintain confidentiality
Hedge Fund RWA Allocations
Problem: Alpha strategies revealed through on-chain portfolio analysis
Solution: ZK commitments hide allocation sizes while proving returns
Corporate Bond Portfolios
Problem: Bond holdings signal creditworthiness and strategic positions
Solution: Private bond tokenization with public yield verification
Pension Fund Fixed-Income
Problem: Public pension funds disclose holdings, facing regulatory scrutiny
Solution: Selective disclosure for auditors, privacy from general public
Private Credit Markets
Problem: Loan terms and amounts are commercially sensitive
Solution: ZK proofs of creditworthiness without revealing loan size
Compliant DeFi for TradFi
Problem: Traditional finance can't use DeFi due to transparency concerns.
Solution: Bridge TradFi and DeFi with cryptographic privacy guarantees
🏗️ Built With
Smart Contracts: Solidity 0.8.20 | Hardhat | OpenZeppelin
Zero-Knowledge: Circom 2.0 | SnarkJS | Groth16 SNARKs | Poseidon Hashing
Frontend: Next.js 16.1 | Wagmi v3 | Reown AppKit | TailwindCSS 3.4
Blockchain: Mantle L2 Sepolia Testnet
Privacy meets institutional compliance on Mantle. 🔐