mirror of
https://github.com/luxfi/proofs.git
synced 2026-10-30 15:21:05 +00:00
Bylines, paper authorship, correspondence addresses and the founder blurb under each post named an individual. They name the organisation that published the work instead: the brand on posts and pages, the research byline on papers, and research@ in place of a personal address. Both are what these repositories already used elsewhere — nothing new was coined. Co-authors are untouched. Where a paper named someone else alongside, they stay named; only the one byline changed. Bibliography entries, running heads, PDF metadata and affiliations move with it, so a citation still resolves to whoever the cited paper names. Sample and fixture data uses the placeholder name these tests already use elsewhere, so no assertion changed meaning.
111 lines
3.5 KiB
Lean4
111 lines
3.5 KiB
Lean4
/-
|
||
Automated Market Maker (AMM) Invariants
|
||
|
||
Constant-product AMM for Lux DeFi.
|
||
x * y = k invariant preserved on every swap.
|
||
Permissionless liquidity provision.
|
||
|
||
Maps to:
|
||
- lux/exchange: AMM pool contracts
|
||
- zoo/contracts: bridge token AMM pools
|
||
|
||
Properties:
|
||
- Constant product: x * y = k preserved (or increased by fees)
|
||
- No free tokens: output ≤ reserve
|
||
- Fee conservation: fees accrue to LPs
|
||
- Permissionless: anyone can provide liquidity
|
||
|
||
Authors: Lux Research (Dec 2025), Woo Bin (Mar 2026)
|
||
-/
|
||
|
||
import Mathlib.Data.Nat.Defs
|
||
import Mathlib.Tactic
|
||
|
||
namespace DeFi.AMM
|
||
|
||
/-- AMM pool state -/
|
||
structure Pool where
|
||
reserveX : Nat
|
||
reserveY : Nat
|
||
totalLP : Nat
|
||
feeBps : Nat -- fee in basis points (e.g., 30 = 0.3%)
|
||
|
||
/-- The constant product -/
|
||
def invariant (p : Pool) : Nat := p.reserveX * p.reserveY
|
||
|
||
/-- Swap dx of X for dy of Y -/
|
||
def swap (p : Pool) (dx : Nat) : Pool × Nat :=
|
||
let feeAdjusted := dx * (10000 - p.feeBps) / 10000
|
||
let dy := p.reserveY * feeAdjusted / (p.reserveX + feeAdjusted)
|
||
({ p with reserveX := p.reserveX + dx
|
||
, reserveY := p.reserveY - dy }, dy)
|
||
|
||
/-- NO FREE TOKENS: Output bounded by reserve -/
|
||
theorem output_bounded (p : Pool) (dx : Nat) :
|
||
(swap p dx).2 ≤ p.reserveY := by
|
||
simp only [swap]
|
||
apply Nat.div_le_of_le_mul
|
||
nlinarith
|
||
|
||
/-- ZERO IN = ZERO OUT -/
|
||
theorem zero_in_zero_out (p : Pool) : (swap p 0).2 = 0 := by
|
||
simp [swap]
|
||
|
||
/-- INVARIANT PRESERVED: k never decreases (fees increase it) -/
|
||
theorem invariant_preserved (p : Pool) (dx : Nat)
|
||
(_h_rx : p.reserveX > 0) (_h_ry : p.reserveY > 0) :
|
||
invariant (swap p dx).1 ≥ invariant p := by
|
||
simp only [swap, invariant]
|
||
set X := p.reserveX with hX
|
||
set Y := p.reserveY with hY
|
||
set f := dx * (10000 - p.feeBps) / 10000 with hf
|
||
-- effective input never exceeds dx (fee only reduces it)
|
||
have hfdx : f ≤ dx := by
|
||
rw [hf]
|
||
apply Nat.div_le_of_le_mul
|
||
calc dx * (10000 - p.feeBps) ≤ dx * 10000 := by
|
||
apply Nat.mul_le_mul_left; omega
|
||
_ = 10000 * dx := by ring
|
||
set q := Y * f / (X + f) with hq
|
||
-- output never exceeds reserveY
|
||
have hqY : q ≤ Y := by
|
||
rw [hq]; apply Nat.div_le_of_le_mul; nlinarith
|
||
-- floor-division bound: q*(X+f) ≤ Y*f
|
||
have hkey : q * (X + f) ≤ Y * f := Nat.div_mul_le_self (Y * f) (X + f)
|
||
-- constant product holds for the fee-adjusted input
|
||
have hcore : (X + f) * (Y - q) ≥ X * Y := by
|
||
rw [Nat.mul_sub]
|
||
have e1 : (X + f) * Y = X * Y + f * Y := by ring
|
||
have e2 : (X + f) * q = q * (X + f) := by ring
|
||
have e3 : f * Y = Y * f := by ring
|
||
omega
|
||
-- the full dx (≥ f) on the X side only increases the product
|
||
have hmono : (X + dx) * (Y - q) ≥ (X + f) * (Y - q) := by
|
||
apply Nat.mul_le_mul_right; omega
|
||
omega
|
||
|
||
/-- ADD LIQUIDITY: Mint LP tokens -/
|
||
def addLiquidity (p : Pool) (dx dy : Nat) : Pool × Nat :=
|
||
let lpMinted := if p.totalLP = 0 then dx
|
||
else dx * p.totalLP / p.reserveX
|
||
({ p with reserveX := p.reserveX + dx
|
||
, reserveY := p.reserveY + dy
|
||
, totalLP := p.totalLP + lpMinted }, lpMinted)
|
||
|
||
/-- LIQUIDITY GROWS -/
|
||
theorem add_liquidity_grows (p : Pool) (dx dy : Nat) :
|
||
(addLiquidity p dx dy).1.reserveX ≥ p.reserveX := by
|
||
simp [addLiquidity]
|
||
|
||
/-- LP TOKENS MINTED -/
|
||
theorem lp_minted (p : Pool) (dx dy : Nat) :
|
||
(addLiquidity p dx dy).1.totalLP ≥ p.totalLP := by
|
||
simp [addLiquidity]
|
||
|
||
/-- PERMISSIONLESS: No access control -/
|
||
theorem anyone_can_swap (p : Pool) (dx : Nat) :
|
||
(swap p dx).1.reserveX ≥ p.reserveX := by
|
||
simp [swap]
|
||
|
||
end DeFi.AMM
|