---
eip: 7945
title: Confidential Transactions Supported Token
description: Outlines a fungible token interface that hides per-account balances, boosting privacy in dApps
author: Siyuan Zheng (@andrewcoder666) <zhengsiyuan.zsy@antgroup.com>, Zhe Han (@iampkuhz) <hanzhe.hz@ant-intl.com>, Xiaoyu Liu (@elizabethxiaoyu) <jiushi.lxy@antgroup.com>, Wenwei Ma (@madyinglight) <huiwei.mww@antgroup.com>, Jun Meng Tan (@chadxeth) <junmeng.t@antgroup.com>, Yuxiang Fu (@tmac4096) <kunfu.fyx@antgroup.com>, Kecheng Gao (@thanks-v-me-50) <gaokecheng.gkc@antgroup.com>, Alwin Ng Jun Wei (@alwinngjw) <alwin.ng@antgroup.com>, Chenxin Wang (@3235773541) <wcx465603@antgroup.com>, Xiang Gao (@GaoYiRu) <gaoxiang.gao@antgroup.com>, yuanshanhshan (@xunayuan) <yuanshanshan.yss@antgroup.com>, Hao Zou (@BruceZH0915) <situ.zh@antgroup.com>, Yanyi Liang <eason.lyy@antgroup.com>, Yuehua Zhang (@astroyhzcc) <ruoying.zyh@antgroup.com>
discussions-to: https://ethereum-magicians.org/t/interface-of-confidential-transactions-supported-token-contract/23586
status: Review
type: Standards Track
category: ERC
created: 2025-05-09
requires: 20
---

## Abstract
Classic token contracts like [ERC-20](./eip-20.md) enable their token holders to make transfers and/or approve others to make transfers on their behalves. The generality of token standard [ERC-20](./eip-20.md) catalyzed decentralized finance and many other blockchain applications. However, when it comes to privacy, although some technical schemes have been proposed, few standards have been established, which limits the evolution of privacy-preserving blockchain applications.

This proposal draws up a standard interface for fungible token contracts supporting confidential transactions. It provides basic transfer functionality without loss of generality, and allowance and approve functionalities. Contracts following the standard can provide confidentiality for users’ balances and token transfer value, and can enable other blockchain applications to make transfers on behalf of owners, which empowers more privacy-preserving capabilities for blockchain applications.

## Motivation
Confidential transactions have been implemented in many blockchains, either natively through blockchain protocols like Monero and Zcash, or through smart contracts like Zether[^1] without modifying the blockchain protocol.

However, few standards are proposed on Ethereum (and/or other EVM-compatible blockchains) to illustrate privacy-preserving contracts without modifying the underlying protocol. Users and applications cannot easily detect whether a token contract supports confidential transactions or not, and so cannot reliably make transfers without revealing the actual amount.

Consequently, this proposal is to standardize confidential-transaction-supported token contracts, without loss of generality, by only specifying core methods and events.

Such a standard interface allows confidential transactions of tokens to be applied by certain parties that are sensitive to transfer amounts, or by privacy-preserving applications.

Compared with application-specific confidential token designs, such as [ERC-7984](./eip-7984.md) using `bytes32` pointers representing confidential balances, open-source projects Tornado Cash and Zeto implementing a UTXO model in smart contracts, this proposal standardizes only the minimum interoperable surface in the setting of an account-based model: balance queries, transfers, delegated transfers, approvals, and related events. This allows different proof systems, ciphertext encodings, and compliance workflows to coexist behind a common interface, so wallets, bridges, exchanges, and other applications can support confidential tokens without being tightly coupled to one implementation. 

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


### Contract Interface
Compliant contracts MUST implement the following interface:

```solidity
interface IERC7945 {
    function confidentialBalanceOf(address owner) external view returns (bytes memory confidentialBalance);

    function confidentialTransfer(
        address _to,
        bytes memory _confidentialTransferValue,
        bytes memory _proof
    ) external returns (bool success);

    function confidentialTransferFrom(
        address _from,
        address _to,
        bytes memory _confidentialTransferValue,
        bytes memory _proof
    ) external returns (bool success);

    function confidentialApprove(
        address _spender,
        bytes memory _confidentialValue,
        bytes memory _proof
    ) external returns (bool success);

    function confidentialAllowance(address _owner, address _spender)
        external
        view
        returns (bytes memory _confidentialValue);

    event ConfidentialTransfer(
        address indexed _spender,
        address indexed _from,
        address indexed _to,
        bytes _confidentialTransferValue
    );

    event ConfidentialApproval(
        address indexed _owner,
        address indexed _spender,
        bytes _currentAllowancePart,
        bytes _allowancePart
    );
}
```

Additionally, compliant contracts MAY implement the following interface:

```solidity
interface IERC7945Metadata {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}
```

#### `IERC7945Metadata`
##### Methods
###### `name`
```solidity
function name() external view returns (string memory)
```

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 this value to be present.

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

Returns the symbol of the token, e.g. `"cHIX"`.

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

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

Returns the number of decimals the token uses - e.g. `8`, meaning the token amount should be divided by `100000000` to get its user representation.

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

#### `IERC7945`
##### Methods

###### `confidentialBalanceOf`

```solidity
function confidentialBalanceOf(address owner) 
external view returns (bytes memory confidentialBalance)
```

Returns the confidential balance of the account with address `owner`.

###### `confidentialTransfer`

```solidity
function confidentialTransfer(
  address _to,
  bytes memory _confidentialTransferValue, 
  bytes memory _proof
) external returns (bool success)
```

Transfers `value` amount of tokens (behind `_confidentialTransferValue`) to address `_to`, and MUST fire the `ConfidentialTransfer` event. The function SHOULD `revert` if the message caller’s `_proof` of this transfer fails to be verified.

Note:

+ Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned.
+ Implementations can fully customize the proof system, (de)serialization strategies of `bytes`, and/or the business workflow. For example, when implementing "Zether"[^1] confidential token contracts, the `_confidentialTransferValue` and accounts' confidential balances will be encrypted homomorphically under ElGamal public keys, and `_proof` will consist of 3 parts to check:
    - `_confidentialTransferValue` is well encrypted under both the caller's public key and `_to`'s;
    - The plaintext `value` behind `_confidentialTransferValue` is non-negative;
    - The caller's confidential balance is actually enough to pay the plaintext `value` behind `_confidentialTransferValue`.

###### `confidentialTransferFrom`

```solidity
function confidentialTransferFrom(
  address _from,
  address _to,
  bytes memory _confidentialTransferValue,
  bytes memory _proof
) external returns (bool success)

```

Transfers `value` amount of tokens (behind `_confidentialTransferValue`) from address `_from` to address `_to`, and MUST fire the `ConfidentialTransfer` event.

The `confidentialTransferFrom` method is used for a withdrawal workflow, allowing contracts to transfer tokens on your behalf. This can be used, for example, to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. The function SHOULD `revert` unless the `_from` account has deliberately authorized the sender of the message via some mechanism, and SHOULD `revert` if the message caller’s `_proof` of this transfer fails to be verified.

Note:

+ Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned.
+ Implementations can fully customize the proof system, (de)serialization strategies of `bytes`, and/or the business workflow. For example, when implementing "Zether" confidential token contracts, the `_confidentialTransferValue` and accounts' confidential balances will be encrypted homomorphically under ElGamal public keys, and `_proof` will consist of 3 parts to check:
    - `_confidentialTransferValue` is well encrypted under public keys of `_from`'s, `_to`'s, and caller's;
    - The plaintext `value` behind `_confidentialTransferValue` is non-negative;
    - The caller's confidential allowance is actually enough to pay the plaintext `value` behind `_confidentialTransferValue`.

###### `confidentialApprove`

```solidity
function confidentialApprove(
  address _spender,
  bytes memory _confidentialValue, 
  bytes memory _proof
) external returns (bool success)
```

Allows `_spender` to withdraw from caller's split part of balances multiple times, up to the amount (allowance value) behind `_confidentialValue` to 0. This function SHOULD `revert` if the message caller’s `_proof` of this transfer fails to be verified.

Caution:

This function behaves much **differently from** `approve(address,uint256)` in [ERC-20](./eip-20.md).

Calling `confidentialApprove` splits the confidential balance of caller's account into *allowance part* and *the left part*.

The values behind two parts above after calling `confidentialApprove`, and the value behind the original confidential balance of caller's account before calling `confidentialApprove`, satisfy the equation:

$$ 
value_{Behind\ Allowance\ Part} + value_{Behind\ Left\ Part} = value_{Behind\ Original\ Confidential\ Balance}
$$

+ The allowance part of the confidential balance allows `_spender` to withdraw multiple times through calling `confidentialTransferFrom` until `_spender` does not call it any more or the value behind this part is 0.
    - Every time `_spender` calls `confidentialTransferFrom`, the value behind this part will be decreased by the value behind `_confidentialTransferValue`.
+ The left part remains as the new confidential balance of the caller's account.

If this function is called again, it:

+ merges the existing allowance part into the confidential balance of the caller's account; and then
+ overwrites the current allowance part with `_confidentialValue`.

Note:

+ Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned.
+ Implementations can fully customize the proof system, (de)serialization strategies of `bytes`, and/or the business workflow. For example, when implementing "Zether" confidential token contracts, the `_confidentialValue` and accounts' confidential balances will be encrypted homomorphically under ElGamal public keys, and `_proof` will consist of 3 parts to check:
    - `_confidentialValue` is well encrypted under public keys of caller's and `_spender`'s;
    - The plaintext `value` behind `_confidentialValue` is non-negative;
    - The caller's confidential balance is actually enough to pay the plaintext `value` behind `_confidentialValue`.

###### `confidentialAllowance`
```solidity
function confidentialAllowance(address _owner, address _spender)
external view returns (bytes memory _confidentialValue)
```

Returns the allowance part that `_spender` is still allowed to withdraw from `_owner`.

##### Events

###### `ConfidentialTransfer`

```solidity
event ConfidentialTransfer(
  address indexed _spender,
  address indexed _from, 
  address indexed _to, 
  bytes _confidentialTransferValue
)
```

MUST trigger when tokens are transferred.

Specifically, if tokens are transferred through function `confidentialTransferFrom`, `_spender` address MUST be set to caller's; otherwise, it SHOULD be set to `0x0`.

A confidential token contract:

+ which creates new tokens SHOULD trigger a `ConfidentialTransfer` with the `_from` address set to `0x0` when tokens are minted;
+ which destroys existing tokens SHOULD trigger a `ConfidentialTransfer` with the `_to` address set to `0x0` when tokens are burned.

###### `ConfidentialApproval`

```solidity
event ConfidentialApproval(
  address indexed _owner,
  address indexed _spender,
  bytes _currentAllowancePart,
  bytes _allowancePart
)
```

MUST trigger on any successful call to `confidentialApprove(address,bytes,bytes)`.

## Rationale


### Optional Accessor of "Confidential Total Supply"

```solidity
function confidentialTotalSupply() external view returns (bytes memory)
```

Confidentiality of transfer amount makes it hard to support a field like `totalSupply()` in [ERC-20](./eip-20.md). When it comes to token minting or burning, if every user in this contract can access `totalSupply()` as well as decrypt it, these users will know the actual token value minted or burned by comparing the `totalSupply()` before and after such operations, which means that confidentiality no longer exists.

Contract implementations can optionally support `confidentialTotalSupply()` by evaluating whether anti-money laundering (see next part) and audit are required. That would be much more plausible by allowing a small group of parties to know the plaintext total supply behind `confidentialTotalSupply()`.

### Anti-money Laundering and Audit
To support audit of confidential transactions and total supply, especially when such token issuers are banks or other financial institutions supervised by governments or monetary authorities, confidential transactions can be implemented without changing the `confidentialTransfer` method signature, by encoding more information into parameters.

For example, in a Zether-like implementation[^2], if token transfers are required to be audited, the `confidentialTransfer` caller encrypts transfer `value` redundantly under public keys of caller's, `to`'s, and a group of auditors', which makes it possible for related parties to know the real `value` behind it exactly. So does `confidentialTotalSupply()`.

### Fat Token
A confidential-transactions-supported token can also implement [ERC-20](./eip-20.md) at the same time.

Token accounts in such tokens can hold two kinds of balances. Such token contracts can optionally provide methods to hide [ERC-20](./eip-20.md) plaintext balances into confidential balances, and vice versa, to reveal confidential balances back to [ERC-20](./eip-20.md) plaintext balances.

[ERC-20](./eip-20.md) interfaces will bring much more usability and utility to confidential-transaction-supported tokens, realizing general confidentiality in the meantime.

## Backwards Compatibility

No backward compatibility issues found.


## Security Considerations
To preserve confidentiality, implementations should avoid creating (minting) or destroying (burning) tokens with plaintext value parameters, since plaintext mint or burn flows may reveal sensitive amounts even if ordinary transfers remain confidential. Implementers should also ensure that any mint, burn, transfer, approval, and delegated transfer workflows use proof and encryption schemes that do not leak transfer values or balance information through calldata, events, or auxiliary state.

## Copyright

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

[^1]:
    ```csl-json
    {
      "type": "article",
      "id": 1,
      "author": [
        {
          "family": "Bünz",
          "given": "Benedikt"
        },
        {
          "family": "Agrawal",
          "given": "Shashank" 
        },
        {
          "family": "Zamani",
          "given": "Mahdi" 
        },
        {
          "family": "Boneh",
          "given": "Dan"
        }
      ],
      "DOI": "10.1007/978-3-030-51280-4_23",
      "title": "Zether: Towards Privacy in a Smart Contract World",
      "original-date": {
        "date-parts": [
          [2020, 2, 10]
        ]
      },
      "URL": "https://eprint.iacr.org/2019/191.pdf",
      "custom": {
        "additional-urls": [
          "https://dl.acm.org/doi/abs/10.1007/978-3-030-51280-4_23"
        ]
      }
    }
    ```

[^2]:
    ```csl-json
    {
      "type": "article",
      "id": 2,
      "author": [
        {
          "family": "Chen",
          "given": "Yu"
        },
        {
          "family": "Ma",
          "given": "Xuecheng"
        },
        {
          "family": "Tang",
          "given": "Cong"
        },
        {
          "family": "Au",
          "given": "Man Ho"
        }
      ],
      "DOI": "10.1007/978-3-030-58951-6_29",
      "title": "PGC: Decentralized Confidential Payment System with Auditability",
      "original-date": {
        "date-parts": [
          [2020, 9, 12]
        ]
      },
      "URL": "https://eprint.iacr.org/2019/319.pdf",
      "custom": {
        "additional-urls": [
          "https://link.springer.com/chapter/10.1007/978-3-030-58951-6_29"
        ]
      }
    }
    ```