ERC20Confidential. Each one links to the page that explains the behavior behind it.
Treat shield and unshield amounts as public
Privacy covers balances and transfers inside the confidential layer, not the boundary. The amount passed toshield is in the call data and in the TokensShielded event. The amount passed to unshield(uint64) is in the call data, and every claim reveals its amount when it settles.
Tell users that what they move in and out is visible. A user who shields 1,000 tokens and later unshields 1,000 links the two. See shield and unshield.
Check the amount that actually moved
A confidential transfer or unshield of more than the balance does not revert. It moves zero. Every transfer returns the amount that moved as asharedEuint64, so a contract that credits a user should credit that returned amount, never the amount it asked for. See call a token from your contract.
Work in confidential units
Transfers,unshield, and _confidentialMint take confidential units, while shield and every ERC-20 function take public base units. For an 18-decimal token one confidential unit is 10^12 base units, and shield leaves anything below that in the public balance. Read confidentialDecimals() instead of assuming 6. See decimals and units.
Use the plaintext supply, or sync before reading the handle
confidentialTotalSupplyPlaintext() is always current. The confidentialTotalSupply() handle goes stale when someone transfers public tokens straight to the pool, and stays stale until anyone calls syncConfidentialTotalSupply(). It is also the zero handle until the first shield. See what total supply counts.
Gate both balances if you freeze accounts
_beforeConfidentialMove covers confidential transfers and unshield only. A freeze built on it alone still lets the account use its public balance, shield, and receive claim payouts. Override _update as well. See freeze accounts.
Backfill the observer when you set it
A compliance observer only gets access to handles created after it is set. CallgrantObserverPast with the existing balance handles, or the observer cannot read balances that have not moved since. See add a compliance observer.
Keep operators short-lived
A confidential operator can move any amount of the holder’s confidential balance until its deadline. It is separate from the public allowance:approve grants nothing on the confidential side, and setOperator grants nothing on the public side. Set a deadline that covers the action you need, and set it to 0 when you are done. See operators.
Link the library and enable the optimizer
DeployERC20ConfidentialLib from fhenix-confidential-contracts@0.4.0 and link every token to it; the address cannot change after deployment. Compile with the optimizer on, so added functions do not push the token past the 24 KB contract size limit. See link the shared library.