Overview
Once value is shielded into the confidential layer,ERC20Confidential exposes the full ERC-7984 surface for moving it privately. This API is identical to FHERC20’s — confidential transfers, a time-based operator system, and safe transfers with receiver callbacks. This page covers each, with the specifics of the ERC20Confidential implementation.
The confidential-transfer API here mirrors FHERC20. If you already know FHERC20’s operators and transfer callbacks, the same mental model applies — only the contract name and errors differ.
Confidential Transfers
Every transfer function comes in two overloads: anInEuint64 overload for encrypted input coming from off-chain users, and an euint64 overload for already-encrypted, contract-to-contract values.
How a transfer is authorized
Theeuint64 overloads require the caller to already hold FHE access to the value; the InEuint64 overloads accept a fresh encrypted input and convert it in-place.
Usage
The Operator System
Like FHERC20,ERC20Confidential replaces ERC-20 allowances (which would leak amounts) with time-based operators. An operator can move any amount of a holder’s confidential balance until an expiration timestamp.
Self is always an operator
isOperator returns true when holder == spender, so a holder can always move their own tokens via confidentialTransferFrom without granting anything.Inclusive expiry
Permission is valid while
block.timestamp <= until. Set until to block.timestamp to revoke immediately, or type(uint48).max for effectively indefinite access.Granting and using operators
confidentialTransferFrom checks operator status before moving tokens:
OperatorSet(holder, operator, until) is emitted on every grant or revocation.
Transfer Callbacks
The...AndCall functions transfer confidential tokens and notify the recipient contract, which can accept or reject the transfer. All four overloads exist:
The accept-or-refund mechanism
ERC20Confidential moves the tokens first, asks the recipient, and refunds whatever the recipient rejects — all under FHE, without revealing amounts:
1
Transfer executes
sent tokens move from from to to via the confidential update engine.2
Recipient is called
FHERC20Utils.checkOnTransferReceived invokes onConfidentialTransferReceived on the recipient (if it’s a contract) and returns an encrypted success flag.3
Rejected amount is refunded
FHE.select(success, 0, sent) computes the refund: zero if accepted, the full amount if rejected. That refund moves back from to to from.4
Net transfer reported
transferred = sent - refund — the actual net amount that stuck with the recipient.The receiver interface
A recipient contract must implementIERC7984Receiver and return an encrypted bool:
- Return
FHE.asEbool(true)to accept the transfer. - Return
FHE.asEbool(false)to reject it — the tokens are refunded to the sender under FHE.
Unlike an all-or-nothing revert, the accept/reject decision is evaluated under encryption and settled by refunding the rejected portion. See FHERC20 Transfer Callbacks for receiver patterns, reentrancy guidance, and data-passing examples — the receiver contract is written the same way.
Errors
Events
ConfidentialTransfer carries an encrypted euint64 handle, never a plaintext amount — you cannot index transfer amounts off-chain from events. The sidecar ERC20ConfidentialIndicator also emits a standard Transfer(from, to, 10110000001) so explorers register activity without exposing amounts.Related Topics
- Bridge value into the confidential layer with Shield & Unshield
- Understand the encrypted bookkeeping in The Dual-Balance Model
- Receiver patterns and reentrancy: FHERC20 Transfer Callbacks
- Review Best Practices for secure operator and access-control usage