ERC20Confidential contract is backed by public tokens that the contract holds aside. This page explains where those tokens sit, what each supply function counts, and what the indicator token shows. Read it before you build accounting or analytics on top of the token.
Where the backing tokens sit
Public tokens backing confidential balances sit in the public balance of a fixed address,CONFIDENTIAL_POOL:
unshield leaves the pool alone. The pool keeps custody of the tokens until the claim settles, so a pending claim is still backed.
Because the pool is an ordinary address, anyone can send public tokens to it with transfer. Those tokens back no confidential balance, and the token has no function that returns them.
What total supply counts
totalSupply() is the OpenZeppelin total of all public balances, and the pool is one of them. Shielding and unshielding move tokens between addresses, so they never change totalSupply(). Only public mints and burns change it, including the public mint inside _confidentialMint.
The confidential supply is the pool’s balance converted to confidential units. The token exposes it two ways:
The confidential supply is not secret: anyone can compute it from the pool’s public balance.
confidentialTotalSupply exists for contracts that need the value as a ciphertext for FHE operations. The handle is the zero handle until the first shield, claim, or confidential mint.
A transfer straight into the pool raises confidentialTotalSupplyPlaintext immediately but leaves the stored handle stale. Anyone can refresh it by calling syncConfidentialTotalSupply().
The stored value saturates at type(uint64).max rather than reverting, so a large transfer into the pool cannot block shield or claims.
The indicator token
TheERC20Confidential constructor deploys a second contract, ERC20ConfidentialIndicator, and records it as indicatorToken(). Wallets and block explorers that only understand ERC-20 can track it to see that confidential activity happened, without seeing amounts.
Each confidential move updates the indicator for both parties. The first move into an account sets its indicator to
1011000.5001, and each later one adds 0.0001, up to 1011000.9999. The first move out sets it to 1011000.4999, and each later one subtracts 0.0001, down to 1011000.0001. The indicator also emits a Transfer event for each move, so the activity shows in transaction history.
The indicator’s transfer, transferFrom, approve, and allowance revert with ERC20ConfidentialIndicatorNoOp. Only the parent token can update it.
Read both balances
The public balance is a plain view call. The confidential balance is a handle, which the holder decrypts with an Access Control Permission (ACP) throughdecryptForView:
confidentialBalance is in confidential units. Multiply it by the rate to compare it with the public balance.