Tokens

This set of interfaces, contracts, and utilities are all related to ERC7984, an evolving confidential token standard. The standard utilizes the Zama fhEVM co-processor for manipulating FHE values. All amounts are stored on-chain as ciphertext handles (or pointers) to values stored on the co-processor.

Core

ERC7984

import "@openzeppelin/confidential-contracts/token/ERC7984/ERC7984.sol";

Reference implementation for IERC7984.

This contract implements a fungible token where balances and transfers are encrypted using the Zama fhEVM, providing confidentiality to users. Token amounts are stored as encrypted, unsigned integers (euint64) that can only be decrypted by authorized parties.

Key features:

  • All balances are encrypted

  • Transfers happen without revealing amounts

  • Support for operators (delegated transfer capabilities with time bounds)

  • Transfer and call pattern

  • Safe overflow/underflow handling for FHE operations

Functions
  • constructor(name_, symbol_, contractURI_)

  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

  • _update(from, to, amount)

Events
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

constructor(string name_, string symbol_, string contractURI_) internal

supportsInterface(bytes4 interfaceId) → bool public

Returns true if this contract implements the interface defined by interfaceId. See the corresponding ERC section to learn more about how these ids are created.

This function call must use less than 30 000 gas.

name() → string public

Returns the name of the token.

symbol() → string public

Returns the symbol of the token.

decimals() → uint8 public

Returns the number of decimals of the token. Recommended to be 6.

contractURI() → string public

Returns the contract URI. See ERC-7572 for details.

confidentialTotalSupply() → euint64 public

Returns the confidential total supply of the token.

confidentialBalanceOf(address account) → euint64 public

Returns the confidential balance of the account account.

isOperator(address holder, address spender) → bool public

Returns true if spender is currently an operator for holder.

setOperator(address operator, uint48 until) public

See IERC7984.setOperator. Operators are given ACL allowance (ability to decrypt) for the transferred amount of transfers they initiate.

confidentialTransfer(address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64 public

Transfers the encrypted amount encryptedAmount to to with the given input proof inputProof.

Returns the encrypted amount that was actually transferred.

confidentialTransfer(address to, euint64 amount) → euint64 public

Similar to confidentialTransfer but without an input proof. The caller must already be allowed by ACL for the given amount.

confidentialTransferFrom(address from, address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64 public

Transfers the encrypted amount encryptedAmount from from to to with the given input proof inputProof. msg.sender must be either from or an operator for from.

Returns the encrypted amount that was actually transferred.

confidentialTransferFrom(address from, address to, euint64 amount) → euint64 public

Similar to confidentialTransferFrom but without an input proof. The caller must be already allowed by ACL for the given amount.

confidentialTransferAndCall(address to, externalEuint64 encryptedAmount, bytes inputProof, bytes data) → euint64 public

Similar to confidentialTransfer but with a callback to to after the transfer.

The callback is made to the IERC7984Receiver.onConfidentialTransferReceived function on the to address with the actual transferred amount (may differ from the given encryptedAmount) and the given data data.

confidentialTransferAndCall(address to, euint64 amount, bytes data) → euint64 public

Similar to confidentialTransfer but with a callback to to after the transfer.

confidentialTransferFromAndCall(address from, address to, externalEuint64 encryptedAmount, bytes inputProof, bytes data) → euint64 public

Similar to confidentialTransferFrom but with a callback to to after the transfer.

confidentialTransferFromAndCall(address from, address to, euint64 amount, bytes data) → euint64 public

Similar to confidentialTransferFrom but with a callback to to after the transfer.

requestDiscloseEncryptedAmount(euint64 encryptedAmount) public

Starts the process to disclose an encrypted amount encryptedAmount publicly by making it publicly decryptable. Emits the AmountDiscloseRequested event.

Both msg.sender and address(this) must have permission to access the encrypted amount encryptedAmount to request disclosure of the encrypted amount encryptedAmount.

discloseEncryptedAmount(euint64 encryptedAmount, uint64 cleartextAmount, bytes decryptionProof) public

Publicly discloses an encrypted value with a given decryption proof. Emits the {AmountDisclosed} event.

May not be tied to a prior request via requestDiscloseEncryptedAmount.

_setOperator(address holder, address operator, uint48 until) internal

_mint(address to, euint64 amount) → euint64 transferred internal

_burn(address from, euint64 amount) → euint64 transferred internal

_transfer(address from, address to, euint64 amount) → euint64 transferred internal

_transferAndCall(address from, address to, euint64 amount, bytes data) → euint64 transferred internal

Transfers the given amount of tokens from from to to and calls the onConfidentialTransferReceived function on the recipient.

The token contract initiates a second transfer refunding the tokens from the recipient to the sender—​the amount is 0 if the callback succeeds, otherwise the amount is the amount that was transferred.

The returned transferred amount is a fresh ciphertext computed as sent - refund and msg.sender only receives a transient FHE allowance for it. This value is generally intended to be processed only in the same transaction. Event observers see sent and refund individually.

The refund triggered when IERC7984Receiver.onConfidentialTransferReceived returns an encrypted false is best-effort only. A receiver that transfers, burns, or otherwise reduces its balance during the hook can still return false, in which case the refund transfers zero tokens. The sender’s tokens end up with the recipient rather than being refunded.
Refunds are subject to the same validation flow as a normal transfer—​they may fail for a variety of reasons (such as failed hook validation in ERC7984Hooked). In these cases, the tokens do not return to the sender.

_update(address from, address to, euint64 amount) → euint64 transferred internal

Safely moves up to amount from from to to, or mints/burns if from/to is the zero address. Emits a confidentialTransfer event with the successfully transferred amount.

AmountDiscloseRequested(euint64 indexed encryptedAmount, address indexed requester) event

Emitted when an encrypted amount encryptedAmount is requested for disclosure by requester.

ERC7984InvalidReceiver(address receiver) error

The given receiver receiver is invalid for transfers.

ERC7984InvalidSender(address sender) error

The given sender sender is invalid for transfers.

ERC7984UnauthorizedSpender(address holder, address spender) error

The given holder holder is not authorized to spend on behalf of spender.

ERC7984UnauthorizedUseOfEncryptedAmount(euint64 amount, address user) error

The caller user does not have access to the encrypted amount amount.

Try using the equivalent transfer function with an input proof.

ERC7984UnauthorizedCaller(address caller) error

The given caller caller is not authorized for the current operation.

Extensions

ERC7984ERC20Wrapper

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol";

A wrapper contract built on top of ERC7984 that allows wrapping an ERC20 token into an ERC7984 token. The wrapper contract implements the IERC1363Receiver interface which allows users to transfer ERC1363 tokens directly to the wrapper with a callback to wrap the tokens.

Minting assumes the full amount of the underlying token transfer has been received, hence some non-standard tokens such as fee-on-transfer or other deflationary-type tokens are not supported by this wrapper.
Functions
  • constructor(underlying_)

  • onTransferReceived(, from, amount, data)

  • wrap(to, amount)

  • unwrap(from, to, amount)

  • unwrap(from, to, encryptedAmount, inputProof)

  • finalizeUnwrap(unwrapRequestId, unwrapAmountCleartext, decryptionProof)

  • decimals()

  • rate()

  • underlying()

  • unwrapAmount(unwrapRequestId)

  • supportsInterface(interfaceId)

  • inferredTotalSupply()

  • maxTotalSupply()

  • unwrapRequester(unwrapRequestId)

  • _checkConfidentialTotalSupply()

  • _update(from, to, amount)

  • _unwrap(from, to, amount)

  • _fallbackUnderlyingDecimals()

  • _maxDecimals()

ERC7984
  • name()

  • symbol()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
IERC7984ERC20Wrapper
  • UnwrapRequested(receiver, unwrapRequestId, amount)

  • UnwrapFinalized(receiver, unwrapRequestId, encryptedAmount, cleartextAmount)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • InvalidUnwrapRequest(unwrapRequestId)

  • ERC7984TotalSupplyOverflow()

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

constructor(contract IERC20 underlying_) internal

onTransferReceived(address, address from, uint256 amount, bytes data) → bytes4 public

ERC1363 callback function which wraps tokens to the address specified in data or the address from (if no address is specified in data). This function refunds any excess tokens sent beyond the nearest multiple of rate to from. See wrap for more details on wrapping tokens.

wrap(address to, uint256 amount) → euint64 public

See IERC7984ERC20Wrapper.wrap. Tokens are exchanged at a fixed rate specified by rate such that amount / rate() confidential tokens are sent. The amount transferred in is rounded down to the nearest multiple of rate.

Returns the amount of wrapped token sent.

unwrap(address from, address to, euint64 amount) → bytes32 public

Unwrap without passing an input proof. See {unwrap-address-address-bytes32-bytes} for more details.

unwrap(address from, address to, externalEuint64 encryptedAmount, bytes inputProof) → bytes32 public

See IERC7984ERC20Wrapper.unwrap. amount * rate() underlying tokens are sent to to.

The unwrap request created by this function must be finalized by calling finalizeUnwrap.

finalizeUnwrap(bytes32 unwrapRequestId, uint64 unwrapAmountCleartext, bytes decryptionProof) public

Finalizes an unwrap request identified by unwrapRequestId with the given unwrapAmountCleartext and decryptionProof.

decimals() → uint8 public

Returns the number of decimals of the token. Recommended to be 6.

rate() → uint256 public

Returns the rate at which the underlying token is converted to the wrapped token. For example, if the rate is 1000, then 1000 units of the underlying token equal 1 unit of the wrapped token.

underlying() → address public

Returns the address of the underlying ERC-20 token that is being wrapped.

unwrapAmount(bytes32 unwrapRequestId) → euint64 public

Returns the amount of wrapper tokens that were unwrapped for a given unwrapRequestId.

supportsInterface(bytes4 interfaceId) → bool public

Returns true if this contract implements the interface defined by interfaceId. See the corresponding ERC section to learn more about how these ids are created.

This function call must use less than 30 000 gas.

inferredTotalSupply() → uint256 public

Returns the underlying balance divided by the rate, a value greater or equal to the actual confidentialTotalSupply.

The return value of this function can be inflated by directly sending underlying tokens to the wrapper contract. Reductions will lag compared to confidentialTotalSupply since it is updated on unwrap while this function updates on finalizeUnwrap.

maxTotalSupply() → uint256 public

Returns the maximum total supply of wrapped tokens supported by the encrypted datatype.

unwrapRequester(bytes32 unwrapRequestId) → address public

Gets the address that will receive the ERC-20 tokens associated with a pending unwrap request identified by unwrapRequestId. Returns address(0) if there is no pending unwrap request with id unwrapRequestId.

_checkConfidentialTotalSupply() internal

This function must revert if the new confidentialTotalSupply is invalid (overflow occurred).

Overflow can be detected here since the wrapper holdings are non-confidential. In other cases, it may be impossible to infer total supply overflow synchronously. This function may revert even if the confidentialTotalSupply did not overflow.

_update(address from, address to, euint64 amount) → euint64 internal

Safely moves up to amount from from to to, or mints/burns if from/to is the zero address. Emits a confidentialTransfer event with the successfully transferred amount.

_unwrap(address from, address to, euint64 amount) → bytes32 internal

Internal logic for handling the creation of unwrap requests. Returns the unwrap request id.

_fallbackUnderlyingDecimals() → uint8 internal

Returns the default number of decimals of the underlying ERC-20 token that is being wrapped. Used as a default fallback when {_tryGetAssetDecimals} fails to fetch decimals of the underlying ERC-20 token.

_maxDecimals() → uint8 internal

Returns the maximum number that will be used for decimals by the wrapper.

InvalidUnwrapRequest(bytes32 unwrapRequestId) error

ERC7984TotalSupplyOverflow() error

ERC7984Freezable

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Freezable.sol";

Extension of ERC7984 that implements a confidential freezing mechanism that can be managed by calling the internal function _setConfidentialFrozen by an inheriting contract.

The freezing mechanism provides the guarantee that a specific confidential amount of tokens held by an account won’t be transferable until those tokens are unfrozen.

Functions
  • confidentialFrozen(account)

  • confidentialAvailable(account)

  • _confidentialAvailable(account)

  • _setConfidentialFrozen(account, encryptedAmount)

  • _update(from, to, encryptedAmount)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
  • TokensFrozen(account, encryptedAmount)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

confidentialFrozen(address account) → euint64 public

Returns the confidential frozen balance of an account.

confidentialAvailable(address account) → euint64 public

Returns the confidential available (unfrozen) balance of an account. Gives ACL allowance to account.

_confidentialAvailable(address account) → euint64 internal

Internal function to calculate the available balance of an account. Does not give any allowances.

_setConfidentialFrozen(address account, euint64 encryptedAmount) internal

Internal function to freeze a confidential amount of tokens for an account.

_update(address from, address to, euint64 encryptedAmount) → euint64 internal

The from account must have sufficient unfrozen balance, otherwise 0 tokens are transferred. The default freezing behavior can be changed (for a pass-through for instance) by overriding _confidentialAvailable. The internal function is used for actual gating (not the public function) to avoid unnecessarily granting ACL allowances.

TokensFrozen(address indexed account, euint64 encryptedAmount) event

Emitted when a confidential amount of token is frozen for an account

ERC7984ObserverAccess

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984ObserverAccess.sol";

Extension of ERC7984 that allows each account to add an observer who is given permanent ACL access to its transfer and balance amounts. An observer can be added or removed at any point in time.

Functions
  • setObserver(account, newObserver)

  • observer(account)

  • _update(from, to, amount)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
  • ERC7984ObserverAccessObserverSet(account, oldObserver, newObserver)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • Unauthorized()

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

setObserver(address account, address newObserver) public

Sets the observer for the given account account to newObserver. Can be called by the account or the existing observer to abdicate the observer role (may only set to address(0)).

observer(address account) → address public

Returns the observer for the given account account.

_update(address from, address to, euint64 amount) → euint64 transferred internal

Safely moves up to amount from from to to, or mints/burns if from/to is the zero address. Emits a confidentialTransfer event with the successfully transferred amount.

ERC7984ObserverAccessObserverSet(address account, address oldObserver, address newObserver) event

Emitted when the observer is changed for the given account account.

Unauthorized() error

Thrown when an account tries to set a newObserver for a given account without proper authority.

ERC7984Restricted

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Restricted.sol";

Extension of ERC7984 that implements user account transfer restrictions through the canTransact function. Inspired by https://github.com/OpenZeppelin/openzeppelin-community-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Restricted.sol.

By default, each account has no explicit restriction. The canTransact function acts as a blocklist. Developers can override canTransact to check that restriction == ALLOWED to implement an allowlist.

Functions
  • getRestriction(account)

  • canTransact(account)

  • _update(from, to, value)

  • _setRestriction(account, restriction)

  • _blockUser(account)

  • _allowUser(account)

  • _resetUser(account)

  • _checkRestriction(account)

  • _checkSenderRestriction(account)

  • _checkRecipientRestriction(account)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
  • UserRestrictionUpdated(account, restriction)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • UserRestricted(account)

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

getRestriction(address account) → enum ERC7984Restricted.Restriction public

Returns the restriction of a user account.

canTransact(address account) → bool public

Returns whether a user account is allowed to receive or send tokens.

Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).

_update(address from, address to, euint64 value) → euint64 internal

See ERC7984._update. Enforces transfer restrictions.

Requirements:

  • from must be allowed to transfer tokens (see canTransact).

  • to must be allowed to receive tokens (see canTransact).

The default restriction behavior can be changed (for a pass-through for instance) by overriding _checkSenderRestriction and/or _checkRecipientRestriction.

_setRestriction(address account, enum ERC7984Restricted.Restriction restriction) internal

Updates the restriction of a user account.

_blockUser(address account) internal

Convenience function to block a user account (set to BLOCKED).

_allowUser(address account) internal

Convenience function to allow a user account (set to ALLOWED).

_resetUser(address account) internal

Convenience function to reset a user account to default restriction.

_checkRestriction(address account) internal

Checks if a user account is restricted. Reverts with UserRestricted if so.

_checkSenderRestriction(address account) internal

Internal function which checks restriction of the from account before a transfer. Working with _update function.

_checkRecipientRestriction(address account) internal

Internal function which checks restriction of the to account before a transfer. Working with _update function.

UserRestrictionUpdated(address indexed account, enum ERC7984Restricted.Restriction restriction) event

Emitted when a user account’s restriction is updated.

UserRestricted(address account) error

The operation failed because the user account is restricted.

ERC7984Omnibus

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Omnibus.sol";

Extension of ERC7984 that emits additional events for omnibus transfers. These events contain encrypted addresses for the sub-account sender and recipient.

There is no onchain accounting for sub-accounts—​integrators must track sub-account balances externally.
Functions
  • confidentialTransferOmnibus(omnibusTo, externalSender, externalRecipient, externalAmount, inputProof)

  • confidentialTransferOmnibus(omnibusTo, sender, recipient, amount)

  • confidentialTransferFromOmnibus(omnibusFrom, omnibusTo, externalSender, externalRecipient, externalAmount, inputProof)

  • confidentialTransferFromOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount)

  • confidentialTransferAndCallOmnibus(omnibusTo, externalSender, externalRecipient, externalAmount, inputProof, data)

  • confidentialTransferAndCallOmnibus(omnibusTo, sender, recipient, amount, data)

  • confidentialTransferFromAndCallOmnibus(omnibusFrom, omnibusTo, externalSender, externalRecipient, externalAmount, inputProof, data)

  • confidentialTransferFromAndCallOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount, data)

  • _confidentialTransferFromOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount)

  • _confidentialTransferFromAndCallOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount, data)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

  • _update(from, to, amount)

Events
  • OmnibusConfidentialTransfer(omnibusFrom, omnibusTo, sender, recipient, amount)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • ERC7984UnauthorizedUseOfEncryptedAddress(addr, user)

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

confidentialTransferOmnibus(address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof) → euint64 public

Wraps the confidentialTransfer function and emits the OmnibusConfidentialTransfer event.

confidentialTransferOmnibus(address omnibusTo, eaddress sender, eaddress recipient, euint64 amount) → euint64 public

Wraps the confidentialTransfer function and emits the OmnibusConfidentialTransfer event.

confidentialTransferFromOmnibus(address omnibusFrom, address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof) → euint64 public

Wraps the confidentialTransferFrom function and emits the OmnibusConfidentialTransfer event.

confidentialTransferFromOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount) → euint64 public

Wraps the confidentialTransferFrom function and emits the OmnibusConfidentialTransfer event.

confidentialTransferAndCallOmnibus(address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof, bytes data) → euint64 public

Wraps the confidentialTransferAndCall function and emits the OmnibusConfidentialTransfer event.

confidentialTransferAndCallOmnibus(address omnibusTo, eaddress sender, eaddress recipient, euint64 amount, bytes data) → euint64 public

Wraps the confidentialTransferAndCall function and emits the OmnibusConfidentialTransfer event.

confidentialTransferFromAndCallOmnibus(address omnibusFrom, address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof, bytes data) → euint64 public

Wraps the confidentialTransferFromAndCall function and emits the OmnibusConfidentialTransfer event.

confidentialTransferFromAndCallOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount, bytes data) → euint64 public

Wraps the confidentialTransferFromAndCall function and emits the OmnibusConfidentialTransfer event.

_confidentialTransferFromOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount) → euint64 internal

Handles the ACL allowances, does the transfer without a callback, and emits OmnibusConfidentialTransfer.

_confidentialTransferFromAndCallOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount, bytes data) → euint64 internal

Handles the ACL allowances, does the transfer with a callback, and emits OmnibusConfidentialTransfer.

OmnibusConfidentialTransfer(address indexed omnibusFrom, address indexed omnibusTo, eaddress sender, eaddress indexed recipient, euint64 amount) event

Emitted when a confidential transfer is made representing the onchain settlement of an omnibus transfer from sender to recipient of amount amount. Settlement occurs between omnibusFrom and omnibusTo and is represented in a matching IERC7984.ConfidentialTransfer event.

omnibusFrom and omnibusTo get permanent ACL allowances for sender and recipient.

ERC7984UnauthorizedUseOfEncryptedAddress(eaddress addr, address user) error

The caller user does not have access to the encrypted address addr.

Try using the equivalent transfer function with an input proof.

ERC7984Rwa

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Rwa.sol";

Extension of ERC7984 that supports confidential Real World Assets (RWAs). This interface provides compliance checks, transfer controls and enforcement actions.

Modifiers
  • onlyAdmin()

  • onlyAgent()

Functions
  • constructor(admin)

  • supportsInterface(interfaceId)

  • isAdmin(account)

  • isAgent(account)

  • addAgent(account)

  • removeAgent(account)

  • pause()

  • unpause()

  • blockUser(account)

  • unblockUser(account)

  • setConfidentialFrozen(account, encryptedAmount, inputProof)

  • setConfidentialFrozen(account, encryptedAmount)

  • confidentialMint(to, encryptedAmount, inputProof)

  • confidentialMint(to, encryptedAmount)

  • confidentialBurn(account, encryptedAmount, inputProof)

  • confidentialBurn(account, encryptedAmount)

  • recoverAddress(lostAccount, newAccount)

  • forceConfidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • forceConfidentialTransferFrom(from, to, encryptedAmount)

  • confidentialAvailable(account)

  • confidentialFrozen(account)

  • paused()

  • canTransact(account)

  • _update(from, to, encryptedAmount)

  • _checkSenderRestriction(account)

  • _checkRecipientRestriction(account)

  • _requireNotPaused()

  • _isForceTransfer(selector)

  • _msgSender()

  • _msgData()

  • AGENT_ROLE()

AccessControl
  • hasRole(role, account)

  • _checkRole(role)

  • _checkRole(role, account)

  • getRoleAdmin(role)

  • grantRole(role, account)

  • revokeRole(role, account)

  • renounceRole(role, callerConfirmation)

  • _setRoleAdmin(role, adminRole)

  • _grantRole(role, account)

  • _revokeRole(role, account)

  • DEFAULT_ADMIN_ROLE()

Multicall
  • multicall(data)

Pausable
  • _requirePaused()

  • _pause()

  • _unpause()

ERC7984Restricted
  • getRestriction(account)

  • _setRestriction(account, restriction)

  • _blockUser(account)

  • _allowUser(account)

  • _resetUser(account)

  • _checkRestriction(account)

ERC7984Freezable
  • _confidentialAvailable(account)

  • _setConfidentialFrozen(account, encryptedAmount)

ERC7984
  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
Pausable
  • Paused(account)

  • Unpaused(account)

ERC7984Restricted
  • UserRestrictionUpdated(account, restriction)

ERC7984Freezable
  • TokensFrozen(account, encryptedAmount)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984Rwa
  • TokensRecovered(lostAccount, newAccount, amount)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

IAccessControl
  • RoleAdminChanged(role, previousAdminRole, newAdminRole)

  • RoleGranted(role, account, sender)

  • RoleRevoked(role, account, sender)

Errors
  • ERC7984RwaSelfRecoveryNotAllowed()

Pausable
  • EnforcedPause()

  • ExpectedPause()

ERC7984Restricted
  • UserRestricted(account)

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

IAccessControl
  • AccessControlUnauthorizedAccount(account, neededRole)

  • AccessControlBadConfirmation()

onlyAdmin() modifier

Checks if the sender is an admin.

onlyAgent() modifier

Checks if the sender is an agent.

constructor(address admin) internal

supportsInterface(bytes4 interfaceId) → bool public

isAdmin(address account) → bool public

Returns true if has admin role, false otherwise.

isAgent(address account) → bool public

Returns true if agent, false otherwise.

addAgent(address account) public

Adds agent.

removeAgent(address account) public

Removes agent.

pause() public

Pauses contract.

unpause() public

Unpauses contract.

blockUser(address account) public

Blocks a user account.

unblockUser(address account) public

Unblocks a user account.

setConfidentialFrozen(address account, externalEuint64 encryptedAmount, bytes inputProof) public

Sets confidential frozen for an account with proof.

setConfidentialFrozen(address account, euint64 encryptedAmount) public

Sets confidential frozen for an account.

confidentialMint(address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64 public

Mints confidential amount of tokens to account with proof.

confidentialMint(address to, euint64 encryptedAmount) → euint64 public

Mints confidential amount of tokens to account.

confidentialBurn(address account, externalEuint64 encryptedAmount, bytes inputProof) → euint64 public

Burns confidential amount of tokens from account with proof.

confidentialBurn(address account, euint64 encryptedAmount) → euint64 public

Burns confidential amount of tokens from account.

recoverAddress(address lostAccount, address newAccount) → euint64 public

Recovers the address of a lost account to a new account.

forceConfidentialTransferFrom(address from, address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64 public

Variant of forceConfidentialTransferFrom with an input proof.

forceConfidentialTransferFrom(address from, address to, euint64 encryptedAmount) → euint64 public

Force transfer callable by the role AGENT_ROLE which transfers tokens from from to to and bypasses the ERC7984Restricted (only on from) and Pausable checks. Frozen tokens are not transferred and must be unfrozen first.

confidentialAvailable(address account) → euint64 public

Returns the confidential available (unfrozen) balance of an account. Gives ACL allowance to account.

confidentialFrozen(address account) → euint64 public

Returns the confidential frozen balance of an account.

paused() → bool public

Returns true if the contract is paused, and false otherwise.

canTransact(address account) → bool public

Returns whether a user account is allowed to receive or send tokens.

Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).

_update(address from, address to, euint64 encryptedAmount) → euint64 internal

Internal function which updates confidential balances while performing frozen and restriction compliance checks.

_checkSenderRestriction(address account) internal

Bypasses ERC7984Restricted from restriction check when performing a forced transfer or token recovery.

_checkRecipientRestriction(address account) internal

Bypasses ERC7984Restricted to restriction check when performing a forced transfer or token recovery.

_requireNotPaused() internal

Bypasses {Pausable} check when performing a forceConfidentialTransferFrom.

_isForceTransfer(bytes4 selector) → bool internal

Internal function which checks if the current function call should be treated as a force transfer.

_msgSender() → address internal

Restrict overrides of {Context._msgSender}. Please use other account abstraction methods instead.

_msgData() → bytes internal

Restrict overrides of {Context._msgData}. Please use other account abstraction methods instead.

AGENT_ROLE() → bytes32 public

Accounts granted the agent role have the following permissioned abilities:

  • Mint/Burn to/from a given address (does not require permission)

  • Force transfer from a given address (does not require permission)

    • Bypasses pause and restriction checks (not frozen)

  • Pause/Unpause the contract

  • Block/Unblock a given account

  • Set frozen amount of tokens for a given account.

ERC7984RwaSelfRecoveryNotAllowed() error

The operation failed because the lost account is the same as the new account.

ERC7984Votes

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Votes.sol";

Extension of ERC7984 supporting confidential votes tracking and delegation.

The amount of confidential voting units an account has is equal to the balance of that account. Voting power is taken into account when an account delegates votes to itself or to another account.

Functions
  • confidentialTotalSupply()

  • _update(from, to, amount)

  • _getVotingUnits(account)

VotesConfidential
  • clock()

  • CLOCK_MODE()

  • getVotes(account)

  • getPastVotes(account, timepoint)

  • getPastTotalSupply(timepoint)

  • delegates(account)

  • delegate(delegatee)

  • delegateBySig(delegatee, nonce, expiry, v, r, s)

  • _delegate(account, delegatee)

  • _transferVotingUnits(from, to, amount)

  • _moveDelegateVotes(from, to, amount)

  • _validateTimepoint(timepoint)

HandleAccessManager
  • getHandleAllowance(handle, account, persistent)

  • _validateHandleAllowance()

EIP712
  • _domainSeparatorV4()

  • _hashTypedDataV4(structHash)

  • eip712Domain()

  • _EIP712Name()

  • _EIP712Version()

Nonces
  • nonces(owner)

  • _useNonce(owner)

  • _useCheckedNonce(owner, nonce)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
VotesConfidential
  • DelegateVotesChanged(delegate, previousVotes, newVotes)

  • DelegateChanged(delegator, fromDelegate, toDelegate)

IERC5267
  • EIP712DomainChanged()

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
VotesConfidential
  • VotesExpiredSignature(expiry)

  • ERC6372InconsistentClock()

  • ERC5805FutureLookup(timepoint, clock)

HandleAccessManager
  • HandleAccessManagerNotAllowed(handle, account)

Nonces
  • InvalidAccountNonce(account, currentNonce)

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

confidentialTotalSupply() → euint64 public

Returns the confidential total supply of the token.

_update(address from, address to, euint64 amount) → euint64 transferred internal

Safely moves up to amount from from to to, or mints/burns if from/to is the zero address. Emits a confidentialTransfer event with the successfully transferred amount.

_getVotingUnits(address account) → euint64 internal

ERC7984Hooked

import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Hooked.sol";

Extension of ERC7984 that supports hook modules. Inspired by ERC-7579 modules.

Modules are called before and after transfers. Before the transfer, modules conduct checks to see if they approve the given transfer and return an encrypted boolean. If any module returns false, the transferred amount becomes 0. After the transfer, modules are notified of the final transfer amount and may do accounting as necessary. Modules may revert on either call, which will propagate and revert the entire transaction.

Hook modules are trusted contracts—​they have access to any private state the token has access to. This arbitrary ACL access allows hook modules to grant themselves (or any other address) allowance to view any handle the token has access to. ACL allowances granted by the hook module persist even after the module is uninstalled.
Modifiers
  • onlyAuthorizedModuleChange()

Functions
  • isModuleInstalled(module)

  • installModule(module, initData)

  • uninstallModule(module)

  • modules(start, end)

  • maxModules()

  • _authorizeModuleChange()

  • _installModule(module, initData)

  • _uninstallModule(module)

  • _update(from, to, encryptedAmount)

  • _runPreTransferHooks(from, to, encryptedAmount)

  • _runPostTransferHooks(from, to, encryptedAmount)

  • _validateHandleAllowance(handle)

HandleAccessManager
  • getHandleAllowance(handle, account, persistent)

ERC7984
  • supportsInterface(interfaceId)

  • name()

  • symbol()

  • decimals()

  • contractURI()

  • confidentialTotalSupply()

  • confidentialBalanceOf(account)

  • isOperator(holder, spender)

  • setOperator(operator, until)

  • confidentialTransfer(to, encryptedAmount, inputProof)

  • confidentialTransfer(to, amount)

  • confidentialTransferFrom(from, to, encryptedAmount, inputProof)

  • confidentialTransferFrom(from, to, amount)

  • confidentialTransferAndCall(to, encryptedAmount, inputProof, data)

  • confidentialTransferAndCall(to, amount, data)

  • confidentialTransferFromAndCall(from, to, encryptedAmount, inputProof, data)

  • confidentialTransferFromAndCall(from, to, amount, data)

  • requestDiscloseEncryptedAmount(encryptedAmount)

  • discloseEncryptedAmount(encryptedAmount, cleartextAmount, decryptionProof)

  • _setOperator(holder, operator, until)

  • _mint(to, amount)

  • _burn(from, amount)

  • _transfer(from, to, amount)

  • _transferAndCall(from, to, amount, data)

Events
  • ERC7984HookedModuleInstalled(module)

  • ERC7984HookedModuleUninstalled(module)

ERC7984
  • AmountDiscloseRequested(encryptedAmount, requester)

IERC7984
  • OperatorSet(holder, operator, until)

  • ConfidentialTransfer(from, to, amount)

  • AmountDisclosed(encryptedAmount, amount)

Errors
  • ERC7984HookedInvalidModule(module)

  • ERC7984HookedDuplicateModule(module)

  • ERC7984HookedNonexistentModule(module)

  • ERC7984HookedExceededMaxModules()

HandleAccessManager
  • HandleAccessManagerNotAllowed(handle, account)

ERC7984
  • ERC7984InvalidReceiver(receiver)

  • ERC7984InvalidSender(sender)

  • ERC7984UnauthorizedSpender(holder, spender)

  • ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)

  • ERC7984UnauthorizedCaller(caller)

onlyAuthorizedModuleChange() modifier

isModuleInstalled(address module) → bool public

Checks if a module is installed.

installModule(address module, bytes initData) public

Installs a hook module.

Consider gas footprint of the module before adding it since all modules will perform both steps (pre-hook, post-hook) on all transfers.

uninstallModule(address module) public

Uninstalls a hook module.

modules(uint256 start, uint256 end) → address[] public

Returns a slice of the list of modules installed on the token with inclusive start and exclusive end.

Use an end value of type(uint256).max to get the entire list of modules.

maxModules() → uint256 public

Returns the maximum number of modules that can be installed.

_authorizeModuleChange() internal

Authorization logic for installing and uninstalling modules. Must be implemented by the concrete contract.

_installModule(address module, bytes initData) internal

Internal function which installs a hook module.

_uninstallModule(address module) internal

Internal function which uninstalls a module.

_update(address from, address to, euint64 encryptedAmount) → euint64 transferred internal

Modified to run pre and post transfer hooks. Zero tokens are transferred if a module does not approve the transfer.

_runPreTransferHooks(address from, address to, euint64 encryptedAmount) → ebool compliant internal

Runs the pre-transfer hooks for all modules.

_runPostTransferHooks(address from, address to, euint64 encryptedAmount) internal

Runs the post-transfer hooks for all modules.

_validateHandleAllowance(bytes32 handle) → bool internal

See HandleAccessManager._validateHandleAllowance. Allow modules to access any handle the token has access to.

ERC7984HookedModuleInstalled(address module) event

Emitted when a module is installed.

ERC7984HookedModuleUninstalled(address module) event

Emitted when a module is uninstalled.

ERC7984HookedInvalidModule(address module) error

The address is not a valid module.

ERC7984HookedDuplicateModule(address module) error

The module is already installed.

ERC7984HookedNonexistentModule(address module) error

The module is not installed.

ERC7984HookedExceededMaxModules() error

The maximum number of modules has been exceeded.

Utilities

ERC7984Utils

import "@openzeppelin/confidential-contracts/token/ERC7984/utils/ERC7984Utils.sol";

Library that provides common ERC7984 utility functions.

Functions
  • checkOnTransferReceived(operator, from, to, amount, data)

checkOnTransferReceived(address operator, address from, address to, euint64 amount, bytes data) → ebool internal

Performs a transfer callback to the recipient of the transfer to. Should be invoked after all transfers "withCallback" on a ERC7984.

The transfer callback is not invoked on the recipient if the recipient has no code (i.e. is an EOA). If the recipient has non-zero code, it must implement IERC7984Receiver.onConfidentialTransferReceived and return an ebool indicating whether the transfer was accepted or not. If the ebool is false, the transfer function should try to refund the from address.

ERC7984HookModule

import "@openzeppelin/confidential-contracts/token/ERC7984/utils/ERC7984HookModule.sol";

An abstract base contract for building ERC-7984 hook modules. Compatible with ERC7984Hooked.

Functions
  • preTransfer(from, to, encryptedAmount)

  • postTransfer(from, to, encryptedAmount)

  • onInstall(initData)

  • supportsInterface(interfaceId)

  • _onInstall(, )

  • _preTransfer(, , , )

  • _postTransfer(, , , )

  • _getTokenHandleAllowance(token, handle)

  • _getTokenHandleAllowance(token, handle, persistent)

  • _emitPreTransferResults(token, from, to, encryptedAmount, compliant, context)

  • _accessHandle(token, handle)

Events
IERC7984HookModule
  • ERC7984HookModuleResult(token, from, to, encryptedAmount, result, context)

Errors
  • ERC7984HookModuleUnauthorizedAccount(account)

  • ERC7984HookModuleUnauthorizedUseOfEncryptedAmount(amount, user)

preTransfer(address from, address to, euint64 encryptedAmount) → ebool public

Hook that runs before a transfer. Should not mutate token state. Module is already granted transient access to encryptedAmount.

postTransfer(address from, address to, euint64 encryptedAmount) public

Performs operation after transfer.

onInstall(bytes initData) public

Performs operations after installation.

supportsInterface(bytes4 interfaceId) → bool public

Returns true if this contract implements the interface defined by interfaceId. See the corresponding ERC section to learn more about how these ids are created.

This function call must use less than 30 000 gas.

_onInstall(address, bytes) internal

Internal function which may be overridden by the derived contract to perform actions when the module is installed. Should clean up dirty state from possible previous installations.

_preTransfer(address, address, address, euint64) → ebool internal

Internal function which runs before a transfer. Transient access is already granted to the module for encryptedAmount. If additional handle access is needed from the token, call _getTokenHandleAllowance.

ACL allowance on encryptedAmount is already checked for msg.sender in preTransfer.

_postTransfer(address, address, address, euint64) internal

Internal function which performs operations after transfers. Transient access is already granted to the module for encryptedAmount. If additional handle access is needed from the token, call _getTokenHandleAllowance.

ACL allowance on encryptedAmount is already checked for msg.sender in postTransfer.

_getTokenHandleAllowance(address token, euint64 handle) internal

Allow modules to get access to token handles during transaction.

_getTokenHandleAllowance(address token, euint64 handle, bool persistent) internal

Allow modules to get access to token handles.

_emitPreTransferResults(address token, address from, address to, euint64 encryptedAmount, ebool compliant, bytes32 context) internal

Optionally emit the result of the pre-transfer hook.

Grants persistent ACL on compliant to both this contract and from.

_accessHandle(address token, euint64 handle) internal

Get transient ACL allowance for the given handle from a contract that inherits HandleAccessManager.

Additionally verifies that the token is authorized to access the handle.

ERC7984HookModuleUnauthorizedAccount(address account) error

The caller account is not authorized to perform the operation.

ERC7984HookModuleUnauthorizedUseOfEncryptedAmount(euint64 amount, address user) error

The caller user does not have access to the encrypted amount amount.

ERC7984BalanceCapHookModule

import "@openzeppelin/confidential-contracts/token/ERC7984/utils/ERC7984BalanceCapHookModule.sol";

An ERC-7984 hook module that limits the balance of each investor.

The cap is stored as an encrypted euint64 value. The pre-transfer hook compares the recipient’s prospective balance to the encrypted cap and emits an encrypted compliance result via ERC7984HookModule._emitPreTransferResults.

This module is compatible with ERC7984Hooked.

This module notifies senders of the result of the pre-transfer hook. This can be used to leak information about the balance of the recipient. This is a potential security risk and should be used with caution. Production use-cases may want to remove this notification.
Functions
  • setMaxBalance(token, newMaxBalance, inputProof)

  • maxBalance(token)

  • _setMaxBalance(token, newMaxBalance)

  • _preTransfer(token, from, to, encryptedAmount)

  • _onInstall(token, initData)

ERC7984HookModule
  • preTransfer(from, to, encryptedAmount)

  • postTransfer(from, to, encryptedAmount)

  • onInstall(initData)

  • supportsInterface(interfaceId)

  • _postTransfer(, , , )

  • _getTokenHandleAllowance(token, handle)

  • _getTokenHandleAllowance(token, handle, persistent)

  • _emitPreTransferResults(token, from, to, encryptedAmount, compliant, context)

  • _accessHandle(token, handle)

Events
  • ERC7984BalanceCapHookModuleMaxBalanceSet(token, newMaxBalance)

IERC7984HookModule
  • ERC7984HookModuleResult(token, from, to, encryptedAmount, result, context)

Errors
ERC7984HookModule
  • ERC7984HookModuleUnauthorizedAccount(account)

  • ERC7984HookModuleUnauthorizedUseOfEncryptedAmount(amount, user)

setMaxBalance(address token, externalEuint64 newMaxBalance, bytes inputProof) public

Sets the max balance for a given token token to the encrypted value newMaxBalance.

msg.sender must have the agent role on token.

maxBalance(address token) → euint64 public

Gets the encrypted max balance for a given token token. Returns the zero handle if unset.

_setMaxBalance(address token, euint64 newMaxBalance) internal

Sets the encrypted max balance for a given token, grants the module persistent ACL, and emits an event.

_preTransfer(address token, address from, address to, euint64 encryptedAmount) → ebool result internal

Internal function which runs before a transfer. Transient access is already granted to the module for encryptedAmount. If additional handle access is needed from the token, call _getTokenHandleAllowance.

ACL allowance on encryptedAmount is already checked for msg.sender in preTransfer.

_onInstall(address token, bytes initData) internal

See ERC7984HookModule._onInstall. The initData must contain the initial max balance for the token along with the input proof for the max balance. These are encoded using standard ABI encoding.

ERC7984BalanceCapHookModuleMaxBalanceSet(address indexed token, euint64 newMaxBalance) event

Emitted when the max balance for a given token is set.

ERC7984HolderCapHookModule

import "@openzeppelin/confidential-contracts/token/ERC7984/utils/ERC7984HolderCapHookModule.sol";

An ERC-7984 hook module that limits the number of holders for a given token.

This module must be installed prior to minting any tokens. After the total supply is initialized, it is not possible to guarantee that the number of holders is 0, so the module can not be installed.
This module may not function correctly with non-standard tokens such as fee on transfer.
Functions
  • setMaxHolderCount(token, maxHolderCount_)

  • maxHolderCount(token)

  • holderCount(token)

  • _setMaxHolderCount(token, maxHolderCount_)

  • _preTransfer(token, from, to, encryptedAmount)

  • _postTransfer(token, from, to, encryptedAmount)

  • _onInstall(token, initData)

ERC7984HookModule
  • preTransfer(from, to, encryptedAmount)

  • postTransfer(from, to, encryptedAmount)

  • onInstall(initData)

  • supportsInterface(interfaceId)

  • _getTokenHandleAllowance(token, handle)

  • _getTokenHandleAllowance(token, handle, persistent)

  • _emitPreTransferResults(token, from, to, encryptedAmount, compliant, context)

  • _accessHandle(token, handle)

Events
  • ERC7984HolderCapHookModuleMaxHolderCountSet(token, newMaxHolderCount)

IERC7984HookModule
  • ERC7984HookModuleResult(token, from, to, encryptedAmount, result, context)

Errors
  • ERC7984HolderCapHookModuleInvalidMaxHolderCount(maxHolderCount)

  • ERC7984HolderCapHookModuleTotalSupplyInitialized()

ERC7984HookModule
  • ERC7984HookModuleUnauthorizedAccount(account)

  • ERC7984HookModuleUnauthorizedUseOfEncryptedAmount(amount, user)

setMaxHolderCount(address token, uint64 maxHolderCount_) public

Sets the max number of holders for the given token token to maxHolderCount_.

msg.sender must have the agent role on token

maxHolderCount(address token) → uint64 public

Gets max number of holders for the given token token.

holderCount(address token) → euint64 public

Gets current number of holders for the given token token.

_setMaxHolderCount(address token, uint64 maxHolderCount_) internal

Sets the max holder count for a given token to maxHolderCount_ and emits an event.

_preTransfer(address token, address from, address to, euint64 encryptedAmount) → ebool result internal

Internal function which runs before a transfer. Transient access is already granted to the module for encryptedAmount. If additional handle access is needed from the token, call _getTokenHandleAllowance.

ACL allowance on encryptedAmount is already checked for msg.sender in preTransfer.

_postTransfer(address token, address from, address to, euint64 encryptedAmount) internal

Internal function which performs operations after transfers. Transient access is already granted to the module for encryptedAmount. If additional handle access is needed from the token, call _getTokenHandleAllowance.

ACL allowance on encryptedAmount is already checked for msg.sender in postTransfer.

_onInstall(address token, bytes initData) internal

See ERC7984HookModule._onInstall. The initData must contain the initial max holder count for the token as a standard ABI encoded uint64.

ERC7984HolderCapHookModuleMaxHolderCountSet(address indexed token, uint64 newMaxHolderCount) event

Emitted when the max holder count for a given token is set.

ERC7984HolderCapHookModuleInvalidMaxHolderCount(uint64 maxHolderCount) error

The new max holder count maxHolderCount is invalid.

ERC7984HolderCapHookModuleTotalSupplyInitialized() error