Deposit USDC into a private deposit address using zero-knowledge proofs
Enter the amount and optionally specify who can redeem. You can generate a new secret or reuse an existing one to top up a deposit.
Leave empty for unbounded mode (any address can redeem with the secret). Specify addresses to restrict redemption to those beneficiaries only (max 4).
Leave empty to generate a new key. Paste an existing key to top up that deposit (must use same beneficiaries).
import { Domain, IbcCoreRegistry } from "@unionlabs/payments";
import { Payment, EvmWalletClient, EvmPublicClient } from "@unionlabs/payments/promises";
const UNIVERSAL_CHAIN_ID = Domain.UniversalChainId.make("base.8453");
// Create from viem clients (wagmi compatible)
const walletClient = await EvmWalletClient.fromViem(viemWalletClient);
const publicClient = await EvmPublicClient.fromViem(viemPublicClient);
// Generate a new payment key
const paymentKey = await Payment.generateKey();
// Derive the deposit address
const depositAddress = await Payment.getDepositAddress({
paymentKey,
beneficiaries: [],
destinationChainId: UNIVERSAL_CHAIN_ID,
});
// Prepare all transactions
const requests = await Payment.prepareDeposit({
depositAddress,
amount: 1n,
destinationChainId: UNIVERSAL_CHAIN_ID,
srcErc20Address: USDC_ADDRESS,
sourceWalletClient: walletClient,
});
// => [approve, wrap, transfer] Standard token approval - lets the contract spend your USDC.
Wrap your USDC into zUSDC. This is a 1:1 wrapper that enables private transfers.
Transfer zUSDC to a deposit address derived from your secret. Looks like a normal transfer on-chain, but only someone who knows the secret (and is a valid beneficiary) can redeem.
Update the light client so funds become available for redemption. This confirms your deposit is included in a verified block.
Done! Save the secret key below - it's the only way to redeem these funds.