ConfidentialUSDCWrapper API
Contract for wrapping USDC into confidential (encrypted) tokens.
Address (Sepolia): 0xf99376BE228E8212C3C9b8B746683C96C1517e8B
Write Functions
wrap
Convert regular USDC to confidential USDC.
function wrap(uint256 amount) external
| Parameter | Type | Description |
|---|---|---|
amount | uint256 | Amount of USDC to wrap (6 decimals) |
Requirements:
- Caller must have approved this contract for
amountof USDC - Caller must have sufficient USDC balance
Emits: Wrapped(account, amount)
Example:
// First approve
await usdc.approve(wrapperAddress, 100_000000n);
// Then wrap
await wrapper.wrap(100_000000n); // Wrap 100 USDC
unwrap
Convert confidential USDC back to regular USDC.
function unwrap(
einput encryptedAmount,
bytes calldata inputProof
) external
| Parameter | Type | Description |
|---|---|---|
encryptedAmount | einput | Encrypted amount to unwrap |
inputProof | bytes | Encryption proof |
Requirements:
- Caller must have sufficient encrypted balance
Emits: Unwrapped(account, amount)
Example:
const { handles, inputProof } = await encryptAmount(50_000000n);
await wrapper.unwrap(handles[0], inputProof);
transferEncrypted
Transfer confidential tokens to another address.
function transferEncrypted(
address to,
einput encryptedAmount,
bytes calldata inputProof
) external returns (bool)
| Parameter | Type | Description |
|---|---|---|
to | address | Recipient address |
encryptedAmount | einput | Encrypted transfer amount |
inputProof | bytes | Encryption proof |
Returns: bool — Success status
Emits: ConfidentialTransfer(from, to)
approveEncrypted
Approve another address to spend your confidential tokens.
function approveEncrypted(
address spender,
einput encryptedAmount,
bytes calldata inputProof
) external returns (bool)
| Parameter | Type | Description |
|---|---|---|
spender | address | Address to approve |
encryptedAmount | einput | Encrypted allowance |
inputProof | bytes | Encryption proof |
Returns: bool — Success status
Emits: EncryptedApproval(owner, spender)
transferFromEncrypted
Transfer from another account (requires approval).
function transferFromEncrypted(
address from,
address to,
einput encryptedAmount,
bytes calldata inputProof
) external returns (bool)
| Parameter | Type | Description |
|---|---|---|
from | address | Source address |
to | address | Destination address |
encryptedAmount | einput | Encrypted amount |
inputProof | bytes | Encryption proof |
Requirements:
- Caller must have sufficient allowance from
from
Read Functions
balanceOfEncrypted
Get encrypted balance of an account.
function balanceOfEncrypted(
address account
) external view returns (euint64)
| Parameter | Type | Description |
|---|---|---|
account | address | Account to check |
Returns: euint64 — Encrypted balance (must be decrypted client-side)
Example:
const encryptedBalance = await wrapper.balanceOfEncrypted(userAddress);
// Decrypt using fhevmjs
const balance = await fhevm.decrypt(encryptedBalance, ...);
allowanceEncrypted
Get encrypted allowance.
function allowanceEncrypted(
address owner,
address spender
) external view returns (euint64)
| Parameter | Type | Description |
|---|---|---|
owner | address | Token owner |
spender | address | Approved spender |
Returns: euint64 — Encrypted allowance
totalWrapped
Get total amount of USDC wrapped (plaintext).
function totalWrapped() external view returns (uint256)
Returns: uint256 — Total USDC held in contract
underlyingToken
Get address of underlying USDC token.
function underlyingToken() external view returns (address)
Returns: address — USDC contract address
decimals
Get token decimals.
function decimals() external view returns (uint8)
Returns: uint8 — Always 6 (matching USDC)
name
Get token name.
function name() external view returns (string memory)
Returns: string — "Confidential USDC"
symbol
Get token symbol.
function symbol() external view returns (string memory)
Returns: string — "cUSDC"
Events
Wrapped
Emitted when USDC is wrapped.
event Wrapped(
address indexed account,
uint256 amount
);
| Parameter | Type | Description |
|---|---|---|
account | address | User who wrapped |
amount | uint256 | Amount wrapped |
Unwrapped
Emitted when confidential USDC is unwrapped.
event Unwrapped(
address indexed account,
uint256 amount
);
| Parameter | Type | Description |
|---|---|---|
account | address | User who unwrapped |
amount | uint256 | Amount unwrapped |
ConfidentialTransfer
Emitted on encrypted transfer.
event ConfidentialTransfer(
address indexed from,
address indexed to
);
Note: Amount is not included — it's confidential!
EncryptedApproval
Emitted when approval is set.
event EncryptedApproval(
address indexed owner,
address indexed spender
);
Decryption
To read an encrypted balance, you need to decrypt it:
Using fhevmjs
import { createInstance } from 'fhevmjs';
async function getBalance(userAddress: string) {
// 1. Get encrypted balance
const encryptedBalance = await wrapper.balanceOfEncrypted(userAddress);
// 2. Initialize fhevm
const fhevm = await createInstance({
networkUrl: 'https://rpc.sepolia.org',
});
// 3. Request reencryption (decryption)
const { publicKey, privateKey } = fhevm.generateKeypair();
const eip712 = fhevm.createEIP712(publicKey, wrapperAddress);
const signature = await signer.signTypedData(eip712);
const decrypted = await fhevm.reencrypt(
encryptedBalance,
privateKey,
publicKey,
signature,
wrapperAddress,
userAddress
);
return decrypted;
}
Decryption Permissions
Only the balance owner can decrypt their balance. This requires:
- Ownership proof (signature)
- Valid keypair for reencryption
- Request to the Zama Gateway
Error Codes
| Error | Description |
|---|---|
InsufficientBalance() | Not enough tokens |
InsufficientAllowance() | Not enough allowance |
InvalidAmount() | Amount is zero |
TransferFailed() | USDC transfer failed |
Integration with PaymentGateway
The PaymentGateway uses this wrapper internally:
// AruviPaymentGateway.sol
function send(address recipient, externalEuint64 encryptedAmount, bytes calldata proof) {
// Transfers confidential tokens via wrapper
wrapper.confidentialTransferFrom(msg.sender, recipient, amount, proof);
// ...
}
Users typically interact via PaymentGateway, not directly with the wrapper.