Confidential Tokens
Confidential tokens are the encrypted versions of regular ERC20 tokens. They're what make private payments possible.
How They Work
When you wrap regular USDC into confidential USDC:
- Deposit: Your regular USDC goes into the wrapper contract
- Mint: You receive an equal amount of confidential USDC
- Encryption: Your balance is stored as encrypted data
The confidential token mirrors the value 1:1, but the amounts are hidden.
100 USDC → [Wrap] → 100 Confidential USDC (encrypted)
The Wrapping Process
Step 1: Approve
Before wrapping, you approve the wrapper contract to move your tokens:
// User approves wrapper to spend their USDC
usdc.approve(wrapperAddress, amount);
This is standard ERC20 behavior — nothing special here.
Step 2: Wrap
Then you call wrap with your amount:
// Wrap 100 USDC into confidential tokens
wrapper.wrap(100_000000); // 100 USDC with 6 decimals
Behind the scenes:
- Contract takes your USDC
- Contract encrypts the amount
- Contract adds to your encrypted balance
Step 3: Receive
Your confidential balance updates. In the UI, you'll see your new balance after a brief decryption delay.
The Unwrapping Process
When you want regular tokens back:
// Unwrap 50 confidential USDC back to regular USDC
wrapper.unwrap(encryptedAmount);
The process:
- Contract verifies your encrypted balance is sufficient
- Contract subtracts from your encrypted balance
- Contract sends regular USDC to your wallet
Privacy Properties
What's Encrypted
- Your confidential token balance
- Transfer amounts
- The total supply (sum of all balances)
What's Visible
- That you hold some confidential tokens
- Token transfer events (without amounts)
- The wrapper contract address
Two-Step Transfer Pattern
Because FHE operations can be complex, Aruvi uses a two-step pattern for some operations:
Step 1: Initiate
Create the transfer with encrypted amount:
gateway.send(recipient, encryptedAmount, proof);
Step 2: Execute
After FHE processing, complete the transfer:
// Usually automatic, but can be manual if needed
gateway.executePendingTransfer(transferId);
This separation ensures reliability even with network issues.
Balance Decryption
Your encrypted balance is just bytes on-chain. To see actual numbers:
- Request: Your wallet asks the Zama Gateway for decryption
- Prove: You sign a message proving you own the address
- Decrypt: Gateway decrypts and returns the value
- Display: Your browser shows the balance
This happens automatically in the Aruvi app. You just see your balance.
Supported Tokens
Currently, Aruvi supports:
| Token | Contract | Status |
|---|---|---|
| USDC | Confidential wrapper | ✅ Live |
More tokens coming:
- USDT
- DAI
- WETH
The wrapper architecture makes adding new tokens straightforward.
Comparison to Regular Tokens
| Feature | Regular ERC20 | Confidential Token |
|---|---|---|
| Balance visible | ✅ Public | ❌ Encrypted |
| Transfer amounts | ✅ Public | ❌ Encrypted |
| Standard wallets | ✅ Yes | ✅ Yes |
| DeFi compatible | ✅ Yes | ⚠️ Limited |
| Transfer speed | Fast | Slightly slower |
| Gas cost | Lower | Higher |
Technical Details
Confidential tokens implement a modified ERC20 interface:
// Standard ERC20 balance is always 0
function balanceOf(address) returns (uint256);
// Encrypted balance for FHE operations
function balanceOfEncrypted(address) returns (euint64);
// Transfer with encrypted amount
function transferEncrypted(address to, einput amount, bytes calldata inputProof);
The contract maintains both interfaces for compatibility, but real balances live in the encrypted mapping.
Best Practices
- Keep some unwrapped: For easy spending at services that don't support confidential tokens
- Batch your wrapping: Reduce gas costs by wrapping larger amounts less frequently
- Understand the delay: Decryption takes a moment — don't panic if balance shows 0 briefly
- Check allowances: Make sure you've approved enough for your intended wrapping amount