Token
Smart contract token utilities and implementations
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.
ERC7984: Implementation ofIERC7984.ERC7984ERC20Wrapper: Extension ofERC7984which wraps anERC20into a confidential token. The wrapper allows for free conversion in both directions at a fixed rate.ERC7984Freezable: An extension ofERC7984, which allows accounts granted the "freezer" role to freeze and unfreeze tokens.ERC7984ObserverAccess: An extension ofERC7984, which allows each account to add an observer who is given access to their transfer and balance amounts.ERC7984Restricted: An extension ofERC7984that implements user account transfer restrictions.ERC7984Omnibus: An extension ofERC7984that emits additional events for omnibus transfers, which contain encrypted addresses for the sub-account sender and recipient.ERC7984Rwa: Extension ofERC7984that supports confidential Real World Assets (RWAs) by providing compliance checks, transfer controls and enforcement actions.ERC7984Utils: A library that provides the on-transfer callback check used byERC7984.
Core
Extensions
ERC7984ERC20Wrapper
ERC7984Freezable
ERC7984ObserverAccess
ERC7984Restricted
ERC7984Omnibus
ERC7984Rwa
Utilities
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)
ERC165
IERC7984
IERC165
Events
Errors
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.
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
#Sets operator as an operator for holder until the timestamp until.
An operator may transfer any amount of tokens on behalf of a holder while approved.
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 interfaces#IERC7984-confidentialTransfer-address-externalEuint64-bytes- 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 transferred
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 transferred
public
#Similar to interfaces#IERC7984-confidentialTransferFrom-address-address-externalEuint64-bytes- 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 transferred
public
#Similar to interfaces#IERC7984-confidentialTransfer-address-externalEuint64-bytes- 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 transferred
public
#Similar to interfaces#IERC7984-confidentialTransfer-address-euint64- but with a callback to to after the transfer.
confidentialTransferFromAndCall(address from, address to, externalEuint64 encryptedAmount, bytes inputProof, bytes data) → euint64 transferred
public
#Similar to interfaces#IERC7984-confidentialTransferFrom-address-address-externalEuint64-bytes- but with a callback to to
after the transfer.
confidentialTransferFromAndCall(address from, address to, euint64 amount, bytes data) → euint64 transferred
public
#Similar to interfaces#IERC7984-confidentialTransferFrom-address-address-euint64- 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 ERC7984.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 IERC7984.AmountDisclosed event.
May not be tied to a prior request via ERC7984.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
#_update(address from, address to, euint64 amount) → euint64 transferred
internal
#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.
ERC7984ZeroBalance(address holder)
error
#The holder holder is trying to send tokens but has a balance of 0.
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.
ERC7984InvalidGatewayRequest(uint256 requestId)
error
#The given gateway request ID requestId is invalid.
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_)
- decimals()
- rate()
- underlying()
- onTransferReceived(, from, amount, data)
- wrap(to, amount)
- unwrap(from, to, amount)
- unwrap(from, to, encryptedAmount, inputProof)
- finalizeUnwrap(burntAmount, burntAmountCleartext, decryptionProof)
- _unwrap(from, to, amount)
- _fallbackUnderlyingDecimals()
- _maxDecimals()
IERC1363Receiver
ERC7984
- supportsInterface(interfaceId)
- 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)
- _update(from, to, amount)
ERC165
IERC7984
IERC165
Events
Errors
IERC1363Receiver
ERC7984
- ERC7984InvalidReceiver(receiver)
- ERC7984InvalidSender(sender)
- ERC7984UnauthorizedSpender(holder, spender)
- ERC7984ZeroBalance(holder)
- ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)
- ERC7984UnauthorizedCaller(caller)
- ERC7984InvalidGatewayRequest(requestId)
ERC165
IERC7984
IERC165
constructor(contract IERC20 underlying_)
internal
#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() → contract IERC20
public
#Returns the address of the underlying ERC-20 token that is being wrapped.
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 ERC7984ERC20Wrapper.rate. See ERC7984ERC20Wrapper.wrap from more details on wrapping tokens.
wrap(address to, uint256 amount)
public
#Wraps amount amount of the underlying token into a confidential token and sends it to
to. Tokens are exchanged at a fixed rate specified by ERC7984ERC20Wrapper.rate such that amount / rate() confidential
tokens are sent. Amount transferred in is rounded down to the nearest multiple of ERC7984ERC20Wrapper.rate.
unwrap(address from, address to, euint64 amount)
public
#Unwraps tokens from from and sends the underlying tokens to to. The caller must be from
or be an approved operator for from. amount * rate() underlying tokens are sent to to.
The unwrap request created by this function must be finalized by calling ERC7984ERC20Wrapper.finalizeUnwrap.
The caller must already be approved by ACL for the given amount.
unwrap(address from, address to, externalEuint64 encryptedAmount, bytes inputProof)
public
#Variant of ERC7984ERC20Wrapper.unwrap that passes an inputProof which approves the caller for the encryptedAmount
in the ACL.
finalizeUnwrap(euint64 burntAmount, uint64 burntAmountCleartext, bytes decryptionProof)
public
#Fills an unwrap request for a given cipher-text burntAmount with the cleartextAmount and decryptionProof.
_unwrap(address from, address to, euint64 amount)
internal
#_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 ERC7984ERC20Wrapper._tryGetAssetDecimals fails to fetch decimals of the underlying
ERC-20 token.
_maxDecimals() → uint8
internal
#Returns the maximum number that will be used for IERC7984.decimals by the wrapper.
UnwrapRequested(address indexed receiver, euint64 amount)
event
#UnwrapFinalized(address indexed receiver, euint64 encryptedAmount, uint64 cleartextAmount)
event
#InvalidUnwrapRequest(euint64 amount)
error
#import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Freezable.sol";Extension of ERC7984 that implements a confidential
freezing mechanism that can be managed by an authorized account with
IERC7984Rwa.setConfidentialFrozen functions.
The freezing mechanism provides the guarantee to the contract owner (e.g. a DAO or a well-configured multisig) 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)
ERC165
IERC7984
IERC165
Events
Errors
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
#See ERC7984._update.
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
ERC7984Freezable._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
import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984ObserverAccess.sol";Extension of ERC7984 that allows each account to add a observer who is given
permanent ACL access to its transfer and balance amounts. A observer can be added or removed at any point in time.
Functions
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)
ERC165
IERC7984
IERC165
Events
Errors
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
#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.
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)
ERC165
IERC7984
IERC165
Events
Errors
confidentialTransferOmnibus(address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransfer-address-externalEuint64-bytes- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferOmnibus(address omnibusTo, eaddress sender, eaddress recipient, euint64 amount) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransfer-address-euint64- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferFromOmnibus(address omnibusFrom, address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferFrom-address-address-externalEuint64-bytes- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferFromOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferFrom-address-address-euint64- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferAndCallOmnibus(address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof, bytes data) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferAndCall-address-externalEuint64-bytes-bytes- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferAndCallOmnibus(address omnibusTo, eaddress sender, eaddress recipient, euint64 amount, bytes data) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferAndCall-address-euint64-bytes- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferFromAndCallOmnibus(address omnibusFrom, address omnibusTo, externalEaddress externalSender, externalEaddress externalRecipient, externalEuint64 externalAmount, bytes inputProof, bytes data) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferFromAndCall-address-address-externalEuint64-bytes-bytes- function and emits the ERC7984Omnibus.OmnibusConfidentialTransfer event.
confidentialTransferFromAndCallOmnibus(address omnibusFrom, address omnibusTo, eaddress sender, eaddress recipient, euint64 amount, bytes data) → euint64
public
#Wraps the interfaces#IERC7984-confidentialTransferFromAndCall-address-address-euint64-bytes- function and emits the ERC7984Omnibus.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 ERC7984Omnibus.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 ERC7984Omnibus.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.
import "@openzeppelin/confidential-contracts/token/ERC7984/extensions/ERC7984Restricted.sol";Extension of ERC7984 that implements user account transfer restrictions through the
IERC7984Rwa.isUserAllowed 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 IERC7984Rwa.isUserAllowed function acts as
a blocklist. Developers can override IERC7984Rwa.isUserAllowed to check that restriction == ALLOWED
to implement an allowlist.
Functions
- getRestriction(account)
- isUserAllowed(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)
ERC165
IERC7984
IERC165
Events
Errors
getRestriction(address account) → enum ERC7984Restricted.Restriction
public
#Returns the restriction of a user account.
isUserAllowed(address account) → bool
public
#Returns whether a user account is allowed to interact with the token.
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 (excluding minting and burning).
Requirements:
frommust be allowed to transfer tokens (seeIERC7984Rwa.isUserAllowed).tomust be allowed to receive tokens (seeIERC7984Rwa.isUserAllowed).
The default restriction behavior can be changed (for a pass-through for instance) by overriding
ERC7984Restricted._checkSenderRestriction and/or ERC7984Restricted._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 ERC7984Restricted.UserRestricted if so.
_checkSenderRestriction(address account)
internal
#Internal function which checks restriction of the from account before a transfer.
Working with ERC7984._update function.
_checkRecipientRestriction(address account)
internal
#Internal function which checks restriction of the to account before a transfer.
Working with ERC7984._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.
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
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)
- forceConfidentialTransferFrom(from, to, encryptedAmount, inputProof)
- forceConfidentialTransferFrom(from, to, encryptedAmount)
- confidentialAvailable(account)
- confidentialFrozen(account)
- paused()
- isUserAllowed(account)
- _update(from, to, encryptedAmount)
- _forceUpdate(from, to, encryptedAmount)
- _checkSenderRestriction(account)
- 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
Pausable
ERC7984Restricted
- getRestriction(account)
- _setRestriction(account, restriction)
- _blockUser(account)
- _allowUser(account)
- _resetUser(account)
- _checkRestriction(account)
- _checkRecipientRestriction(account)
ERC7984Freezable
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)
ERC165
IERC7984Rwa
IERC7984
IERC165
IAccessControl
Events
Errors
AccessControl
Multicall
Pausable
ERC7984Restricted
ERC7984Freezable
ERC7984
- ERC7984InvalidReceiver(receiver)
- ERC7984InvalidSender(sender)
- ERC7984UnauthorizedSpender(holder, spender)
- ERC7984ZeroBalance(holder)
- ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)
- ERC7984UnauthorizedCaller(caller)
- ERC7984InvalidGatewayRequest(requestId)
ERC165
IERC7984Rwa
IERC7984
IERC165
IAccessControl
onlyAdmin()
internal
#Checks if the sender is an admin.
onlyAgent()
internal
#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.
forceConfidentialTransferFrom(address from, address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64
public
#Variant of interfaces#IERC7984Rwa-forceConfidentialTransferFrom-address-address-euint64- with an input proof.
forceConfidentialTransferFrom(address from, address to, euint64 encryptedAmount) → euint64 transferred
public
#Force transfer callable by the role ERC7984Rwa.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.
isUserAllowed(address account) → bool
public
#Returns whether a user account is allowed to interact with the token.
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.
_forceUpdate(address from, address to, euint64 encryptedAmount) → euint64
internal
#Internal function which forces transfer of confidential amount of tokens from account to account by skipping compliance checks.
_checkSenderRestriction(address account)
internal
#Bypasses the from restriction check when performing a IERC7984Rwa.forceConfidentialTransferFrom.
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.
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. Voing power is taken into account when an account delegates votes to itself or to another account.
Functions
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
IERC6372
EIP712
IERC5267
Nonces
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)
ERC165
IERC7984
IERC165
Events
VotesConfidential
- DelegateVotesChanged(delegate, previousVotes, newVotes)
- DelegateChanged(delegator, fromDelegate, toDelegate)
HandleAccessManager
IERC6372
EIP712
IERC5267
Nonces
ERC7984
ERC165
IERC7984
- OperatorSet(holder, operator, until)
- ConfidentialTransfer(from, to, amount)
- AmountDisclosed(encryptedAmount, amount)
IERC165
Errors
VotesConfidential
HandleAccessManager
IERC6372
EIP712
IERC5267
Nonces
ERC7984
- ERC7984InvalidReceiver(receiver)
- ERC7984InvalidSender(sender)
- ERC7984UnauthorizedSpender(holder, spender)
- ERC7984ZeroBalance(holder)
- ERC7984UnauthorizedUseOfEncryptedAmount(amount, user)
- ERC7984UnauthorizedCaller(caller)
- ERC7984InvalidGatewayRequest(requestId)
ERC165
IERC7984
IERC165
confidentialTotalSupply() → euint64
public
#Returns the confidential total supply of the token.
_update(address from, address to, euint64 amount) → euint64 transferred
internal
#_getVotingUnits(address account) → euint64
internal
#import "@openzeppelin/confidential-contracts/token/ERC7984/utils/ERC7984Utils.sol";Library that provides common ERC7984 utility functions.
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.