Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7984: Confidential Fungible Token

Confidential fungible tokens use an account-based accounting model while maintaining the confidentiality of transfer amounts and balances.

Authors 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)
Created 2025-07-03
Discussion Link https://ethereum-magicians.org/t/erc-7984-confidential-fungible-token-interface/24735
Requires EIP-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 and RFC 8174.

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. 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".

OPTIONAL - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present.

function name() external view returns (string memory)

symbol()

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

OPTIONAL - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present.

function symbol() external view returns (string memory)

decimals()

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

function decimals() external view returns (uint8)

contractURI()

Returns the metadata URI for the token. SHOULD follow the schema defined in ERC-7572.

function contractURI() external view returns (string memory)

confidentialTotalSupply()

Returns the total token supply.

function confidentialTotalSupply() external view returns (bytes32)

confidentialBalanceOf(address)

Returns the balance of account.

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.

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.

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.

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.

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.

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.

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 below for details on the callback flow.

Returns the actual amount that was transferred.

MUST emit the ConfidentialTransfer event.

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 below for details on the callback flow.

Returns the actual amount that was transferred.

MUST emit the ConfidentialTransfer event.

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 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.

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 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.

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.

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

OperatorSet

MUST trigger on any successful call to setOperator.

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

AmountDisclosed

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

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 onConfidentialTokenReceived function with the 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 onConfidentialTokenReceived(address, bytes32, bytes) 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 onConfidentialTokenReceived function:

onConfidentialTokenReceived

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.

function onConfidentialTokenReceived(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 and related rights waived via CC0.

Citation

Please cite this document as:

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), "ERC-7984: Confidential Fungible Token [DRAFT]," Ethereum Improvement Proposals, no. 7984, July 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7984.