# How FHE Powers cTokens

The privacy of confidential tokens is enabled by FHE, which allows encrypted integers (`euint64`) to be manipulated inside smart contracts.

## Encrypted Balances <a href="#encrypted-balances" id="encrypted-balances"></a>

When you hold cUSDC, your balance isn't stored as a regular number like "1000". Instead, it's stored as an encrypted value called a euint64: an encrypted 64-bit unsigned integer. Think of it as a locked box containing a number between 0 and 18.4 quintillion.

Only the holder (or authorised parties) can decrypt it to see the actual value. To everyone else, it's just encrypted values.

## Encrypted Operations <a href="#encrypted-operations" id="encrypted-operations"></a>

When you transfer 100 cUSDC to someone:

* Your encrypted balance: `euint64_A`
* Transfer amount: `euint64_transfer`
* Their encrypted balance: `euint64_B`

The smart contract performs:

* `euint64_A = euint64_A - euint64_transfer` (FHE subtraction)
* `euint64_B = euint64_B + euint64_transfer` (FHE addition)

These operations happen entirely on encrypted values. The blockchain nodes processing your transaction never see the actual amounts. They just shuffle around encrypted data and perform encrypted arithmetic.

## Selective Decryption <a href="#selective-decryption" id="selective-decryption"></a>

You control who can see your encrypted balances. When you need to view your balance in a wallet, your private key allows you to decrypt it. When you need to unshield (convert back to regular tokens), the amount is made publicly decryptable so you can decrypt it yourself using the fhEVM SDK and provide it to the wrapper contract.

## The ERC-7984 Standard and FHE <a href="#the-erc-7984-standard-and-fhe" id="the-erc-7984-standard-and-fhe"></a>

The ERC-7984 standard specifies how confidential tokens should use FHE:

* Balances are stored as `euint64` (encrypted 64-bit integers)
* Transfers use `confidentialTransfer()` with encrypted amounts
* The `confidentialTransferAndCall()` pattern enables smart contract interactions
* Total supply can optionally be public (since wrapping/unwrapping reveals it anyway)

This standardisation means:

* Wallets can support all ERC-7984 tokens with one integration
* DeFi protocols can interact with confidential tokens using known patterns
* Developers can build on a solid, audited foundation (OpenZeppelin)

## Public Decryption <a href="#public-decryption" id="public-decryption"></a>

Certain operations (notably unshielding) require decrypting an encrypted value publicly. This is handled through public decryption:

1. The smart contract marks a value as "publicly decryptable" via `FHE.makePubliclyDecryptable()`
2. An indexer monitors blockchain events and exposes these encrypted handles
3. Anyone can decrypt the value using the fhEVM SDK's `decryptPublic()` function
4. The decrypted value is submitted to the blockchain in the finalisation transaction
5. The smart contract uses the decrypted value to complete the operation

This process is secure because only values explicitly marked as publicly decryptable can be decrypted this way. Your regular encrypted balances remain confidential. We'll see this in action in the [unshield](/wiki/zaiffer/unshielding-tokens-unwrapping.md) process.

## Understanding euint64 Limits <a href="#understanding-euint64-limits" id="understanding-euint64-limits"></a>

The `euint64` type can hold values from 0 to 18,446,744,073,709,551,615 (about 18.4 quintillion). This sounds like a lot, but tokens on Ethereum can have up to 18 decimals. A token with 18 decimals uses the smallest unit (wei for ETH), meaning 1 ETH = 1,000,000,000,000,000,000 wei.

If we tried to store large ETH balances directly as `euint64`, we'd quickly overflow. That's why the system uses [<mark style="color:$primary;">rate conversion</mark>](#the-rate-conversion-system) to scale down high-decimal tokens to fit comfortably within `euint64` limits.

## The Rate Conversion System <a href="#the-rate-conversion-system" id="the-rate-conversion-system"></a>

Because many ERC-20 tokens use 18 decimals, storing raw values in euint64 could overflow. Zaïffer uses **rate conversion** to scale values down to a uniform **6 decimal** internal precision.

This ensures:

* all tokens fit safely within euint64
* consistent precision across tokens
* predictable behaviour for developers

Examples:

* USDC uses 6 decimals (1 USDC = 1,000,000 smallest units) → fits naturally
* ETH uses 18 decimals (1 ETH = 1,000,000,000,000,000,000 wei) → too large for euint64

Without scaling, users could hold as little as \~18 ETH before reaching the encrypted integer limit. To solve this, confidential tokens standardise on a maximum of **6 decimals internally**. The rate conversion formula is:

* **For tokens with ≤6 decimals**: `rate = 1` (no conversion needed)
* **For tokens with >6 decimals**: `rate = 10^(decimals - 6)`

**Examples:**

<table><thead><tr><th width="87.46484375">Token</th><th width="108.34765625">Decimals</th><th width="158.19921875">Rate</th><th width="198.2734375">Example Conversion</th><th>Notes</th></tr></thead><tbody><tr><td><strong>USDC</strong></td><td>6</td><td>1</td><td>1,000 USDC = 1,000 cUSDC</td><td>Direct 1:1 mapping</td></tr><tr><td><strong>WETH</strong></td><td>18</td><td>10^(18 - 6) = 10^12</td><td>1^18 wei = 1^6 cETH units</td><td>scales 18 → 6 decimals</td></tr></tbody></table>

Rate conversion is handled automatically and invisibly by the wrapper contract. You:

* Shield 1.5 ETH → Receive equivalent in cETH (automatically rate-adjusted)
* Transfer cETH to someone → Amounts are encrypted, rate doesn't matter
* Unshield cETH → Receive 1.5 ETH back (automatically rate-adjusted)

When converting between decimal formats, tiny remainders may occur. These are **dust amounts** too small to represent in 6-decimal precision.

Example: Shielding 1.000000000000000001 ETH (18 decimals):

* After rate conversion to 6 decimals: 1.000000 cETH
* Dust: 0.000000000000000001 ETH (too small to represent)

This **dust** is sent to the protocol fee recipient, ensuring no tokens are "lost" in conversion. They're just too small to be meaningful and go toward protocol revenue. In practice, dust amounts are negligible (fractions of a cent).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zaiffer.gitbook.io/wiki/zaiffer/how-fhe-powers-ctokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
