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
| Constant | Value | Description |
|---|---|---|
BPS_DENOMINATOR | 1,000,000 | Basis points scale |
WITHDRAWAL_FEE_BPS | 500 | 0.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:
- Generates a fresh random factor
obfuscatedReserveA = reserveA * factorobfuscatedReserveB = reserveB * factorobfuscatedLPSupply = totalSupply * factor- All three marked
publiclyDecryptable
Privacy Properties
| Property | Status | Notes |
|---|---|---|
| Price ratio | Publicly derivable | By design (necessary for AMM) |
| Reserve magnitudes | Hidden | ~3x uncertainty |
| Trade amounts | Encrypted | Never revealed |
| LP positions | Encrypted | CERC20 balances |
| Factor value | Encrypted | Rotated 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);