Skip to main content

Lunarys Protocol Overview

Executive Summary

Lunarys is the world's first fully encrypted decentralized exchange (eDEX) built with Fully Homomorphic Encryption (FHE). Every aspect of the protocol -- from trading volumes to liquidity depths -- remains encrypted on-chain, providing unprecedented privacy while maintaining complete decentralization.

Core Architecture

The Lunarys protocol consists of the following components:

1. EPOOL (Encrypted Pool)

The core AMM contract implementing a Uniswap V2-style constant product formula with fully encrypted reserves.

  • Reserves stored as encrypted euint64 values
  • Obfuscated reserves publicly visible for price discovery (multiplied by random factor 1M-3M)
  • Atomic swaps -- single-transaction execution, no oracle settlement phase
  • 4-term Taylor approximation for efficient FHE pricing
  • CERC20 LP token with encrypted shares

2. EPoolFactory

Deploys new EPOOL instances with deterministic pool keys based on (token0, token1, swapFee). Canonical token ordering ensures each pair has exactly one pool per fee tier.

3. UniversalRouter

Pool discovery and route validation helper. Due to FHE encrypted input verification, the router cannot execute swaps on behalf of users. Users must call pool functions directly.

4. Token System (CERC20 / ERC7984)

Confidential ERC20 tokens with encrypted balances. All tokens use 6 decimals. Operator approvals via setOperator allow pools to transfer tokens.

How Swaps Work (Atomic)

Unlike traditional DEXes where everything is public, Lunarys uses obfuscated reserves and encrypted inputs for privacy-preserving execution in a single transaction.

flowchart LR
A[User] -->|1. Fetch obfuscated reserves| B[EPOOL]
B -->|2. Decrypt via gateway| C[FHE Gateway]
C -->|clear values + proof| A
A -->|3. Encrypt swap amount| D[FHE SDK]
D -->|encrypted handles| A
A -->|4. atomicSwapAForB| B
B -->|5. Validate proof & compute| B
B -->|6a. Success: transfer output| A
B -->|6b. Fail: refund input| A
B -->|7. Rotate factor| B

style A fill:#805ad5,color:#fff
style B fill:#2d3748,color:#fff
style C fill:#d69e2e,color:#000
style D fill:#4a5568,color:#fff

Step-by-Step Swap Flow

1. User fetches obfuscated reserves from pool
-> obfuscatedStates() returns (obfReserveA, obfReserveB, obfLPSupply)

2. User decrypts obfuscated reserves via the FHE gateway
-> Gets clear values + cryptographic proof

3. User encrypts swap amount client-side
-> Creates encrypted (amountIn, minAmountOut) via FHE SDK

4. User calls atomicSwapAForB(
amountInExt, minAmountOutExt, proofIn,
recipient,
decryptedORA, decryptedORB, reserveProof
)

5. Pool validates:
- reserveProof matches current obfuscated ciphertexts
- Pulls amountIn from user

6. Pool computes (all encrypted):
- effectiveIn = amountIn * (1 - swapFeeBps / 1,000,000)
- amountOut via 4-term Taylor approximation
- Checks: effectiveIn <= maxEffectiveIn (Taylor bound)
- Checks: amountOut >= minAmountOut (slippage)

7. If both checks pass:
- Transfer amountOut to recipient
- Add amountIn to reserves
If either fails:
- Refund amountIn to caller

8. Pool rotates obfuscation factor (fresh RNG)
-> New obfuscated reserves publicly available

Privacy Guarantees

What remains encryptedWhat is public
True reserve amountsPool exists (pair address)
Trade input/output amountsSwap occurred (event emitted)
LP positionsDirection (A-to-B or B-to-A)
Price impactParticipant addresses

Obfuscation Mechanism

True reserves are never revealed. Instead, the pool exposes obfuscated reserves:

obfuscatedReserveA = reserveA * factor
obfuscatedReserveB = reserveB * factor
obfuscatedLPSupply = totalSupply * factor

Where factor is a random value in range [1,000,000 to ~2,966,050] (~3x uncertainty). The same factor is used for all three values, so the price ratio is preserved but absolute magnitudes are hidden.

The factor is rotated on every state-changing operation (swap, liquidity add/remove) to prevent correlation attacks.

How Liquidity Works

Bootstrap (One-Time Initialization)

The pool owner calls bootstrap() once to seed initial liquidity:

bootstrap(amountAExt, amountBExt, inputProof)
-> Pulls encrypted amounts of both tokens
-> LP tokens minted = (amountA >> 1) + (amountB >> 1)
-> Sets reservesInitialized = true

Contribute (Any User, After Bootstrap)

contributeLiquidity(
amountAExt, amountBExt, amountProof,
decryptedORA, decryptedORB, decryptedOL, OProof
)
-> Validates obfuscated state proof
-> Pulls both token amounts
-> Mints LP = min(amountA * obfTotalSupply / obfReserveA,
amountB * obfTotalSupply / obfReserveB)
(factor cancels in the ratio)

Remove Liquidity

removeLiquidity(
sharesToRemoveExt, sharesProof,
decryptedORA, decryptedORB, decryptedOL, OProof
)
-> Proportional withdrawal: grossX = shares * obfReserveX / obfTotalSupply
-> 0.05% withdrawal fee (prevents JIT attacks)
-> Net amounts transferred to user
-> LP tokens burned

Fee Model (Uniswap V2 Style)

Fee TypeAmountDescription
Swap feeConfigurable (e.g. 0.3% = 3,000 BPS)Deducted from input amount
Withdrawal fee0.05% (500 BPS)Applied on liquidity removal
BPS denominator1,000,000All fees expressed in this scale
  • Fees stay implicitly in reserves (no fee accumulator or growth tracking)
  • LPs realize accumulated fees when removing liquidity
  • No public fee tracking that could leak trading activity

Deployed Contracts (Sepolia)

See Deployed Addresses for complete details.

ContractAddress
EPoolFactory0xa830205E7b5e1b75a6e6EED34207C7FEc7aBEEAE
UniversalRouter0x6ef96225151e207cA92cF923C4edD0aC3235842c
Airdrop0x5509c8b9995EfEB21A9B6a25995040fF75b960b9

Tokens (All 6 Decimals)

SymbolAddress
eBTC0xF7De724CC4ef8c881a5aEbae274A3c05dEF7aa40
eETH0x5112d35acc479EA1a9B406d1c7B36b37C2A196d7
eUSD0x531385Bf03cF41CbfAfc424C67e6A6e9f5B6cad7
LUN0x7F1117204141c6044579C965Ce1fcca1e51E74f2
eUSDT0x8EFe087A2895D942574DB6764A884612fCe4EBE1
eBNB0x25aE630fBdB2EDc6D0053cf93a5e1D9739cBb528