Skip to main content

EPOOL Architecture

Overview

The EPOOL (Encrypted Pool) is the core AMM contract implementing a Uniswap V2-style constant product formula (x * y = k) with fully encrypted reserves and obfuscated public state for price discovery.

State Variables

// Assets
IERC7984 public immutable assetA; // First confidential token
IERC7984 public immutable assetB; // Second confidential token
uint24 public swapFeeBps; // Swap fee (e.g. 3000 = 0.3%)

// Encrypted reserves (private)
euint64 private reserveA;
euint64 private reserveB;

// Obfuscation parameters (encrypted)
euint64 private minObfuscationFactor; // Min factor (e.g. 1,000,000)
euint64 private obfuscationFactorStep; // Step per RNG unit (e.g. 30)

// Public state
uint32 public lastUpdate;
bool public reservesInitialized;
EPoolTypes.obfuscatedStatesStruct public obfuscatedStates;

Obfuscated States Structure

struct obfuscatedStatesStruct {
euint64 obfuscatedReserveA; // reserveA * factor
euint64 obfuscatedReserveB; // reserveB * factor
euint64 lpSupply; // totalSupply * factor
}

Constants

ConstantValueDescription
BPS_DENOMINATOR1,000,000Basis points scale
WITHDRAWAL_FEE_BPS5000.05% withdrawal fee

Core Functions

bootstrap

function bootstrap(
externalEuint64 amountAExt,
externalEuint64 amountBExt,
bytes calldata inputProof
) external

Owner-only, one-time pool initialization. Pulls encrypted amounts of both tokens, mints LP tokens = (amountA >> 1) + (amountB >> 1), and sets reservesInitialized = true.

atomicSwapAForB / atomicSwapBForA

function atomicSwapAForB(
externalEuint64 amountInExt,
externalEuint64 minAmountOutExt,
bytes calldata proofIn,
address recipient,
uint128 decryptedORA,
uint128 decryptedORB,
bytes calldata reserveProof
) external

Single-transaction swap. Validates proof, computes output via 4-term Taylor, checks slippage, and either executes or refunds.

contributeLiquidity

function contributeLiquidity(
externalEuint64 amountAExt,
externalEuint64 amountBExt,
bytes calldata amountProof,
uint128 decryptedORA,
uint128 decryptedORB,
uint128 decryptedOL,
bytes calldata OProof
) external

Symmetric deposit with proportional LP minting.

removeLiquidity

function removeLiquidity(
externalEuint64 sharesToRemoveExt,
bytes calldata sharesProof,
uint128 decryptedORA,
uint128 decryptedORB,
uint128 decryptedOL,
bytes calldata OProof
) external

Proportional withdrawal with 0.05% fee.

Swap Flow Detail

1. Validate reserveProof against obfuscatedStates ciphertexts
2. Pull amountIn from user via confidentialTransferFrom
3. Compute effectiveIn = amountIn * (BPS - swapFeeBps) / BPS
4. Compute amountOut via SwapLib.computeConstantProductOutput:
- price = obfOut * SCALE / obfIn (clear math, factor cancels)
- 4-term Taylor: linear - quad + cubic - quartic
- reserveInLowerBound = obfIn / MAX_OBFUSCATION_FACTOR
5. Check Taylor bound: effectiveIn <= reserveInLowerBound / 16
6. Check slippage: amountOut >= minAmountOut
7. If pass: transfer output, update reserves
If fail: refund input
8. Rotate obfuscation factor

Obfuscation Mechanism

Factor Generation (3 FHE Operations)

euint16 seed = FHE.randEuint16();                    // [0, 65535]
euint64 offset = FHE.mul(FHE.asEuint64(seed), step); // seed * 30
euint64 factor = FHE.add(offset, minFactor); // 1M + offset
// Range: [1,000,000 to ~2,966,050]

Factor Application

Every state-changing operation:

  1. Generates a fresh random factor
  2. obfuscatedReserveA = reserveA * factor
  3. obfuscatedReserveB = reserveB * factor
  4. obfuscatedLPSupply = totalSupply * factor
  5. All three marked publiclyDecryptable

Privacy Properties

PropertyStatusNotes
Price ratioPublicly derivableBy design (necessary for AMM)
Reserve magnitudesHidden~3x uncertainty
Trade amountsEncryptedNever revealed
LP positionsEncryptedCERC20 balances
Factor valueEncryptedRotated per operation

Events

event AtomicSwapExecuted(
address indexed caller,
address indexed recipient,
bool aForB,
bytes32 amountOutHandle
);
event AtomicSwapRefunded(address indexed caller, bool aForB, string reason);
event SwapExecuted(address indexed sender, address indexed recipient, bool aForB);
event LiquiditySeeded(address indexed provider);
event LiquidityAdjusted(address indexed caller, bool add);
event WithdrawalFeeCollected(uint256 indexed tokenId, bytes32 feeAHandle, bytes32 feeBHandle);