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 offchain 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 offchain 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