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.
Videos
Tech Stack
Description
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. π