# Ethereum - ERC7984 Tokens

Source: https://developers.bitgo.com/docs/ethereum-erc7984-tokens

## Overview

ERC7984 is a token standard for **confidential fungible tokens** on Ethereum. Unlike ERC20, balances and transfer
amounts are encrypted on-chain using Fully Homomorphic Encryption (FHE), powered by the
<a href="https://docs.zama.org/protocol" target="_blank" rel="noreferrer">Zama Protocol</a>. Token contracts do not
expose ERC20's `balanceOf`/`transfer`/`approve` functions. Instead they expose their own, distinctly named functions —
`confidentialBalanceOf`, `confidentialTransfer`/`confidentialTransferFrom`, and a time-limited `setOperator` in place
of `approve` — whose amounts are opaque encrypted handles (`bytes32` pointers) rather than plaintext integers. Only
parties holding the right decryption key can learn the actual amount behind a handle.

> 📘 **Note:** ERC7984 tokens are supported on multisig and MPC wallets, but not on wallet version 6 or later (v6+).
> A v6+ wallet cannot enable or hold ERC7984 tokens.

## How ERC7984 differs from ERC20

ERC7984 tokens share a wallet with their parent Ethereum wallet the same way ERC20 tokens do (no separate keychains,
addresses, or wallet objects). However, the confidentiality model changes several behaviors that developers relying on
standard ERC20 flows need to account for:

| Behavior | ERC20 | ERC7984 |
|:---------|:------|:--------|
| Balances / transfer amounts | Plaintext, readable directly from the contract | Encrypted on-chain; BitGo must decrypt them via a viewing key before they can be displayed |
| Token enablement | Not required | Requires an on-chain delegation transaction, submitted separately per address, before BitGo can decrypt balances/transfers for that address |
| Balance & transfer visibility | Available immediately once indexed | Available asynchronously, after BitGo completes decryption |
| Consolidation | Automatic via forwarders | Manual only, and only from receive addresses that have already delegated |
| Recipients per transaction | 1 | 1 |
| Chains supported | Ethereum + most EVM chains BitGo supports | Ethereum only, currently |

### Confidential balances and encrypted amounts

An ERC7984 contract's `confidentialBalanceOf` and transfer functions return an **encrypted handle**, not a plaintext
value. To show a usable balance or transfer amount, BitGo decrypts these handles using a per-enterprise viewing key.
This means:

- Balances on a wallet's confidential tokens are only meaningful once BitGo has decrypted them; consumers of the API
  should expect balance/amount fields to populate asynchronously rather than immediately after a transfer is seen
  on-chain.
- Decryption is scoped to the enterprise's viewing key — only BitGo can read the actual amounts. The chain itself
  never reveals plaintext balances.

### Token enablement (delegation)

ERC20 tokens require no wallet-level setup before use. ERC7984 tokens do: before BitGo can decrypt balances or
transfers for an address, that address's owner must call `enableToken` to submit an on-chain **delegation
transaction** that grants BitGo's viewing key the right to decrypt that address's encrypted data on the token's ACL
contract. This follows the same [token enablement](/docs/wallets-token-enablement) pattern used for other
enablement-required assets (for example SOL, HBAR, and ALGO) — a normal transaction that must be built, signed, and
sent before the token is usable — except that for ERC7984 tokens, "enabling" the token means delegating decryption
rights rather than creating an account or trustline.

This is a **one-time setup per address, per ERC7984 token**. Clients must call `enableToken` for an address before
attempting deposits or transfers of that token to or from it — until that address is enabled, BitGo cannot decrypt
its balances or transfer amounts.

Delegation is scoped **per address, not per wallet**. Enabling the token on a wallet's base address does not delegate
decryption rights for its receive addresses — each receive address must have its own delegation transaction submitted
before BitGo can decrypt balances or transfers held at that address. This also means consolidation will not pick up a
receive address's confidential token balance until that address has delegated; consolidation attempts against a
non-delegated receive address will not succeed.

The delegation transaction for an address can only be sent once that address's forwarder contract has been deployed.
The forwarder is deployed the first time the address receives any asset — a receive address must have previously
received a deposit (ETH or any token) before an enable-token/delegation transaction can be built and sent for it.

If a confidential transfer is received at an address while delegation is not active for it (for example, before the
address delegated, or if delegation was later revoked), the transfer cannot be decrypted immediately. It is surfaced
as a pending, "awaiting delegation" transaction. To resolve it, the address owner calls `enableToken` for that
address — once the resulting delegation transaction confirms on-chain, BitGo decrypts the stuck transfer and it
finalizes normally.

### Building confidential transfers

Building, signing, and sending a confidential transfer uses the same API flow as an ERC20 transfer, and, as with
ERC20, only a single recipient is supported per transaction. The transfer amount still needs to be encrypted before
it's submitted on-chain, but BitGo handles that step internally when building the transaction — there's nothing
different an API consumer needs to do to build a confidential transfer.

### Consolidation

For ERC20 tokens, deposits are auto-flushed from the receiving address to the wallet's base address with no client
action needed. ERC7984 deposits stay on the receiving address until the client explicitly triggers consolidation by
calling `POST /api/v2/:coin/wallet/:walletId/consolidateAccount/build`, and only after that receive address has
completed its own delegation transaction — consolidation cannot decrypt or move a confidential balance from an
address that has not delegated.

### Webhooks

Register a webhook with `type: pendingDecryption` (via [Add Wallet Webhook](/reference/v2walletaddwebhook)) on the
wallet's base Ethereum coin to be notified when a confidential deposit can't be decrypted because the receiving
address hasn't delegated yet. The payload looks like:

```json
{
  "event": "erc7984_deposit_awaiting_delegation",
  "walletId": "<walletId>",
  "coin": "<token coin, e.g. eth:cusdc>",
  "data": {
    "walletName": "<wallet label>",
    "address": "<receive address awaiting delegation>",
    "txHashes": ["<txHash>"],
    "receivedAt": "<ISO 8601 timestamp>"
  }
}
```

No transfer record exists yet at this point, so calling [Get Transfer](/reference/v2walletgettransfer) for a `txHash`
from this payload will 404. Once the address delegates and BitGo completes decryption, the deposit is recorded as a
normal transfer and the standard transfer webhook fires — at that point, use Get Transfer with the token's coin name
to retrieve the decrypted amount and current state.
