Created
November 4, 2025 16:29
-
-
Save DinhKhai0201/d67a186b13178fd2530b8206646e1347 to your computer and use it in GitHub Desktop.
dex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # DEX - Tài liệu Chi tiết Contracts | |
| ## Mục lục | |
| 1. [Tổng quan kiến trúc](#tổng-quan-kiến-trúc) | |
| 2. [AMM Fundamentals - Giải thích Reserve và Công thức](#amm-fundamentals---giải-thích-reserve-và-công-thức) | |
| 3. [Constants Contract](#constants-contract) | |
| 4. [Math Contract](#math-contract) | |
| 5. [PairTemplate Contract](#pairtemplate-contract) | |
| 6. [AmmPair Contract](#ammpair-contract) | |
| 7. [StableTokenPair Contract](#stabletokenpair-contract) | |
| 8. [Twamm Contract (Orderbook)](#twamm-contract-orderbook) | |
| 9. [Router Contract](#router-contract) | |
| 10. [TokenPairFactory Contract](#tokenpairfactory-contract) | |
| 11. [Flow tổng thể](#flow-tổng-thể) | |
| --- | |
| ## Tổng quan kiến trúc | |
| DEX được xây dựng với kiến trúc modular: | |
| ``` | |
| Constants (base constants & errors) | |
| ↑ | |
| Math (safe arithmetic operations) | |
| ↑ | |
| PairTemplate (base pair logic: mint/burn/staking) | |
| ↑ | |
| Twamm (TWAMM & DCA orderbook logic) | |
| ↑ | |
| ┌─────────────────┬─────────────────┐ | |
| │ AmmPair │ StableTokenPair │ | |
| │ (Volatile AMM) │ (Stable AMM) │ | |
| └─────────────────┴─────────────────┘ | |
| ↑ ↑ | |
| └──────────────────┘ | |
| ↓ | |
| Router (swap routing) | |
| ↓ | |
| TokenPairFactory (pair creation) | |
| ``` | |
| --- | |
| ## AMM Fundamentals - Giải thích Reserve và Công thức | |
| ### Reserve0 và Reserve1 là gì? | |
| **Reserve** = Số lượng token được lưu trữ trong pool (kho dự trữ) | |
| - **reserve0**: Số lượng token0 hiện có trong pool | |
| - **reserve1**: Số lượng token1 hiện có trong pool | |
| **Ví dụ**: | |
| ``` | |
| Pool ALPH/USDT: | |
| - reserve0 (ALPH) = 10,000 ALPH | |
| - reserve1 (USDT) = 20,000 USDT | |
| Tỷ giá hiện tại: 1 ALPH = 2 USDT | |
| ``` | |
| ### Constant Product Formula (Công thức AMM) | |
| DEX sử dụng **Constant Product Market Maker (CPMM)** với công thức: | |
| ``` | |
| x * y = k | |
| ``` | |
| Trong đó: | |
| - `x` = reserve0 (số lượng token0) | |
| - `y` = reserve1 (số lượng token1) | |
| - `k` = constant product (tích số không đổi) | |
| **Quy tắc**: Khi swap, `k` phải được duy trì hoặc tăng lên (sau khi tính phí). | |
| ### Công thức tính Output khi Swap | |
| Khi bạn swap `amountIn` token vào pool, bạn nhận được `amountOut` token: | |
| ``` | |
| amountOut = (reserveOut * amountIn) / (reserveIn + amountIn) | |
| ``` | |
| **Nhưng** trong thực tế, có phí 0.3%: | |
| ``` | |
| fee = amountIn * 0.3% = amountIn * 3 / 1000 | |
| amountInAfterFee = amountIn - fee | |
| amountOut = (reserveOut * amountInAfterFee) / (reserveIn + amountInAfterFee) | |
| ``` | |
| ### Ví dụ cụ thể | |
| #### Tình huống ban đầu: | |
| ``` | |
| Pool ALPH/USDT: | |
| - reserve0 (ALPH) = 10,000 ALPH | |
| - reserve1 (USDT) = 20,000 USDT | |
| - k = 10,000 * 20,000 = 200,000,000 (constant) | |
| ``` | |
| #### Bạn muốn swap: 1,000 ALPH → USDT | |
| **Bước 1: Tính phí** | |
| ``` | |
| fee = 1,000 * 3 / 1000 = 3 ALPH | |
| amountInAfterFee = 1,000 - 3 = 997 ALPH | |
| ``` | |
| **Bước 2: Tính output** | |
| ``` | |
| reserveIn = 10,000 ALPH (sẽ tăng) | |
| reserveOut = 20,000 USDT (sẽ giảm) | |
| amountInAfterFee = 997 ALPH | |
| amountOut = (20,000 * 997) / (10,000 + 997) | |
| = 19,940,000 / 10,997 | |
| = 1,813.4 USDT | |
| ``` | |
| **Bước 3: Cập nhật reserves** | |
| ``` | |
| newReserve0 = 10,000 + 1,000 = 11,000 ALPH | |
| newReserve1 = 20,000 - 1,813.4 = 18,186.6 USDT | |
| newK = 11,000 * 18,186.6 = 200,052,600 | |
| ``` | |
| **Kết quả**: | |
| - Bạn nhận được: **1,813.4 USDT** | |
| - Tỷ giá sau swap: 1 ALPH = 1.654 USDT (giá giảm vì bạn bán ALPH) | |
| - `k` tăng lên (do phí) → LPs được hưởng lợi | |
| ### Tại sao công thức này hoạt động? | |
| 1. **Tự động định giá**: | |
| - Càng swap nhiều token vào → giá token đó giảm | |
| - Càng swap token ra → giá token đó tăng | |
| - Đảm bảo luôn có thanh khoản | |
| 2. **Slippage (độ trượt giá)**: | |
| - Swap nhỏ → slippage nhỏ | |
| - Swap lớn → slippage lớn (giá thay đổi nhiều) | |
| **Ví dụ**: | |
| ``` | |
| Swap 100 ALPH → ~1,980 USDT (slippage nhỏ) | |
| Swap 5,000 ALPH → ~9,000 USDT (slippage lớn vì chiếm 50% pool) | |
| ``` | |
| 3. **Phí 0.3%**: | |
| - 50% phí → LP fees (stay in reserves, tăng k) | |
| - 50% phí → Staking fees (cho stakers) | |
| - Phí làm cho `k` tăng → LPs được hưởng lợi | |
| ### Ví dụ minh họa chi tiết | |
| #### Scenario 1: Swap nhỏ (slippage thấp) | |
| ``` | |
| Trước swap: | |
| - reserve0 = 10,000 ALPH | |
| - reserve1 = 20,000 USDT | |
| - k = 200,000,000 | |
| Swap: 100 ALPH → USDT | |
| Tính toán: | |
| 1. fee = 100 * 0.3% = 0.3 ALPH | |
| 2. amountInAfterFee = 99.7 ALPH | |
| 3. amountOut = (20,000 * 99.7) / (10,000 + 99.7) = 1,985.8 USDT | |
| Sau swap: | |
| - reserve0 = 10,100 ALPH | |
| - reserve1 = 18,014.2 USDT | |
| - newK = 181,943,420 (tăng do phí) | |
| Kết quả: | |
| - Bạn nhận: 1,985.8 USDT | |
| - Giá: 1 ALPH = 1,985.8/100 = 19.858 USDT (gần với giá ban đầu 20 USDT) | |
| - Slippage: (20 - 19.858) / 20 = 0.71% (thấp) | |
| ``` | |
| #### Scenario 2: Swap lớn (slippage cao) | |
| ``` | |
| Trước swap: | |
| - reserve0 = 10,000 ALPH | |
| - reserve1 = 20,000 USDT | |
| - k = 200,000,000 | |
| Swap: 5,000 ALPH → USDT (50% pool!) | |
| Tính toán: | |
| 1. fee = 5,000 * 0.3% = 15 ALPH | |
| 2. amountInAfterFee = 4,985 ALPH | |
| 3. amountOut = (20,000 * 4,985) / (10,000 + 4,985) = 6,652.4 USDT | |
| Sau swap: | |
| - reserve0 = 15,000 ALPH | |
| - reserve1 = 13,347.6 USDT | |
| - newK = 200,214,000 | |
| Kết quả: | |
| - Bạn nhận: 6,652.4 USDT | |
| - Giá: 1 ALPH = 6,652.4/5,000 = 1.33 USDT (giảm mạnh!) | |
| - Slippage: (20 - 1.33) / 20 = 93.35% (rất cao!) | |
| ``` | |
| ### So sánh: Constant Product vs Stable Swap | |
| | Tính năng | Constant Product (AmmPair) | Stable Swap (StableTokenPair) | | |
| |-----------|---------------------------|------------------------------| | |
| | **Công thức** | `x * y = k` | `x³y + y³x = k` | | |
| | **Dùng cho** | Volatile tokens (ALPH/USDT, BTC/ETH) | Stablecoins (USDT/USDC) | | |
| | **Slippage** | Cao hơn | Thấp hơn (giữ tỷ giá 1:1) | | |
| | **Tính toán** | Đơn giản | Phức tạp hơn (Newton's method) | | |
| ### Tóm tắt | |
| 1. **Reserve0 và Reserve1**: Số lượng token trong pool | |
| 2. **Constant Product**: `x * y = k` - tích số không đổi | |
| 3. **Công thức swap**: `amountOut = (reserveOut * amountInAfterFee) / (reserveIn + amountInAfterFee)` | |
| 4. **Phí 0.3%**: 50% LP fees, 50% staking fees | |
| 5. **Slippage**: Tăng theo kích thước swap | |
| 6. **K tăng**: Do phí → LPs được hưởng lợi | |
| --- | |
| ## Constants Contract | |
| **Mục đích**: Định nghĩa các constants và error codes được sử dụng xuyên suốt hệ thống. | |
| ### Constants | |
| #### `MIN_RESERVE = 1000` | |
| - **Công dụng**: Giá trị reserve tối thiểu để đảm bảo pool có thanh khoản hợp lý | |
| - **Tại sao cần**: | |
| 1. **Tránh Dust Attacks**: Ngăn ai đó deposit số lượng rất nhỏ (ví dụ: 1 wei) để tạo pool với thanh khoản không đủ | |
| 2. **Đảm bảo tính toán chính xác**: Với reserve quá nhỏ, các phép tính chia có thể mất precision | |
| 3. **Bảo vệ người dùng**: Đảm bảo pool có đủ liquidity để thực hiện swaps | |
| - **Ví dụ**: | |
| - ❌ **Không hợp lệ**: reserve0 = 100, reserve1 = 50 → Quá nhỏ, không đủ cho swap | |
| - ✅ **Hợp lệ**: reserve0 = 1000, reserve1 = 2000 → Đủ lớn để thực hiện swaps | |
| - **Khi nào được kiểm tra**: | |
| - Trước mọi phép tính toán reserves (validateReserve()) | |
| - Sau khi update reserves (mint, burn, swap) | |
| - Trong AMM calculations (safeAmmOutput, safeConstantProduct) | |
| - **Lưu ý**: Khi burn toàn bộ liquidity (totalSupply = 0), reserves có thể = 0 (không check MIN_RESERVE) | |
| #### `MAX_RESERVE = ~2^192` | |
| - **Công dụng**: Giá trị reserve tối đa để tránh overflow trong các phép tính toán | |
| - **Tại sao không dùng 2^256**: | |
| 1. **Overflow trong phép nhân (Constant Product)**: | |
| - Khi tính k = reserve0 * reserve1 cho AMM | |
| - Nếu reserve0 = 2^128 và reserve1 = 2^128 → k = 2^256 (đã là max U256) | |
| - Nếu cả 2 reserves đều > 2^128 → k sẽ overflow U256! | |
| - Với MAX_RESERVE = 2^192: | |
| - reserve0 max = 2^192, reserve1 max = 2^192 | |
| - k max = 2^192 * 2^192 = 2^384 → Vẫn overflow! | |
| - **Nhưng**: Thực tế reserves không bao giờ đạt đến 2^192 | |
| - Với reserves thực tế như 2^128: k = 2^256 (vừa đủ) | |
| 2. **Overflow trong stable pair**: | |
| - Tính x³y + y³x với x = y = 2^192 | |
| - x³ = (2^192)³ = 2^576 → Quá lớn, overflow! | |
| - **Nhưng**: Reserves thực tế không bao giờ đạt đến 2^192 | |
| - MAX_RESERVE là giới hạn lý thuyết để đảm bảo các tính toán intermediate không overflow | |
| 3. **Safety margin**: | |
| - Giữ lại margin để đảm bảo các intermediate calculations (như x², x³) không overflow | |
| - 2^192 là giá trị đủ lớn cho mọi use case thực tế nhưng vẫn an toàn | |
| - **Ví dụ thực tế**: | |
| - ❌ **Nguy hiểm nếu không có giới hạn**: | |
| - reserve0 = 2^128, reserve1 = 2^128 | |
| - k = 2^128 * 2^128 = 2^256 (max U256) → Nếu reserve tăng thêm → Overflow! | |
| - ✅ **An toàn với MAX_RESERVE = 2^192**: | |
| - reserve0 = 1,000,000, reserve1 = 2,000,000 | |
| - k = 2,000,000,000,000 → Rất xa MAX_RESERVE, an toàn | |
| - Có thể tăng reserves lên rất nhiều trước khi chạm giới hạn | |
| - ✅ **Giới hạn hợp lý**: | |
| - Với token có 18 decimals: 2^192 = ~6.3 * 10^57 units | |
| - Đây là số lượng cực kỳ lớn, không bao giờ đạt đến trong thực tế | |
| - **Khi nào được kiểm tra**: | |
| - Trước mọi phép tính toán reserves (validateReserve()) | |
| - Trong sqrt() để tránh overflow trong intermediate calculations | |
| - Trong safeConstantProduct() và safeStableInvariant() | |
| - Sau khi update reserves (mint, burn, swap) để đảm bảo không vượt quá | |
| - **Lưu ý quan trọng**: | |
| - MAX_RESERVE không phải là giới hạn cứng cho k (constant product) | |
| - Nó là giới hạn cho từng reserve để đảm bảo các phép tính không overflow | |
| - Trong thực tế, reserves sẽ không bao giờ đạt đến giá trị này | |
| #### `MAX_U256` | |
| - **Công dụng**: Giá trị tối đa của U256 (2^256 - 1) | |
| - **Sử dụng**: Reference cho overflow checks | |
| ### Tóm tắt MIN_RESERVE và MAX_RESERVE | |
| **MIN_RESERVE = 1000** - "Sàn dưới" | |
| - Đảm bảo pool có đủ thanh khoản tối thiểu | |
| - Tránh các pool với reserves quá nhỏ (dust) | |
| - Ví dụ: Không cho phép pool có 1 token này và 2 token kia | |
| **MAX_RESERVE = ~2^192** - "Trần trên" | |
| - Giới hạn lý thuyết để đảm bảo tính toán không overflow | |
| - Trong thực tế, reserves không bao giờ đạt đến giá trị này | |
| - Ví dụ: Với token 18 decimals, 2^192 = ~6.3 * 10^57 units (số lượng cực lớn) | |
| **Khi nào được kiểm tra**: | |
| - Mỗi khi tính toán reserves: `validateReserve(reserve)` | |
| - Trước và sau mọi operations (mint, burn, swap) | |
| - Trong các phép tính toán AMM (constant product, stable invariant) | |
| **Ví dụ thực tế**: | |
| ``` | |
| Pool hợp lệ: | |
| - reserve0 = 1,000,000 tokens | |
| - reserve1 = 2,000,000 tokens | |
| - ✅ MIN_RESERVE (1000) < 1,000,000 < MAX_RESERVE (2^192) | |
| Pool không hợp lệ (quá nhỏ): | |
| - reserve0 = 50 tokens | |
| - reserve1 = 100 tokens | |
| - ❌ 50 < MIN_RESERVE (1000) → Revert! | |
| Pool không hợp lệ (quá lớn - lý thuyết): | |
| - reserve0 = 2^192 tokens | |
| - reserve1 = 2^192 tokens | |
| - ❌ 2^192 > MAX_RESERVE → Revert! | |
| - (Trong thực tế không bao giờ xảy ra) | |
| ``` | |
| ### Error Codes | |
| | Code | Tên | Ý nghĩa | | |
| |------|-----|---------| | |
| | 2 | InsufficientLiquidityMinted | Liquidity minted quá thấp | | |
| | 3 | InsufficientLiquidityBurned | Liquidity burned không hợp lệ | | |
| | 5 | InsufficientLiquidity | Pool không đủ thanh khoản | | |
| | 8 | InvalidK | Vi phạm constant product invariant | | |
| | 9 | InsufficientOutputAmount | Output amount thấp hơn expected | | |
| | 10 | InsufficientInputAmount | Input amount = 0 hoặc quá thấp | | |
| | 12 | Expired | Deadline đã qua | | |
| | 13-14 | InsufficientToken0/1Amount | Token amount không đủ | | |
| | 15 | InvariantViolation | AMM invariant bị vi phạm | | |
| | 16-18 | Arithmetic errors | Overflow/Underflow/Division by zero | | |
| | 19-21 | InvalidReserve | Reserve không hợp lệ | | |
| | 22 | InvalidGuess | Invalid guess cho Newton's method | | |
| --- | |
| ## Math Contract | |
| **Mục đích**: Cung cấp các hàm toán học an toàn với overflow/underflow protection. | |
| ### Safe Arithmetic Functions | |
| #### `safeMul(a: U256, b: U256) -> U256` | |
| - **Công dụng**: Nhân an toàn với overflow check | |
| - **Logic**: | |
| - Nếu a = 0 → return 0 | |
| - Verify `result / a == b` để detect overflow | |
| - **Sử dụng**: Tất cả phép nhân trong AMM calculations | |
| #### `safeDiv(a: U256, b: U256) -> U256` | |
| - **Công dụng**: Chia an toàn với zero check | |
| - **Logic**: Assert b > 0 trước khi chia | |
| - **Sử dụng**: Tất cả phép chia | |
| #### `safeAdd(a: U256, b: U256) -> U256` | |
| - **Công dụng**: Cộng an toàn | |
| - **Logic**: Verify `result >= a` để detect overflow | |
| - **Sử dụng**: Cập nhật reserves, fees accumulation | |
| #### `safeSub(a: U256, b: U256) -> U256` | |
| - **Công dụng**: Trừ an toàn với underflow check | |
| - **Logic**: Assert `a >= b` trước khi trừ | |
| - **Sử dụng**: Tính toán output amounts, reserve updates | |
| #### `validateReserve(reserve: U256) -> ()` | |
| - **Công dụng**: Validate reserve nằm trong bounds | |
| - **Logic**: Check `MIN_RESERVE <= reserve <= MAX_RESERVE` | |
| - **Sử dụng**: Trước mọi reserve calculations | |
| ### AMM Math Functions | |
| #### `safeConstantProduct(reserveZero: U256, reserveOne: U256) -> U256` | |
| - **Công dụng**: Tính constant product k = x * y | |
| - **Logic**: Validate reserves → safeMul(x, y) | |
| - **Sử dụng**: Verify invariant trong swaps | |
| #### `safeAmmOutput(reserveIn: U256, reserveOut: U256, amountIn: U256) -> U256` | |
| - **Công dụng**: Tính output amount theo constant product formula | |
| - **Công thức**: `(reserveOut * amountIn) / (reserveIn + amountIn)` | |
| - **Logic**: | |
| 1. Validate reserves và amountIn | |
| 2. numerator = safeMul(reserveOut, amountIn) | |
| 3. denominator = safeAdd(reserveIn, amountIn) | |
| 4. Return safeDiv(numerator, denominator) | |
| - **Sử dụng**: Tất cả swap calculations trong AmmPair | |
| ### Stable Pair Math Functions | |
| #### `safeCube(x: U256) -> U256` | |
| - **Công dụng**: Tính x³ an toàn | |
| - **Logic**: x² = safeMul(x, x) → x³ = safeMul(x², x) | |
| - **Sử dụng**: Stable invariant calculation | |
| #### `safeStableInvariant(x: U256, y: U256) -> U256` | |
| - **Công dụng**: Tính stable swap invariant: k = x³y + y³x | |
| - **Logic**: | |
| 1. x³ = safeCube(x) | |
| 2. y³ = safeCube(y) | |
| 3. term1 = safeMul(x³, y) | |
| 4. term2 = safeMul(y³, x) | |
| 5. Return safeAdd(term1, term2) | |
| - **Sử dụng**: Stable pair swaps | |
| #### `sqrt(y: U256) -> U256` | |
| - **Công dụng**: Tính căn bậc 2 bằng Babylonian method | |
| - **Logic**: | |
| - Iterative method với max 50 iterations | |
| - Overflow protection | |
| - **Sử dụng**: Initial liquidity calculation trong mint() | |
| #### `uqdiv(a: U256, b: U256) -> U256` | |
| - **Công dụng**: Fixed-point division (Q112 format) | |
| - **Logic**: Shift left 112 bits trước khi chia | |
| - **Sử dụng**: Precision calculations | |
| --- | |
| ## PairTemplate Contract | |
| **Mục đích**: Base contract chứa logic chung cho tất cả token pairs (volatile và stable). | |
| **Inheritance**: Extends `Math()`, `Constants()`, `Twamm()`, implements `IFungibleToken`, `TokenPair` | |
| ### State Variables | |
| - `reserve0`, `reserve1`: Reserves của 2 tokens | |
| - `totalSupply`: Tổng LP tokens được mint | |
| - `accumulatedFees0/1`: LP fees tích lũy (stay in reserves) | |
| - `stakingFees0/1`: Staking fees tích lũy | |
| - `totalStaked`: Tổng LP tokens staked | |
| - `stakedBalances[Address]`: Mapping staked balance per user | |
| - `rewardDebt0/1[Address]`: Mapping reward debt để track claimed rewards | |
| ### View Functions | |
| #### `getReserves() -> (U256, U256)` | |
| - **Công dụng**: Lấy current reserves | |
| - **Return**: (reserve0, reserve1) | |
| #### `getTokenPair() -> (ByteVec, ByteVec)` | |
| - **Công dụng**: Lấy token IDs | |
| - **Return**: (token0Id, token1Id) | |
| #### `getTotalSupply() -> U256` | |
| - **Công dụng**: Lấy total LP supply | |
| - **Return**: totalSupply | |
| ### Liquidity Functions | |
| #### `mint(caller: Address, amount0: U256, amount1: U256) -> U256` | |
| - **Công dụng**: Mint LP tokens bằng cách deposit 2 tokens | |
| - **Flow**: | |
| 1. Validate amount0 > 0 và amount1 > 0 | |
| 2. **Nếu totalSupply == 0** (initial liquidity): | |
| - product = safeMul(amount0, amount1) | |
| - sqrtProduct = sqrt(product) | |
| - liquidity = sqrtProduct - MINIMUM_LIQUIDITY | |
| - totalSupply = MINIMUM_LIQUIDITY (burned permanently) | |
| 3. **Nếu totalSupply > 0**: | |
| - liquidity0 = (amount0 * totalSupply) / reserve0 | |
| - liquidity1 = (amount1 * totalSupply) / reserve1 | |
| - liquidity = min(liquidity0, liquidity1) | |
| 4. Transfer tokens từ caller → contract | |
| 5. Mint LP tokens từ contract → caller | |
| 6. Update reserves: reserve0 += amount0, reserve1 += amount1 | |
| 7. Update totalSupply += liquidity | |
| 8. Emit Mint event | |
| - **State Changes**: | |
| - reserve0 ↑, reserve1 ↑, totalSupply ↑ | |
| - LP token balance của caller ↑ | |
| #### `burn(caller: Address, liquidity: U256) -> (U256, U256)` | |
| - **Công dụng**: Burn LP tokens và nhận lại 2 tokens | |
| - **Flow**: | |
| 1. Validate liquidity > 0 và totalSupply > 0 | |
| 2. Calculate amounts: | |
| - amount0 = (liquidity * reserve0) / totalSupply | |
| - amount1 = (liquidity * reserve1) / totalSupply | |
| 3. Transfer LP tokens từ caller → contract | |
| 4. Transfer tokens từ contract → caller | |
| 5. Update reserves: reserve0 -= amount0, reserve1 -= amount1 | |
| 6. Update totalSupply -= liquidity | |
| 7. Emit Burn event | |
| - **State Changes**: | |
| - reserve0 ↓, reserve1 ↓, totalSupply ↓ | |
| - LP token balance của caller ↓ | |
| ### Staking Functions | |
| #### `stake(caller: Address, amount: U256) -> ()` | |
| - **Công dụng**: Stake LP tokens để earn staking rewards | |
| - **Flow**: | |
| 1. Validate amount > 0 | |
| 2. Nếu user đã có stake → claim pending rewards trước | |
| 3. Transfer LP tokens từ caller → contract | |
| 4. Update stakedBalances[caller] += amount | |
| 5. Update totalStaked += amount | |
| 6. Update reward debt snapshot | |
| 7. Emit Staked event | |
| - **State Changes**: | |
| - stakedBalances[caller] ↑ | |
| - totalStaked ↑ | |
| - LP token balance của caller ↓ | |
| #### `unstake(caller: Address, amount: U256) -> ()` | |
| - **Công dụng**: Unstake LP tokens | |
| - **Flow**: | |
| 1. Validate amount > 0 và caller có đủ stake | |
| 2. Claim pending rewards trước | |
| 3. Update stakedBalances[caller] -= amount | |
| 4. Update totalStaked -= amount | |
| 5. Update reward debt | |
| 6. Transfer LP tokens từ contract → caller | |
| 7. Emit Unstaked event | |
| - **State Changes**: | |
| - stakedBalances[caller] ↓ | |
| - totalStaked ↓ | |
| - LP token balance của caller ↑ | |
| #### `claimStakingRewards(caller: Address) -> (U256, U256)` | |
| - **Công dụng**: Claim accumulated staking rewards | |
| - **Flow**: | |
| 1. Calculate pending rewards: | |
| - pending0 = (stakingFees0 * userStake) / totalStaked | |
| - pending1 = (stakingFees1 * userStake) / totalStaked | |
| 2. Subtract already claimed (rewardDebt) | |
| 3. Update reward debt snapshot | |
| 4. Transfer tokens từ contract → caller | |
| 5. Emit RewardsClaimed event | |
| - **State Changes**: | |
| - rewardDebt0[caller] ↑ | |
| - rewardDebt1[caller] ↑ | |
| - Token balances của caller ↑ | |
| ### Helper Functions | |
| #### `executeSwap(caller: Address, tokenPair: TokenPair, params: SwapParams) -> ()` | |
| - **Công dụng**: Execute swap thông qua TokenPair interface | |
| - **Logic**: Route swap call đến đúng pair contract dựa trên token direction | |
| --- | |
| ## AmmPair Contract | |
| **Mục đích**: Implement volatile AMM pair với constant product formula (x * y = k). | |
| **Inheritance**: Extends `PairTemplate`, implements `TokenPair`, `DcaTwamm` | |
| ### Swap Function | |
| #### `swap(caller: Address, amount0In: U256, amount1In: U256, amount0Out: U256, amount1Out: U256) -> ()` | |
| - **Công dụng**: Swap tokens theo constant product formula | |
| - **Flow**: | |
| 1. **Validation**: | |
| - amount0Out > 0 hoặc amount1Out > 0 | |
| - amount0Out < reserve0 và amount1Out < reserve1 | |
| - amount0In > 0 hoặc amount1In > 0 | |
| 2. **Transfer tokens**: | |
| - Transfer input tokens từ caller → contract | |
| - Transfer output tokens từ contract → caller | |
| 3. **Calculate với constant product**: | |
| - Determine (reserveIn, reserveOut, amountIn) | |
| - feeAmount = (amountIn * 3) / 1000 (0.3% fee) | |
| - amountInAfterFee = amountIn - feeAmount | |
| - calculatedAmountOut = safeAmmOutput(reserveIn, reserveOut, amountInAfterFee) | |
| - Verify calculatedAmountOut >= expectedAmountOut | |
| 4. **Split fees** (50/50): | |
| - lpFee = feeAmount * 500 / 1000 → accumulatedFees (stay in reserves) | |
| - stakingFee = feeAmount * 500 / 1000 → stakingFees | |
| 5. **Update reserves**: | |
| - newReserve0 = reserve0 + amount0In - amount0Out | |
| - newReserve1 = reserve1 + amount1In - amount1Out | |
| 6. **Verify invariant**: newK >= oldK | |
| 7. **Validate new reserves** | |
| 8. **Update state và emit Swap event** | |
| - **State Changes**: | |
| - reserve0, reserve1 thay đổi (phụ thuộc direction) | |
| - accumulatedFees0/1 ↑ (LP fees) | |
| - stakingFees0/1 ↑ (staking fees) | |
| - Token balances của caller thay đổi | |
| ### TWAMM Execution Functions | |
| #### `executeOrderChunk(orderId: U256) -> U256` | |
| - **Công dụng**: Execute một chunk của TWAMM order | |
| - **Flow**: | |
| 1. Validate order exists, not executed/cancelled, startTime passed | |
| 2. Calculate executable amount và chunk size | |
| 3. Apply AMM formula với safe math | |
| 4. Split fees 50/50 (LP/staking) | |
| 5. Update reserves | |
| 6. Update executedAmounts[orderId] | |
| 7. Nếu order completed → mark executed, transfer remaining fees | |
| 8. Transfer output tokens đến user | |
| 9. Pay gas từ order fees | |
| 10. Emit events | |
| - **State Changes**: | |
| - reserves thay đổi | |
| - fees accumulated | |
| - executedAmounts[orderId] ↑ | |
| - order.executed có thể = true | |
| - order.feesRemaining ↓ | |
| #### `executeOrdersBatch(orderIds: ByteVec) -> U256` | |
| - **Công dụng**: Execute nhiều orders trong một batch | |
| - **Flow**: Loop qua orderIds và execute mỗi order nếu có thể | |
| - **Sử dụng**: Gas efficient khi execute nhiều orders | |
| ### DCA Execution Functions | |
| #### `executeDcaOrder(orderId: U256) -> U256` | |
| - **Công dụng**: Execute một execution của DCA order | |
| - **Flow**: | |
| 1. Validate order exists, not cancelled, execution time valid | |
| 2. Check time interval đã đủ | |
| 3. Calculate execution amount (amountPerExecution hoặc remaining) | |
| 4. Apply AMM formula | |
| 5. Verify minAmountOut | |
| 6. Split fees 50/50 | |
| 7. Update reserves | |
| 8. Update tracking: | |
| - dcaExecutedAmounts[orderId] += executionAmount | |
| - dcaOrder.executionsCompleted += 1 | |
| - dcaOrder.lastExecutionTime = currentTime | |
| 9. Nếu completed → mark và transfer remaining fees | |
| 10. Transfer output tokens | |
| 11. Pay gas | |
| 12. Emit events | |
| - **State Changes**: | |
| - reserves thay đổi | |
| - fees accumulated | |
| - dcaExecutedAmounts[orderId] ↑ | |
| - dcaOrder.executionsCompleted ↑ | |
| - dcaOrder.lastExecutionTime updated | |
| --- | |
| ## StableTokenPair Contract | |
| **Mục đích**: Implement stable pair với stable-swap invariant (x³y + y³x = k) cho stablecoins. | |
| **Inheritance**: Extends `PairTemplate`, implements `TokenPair`, `DcaTwamm` | |
| ### Swap Function | |
| #### `swap(caller: Address, amount0In: U256, amount1In: U256, amount0Out: U256, amount1Out: U256) -> ()` | |
| - **Công dụng**: Swap tokens theo stable-swap formula | |
| - **Flow tương tự AmmPair nhưng**: | |
| - Sử dụng `calculateStableSwapOutput()` thay vì constant product | |
| - Invariant là x³y + y³x thay vì x * y | |
| - **State Changes**: Tương tự AmmPair | |
| ### Stable Swap Calculation | |
| #### `calculateStableSwapOutput(amountIn: U256, isToken0: Bool) -> U256` | |
| - **Công dụng**: Tính output amount cho stable swap | |
| - **Flow**: | |
| 1. Calculate fee: feeAmount = (amountIn * 3) / 1000 | |
| 2. amountInAfterFee = amountIn - feeAmount | |
| 3. Get current reserves (x, y) | |
| 4. Calculate current invariant: k = x³y + y³x | |
| 5. newX = x + amountInAfterFee | |
| 6. Solve for newY using Newton's method: newX³ * newY + newY³ * newX = k | |
| 7. amountOut = y - newY | |
| 8. Return amountOut | |
| - **Sử dụng**: Trong swap(), executeOrderChunk(), executeDcaOrder() | |
| #### `solveForNewY(newX: U256, k: U256, initialGuess: U256) -> U256` | |
| - **Công dụng**: Giải phương trình newX³ * newY + newY³ * newX = k bằng Newton's method | |
| - **Flow**: | |
| 1. Initial guess = current reserve y | |
| 2. Loop tối đa 6 iterations: | |
| - Calculate f(y) = newX * y³ + newX³ * y - k | |
| - Calculate f'(y) = 3 * newX * y² + newX³ | |
| - Newton step: newY = newY - f/f' | |
| - Check convergence | |
| 3. Return newY | |
| - **Sử dụng**: Trong calculateStableSwapOutput() | |
| ### TWAMM/DCA Execution | |
| - Tương tự AmmPair nhưng sử dụng stable swap formula | |
| --- | |
| ## Twamm Contract (Orderbook) | |
| **Mục đích**: Quản lý TWAMM orders và DCA orders. | |
| **Inheritance**: Extends `Upgrade(admin)` | |
| ### State Variables | |
| - `orders[U256]`: Mapping TWAMM orders | |
| - `executedAmounts[U256]`: Mapping executed amount per order | |
| - `dcaOrders[U256]`: Mapping DCA orders | |
| - `dcaExecutedAmounts[U256]`: Mapping executed amount per DCA order | |
| - `orderFees`: Accumulated ALPH fees từ orders | |
| ### Constants | |
| - `EXECUTION_INTERVAL = 300000` (5 phút): Interval giữa các executions | |
| - `BASE_FEE_PER_INTERVAL = 0.02 ALPH`: Fee cho mỗi interval | |
| - `MIN_ORDER_DURATION = 300000`: Minimum order duration | |
| - `MAX_ORDER_DURATION = 7 days + 10 phút` | |
| - `MIN_DCA_INTERVAL = 5 phút` | |
| - `MAX_DCA_INTERVAL = 30 ngày` | |
| ### TWAMM Functions | |
| #### `placeProgressiveOrder(tokenIn: ByteVec, amountIn: U256, startTime: U256, endTime: U256, minAmountOut: U256) -> U256` | |
| - **Công dụng**: Tạo TWAMM order (progressive time-weighted order) | |
| - **Flow**: | |
| 1. Validate inputs: | |
| - amountIn > 0, startTime > currentTime, endTime > startTime | |
| - Duration >= MIN_ORDER_DURATION | |
| - tokenIn phải là token0 hoặc token1 | |
| 2. Calculate order fee: duration / 5 phút * 0.02 ALPH | |
| 3. Transfer tokens và ALPH fee từ user → contract | |
| 4. Create order với nextOrderId | |
| 5. Initialize executedAmounts[orderId] = 0 | |
| 6. Increment nextOrderId | |
| 7. Emit OrderPlaced event | |
| 8. Return orderId | |
| - **State Changes**: | |
| - orders[orderId] = new order | |
| - executedAmounts[orderId] = 0 | |
| - nextOrderId ↑ | |
| - Token balances của user ↓ | |
| - Contract token balances ↑ | |
| #### `calculateChunkSize(orderId: U256) -> U256` | |
| - **Công dụng**: Tính chunk size cho mỗi execution interval | |
| - **Logic**: `amountIn / (totalDuration / EXECUTION_INTERVAL)` | |
| - **Return**: Amount per 5-minute chunk | |
| #### `getExecutableAmount(orderId: U256) -> U256` | |
| - **Công dụng**: Tính amount có thể execute tại thời điểm hiện tại | |
| - **Logic**: | |
| - elapsedTime = currentTime - startTime (max = endTime - startTime) | |
| - maxExecutableAmount = (amountIn * elapsedTime) / totalDuration | |
| - executableAmount = maxExecutableAmount - alreadyExecuted | |
| - **Return**: Executable amount (0 nếu không có) | |
| #### `cancelOrder(orderId: U256) -> U256` | |
| - **Công dụng**: Cancel TWAMM order và refund unexecuted amount | |
| - **Flow**: | |
| 1. Validate order exists, caller is owner, not executed/cancelled | |
| 2. Calculate refundAmount = amountIn - executedAmount | |
| 3. Transfer refundAmount từ contract → user | |
| 4. Mark order as cancelled | |
| 5. Transfer remaining fees → orderFees | |
| 6. Remove mappings | |
| 7. Emit OrderCancelled event | |
| - **State Changes**: | |
| - order.cancelled = true | |
| - orders[orderId] removed | |
| - executedAmounts[orderId] removed | |
| - orderFees ↑ | |
| - User token balance ↑ | |
| ### DCA Functions | |
| #### `placeDcaOrder(tokenIn: ByteVec, totalAmountIn: U256, amountPerExecution: U256, startTime: U256, executionInterval: U256, totalExecutions: U256, minAmountOut: U256) -> U256` | |
| - **Công dụng**: Tạo DCA order (recurring swaps) | |
| - **Flow**: | |
| 1. Validate inputs: | |
| - totalAmountIn, amountPerExecution, totalExecutions > 0 | |
| - startTime > currentTime | |
| - executionInterval trong [5 phút, 30 ngày] | |
| - totalAmountIn >= totalExecutions * amountPerExecution | |
| 2. Calculate fee: totalExecutions * 0.02 ALPH | |
| 3. Transfer tokens và fee từ user → contract | |
| 4. Create DCA order với nextOrderId | |
| 5. Initialize dcaExecutedAmounts[orderId] = 0 | |
| 6. Increment nextOrderId | |
| 7. Emit DcaOrderPlaced event | |
| 8. Return orderId | |
| - **State Changes**: | |
| - dcaOrders[orderId] = new order | |
| - dcaExecutedAmounts[orderId] = 0 | |
| - nextOrderId ↑ | |
| - User token balances ↓ | |
| #### `topUpDcaOrder(orderId: U256, additionalAmount: U256) -> ()` | |
| - **Công dụng**: Thêm funds vào DCA order đang chạy | |
| - **Flow**: | |
| 1. Validate order exists, caller is owner, not cancelled, not completed | |
| 2. Transfer additionalAmount từ user → contract | |
| 3. Update dcaOrder.totalAmountIn += additionalAmount | |
| 4. Emit DcaOrderToppedUp event | |
| - **State Changes**: | |
| - dcaOrder.totalAmountIn ↑ | |
| - User token balance ↓ | |
| #### `cancelDcaOrder(orderId: U256) -> U256` | |
| - **Công dụng**: Cancel DCA order và refund unexecuted amount | |
| - **Flow**: Tương tự cancelOrder() | |
| - **State Changes**: Tương tự cancelOrder() | |
| #### `canExecuteDcaOrder(orderId: U256) -> Bool` | |
| - **Công dụng**: Check xem DCA order có thể execute không | |
| - **Logic**: | |
| - Order exists, not cancelled, not completed | |
| - startTime passed | |
| - Interval từ last execution đã đủ | |
| - Remaining amount >= amountPerExecution | |
| - **Return**: true nếu có thể execute | |
| ### View Functions | |
| #### `getOrderInfo(orderId: U256) -> (...)` | |
| - **Công dụng**: Lấy thông tin TWAMM order | |
| - **Return**: (user, tokenIn, amountIn, startTime, endTime, minAmountOut, executed, cancelled) | |
| #### `getDcaOrderInfo(orderId: U256) -> (...)` | |
| - **Công dụng**: Lấy thông tin DCA order | |
| - **Return**: Tất cả fields của DCA order | |
| #### `estimateOrderOutput(orderId: U256) -> U256` | |
| - **Công dụng**: Estimate output cho TWAMM order | |
| - **Logic**: Tính AMM output với executable amount hiện tại | |
| #### `estimateDcaOrderOutput(orderId: U256) -> U256` | |
| - **Công dụng**: Estimate output cho DCA order | |
| - **Logic**: Tính AMM output với amountPerExecution | |
| ### Fee Management | |
| #### `withdrawOrderFees() -> ()` | |
| - **Công dụng**: Admin withdraw accumulated order fees | |
| - **Access**: Chỉ admin | |
| - **Flow**: Transfer orderFees từ contract → admin, reset orderFees = 0 | |
| - **State Changes**: orderFees = 0, admin ALPH balance ↑ | |
| --- | |
| ## Router Contract | |
| **Mục đích**: Router để quản lý liquidity và routing swaps. | |
| **Inheritance**: Extends `Constants()`, `Upgrade(admin)` | |
| ### Liquidity Functions | |
| #### `addLiquidity(tokenPair: TokenPair, amount0Desired: U256, amount1Desired: U256, amount0Min: U256, amount1Min: U256, deadline: U256) -> (U256, U256, U256)` | |
| - **Công dụng**: Add liquidity với optimal amounts | |
| - **Flow**: | |
| 1. Validate deadline >= currentTime | |
| 2. Get reserves từ pair | |
| 3. Calculate optimal amounts với `addLiquidity_()`: | |
| - Nếu reserves = 0 → return amount0Desired, amount1Desired | |
| - Nếu không → tính optimal ratio | |
| 4. Call pair.mint() với optimal amounts | |
| 5. Emit Add event | |
| 6. Return (amount0, amount1, liquidity) | |
| - **State Changes**: Pair reserves ↑, LP supply ↑ | |
| #### `addLiquidity_(reserve0: U256, reserve1: U256, amount0Desired: U256, amount1Desired: U256, amount0Min: U256, amount1Min: U256) -> (U256, U256)` | |
| - **Công dụng**: Internal function tính optimal amounts | |
| - **Logic**: | |
| - amount1Optimal = amount0Desired * reserve1 / reserve0 | |
| - Nếu amount1Optimal <= amount1Desired → return (amount0Desired, amount1Optimal) | |
| - Nếu không → amount0Optimal = amount1Desired * reserve0 / reserve1 | |
| - Return (amount0Optimal, amount1Desired) | |
| - **Sử dụng**: Trong addLiquidity() | |
| #### `removeLiquidity(tokenPairId: ByteVec, liquidity: U256, amount0Min: U256, amount1Min: U256, deadline: U256) -> (U256, U256)` | |
| - **Công dụng**: Remove liquidity với slippage protection | |
| - **Flow**: | |
| 1. Validate deadline | |
| 2. Call pair.burn() với liquidity | |
| 3. Validate amounts >= mins | |
| 4. Emit Remove event | |
| 5. Return (amount0, amount1) | |
| - **State Changes**: Pair reserves ↓, LP supply ↓ | |
| ### Swap Functions | |
| #### `swapExactTokenForToken(tokenPair: TokenPair, tokenInId: ByteVec, amountIn: U256, amountOutMin: U256, deadline: U256) -> ()` | |
| - **Công dụng**: Swap exact input amount, min output | |
| - **Flow**: | |
| 1. Validate deadline | |
| 2. Get reserves | |
| 3. Calculate amountOut với formula: | |
| - amountInExcludeFee = 997 * amountIn / 1000 | |
| - amountOut = (amountInExcludeFee * reserveOut) / (amountInExcludeFee + 1000 * reserveIn) | |
| 4. Validate amountOut >= amountOutMin | |
| 5. Call swap() | |
| - **State Changes**: Pair reserves thay đổi | |
| #### `swapTokenForExactToken(tokenPair: TokenPair, tokenInId: ByteVec, amountInMax: U256, amountOut: U256, deadline: U256) -> ()` | |
| - **Công dụng**: Swap for exact output, max input | |
| - **Flow**: | |
| 1. Validate deadline | |
| 2. Get reserves | |
| 3. Calculate amountIn: | |
| - amountIn = ((reserveIn * amountOut * 1000) / ((reserveOut - amountOut) * 997)) + 1 | |
| 4. Validate amountIn <= amountInMax | |
| 5. Call swap() | |
| - **State Changes**: Pair reserves thay đổi | |
| #### `swap(tokenPair: TokenPair, tokenInId: ByteVec, amountIn: U256, amountOut: U256) -> ()` | |
| - **Công dụng**: Internal swap function | |
| - **Logic**: Route đến pair.swap() với đúng parameters dựa trên tokenInId | |
| ### Helper Functions | |
| #### `getReserveInAndReserveOut(tokenPair: TokenPair, tokenInId: ByteVec) -> (U256, U256)` | |
| - **Công dụng**: Get reserves theo direction của swap | |
| - **Logic**: Return (reserveIn, reserveOut) dựa trên tokenInId | |
| --- | |
| ## TokenPairFactory Contract | |
| **Mục đích**: Factory để tạo token pairs (volatile và stable). | |
| **Inheritance**: Extends `Constants()`, `Upgrade(admin)` | |
| ### State Variables | |
| - `pairTemplateId`: Template contract ID cho volatile pairs | |
| - `stableTemplateId`: Template contract ID cho stable pairs | |
| - `adminAddress`: Admin address (có thể khác với admin) | |
| - `pairSize`: Số lượng pairs đã tạo | |
| ### Functions | |
| #### `getId() -> ByteVec` | |
| - **Công dụng**: Lấy contract ID của factory | |
| - **Return**: selfContractId | |
| #### `sortTokens(tokenA: ByteVec, tokenB: ByteVec) -> (ByteVec, ByteVec)` | |
| - **Công dụng**: Sort tokens theo U256 value để đảm bảo consistent ordering | |
| - **Logic**: | |
| - Convert to U256 | |
| - Return (tokenA, tokenB) nếu tokenA < tokenB, ngược lại return (tokenB, tokenA) | |
| - **Sử dụng**: Trong createPair() để đảm bảo token0 < token1 | |
| #### `createPair(token0Id: ByteVec, token1Id: ByteVec, isStable: Bool) -> ByteVec` | |
| - **Công dụng**: Tạo mới token pair (volatile hoặc stable) | |
| - **Flow**: | |
| 1. Sort tokens: (t0, t1) = sortTokens(token0Id, token1Id) | |
| 2. **Nếu isStable = true**: | |
| - Validate caller == adminAddress (chỉ admin tạo stable pairs) | |
| 3. Create pairKey = t0 ++ t1 | |
| 4. Encode fields với initial values: | |
| - reserves = 0, totalSupply = 0, fees = 0, etc. | |
| 5. Deploy sub-contract: | |
| - Template = pairTemplateId (volatile) hoặc stableTemplateId (stable) | |
| - Use copyCreateSubContractWithToken! | |
| 6. Increment pairSize | |
| 7. Emit PairCreated event | |
| 8. Return pairContractId | |
| - **State Changes**: | |
| - pairSize ↑ | |
| - New contract deployed | |
| - **Access Control**: | |
| - Volatile pairs: Anyone | |
| - Stable pairs: Chỉ adminAddress | |
| --- | |
| ## Flow tổng thể | |
| ### 1. Deployment Flow | |
| ``` | |
| 1. Deploy TokenPairFactory | |
| ↓ | |
| 2. Deploy AmmPair template → pairTemplateId | |
| ↓ | |
| 3. Deploy StableTokenPair template → stableTemplateId | |
| ↓ | |
| 4. Update factory với template IDs | |
| ↓ | |
| 5. Deploy Router | |
| ``` | |
| ### 2. Create Pair Flow | |
| ``` | |
| User → TokenPairFactory.createPair() | |
| ↓ | |
| Factory.sortTokens() → (token0, token1) | |
| ↓ | |
| Factory.validate (nếu stable → check admin) | |
| ↓ | |
| Factory.encodeFields() → initial state | |
| ↓ | |
| Factory.copyCreateSubContractWithToken!() → deploy pair | |
| ↓ | |
| Pair deployed với reserves = 0 | |
| ↓ | |
| Emit PairCreated event | |
| ``` | |
| ### 3. Add Liquidity Flow | |
| ``` | |
| User → Router.addLiquidity(tokenPair, amounts, mins, deadline) | |
| ↓ | |
| Router.validate deadline | |
| ↓ | |
| Router.addLiquidity_() → calculate optimal amounts | |
| ↓ | |
| Router.call tokenPair.mint() | |
| ↓ | |
| Pair.mint(): | |
| ├─ Validate amounts | |
| ├─ Calculate liquidity: | |
| │ ├─ Nếu first mint: sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY | |
| │ └─ Nếu không: min((amount0 * totalSupply) / reserve0, ...) | |
| ├─ Transfer tokens user → pair | |
| ├─ Mint LP tokens pair → user | |
| ├─ Update reserves | |
| └─ Emit Mint event | |
| ↓ | |
| Router.emit Add event | |
| ``` | |
| ### 4. Swap Flow (Volatile) | |
| ``` | |
| User → Router.swapExactTokenForToken(pair, tokenIn, amountIn, minOut, deadline) | |
| ↓ | |
| Router.validate deadline | |
| ↓ | |
| Router.getReserveInAndReserveOut() → (reserveIn, reserveOut) | |
| ↓ | |
| Router.calculate amountOut với formula | |
| ↓ | |
| Router.validate amountOut >= minOut | |
| ↓ | |
| Router.swap() → call pair.swap() | |
| ↓ | |
| Pair.swap(): | |
| ├─ Validate inputs | |
| ├─ Transfer tokens | |
| ├─ Calculate với constant product: | |
| │ ├─ feeAmount = amountIn * 3 / 1000 | |
| │ ├─ amountInAfterFee = amountIn - feeAmount | |
| │ └─ amountOut = (reserveOut * amountInAfterFee) / (reserveIn + amountInAfterFee) | |
| ├─ Split fees 50/50 (LP/staking) | |
| ├─ Update reserves | |
| ├─ Verify invariant (newK >= oldK) | |
| └─ Emit Swap event | |
| ``` | |
| ### 5. Swap Flow (Stable) | |
| ``` | |
| Tương tự volatile nhưng: | |
| ↓ | |
| Pair.swap() → calculateStableSwapOutput() | |
| ↓ | |
| calculateStableSwapOutput(): | |
| ├─ Calculate fee | |
| ├─ Get current invariant: k = x³y + y³x | |
| ├─ newX = x + amountInAfterFee | |
| ├─ solveForNewY() → Newton's method | |
| └─ amountOut = y - newY | |
| ``` | |
| ### 6. TWAMM Order Flow | |
| ``` | |
| User → Pair.placeProgressiveOrder(tokenIn, amountIn, startTime, endTime, minOut) | |
| ↓ | |
| Twamm.validate inputs | |
| ↓ | |
| Twamm.calculateOrderFee() → (duration / 5 phút) * 0.02 ALPH | |
| ↓ | |
| Twamm.transfer tokens + fee từ user → contract | |
| ↓ | |
| Twamm.create order với nextOrderId | |
| ↓ | |
| Twamm.initialize executedAmounts[orderId] = 0 | |
| ↓ | |
| Twamm.emit OrderPlaced event | |
| ↓ | |
| [Time passes - every 5 minutes] | |
| ↓ | |
| Executor → Pair.executeOrderChunk(orderId) | |
| ↓ | |
| Twamm.getExecutableAmount() → calculate based on elapsed time | |
| ↓ | |
| Twamm.calculateChunkSize() → amount per interval | |
| ↓ | |
| Pair.executeOrderChunk(): | |
| ├─ Get actual chunk size (min of executable, chunk size) | |
| ├─ Apply AMM formula | |
| ├─ Split fees | |
| ├─ Update reserves | |
| ├─ Update executedAmounts[orderId] | |
| ├─ Check if completed → mark executed | |
| ├─ Transfer output tokens → user | |
| └─ Pay gas từ fees | |
| ↓ | |
| [Repeat until order completed] | |
| ``` | |
| ### 7. DCA Order Flow | |
| ``` | |
| User → Pair.placeDcaOrder(tokenIn, totalAmount, perExecution, startTime, interval, executions, minOut) | |
| ↓ | |
| Twamm.validate inputs | |
| ↓ | |
| Twamm.calculateDcaOrderFee() → totalExecutions * 0.02 ALPH | |
| ↓ | |
| Twamm.transfer tokens + fee từ user → contract | |
| ↓ | |
| Twamm.create DCA order | |
| ↓ | |
| Twamm.emit DcaOrderPlaced event | |
| ↓ | |
| [At startTime] | |
| ↓ | |
| Executor → Pair.executeDcaOrder(orderId) | |
| ↓ | |
| Twamm.validate timing và remaining amount | |
| ↓ | |
| Pair.executeDcaOrder(): | |
| ├─ Calculate execution amount | |
| ├─ Apply AMM formula | |
| ├─ Split fees | |
| ├─ Update reserves | |
| ├─ Update tracking (executionsCompleted, lastExecutionTime) | |
| ├─ Check if completed | |
| ├─ Transfer output tokens → user | |
| └─ Pay gas | |
| ↓ | |
| [Wait for interval] | |
| ↓ | |
| [Repeat until all executions done] | |
| ``` | |
| ### 8. Staking Flow | |
| ``` | |
| User → Pair.stake(amount) | |
| ↓ | |
| Pair.validate amount > 0 | |
| ↓ | |
| Pair.claimRewards_() nếu đã có stake | |
| ↓ | |
| Pair.transfer LP tokens từ user → contract | |
| ↓ | |
| Pair.update stakedBalances[user] += amount | |
| ↓ | |
| Pair.update totalStaked += amount | |
| ↓ | |
| Pair.updateRewardDebt() → snapshot rewards | |
| ↓ | |
| Pair.emit Staked event | |
| ↓ | |
| [Fees accumulate from swaps] | |
| ↓ | |
| User → Pair.claimStakingRewards() | |
| ↓ | |
| Pair.calculate pending rewards: | |
| ├─ pending0 = (stakingFees0 * userStake) / totalStaked | |
| └─ pending1 = (stakingFees1 * userStake) / totalStaked | |
| ↓ | |
| Pair.subtract rewardDebt (already claimed) | |
| ↓ | |
| Pair.transfer rewards từ contract → user | |
| ↓ | |
| Pair.update reward debt snapshot | |
| ↓ | |
| Pair.emit RewardsClaimed event | |
| ``` | |
| --- | |
| ## Tóm tắt State Changes | |
| ### Mint | |
| - `reserve0` ↑, `reserve1` ↑ | |
| - `totalSupply` ↑ | |
| - User LP token balance ↑ | |
| - User token0/1 balances ↓ | |
| ### Burn | |
| - `reserve0` ↓, `reserve1` ↓ | |
| - `totalSupply` ↓ | |
| - User LP token balance ↓ | |
| - User token0/1 balances ↑ | |
| ### Swap | |
| - `reserve0` và `reserve1` thay đổi (phụ thuộc direction) | |
| - `accumulatedFees0/1` ↑ (LP fees) | |
| - `stakingFees0/1` ↑ (staking fees) | |
| - User input token balance ↓ | |
| - User output token balance ↑ | |
| ### TWAMM Order | |
| - `executedAmounts[orderId]` ↑ | |
| - `order.executed` có thể = true | |
| - `order.feesRemaining` ↓ | |
| - Reserves thay đổi (như swap) | |
| - User output token balance ↑ | |
| ### DCA Order | |
| - `dcaExecutedAmounts[orderId]` ↑ | |
| - `dcaOrder.executionsCompleted` ↑ | |
| - `dcaOrder.lastExecutionTime` updated | |
| - `dcaOrder.feesRemaining` ↓ | |
| - Reserves thay đổi (như swap) | |
| - User output token balance ↑ | |
| ### Staking | |
| - `stakedBalances[user]` ↑ | |
| - `totalStaked` ↑ | |
| - `rewardDebt0/1[user]` updated | |
| - User LP token balance ↓ | |
| ### Claim Rewards | |
| - `rewardDebt0/1[user]` ↑ | |
| - User token0/1 balances ↑ | |
| --- | |
| ## Security Features | |
| 1. **Safe Math**: Tất cả calculations sử dụng safe math functions | |
| 2. **Reserve Validation**: Validate reserves trước và sau mọi operations | |
| 3. **Invariant Verification**: Verify constant product hoặc stable invariant | |
| 4. **Access Control**: Admin-only functions cho upgrades và fee withdrawal | |
| 5. **Deadline Protection**: Tất cả transactions có deadline validation | |
| 6. **Slippage Protection**: Min/max amounts validation | |
| 7. **Fee Splitting**: 50% LP fees (stay in reserves), 50% staking fees | |
| 8. **Order Validation**: Comprehensive validation cho TWAMM/DCA orders | |
| --- | |
| ## Gas Optimization | |
| 1. **Batch Execution**: `executeOrdersBatch()` để execute nhiều orders | |
| 2. **Efficient Storage**: Sử dụng mappings thay vì arrays | |
| 3. **Early Returns**: Return sớm trong validation functions | |
| 4. **Minimal State Changes**: Chỉ update state khi cần thiết | |
| --- | |
| ## Events | |
| Tất cả major operations emit events để tracking: | |
| - `Mint`, `Burn`, `Swap` | |
| - `Staked`, `Unstaked`, `RewardsClaimed` | |
| - `OrderPlaced`, `OrderChunkExecuted`, `OrderCompleted`, `OrderCancelled` | |
| - `DcaOrderPlaced`, `DcaOrderExecuted`, `DcaOrderCompleted`, `DcaOrderCancelled` | |
| - `PairCreated`, `Add`, `Remove` | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment