Skip to main content
Every confidential token in fhenix-confidential-contracts has an upgradeable variant for deployment behind a proxy. The variants share their logic with the constructor-based contracts and differ only in setup: you call an initializer instead of a constructor. This page covers the initializers, the deploy and upgrade calls, and what to check before you upgrade an existing proxy.

Which variant and initializer

The initializers are internal and onlyInitializing. You call them from your own initialize function marked initializer. Disable initializers in the constructor so nobody can initialize the implementation contract itself.

Write the token

An upgradeable FHERC20:
ConfidentialTokenUpgradeable.sol
A wrapper initializes the FHERC20 part and the wrapper part:
ConfidentialUSDCUpgradeable.sol
ERC20ConfidentialUpgradeable initializes the public ERC-20 and the confidential layer in one call:
DualTokenUpgradeable.sol
__ERC20Confidential_init deploys the token’s indicator token, so each proxy gets its own.

Deploy and upgrade

With the OpenZeppelin upgrades plugin for Hardhat, FHERC20Upgradeable deploys like any upgradeable contract:
The wrappers and ERC20ConfidentialUpgradeable call into ERC20ConfidentialLib, so you link it into the factory and allow linked libraries on both the deploy and every later upgrade:
Without the flag, the plugin rejects the implementation as not upgrade safe. The flag tells it you have checked the library yourself. ERC20ConfidentialLib holds no storage of its own: it runs against the token’s storage through delegatecall. See link the shared library for deploying the library.

Where state lives

State sits in ERC-7201 namespaced storage slots, so it does not collide with the storage of contracts you inherit alongside: The constructor-based contracts use the same slots. The public ERC-20 ledger of ERC20ConfidentialUpgradeable lives in OpenZeppelin’s ERC20Upgradeable storage.

Before you upgrade an existing proxy

An FHERC20Upgradeable proxy from 0.3.x keeps its balances when you upgrade it to 0.4.0, because the FHERC20 storage slot did not change. Two cases need action:
  • Wrapper proxies with pending claims. 0.4.0 keys claims by claim ID instead of by handle, in a layout that is not compatible with the 0.3.x claim store. Claims still pending at upgrade time cannot be settled afterwards. Have users claim, or claim for them, before you upgrade.
  • ERC20ConfidentialUpgradeable proxies from a pre-release build. confidentialTotalSupply() reads a stored handle that older implementations did not write, and returns a zero handle until something refreshes it. Call syncConfidentialTotalSupply() once after the upgrade. Anyone can call it.
Callers also need the 0.4.0 interface after the upgrade. The confidential contracts overview lists what changed for callers since 0.3.