---
eip: 7984
title: Confidential Fungible Token
description: Confidential fungible tokens use an account-based accounting model while maintaining the confidentiality of transfer amounts and balances.
author: Aryeh Greenberg (@arr00), Ernesto García (@ernestognw), Hadrien Croubois (@Amxx), Ghazi Ben Amor (@GBAZama), Clement Danjou (@immortal-tofu), Joseph Andre Turk (@jatZama), Silas Davis (@silasdavis), Nicolas Pasquier (@npasquie)
discussions-to: https://ethereum-magicians.org/t/erc-7984-confidential-fungible-token-interface/24735
status: Draft
type: Standards Track
category: ERC
created: 2025-07-03
requires: 165
---

## Abstract

The following standard describes confidential fungible tokens via pointers. All amounts in this standard are represented by confidential pointers; therefore, balances and transfer amounts are confidential. Pointers refer to data stored elsewhere--onchain or offchain. The logistics of pointer resolution, operation, and location are implementation specific. The interface defines functions to transfer tokens with pointers, as well as approve operators, allowing the token to be transferred by a third party.

## Motivation

Confidential tokens enable private value transfer which is vital for many usecases such as payroll, confidential DeFi, institutional settlement, and more.
A standard interface allows pointer based confidential tokens on Ethereum to be reused by other applications: from privacy-focused wallets to decentralized exchanges, while keeping transaction amounts private from public view.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174).

### Nomenclature

All amounts in this ERC are pointer based amounts represented by `bytes32` pointers unless otherwise specified. The resolution and manipulation of these pointers is implementation specific.

### Token

Compliant tokens MUST implement [ERC-165](./eip-165.md). The `supportsInterface` function MUST return `true` if `0x4958f2a4` is passed through the `interfaceID` argument.

### Methods

Compliant tokens MUST implement the following methods, unless otherwise specified:

- #### `name()`

  Returns the name of the token - e.g. `"MyConfidentialToken"`.

  ```solidity
  function name() external view returns (string memory)
  ```

- #### `symbol()`

  Returns the symbol of the token - e.g. `"MCT"`.

  ```solidity
  function symbol() external view returns (string memory)
  ```

- #### `decimals()`

  Returns the number of decimals the token uses (e.g. `6`) as a plaintext `uint8`.

  ```solidity
  function decimals() external view returns (uint8)
  ```

- #### `contractURI()`

  Returns the metadata URI for the token. SHOULD follow the schema defined in [ERC-7572](./eip-7572.md).

  ```solidity
  function contractURI() external view returns (string memory)
  ```

- #### `confidentialTotalSupply()`

  Returns the total token supply.

  ```solidity
  function confidentialTotalSupply() external view returns (bytes32)
  ```

- #### `confidentialBalanceOf(address)`

  Returns the balance of `account`.

  ```solidity
  function confidentialBalanceOf(address account) external view returns (bytes32)
  ```

- #### `isOperator(address,address)`

  Returns `true` if `spender` is currently authorized to transfer tokens on behalf of `holder`.

  ```solidity
  function isOperator(address holder, address spender) external view returns (bool)
  ```

- #### `setOperator(address,uint48)`

  Authorizes `operator` to transfer tokens on behalf of the caller until timestamp `until`--passed as a plaintext `uint48`. An operator may transfer any amount of tokens on behalf of a holder while approved. Accounts may have multiple simultaneous operators.

  MUST emit the `OperatorSet` event.

  ```solidity
  function setOperator(address operator, uint48 until) external
  ```

- #### `confidentialTransfer(address,bytes32)`

  Transfers `amount` of tokens to address `to`. The function MAY revert if the caller's balance does not have enough tokens to spend.

  Returns the actual amount that was transferred.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransfer(address to, bytes32 amount) external returns (bytes32)
  ```

- #### `confidentialTransfer(address,bytes32,bytes)`

  Transfers `amount` of tokens to address `to`. The function MAY revert if the caller's balance does not have enough tokens to spend.

  The `data` parameter contains implementation-specific information such as cryptographic proofs.

  Returns the actual amount that was transferred.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransfer(address to, bytes32 amount, bytes calldata data) external returns (bytes32)
  ```

- #### `confidentialTransferFrom(address,address,bytes32)`

  Transfers `amount` of tokens from address `from` to address `to`. The function MAY revert if the `from`'s account balance does not have enough tokens to spend.

  Returns the actual amount that was transferred.

  MUST revert if the caller is not an operator for `from`.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferFrom(address from, address to, bytes32 amount, bytes calldata data) external returns (bytes32)
  ```

- #### `confidentialTransferFrom(address,address,bytes32,bytes)`

  Transfers `amount` of tokens from address `from` to address `to`. The function MAY revert if the `from`'s account balance does not have enough tokens to spend.

  The `data` parameter contains implementation-specific information such as cryptographic proofs.

  Returns the actual amount that was transferred.

  MUST revert if the caller is not an operator for `from`.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferFrom(address from, address to, bytes32 amount, bytes calldata data) external returns (bytes32)
  ```

- #### `confidentialTransferAndCall(address,bytes32,bytes)`

  Transfers `amount` of tokens to address `to`. The function MAY revert if the caller's balance does not have enough tokens to spend.

  The `data` parameter contains implementation-specific information such as cryptographic proofs.

  See [Callback Details](#callback-details) below for details on the callback flow.

  Returns the actual amount that was transferred.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferAndCall(address to, bytes32 amount, bytes calldata callData) external returns (bytes32)
  ```

- #### `confidentialTransferAndCall(address,bytes32,bytes,bytes)`

  Transfers `amount` of tokens to address `to`. The function MAY revert if the caller's balance does not have enough tokens to spend.

  The `data` parameter contains implementation-specific information such as cryptographic proofs.

  See [Callback Details](#callback-details) below for details on the callback flow.

  Returns the actual amount that was transferred.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferAndCall(address to, bytes32 amount, bytes calldata data, bytes calldata callData) external returns (bytes32)
  ```

- #### `confidentialTransferFromAndCall(address,address,bytes32,bytes)`

  Transfers `amount` of tokens from address `from` to address `to`. The function MAY revert if the `from`'s account balance does not have enough tokens to spend.

  See [Callback Details](#callback-details) below for details on the callback flow.

  Returns the actual amount that was transferred.

  MUST revert if the caller is not an operator for `from`.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferFromAndCall(address from, address to, bytes32 amount, bytes calldata callData) external returns (bytes32)
  ```

- #### `confidentialTransferFromAndCall(address,address,bytes32,bytes,bytes)`

  Transfers `amount` of tokens from address `from` to address `to`. The function MAY revert if the `from`'s account balance does not have enough tokens to spend.

  The `data` parameter contains implementation-specific information such as cryptographic proofs.

  See [Callback Details](#callback-details) below for details on the callback flow.

  Returns the actual amount that was transferred.

  MUST revert if the caller is not an operator for `from`.

  MUST emit the `ConfidentialTransfer` event.

  ```solidity
  function confidentialTransferFromAndCall(address from, address to, bytes32 amount, bytes calldata data, bytes calldata callData) external returns (bytes32)
  ```

### Events

- #### ConfidentialTransfer

  MUST trigger when confidential tokens are transferred, including zero value transfers.

  A token contract which creates new tokens SHOULD trigger a ConfidentialTransfer event with the `from` address set to `0x0` when tokens are created.

  ```solidity
  event ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)
  ```

- #### OperatorSet

  MUST trigger on any successful call to `setOperator`.

  ```solidity
  event OperatorSet(address indexed holder, address indexed operator, uint48 until)
  ```

- #### AmountDisclosed

  SHOULD trigger when a pointer amount is publicly disclosed through implementation-specific mechanisms.

  ```solidity
  event AmountDisclosed(bytes32 indexed handle, uint256 amount)
  ```

### Callback Details

Transfer functions suffixed with `andCall` execute a callback to the `to` address AFTER all transfer logic is completed. The callback calls the `onConfidentialTransferReceived` function with the transfer initiator (operator), from address, actual amount sent, and given `callData` bytes (the last parameter for `andCall` functions). The callback flow is as follows:

- If `address(to).code.length == 0` the callback is a no-op and returns successfully.
- Call [`onConfidentialTransferReceived(address, address, bytes32, bytes)`](#onconfidentialtransferreceived) on `to`.
- If the function call reverts, revert.
- If the function call returns the false boolean, attempt to transfer back the tokens to the original holder and return.

### Contract Receivers

For a contract to receive a transfer with a callback, it MUST implement the `onConfidentialTransferReceived` function:

#### onConfidentialTransferReceived

If the callback is unsuccessful, the function SHOULD revert or return a pointer to the false boolean.

The token will attempt to return tokens from the receiver to the sender if false is returned. Note that this reversal may fail if the receiver spends tokens as part of the callback.

```solidity
function onConfidentialTransferReceived(address operator, address from, bytes32 amount, bytes calldata data) external returns (bytes32 success);
```

## Rationale

### Technology Agnostic Design

Using `bytes32` allows implementations using pointer based systems and privacy mechanisms including FHE systems, zero-knowledge proofs, secure enclaves, or future technologies to be compliant.

### Operator Model

Time-limited operators provide granular control while enabling DeFi protocol integration and natural permission expiration. This approach reduces the load on the external system by removing the need to track approval amounts.

### Data Parameter

The `bytes calldata data` parameter in transfer functions allows implementations to include cryptographic proofs, access permissions, or other privacy-mechanism-specific information.

## Security Considerations

Security depends on the underlying pointer based mechanism. Implementations must guard against side-channel attacks and ensure proper key management for offchain operations.

Token callbacks are associated with inherent security risks, including reentrancy and gas griefing. When utilizing callbacks, consider using reentrancy protection and setting a gas limit.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
