Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.skale.space/llms.txt

Use this file to discover all available pages before exploring further.

Beta on SKALE Base Sepolia — Confidential Tokens are available for testing and development on testnet. Mainnet deployment coming soon. API is stable but may see refinements.

Why Confidential Tokens?

Standard ERC20 tokens store balances as plaintext onchain — anyone can see who holds what. For payroll, lending, gaming, or any application where financial privacy matters, this is a non-starter. Confidential Tokens solve this by encrypting every balance using a dual-layer model: threshold encryption for onchain processing (transfers, sufficiency checks) and ECIES encryption for private off-chain viewing.

What Are Confidential Tokens?

Confidential Tokens are ERC20 tokens where balances are encrypted onchain. No plaintext balance is ever stored. They use a dual-encryption model — threshold encryption for on-chain logic and ECIES encryption for off-chain viewing.

Quick Start

forge install skalenetwork/confidential-token
import "@skalenetwork/confidential-token/ConfidentialToken.sol";

// Balances are encrypted automatically — no manual encryption needed
// Transfers use CTX under the hood for secure processing
confidentialToken.transfer(recipient, amount);

// Balance is readable only by the holder via their viewer key
uint256 balance = confidentialToken.balanceOf(msg.sender);

Dual-Encryption Model

LayerKeyPurposeWho Can Decrypt
TE (Threshold Encryption)Network BLS keyOn-chain logic (transfers, sufficiency checks)Consensus via CTX callback
ECIESRecipient’s secp256k1 keyOff-chain balance viewingToken holder’s private key
Both layers encrypt every balance. The TE layer allows the network to verify and process transfers without seeing amounts. The ECIES layer allows the token holder to read their balance privately off-chain.

Architecture

A confidential token transfer works like this — encryption of new balances happens inside the CTX callback, not upfront:
transfer(from, to, amount)
  → SubmitCTX(0x1B, from_encBalance, to_encBalance, amount, [plaintext metadata])
    → Validators decrypt encrypted args
      → onDecrypt() callback called via ephemeral wallet
        → Validate from_balance >= amount
        → Compute new_balance_from, new_balance_to
        → EncryptTE(0x1D, new_balance_from) → store in _thresholdBalances
        → EncryptTE(0x1D, new_balance_to)   → store in _thresholdBalances
        → EncryptECIES(0x1C, new_balance_from, from_viewerKey) → _userBalances
        → EncryptECIES(0x1C, new_balance_to, to_viewerKey)     → _userBalances

Key Contracts

ContractPurpose
ConfidentialTokenCore confidential ERC20
ConfidentialWrapperWraps an existing ERC20 into a confidential token
MintableConfidentialTokenConfidentialToken + restricted mint
ConfidentialEIP3009EIP-3009 with encrypted value parameters

Roles

RoleCan DoCan See Balance
HolderTransfer, approveOnly via registered viewer key
ViewerDecrypt ECIES balance off-chainYes (if granted access)
AnyoneView encrypted ciphertext onchainEncrypted only
A holder registers a viewer public key via setViewerPublicKey(). The holder can be their own viewer.

Learn More