Skip to content

0xan0nxyz/dark-pool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dark-pool

MEV-resistant commit-reveal AMM — front-run nothing, swap anything.

A minimal constant-product AMM where swap intent is hidden from block builders until the moment of execution. Searchers see an opaque hash on-chain. By the time they know the trade params, it's already settled.


How It Works

Phase 1 — Commit (any block)

bytes32 secret = keccak256(abi.encode(myAddress, block.timestamp)); // keep private
bytes32 hash   = pool.buildHash(tokenIn, amountIn, minAmountOut, deadline, secret);

pool.commit(hash);

The AMM stores only hash → {trader, commitBlock}. Nothing about the swap params leaks on-chain.

Phase 2 — Reveal (after REVEAL_DELAY blocks)

pool.reveal(tokenIn, amountIn, minAmountOut, deadline, secret);

The contract re-hashes the plaintext, verifies it matches the stored commitment, checks the reveal window, and executes the constant-product swap atomically. Tokens are pulled and sent in the same transaction.

Reveal Window

Constant Value Purpose
REVEAL_DELAY 1 block Must wait at least one block — prevents same-block sandwich
REVEAL_DEADLINE 256 blocks Commitment expires if not revealed — prevents stale commitments

Anti-MEV Properties

  • No lookahead: block builders see commit(hash) but tokenIn, amountIn, and minAmountOut are hidden inside the hash until reveal.
  • No same-block sandwich: REVEAL_DELAY forces at least one block between commit and reveal. A searcher cannot insert a front-run in the same block as the commit.
  • No front-running on reveal: the swap executes in the same tx as the reveal — there is no gap to exploit between approval and execution.
  • One-time use: each commitment hash can only be revealed once (I-5).

Invariants

ID Invariant
I-1 k_after >= k_before — fees only increase the pool
I-2 totalShares > 0 → reserve0 > 0 && reserve1 > 0
I-3 shares[addr] / totalShares == addr's proportional claim
I-4 MINIMUM_LIQUIDITY permanently locked to address(1) on first deposit
I-5 Each commitment hash is consumed exactly once

Interface

Function Phase Description
addLiquidity(amount0, amount1) LP Deposit tokens, receive LP shares
removeLiquidity(shares) LP Burn shares, receive proportional tokens
commit(hash) Swap Phase 1 Register intent — hash only, no tokens locked
reveal(tokenIn, amountIn, minOut, deadline, secret) Swap Phase 2 Verify + execute atomically
getAmountOut(tokenIn, amountIn) View Quote for UI
buildHash(...) View Helper to compute commitment hash off-chain

Getting Started

git clone https://github.com/0xan0nxyz/dark-pool
cd dark-pool
forge install
forge test

Test Coverage

17 tests — 0 failed

Unit:  addLiquidity, removeLiquidity, commit, reveal (happy path + all 7 revert cases)
Fuzz:  k-invariant across 256 random swap sizes, proportional LP removal

Limitations and Trade-offs

  • Latency: Users must wait REVEAL_DELAY blocks. On Ethereum (~12s/block) this is ~12 seconds minimum.
  • Commitment expiry: Unrevealed commitments expire after 256 blocks (~51 min). No tokens are locked so there is nothing to refund.
  • Fixed input: Each commitment is for an exact amountIn. Slippage protection is via minAmountOut set at commit time.
  • No flash loans: The pool does not lend reserves intra-transaction.

License

MIT

About

MEV-resistant commit-reveal AMM — front-run nothing, swap anything.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors