Skip to Content
ReferenceContract Surface

Contract Surface

The subset of the verified ABIs an integrator actually touches. Full ABIs, Sourcify exact-match, extracted from the deployed implementations, live in packages/shared/src/abis.

Registry

Read functions

FunctionReturnsUse
getTokenConfidentialTokenPairsLength()uint256Total pair count, for pagination
getTokenConfidentialTokenPairsSlice(uint256 fromIndex, uint256 toIndex)TokenWrapperPair[]Page through pairs; toIndex exclusive
getTokenConfidentialTokenPair(uint256 index)TokenWrapperPairSingle pair by index
getTokenConfidentialTokenPairs()TokenWrapperPair[]Whole list at once (fine while small)
getConfidentialTokenAddress(address token)(bool isValid, address wrapper)Token → wrapper lookup
getTokenAddress(address wrapper)(bool isValid, address token)Wrapper → token lookup
isConfidentialTokenValid(address wrapper)boolRevocation check before any write
getTokenIndex(address token)uint256Index of a registered token
struct TokenWrapperPair { address tokenAddress; address confidentialTokenAddress; bool isValid; }

Events

EventEmitted when
ConfidentialTokenRegistered(address indexed tokenAddress, address indexed confidentialTokenAddress)A new pair is registered
ConfidentialTokenRevoked(address indexed tokenAddress, address indexed confidentialTokenAddress)A wrapper is revoked

Errors worth handling

ErrorMeaning
TokenNotRegistered(address)Lookup for a token with no wrapper
RevokedConfidentialToken(address)Acting on a revoked wrapper
FromIndexGreaterOrEqualToIndex(uint256, uint256)Bad slice bounds

Wrapper (ERC-7984)

Conversion and supply

FunctionReturnsUse
underlying()addressThe wrapped ERC-20
rate()uint256Underlying units per wrapper unit; drives rounding
decimals()uint8Wrapper decimals (6)
inferredTotalSupply()uint256Outstanding supply in underlying units: Total Value Shielded
maxTotalSupply()uint256uint64 cap in underlying units

Wrap and unwrap

FunctionNotes
wrap(address to, uint256 amount)After ERC-20 approval; rounds amount down to a multiple of rate
unwrap(address from, address to, bytes32 encryptedAmount, bytes inputProof)Step 1: burns the encrypted amount, emits UnwrapRequested; returns the request id
unwrap(address from, address to, bytes32 amount)Overload taking an existing euint64 handle instead of a fresh encrypted input
finalizeUnwrap(bytes32 unwrapRequestId, uint64 unwrapAmountCleartext, bytes decryptionProof)Step 2: verifies the KMS proof, releases underlying. Permissionless
unwrapRequester(bytes32 unwrapRequestId)Requester address; zero address ⇒ request already finalized or unknown
unwrapAmount(bytes32 unwrapRequestId)The burned euint64 handle for a pending request

Balances and transfers

FunctionNotes
confidentialBalanceOf(address account)Returns the euint64 balance handle (bytes32)
confidentialTotalSupply()Encrypted total supply handle
confidentialTransfer(address to, bytes32 encryptedAmount, bytes inputProof)Private transfer from a fresh encrypted input; returns the transferred handle
confidentialTransfer(address to, bytes32 amount)Overload for an existing handle the sender may use
confidentialTransferFrom(address from, address to, …)Operator-driven transfer (both overloads)
confidentialTransferAndCall(…) / confidentialTransferFromAndCall(…)Transfer + receiver callback variants
setOperator(address operator, uint48 until)Delegate transfer rights until a timestamp
isOperator(address holder, address spender)Check a delegation

Disclosure (opt-in publicity)

FunctionNotes
requestDiscloseEncryptedAmount(bytes32 encryptedAmount)Holder asks to make one ciphertext publicly decryptable
discloseEncryptedAmount(bytes32, uint64, bytes)Completes disclosure with the public-decryption proof

Events

EventNotes
Wrap(address indexed to, uint256 roundedAmount, bytes32 encryptedWrappedAmount)Wrap amount is public
UnwrapRequested(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 amount)The id doubles as the burned ciphertext handle
UnwrapFinalized(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 encryptedAmount, uint64 cleartextAmount)Cleartext amount becomes public here
ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)Amount stays an encrypted handle
OperatorSet(address indexed holder, address indexed operator, uint48 until)Delegation granted or revoked

Errors worth handling

ErrorMeaningTypical cause
BlockedUser(address)Address is block-listed on the wrapperCompliance block
SenderNotAllowedToUseHandle(bytes32, address)FHEVM ACL rejected the handle useUsing a ciphertext you were never allowed on
ERC7984UnauthorizedUseOfEncryptedAmount(bytes32, address)Same idea, ERC-7984 layerReusing someone else’s encrypted input
ERC7984UnauthorizedSpender(address, address)No operator grantconfidentialTransferFrom without setOperator
ERC7984ZeroBalance(address)Account holds no ciphertextActing on a never-funded account
InvalidUnwrapRequest(bytes32)Unknown or finalized request idDouble-finalize; check unwrapRequester first
InvalidKMSSignatures()Decryption proof failed verificationWrong or stale proof passed to finalizeUnwrap
ERC7984TotalSupplyOverflow()Wrap would exceed the uint64 capAmount too large

Both contracts are UUPS proxies (Upgraded event, upgradeToAndCall) owned by Zama. Pin your integration to the proxy addresses on the addresses page, never to implementations.

Last updated on