Skip to content
Lunarys

Lunarys

Privacy First DEX using FHENIX.

Created on 4th December 2025

Lunarys

Lunarys

Privacy First DEX using FHENIX.

The problem Lunarys solves

Financial Privacy on Public Blockchains

Today, every transaction on Ethereum is fully transparent. Anyone can see:

  • Your wallet balance
  • Who you're trading with
  • How much you're swapping
  • Your liquidity positions

This creates serious problems:

  • Front-running & MEV attacks exploit visible pending transactions
  • Competitive intelligence leaks expose trading strategies
  • Personal security risks from publicly visible wealth
  • Regulatory concerns for institutions handling client data

Lunarys DEX: Private DeFi with FHE

Lunarys is a confidential decentralized exchange powered by Fully Homomorphic Encryption (FHE). It enables:

FeatureWhat It Does
Private SwapsTrade encrypted tokens without revealing amounts or counterparties
Confidential LiquidityProvide liquidity to pools where reserves stay encrypted
Hidden BalancesYour token holdings are encrypted on-chain—only you can decrypt them
Encrypted PositionsLP positions represented as NFTs with confidential data

How It Makes DeFi Safer

Traditional DEX: Lunarys DEX:
┌─────────────────────┐ ┌─────────────────────┐
│ Swap 10,000 USDC │ │ Swap ████████ eUSDC │
│ for 9,200 EURC │ → │ for ████████ eEURC │
│ Wallet: 0x1234... │ │ Wallet: 0x1234... │
│ Balance: $50,000 │ │ Balance: ██████████ │
└─────────────────────┘ └─────────────────────┘
Everyone can see Only you can see

Key Benefits:

  • Zero MEV Exposure — Bots can't front-run trades they can't see
  • Institutional Ready — Trade without exposing client positions
  • Personal Security — No one can target you based on visible wealth
  • Compliance Compatible — Audit trails exist without public exposure

Use Cases

  1. Private Token Swaps — Convert between encrypted stablecoins (eUSDC ↔ eEURC) without revealing trade size
  2. Confidential Yield Farming — Earn APY on liquidity pools while keeping position sizes private
  3. Secure Portfolio Management — View and manage encrypted balances, transfer tokens privately
  4. Institutional Trading — Execute large trades without market impact from front-runners

Technology Stack

  • FHE (Fhenix CoFHE) — Enables computation on encrypted data without decryption
  • Encrypted Tokens — Encrypted token standard for confidential balances
  • Constant Product AMM — Standard x*y=k formula with encrypted reserves
  • Position NFTs — Liquidity positions as transferable encrypted NFTs

Challenges I ran into

The most frustrating issue we encountered was with balance decryption after swaps. After executing a successful swap transaction:

User swaps eUSDC → eEURC
Transaction confirmed ✅
Try to decrypt new eEURC balance... ❌ FAILS
Wait ~2 minutes...
Try again... ✅ Works perfectly

The Problem:
When a user receives encrypted tokens from a swap, attempting to decrypt the new balance immediately fails. The cofhejs.unseal() call either returns an error or stale data for approximately 2 minutes after
the transaction confirms.

What We Tried:

  • Invalidating local FHE permit cache
  • Re-fetching the encrypted balance handle
  • Adding retry logic with exponential backoff

Current Workaround:
We implemented a polling mechanism with user feedback:

// Show "Balance updating..." state
// Retry decryption every 15 seconds
// After ~2 min, decryption succeeds

Uncertainty:
We're still not 100% sure if this is:

  • A CoFHE SDK limitation — the SDK caches something that needs to invalidate
  • On-chain propagation delay — FHE ciphertext needs a few blocks to be "readable"
  • Fhenix network latency — decryption nodes need time to sync new encrypted state

This doesn't break functionality, but it impacts UX. Users see their swap succeed but can't immediately verify their new balance.


  1. Encrypted Arithmetic Precision

FHE operations on euint64 don't support decimals. Implementing the AMM's constant product formula with proper precision required careful handling:

// Problem: k = reserveA * reserveB can overflow euint64
// Solution: Use euint128 for intermediate calculations
euint128 k = FHE.mul(
FHE.asEuint128(reserveA),
FHE.asEuint128(reserveB)
);

Fee calculations with basis points (0.3% = 3000/1000000) needed RAY scaling (10^18) to maintain precision without decimals.


  1. Async Decryption Pattern

Unlike regular Solidity where you can read values synchronously, FHE decryption is asynchronous:

// Step 1: Request decryption (transaction 1)
FHE.decrypt(encryptedValue);

// Step 2: Wait for Fhenix network to process...

// Step 3: Retrieve result (transaction 2 or view call)
(uint256 result, bool ready) = FHE.getDecryptResultSafe(handle);

This required restructuring our entire flow for features like "mid-price oracle" — users must wait between requesting and receiving the price.


  1. Permission Management Complexity

FHE values require explicit permission grants. When transferring Position NFTs, we had to ensure the new owner gets FHE access:

function _update(address to, uint256 tokenId, address auth) internal override {
super._update(to, tokenId, auth);

// Grant FHE permissions to new owner Position storage pos = _positions[tokenId]; FHE.allow(pos.liquidity, to); FHE.allow(pos.token0Amount, to); FHE.allow(pos.token1Amount, to);

}

Forgetting a single FHE.allow() meant users couldn't access their own encrypted data.

Cheer Project

Cheering for a project means supporting a project you like with as little as 0.0025 ETH. Right now, you can Cheer using ETH on Arbitrum, Optimism and Base.

Discussion

Builders also viewed

See more projects on Devfolio