ConfidentialPaymentRouterV2 contract wraps your tokens into a ConfidentialWrapper, moves them as an encrypted cToken, then unwraps and delivers plain ERC-20 to the receiver — all in a single flow. The receiver never needs to interact with FHE or hold cTokens.
Payment Flow
The
finalize() function is permissionless — anyone can submit the KMS proof on behalf of a payment. The HideMe relayer does this automatically, but you or any third party can call it if needed.send()
The ERC-20 token address you want to send. A
ConfidentialWrapper must already exist for this token in WrapperFactory. Call getWrapper(token) on the factory first to verify it returns a non-zero address.The wallet address that will receive the plain ERC-20 after finalization.
Amount in the token’s native decimals (e.g.
1_000_000 for 1 USDC, 1e18 for 1 WETH).A human-readable note stored on-chain with the payment record.
0.00005 ETH (MIN_RELAYER_FEE) as msg.value. This covers the relayer’s gas cost for the finalization transaction.
Before calling send(), approve the router:
send() call.
finalize()
- The wrapper’s
finalizeUnwrap()is called, burning the cToken and releasing the underlying ERC-20. - The underlying ERC-20 is forwarded to
receiver. - The
relayerFeeETH is sent to the caller (the relayer).
The ID returned by
send() and emitted in the PaymentCreated event.The FHE ciphertext handles being decrypted — from the
PaymentUnwrapRequested event.ABI-encoded decrypted values from the KMS network.
KMS threshold signatures authorising the decryption.
cancel()
- Calls
cancelUnwrap()on the wrapper to clear the restriction. - Returns the cToken balance to the sender via
transferPlaintext. - Refunds the
relayerFeeETH to the sender.
Payment struct fields
Wallet that initiated the payment.
Wallet that will receive the plain ERC-20.
Address of the
ConfidentialWrapper used for this token.Amount in 6-decimal cToken units (after decimal adjustment from the underlying token).
The request ID passed to the wrapper’s
unwrap() function. Used in finalize().The FHE ciphertext handle for the
canUnwrap encrypted boolean submitted to the KMS.ETH locked for the relayer, paid out on successful finalization.
Human-readable note attached to the payment.
Unix timestamp when
send() was called.true after finalize() has been called successfully.true if the sender cancelled after the timeout.Batch Payments
You can send multiple payments in a single session. However, they must be processed sequentially — you must wait for each payment to be finalized before sending the next one using the same token. This is because theConfidentialWrapper restricts the router’s account (isRestricted = true) during a pending unwrap. The restriction is cleared only after finalizeUnwrap() completes.
Payments for different tokens can be sent in parallel because each token has its own
ConfidentialWrapper contract with independent restriction state.Prerequisites
Contract Addresses
| Contract | Network | Address |
|---|---|---|
| PaymentRouterV2 | Ethereum Mainnet | 0x087D50Bb21a4C7A5E9394E9739809cB3AA6576Fa |
| WrapperFactory | Ethereum Mainnet | 0xde8d3122329916968BA9c5E034Bbade431687408 |
| cWETH Wrapper | Ethereum Mainnet | 0x7a339078f9abde76c7cf9360238eafd2a64c0ee7 |
| cUSDC Wrapper | Ethereum Mainnet | 0x1704cd8697f1c4f21bab3e0c4cf149cb7b1e5147 |