/ docs / security / contract-patterns.md
contract-patterns.md
  1  # Alpha/Delta Smart Contract Security Patterns
  2  
  3  Generated: 2026-01-08
  4  Source: components/security.cspec (S001)
  5  Version: 1.0.0
  6  
  7  ## Overview
  8  
  9  This document defines security patterns for smart contracts on the Alpha/Delta Protocol, covering both AlphaVM (privacy-focused) and DeltaVM (exchange-focused) environments.
 10  
 11  ---
 12  
 13  ## 1. Language Security (ADL)
 14  
 15  ### 1.1 Alpha Delta Language (ADL)
 16  
 17  ADL is the contract language for Alpha/Delta, derived from Leo with additional safety features.
 18  
 19  | Feature | Security Benefit |
 20  |---------|-----------------|
 21  | Static typing | Prevents type confusion attacks |
 22  | Ownership model | Prevents unauthorized access |
 23  | Bounded types | Prevents overflow/underflow |
 24  | Private by default | Functions/data hidden unless explicit |
 25  
 26  ### 1.2 Compiler Guarantees
 27  
 28  | Check | Description | Enforced At |
 29  |-------|-------------|-------------|
 30  | Type safety | All operations type-checked | Compile time |
 31  | Bounds checking | Array access verified | Compile time + Runtime |
 32  | Ownership verification | Resource tracking | Compile time |
 33  | ZK circuit validation | Proof generation verified | Compile time |
 34  
 35  ---
 36  
 37  ## 2. Reentrancy Protection
 38  
 39  ### 2.1 The Problem
 40  
 41  Reentrancy occurs when external calls allow re-entry before state updates complete.
 42  
 43  ```
 44  Vulnerable Pattern:
 45  1. Check balance (passes)
 46  2. External call (attacker re-enters)
 47  3. Update balance (never reached in first call)
 48  ```
 49  
 50  ### 2.2 Checks-Effects-Interactions (CEI)
 51  
 52  **Pattern**: Perform checks, update state, then make external calls.
 53  
 54  ```
 55  // CORRECT: CEI Pattern
 56  function withdraw(amount: u64) {
 57      // 1. CHECKS
 58      assert(balances[caller] >= amount);
 59  
 60      // 2. EFFECTS (state changes)
 61      balances[caller] -= amount;
 62  
 63      // 3. INTERACTIONS (external calls)
 64      transfer(caller, amount);
 65  }
 66  ```
 67  
 68  ```
 69  // WRONG: Interactions before effects
 70  function withdraw_vulnerable(amount: u64) {
 71      assert(balances[caller] >= amount);
 72      transfer(caller, amount);  // External call BEFORE state update
 73      balances[caller] -= amount;  // Never reached on reentry
 74  }
 75  ```
 76  
 77  ### 2.3 Reentrancy Guard
 78  
 79  For complex cases, use a mutex pattern:
 80  
 81  ```
 82  state {
 83      locked: bool = false;
 84  }
 85  
 86  modifier nonReentrant() {
 87      assert(!locked, "Reentrancy detected");
 88      locked = true;
 89      _;  // Execute function
 90      locked = false;
 91  }
 92  
 93  function sensitiveOperation() with nonReentrant {
 94      // Safe from reentrancy
 95  }
 96  ```
 97  
 98  ### 2.4 ADL Reentrancy Protection
 99  
100  ADL provides built-in reentrancy protection:
101  
102  | Feature | Mechanism |
103  |---------|-----------|
104  | Single-entry enforcement | Runtime lock on contract entry |
105  | Async call isolation | External calls complete before return |
106  | State snapshot | Rollback on failure |
107  
108  ---
109  
110  ## 3. Integer Safety
111  
112  ### 3.1 The Problem
113  
114  Integer overflow/underflow can bypass critical checks.
115  
116  ```
117  // Overflow example (in languages without protection):
118  uint256 max = 2^256 - 1;
119  uint256 overflow = max + 1;  // Wraps to 0!
120  ```
121  
122  ### 3.2 Safe Math in ADL
123  
124  ADL uses bounded types that prevent overflow:
125  
126  | Type | Range | Overflow Behavior |
127  |------|-------|------------------|
128  | u8 | 0 to 255 | Compile error or runtime panic |
129  | u16 | 0 to 65,535 | Compile error or runtime panic |
130  | u32 | 0 to 4,294,967,295 | Compile error or runtime panic |
131  | u64 | 0 to 18,446,744,073,709,551,615 | Compile error or runtime panic |
132  | u128 | 0 to 2^128-1 | Compile error or runtime panic |
133  
134  ### 3.3 Checked Operations
135  
136  ```
137  // ADL automatically uses checked arithmetic
138  function safe_add(a: u64, b: u64) -> u64 {
139      return a + b;  // Panics on overflow
140  }
141  
142  // Explicit overflow handling
143  function safe_add_checked(a: u64, b: u64) -> Option<u64> {
144      return a.checked_add(b);  // Returns None on overflow
145  }
146  ```
147  
148  ### 3.4 Token Amount Handling
149  
150  | Practice | Description |
151  |----------|-------------|
152  | Use u128 for totals | Prevent overflow in aggregations |
153  | Validate before operations | Check bounds explicitly |
154  | Use decimals consistently | AX: 4 decimals, DX: 0 decimals |
155  
156  ---
157  
158  ## 4. Oracle Manipulation Protection
159  
160  ### 4.1 The Problem
161  
162  Price oracles can be manipulated to exploit contracts.
163  
164  ```
165  Attack scenario:
166  1. Manipulate oracle price (flash loan, low liquidity)
167  2. Execute contract using manipulated price
168  3. Profit from price discrepancy
169  4. Oracle returns to normal
170  ```
171  
172  ### 4.2 Time-Weighted Average Price (TWAP)
173  
174  Use time-averaged prices to resist manipulation:
175  
176  ```
177  struct PriceOracle {
178      cumulative_price: u128,
179      last_update: u64,
180      twap_period: u64,  // e.g., 30 minutes
181  }
182  
183  function get_twap_price(oracle: PriceOracle) -> u64 {
184      let time_elapsed = now() - oracle.last_update;
185      assert(time_elapsed >= oracle.twap_period, "TWAP period not met");
186  
187      let current_cumulative = get_cumulative_price();
188      let price_delta = current_cumulative - oracle.cumulative_price;
189  
190      return price_delta / time_elapsed;
191  }
192  ```
193  
194  ### 4.3 Multi-Source Validation
195  
196  Aggregate prices from multiple sources:
197  
198  ```
199  function get_validated_price(sources: Vec<PriceSource>) -> u64 {
200      assert(sources.len() >= 3, "Minimum 3 sources required");
201  
202      let prices: Vec<u64> = sources.map(|s| s.get_price());
203  
204      // Remove outliers (> 5% deviation from median)
205      let median = calculate_median(prices);
206      let valid_prices = prices.filter(|p|
207          abs_diff(*p, median) <= median / 20
208      );
209  
210      assert(valid_prices.len() >= 2, "Insufficient valid prices");
211  
212      return calculate_average(valid_prices);
213  }
214  ```
215  
216  ### 4.4 Circuit Breakers
217  
218  Pause operations when prices are suspicious:
219  
220  | Condition | Action |
221  |-----------|--------|
222  | Price change > 10% in 1 block | Pause, require manual review |
223  | Oracle not updated > 1 hour | Use stale price flag |
224  | Source disagreement > 5% | Pause until resolution |
225  
226  ---
227  
228  ## 5. Access Control Patterns
229  
230  ### 5.1 Ownership Model
231  
232  ```
233  state {
234      owner: Address,
235      admins: Set<Address>,
236  }
237  
238  modifier onlyOwner() {
239      assert(caller == owner, "Not owner");
240      _;
241  }
242  
243  modifier onlyAdmin() {
244      assert(admins.contains(caller) || caller == owner, "Not admin");
245      _;
246  }
247  ```
248  
249  ### 5.2 Role-Based Access Control (RBAC)
250  
251  ```
252  enum Role {
253      None,
254      Operator,
255      Manager,
256      Admin,
257  }
258  
259  state {
260      roles: Map<Address, Role>,
261  }
262  
263  function has_role(addr: Address, required: Role) -> bool {
264      let user_role = roles.get(addr).unwrap_or(Role::None);
265      return user_role >= required;
266  }
267  
268  modifier requireRole(required: Role) {
269      assert(has_role(caller, required), "Insufficient role");
270      _;
271  }
272  ```
273  
274  ### 5.3 Timelock for Critical Operations
275  
276  ```
277  struct PendingAction {
278      action_hash: Hash,
279      execute_after: u64,
280      executed: bool,
281  }
282  
283  state {
284      pending_actions: Map<Hash, PendingAction>,
285      timelock_delay: u64 = 48 * 3600,  // 48 hours
286  }
287  
288  function propose_action(action_hash: Hash) with onlyAdmin {
289      pending_actions.insert(action_hash, PendingAction {
290          action_hash,
291          execute_after: now() + timelock_delay,
292          executed: false,
293      });
294  }
295  
296  function execute_action(action_hash: Hash) with onlyAdmin {
297      let action = pending_actions.get_mut(action_hash).unwrap();
298      assert(now() >= action.execute_after, "Timelock not expired");
299      assert(!action.executed, "Already executed");
300  
301      action.executed = true;
302      // Execute the action
303  }
304  ```
305  
306  ---
307  
308  ## 6. Privacy-Specific Patterns (AlphaVM)
309  
310  ### 6.1 Record-Based State
311  
312  AlphaVM uses a record (UTXO) model for privacy:
313  
314  ```
315  record Token {
316      owner: Address,
317      amount: u64,
318      // Private fields hidden in ZK proofs
319  }
320  
321  // Consuming records reveals only serial numbers
322  function transfer(input: Token, to: Address, amount: u64) -> (Token, Token) {
323      assert(input.amount >= amount, "Insufficient balance");
324  
325      let output_to = Token { owner: to, amount: amount };
326      let output_change = Token { owner: input.owner, amount: input.amount - amount };
327  
328      return (output_to, output_change);
329  }
330  ```
331  
332  ### 6.2 ZK Proof Verification
333  
334  | Check | Purpose |
335  |-------|---------|
336  | Proof validity | Cryptographic verification |
337  | Serial number uniqueness | Prevent double-spend |
338  | Commitment consistency | State transition validity |
339  
340  ### 6.3 Privacy Leaks to Avoid
341  
342  | Leak Vector | Mitigation |
343  |-------------|------------|
344  | Transaction timing | Add random delays |
345  | Amount patterns | Use fixed denominations |
346  | Address reuse | Generate new addresses per transaction |
347  | Metadata | Strip unnecessary transaction data |
348  
349  ---
350  
351  ## 7. DEX-Specific Patterns (DeltaVM)
352  
353  ### 7.1 Order Matching Security
354  
355  ```
356  struct Order {
357      maker: Address,
358      pair: (Token, Token),
359      price: u64,
360      amount: u64,
361      expiry: u64,
362      nonce: u64,
363      signature: Signature,
364  }
365  
366  function verify_order(order: Order) -> bool {
367      // Check expiry
368      assert(now() < order.expiry, "Order expired");
369  
370      // Verify signature
371      let message = hash(order.maker, order.pair, order.price, order.amount, order.expiry, order.nonce);
372      assert(verify_signature(order.signature, message, order.maker), "Invalid signature");
373  
374      // Check nonce not used
375      assert(!used_nonces.contains((order.maker, order.nonce)), "Nonce reused");
376  
377      return true;
378  }
379  ```
380  
381  ### 7.2 Frontrunning Protection
382  
383  | Technique | Description |
384  |-----------|-------------|
385  | Commit-reveal | Hide order details until execution |
386  | Private transactions | Use ZK to hide pending orders |
387  | Batch auctions | Process orders in batches |
388  | Maximum slippage | User-defined price bounds |
389  
390  ### 7.3 Liquidity Pool Security
391  
392  ```
393  function swap(
394      pool: LiquidityPool,
395      token_in: Token,
396      amount_in: u64,
397      min_amount_out: u64  // Slippage protection
398  ) -> u64 {
399      let amount_out = calculate_output(pool, token_in, amount_in);
400  
401      // Slippage protection
402      assert(amount_out >= min_amount_out, "Slippage exceeded");
403  
404      // CEI: Update state before transfer
405      update_pool_reserves(pool, token_in, amount_in, amount_out);
406  
407      // Transfer tokens
408      transfer_from(caller, pool.address, token_in, amount_in);
409      transfer(caller, other_token(pool, token_in), amount_out);
410  
411      return amount_out;
412  }
413  ```
414  
415  ---
416  
417  ## 8. Testing Requirements
418  
419  ### 8.1 Unit Tests
420  
421  | Test Category | Coverage Target |
422  |---------------|-----------------|
423  | Access control | 100% |
424  | Math operations | 100% |
425  | State transitions | 100% |
426  | Error conditions | 100% |
427  
428  ### 8.2 Fuzzing
429  
430  | Target | Fuzzer |
431  |--------|--------|
432  | Input validation | Property-based testing |
433  | Arithmetic | Overflow/underflow cases |
434  | State machines | Invariant testing |
435  
436  ### 8.3 Formal Verification
437  
438  | Property | Verification Method |
439  |----------|-------------------|
440  | No unauthorized minting | Symbolic execution |
441  | Balance conservation | Theorem proving |
442  | Access control invariants | Model checking |
443  
444  ---
445  
446  ## 9. Deployment Checklist
447  
448  ### Pre-Deployment
449  
450  - [ ] All tests passing (unit, integration, fuzz)
451  - [ ] Code review by 2+ developers
452  - [ ] External audit for high-value contracts
453  - [ ] Deployment script reviewed
454  - [ ] Upgrade path documented (if applicable)
455  
456  ### Post-Deployment
457  
458  - [ ] Verify deployed bytecode matches source
459  - [ ] Verify constructor parameters
460  - [ ] Monitor for unusual activity
461  - [ ] Document deployment transaction
462  
463  ---
464  
465  ## References
466  
467  - S001_threat_model (components/security.cspec)
468  - ADL Compiler (components/alpha/A002-adl.component.cspec)
469  - Attack Vectors (docs/security/attack-vectors.md)
470  - DeltaVM Specification (components/delta/D001-deltavm.component.cspec)