agentic-team-templates 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +280 -0
  2. package/bin/cli.js +5 -0
  3. package/package.json +47 -0
  4. package/src/index.js +521 -0
  5. package/templates/_shared/code-quality.md +162 -0
  6. package/templates/_shared/communication.md +114 -0
  7. package/templates/_shared/core-principles.md +62 -0
  8. package/templates/_shared/git-workflow.md +165 -0
  9. package/templates/_shared/security-fundamentals.md +173 -0
  10. package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
  11. package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
  12. package/templates/blockchain/.cursorrules/overview.md +130 -0
  13. package/templates/blockchain/.cursorrules/security.md +318 -0
  14. package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
  15. package/templates/blockchain/.cursorrules/testing.md +415 -0
  16. package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
  17. package/templates/blockchain/CLAUDE.md +389 -0
  18. package/templates/cli-tools/.cursorrules/architecture.md +412 -0
  19. package/templates/cli-tools/.cursorrules/arguments.md +406 -0
  20. package/templates/cli-tools/.cursorrules/distribution.md +546 -0
  21. package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
  22. package/templates/cli-tools/.cursorrules/overview.md +136 -0
  23. package/templates/cli-tools/.cursorrules/testing.md +537 -0
  24. package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
  25. package/templates/cli-tools/CLAUDE.md +356 -0
  26. package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
  27. package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
  28. package/templates/data-engineering/.cursorrules/overview.md +85 -0
  29. package/templates/data-engineering/.cursorrules/performance.md +339 -0
  30. package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
  31. package/templates/data-engineering/.cursorrules/security.md +460 -0
  32. package/templates/data-engineering/.cursorrules/testing.md +452 -0
  33. package/templates/data-engineering/CLAUDE.md +974 -0
  34. package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
  35. package/templates/devops-sre/.cursorrules/change-management.md +584 -0
  36. package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
  37. package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
  38. package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
  39. package/templates/devops-sre/.cursorrules/observability.md +714 -0
  40. package/templates/devops-sre/.cursorrules/overview.md +230 -0
  41. package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
  42. package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
  43. package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
  44. package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
  45. package/templates/devops-sre/CLAUDE.md +1007 -0
  46. package/templates/documentation/.cursorrules/adr.md +277 -0
  47. package/templates/documentation/.cursorrules/api-documentation.md +411 -0
  48. package/templates/documentation/.cursorrules/code-comments.md +253 -0
  49. package/templates/documentation/.cursorrules/maintenance.md +260 -0
  50. package/templates/documentation/.cursorrules/overview.md +82 -0
  51. package/templates/documentation/.cursorrules/readme-standards.md +306 -0
  52. package/templates/documentation/CLAUDE.md +120 -0
  53. package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
  54. package/templates/fullstack/.cursorrules/architecture.md +298 -0
  55. package/templates/fullstack/.cursorrules/overview.md +109 -0
  56. package/templates/fullstack/.cursorrules/shared-types.md +348 -0
  57. package/templates/fullstack/.cursorrules/testing.md +386 -0
  58. package/templates/fullstack/CLAUDE.md +349 -0
  59. package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
  60. package/templates/ml-ai/.cursorrules/deployment.md +601 -0
  61. package/templates/ml-ai/.cursorrules/model-development.md +538 -0
  62. package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
  63. package/templates/ml-ai/.cursorrules/overview.md +131 -0
  64. package/templates/ml-ai/.cursorrules/security.md +637 -0
  65. package/templates/ml-ai/.cursorrules/testing.md +678 -0
  66. package/templates/ml-ai/CLAUDE.md +1136 -0
  67. package/templates/mobile/.cursorrules/navigation.md +246 -0
  68. package/templates/mobile/.cursorrules/offline-first.md +302 -0
  69. package/templates/mobile/.cursorrules/overview.md +71 -0
  70. package/templates/mobile/.cursorrules/performance.md +345 -0
  71. package/templates/mobile/.cursorrules/testing.md +339 -0
  72. package/templates/mobile/CLAUDE.md +233 -0
  73. package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
  74. package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
  75. package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
  76. package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
  77. package/templates/platform-engineering/.cursorrules/observability.md +747 -0
  78. package/templates/platform-engineering/.cursorrules/overview.md +215 -0
  79. package/templates/platform-engineering/.cursorrules/security.md +855 -0
  80. package/templates/platform-engineering/.cursorrules/testing.md +878 -0
  81. package/templates/platform-engineering/CLAUDE.md +850 -0
  82. package/templates/utility-agent/.cursorrules/action-control.md +284 -0
  83. package/templates/utility-agent/.cursorrules/context-management.md +186 -0
  84. package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
  85. package/templates/utility-agent/.cursorrules/overview.md +78 -0
  86. package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
  87. package/templates/utility-agent/CLAUDE.md +513 -0
  88. package/templates/web-backend/.cursorrules/api-design.md +255 -0
  89. package/templates/web-backend/.cursorrules/authentication.md +309 -0
  90. package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
  91. package/templates/web-backend/.cursorrules/error-handling.md +366 -0
  92. package/templates/web-backend/.cursorrules/overview.md +69 -0
  93. package/templates/web-backend/.cursorrules/security.md +358 -0
  94. package/templates/web-backend/.cursorrules/testing.md +395 -0
  95. package/templates/web-backend/CLAUDE.md +366 -0
  96. package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
  97. package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
  98. package/templates/web-frontend/.cursorrules/overview.md +72 -0
  99. package/templates/web-frontend/.cursorrules/performance.md +325 -0
  100. package/templates/web-frontend/.cursorrules/state-management.md +227 -0
  101. package/templates/web-frontend/.cursorrules/styling.md +271 -0
  102. package/templates/web-frontend/.cursorrules/testing.md +311 -0
  103. package/templates/web-frontend/CLAUDE.md +399 -0
@@ -0,0 +1,520 @@
1
+ # DeFi Protocol Patterns
2
+
3
+ Advanced patterns for building DeFi protocols: AMMs, lending, yield strategies, and MEV protection.
4
+
5
+ ## Token Standards
6
+
7
+ ### ERC-20 (Fungible Tokens)
8
+
9
+ ```solidity
10
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
11
+
12
+ contract MyToken is ERC20 {
13
+ constructor() ERC20("My Token", "MTK") {
14
+ _mint(msg.sender, 1_000_000e18);
15
+ }
16
+ }
17
+
18
+ // With extensions
19
+ import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
20
+ import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
21
+ import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
22
+
23
+ contract AdvancedToken is ERC20, ERC20Burnable, ERC20Pausable, ERC20Permit {
24
+ // Permit allows gasless approvals via signatures
25
+ }
26
+ ```
27
+
28
+ ### ERC-721 (NFTs)
29
+
30
+ ```solidity
31
+ import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
32
+ import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
33
+
34
+ contract MyNFT is ERC721, ERC721URIStorage {
35
+ uint256 private s_tokenIdCounter;
36
+
37
+ constructor() ERC721("My NFT", "MNFT") {}
38
+
39
+ function mint(address to, string memory uri) external {
40
+ uint256 tokenId = s_tokenIdCounter++;
41
+ _safeMint(to, tokenId);
42
+ _setTokenURI(tokenId, uri);
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### ERC-1155 (Multi-Token)
48
+
49
+ ```solidity
50
+ import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
51
+
52
+ contract GameItems is ERC1155 {
53
+ uint256 public constant GOLD = 0;
54
+ uint256 public constant SILVER = 1;
55
+ uint256 public constant SWORD = 2;
56
+ uint256 public constant SHIELD = 3;
57
+
58
+ constructor() ERC1155("https://game.example/api/item/{id}.json") {
59
+ _mint(msg.sender, GOLD, 10**18, "");
60
+ _mint(msg.sender, SILVER, 10**27, "");
61
+ _mint(msg.sender, SWORD, 100, "");
62
+ _mint(msg.sender, SHIELD, 50, "");
63
+ }
64
+ }
65
+ ```
66
+
67
+ ### ERC-4626 (Tokenized Vaults)
68
+
69
+ The standard for yield-bearing tokens:
70
+
71
+ ```solidity
72
+ import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
73
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
74
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
75
+
76
+ contract YieldVault is ERC4626 {
77
+ constructor(IERC20 asset_)
78
+ ERC4626(asset_)
79
+ ERC20("Yield Vault Token", "yVLT")
80
+ {}
81
+
82
+ // Override to implement yield strategy
83
+ function totalAssets() public view override returns (uint256) {
84
+ return IERC20(asset()).balanceOf(address(this)) + _accruedYield();
85
+ }
86
+
87
+ function _accruedYield() internal view returns (uint256) {
88
+ // Calculate yield from strategy
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## AMM Patterns
94
+
95
+ ### Constant Product Market Maker (x * y = k)
96
+
97
+ ```solidity
98
+ contract SimpleAMM {
99
+ IERC20 public immutable token0;
100
+ IERC20 public immutable token1;
101
+
102
+ uint256 public reserve0;
103
+ uint256 public reserve1;
104
+
105
+ uint256 private constant FEE_BPS = 30; // 0.3%
106
+ uint256 private constant BPS = 10_000;
107
+
108
+ event Swap(
109
+ address indexed sender,
110
+ uint256 amountIn,
111
+ uint256 amountOut,
112
+ bool zeroForOne
113
+ );
114
+
115
+ function swap(uint256 amountIn, bool zeroForOne, uint256 minAmountOut)
116
+ external
117
+ returns (uint256 amountOut)
118
+ {
119
+ (IERC20 tokenIn, IERC20 tokenOut, uint256 reserveIn, uint256 reserveOut) =
120
+ zeroForOne
121
+ ? (token0, token1, reserve0, reserve1)
122
+ : (token1, token0, reserve1, reserve0);
123
+
124
+ // Transfer in
125
+ tokenIn.transferFrom(msg.sender, address(this), amountIn);
126
+
127
+ // Calculate output: dy = (dx * y * (1 - fee)) / (x + dx * (1 - fee))
128
+ uint256 amountInWithFee = amountIn * (BPS - FEE_BPS);
129
+ amountOut = (amountInWithFee * reserveOut) / (reserveIn * BPS + amountInWithFee);
130
+
131
+ // Slippage protection
132
+ if (amountOut < minAmountOut) revert SlippageExceeded();
133
+
134
+ // Update reserves
135
+ if (zeroForOne) {
136
+ reserve0 += amountIn;
137
+ reserve1 -= amountOut;
138
+ } else {
139
+ reserve1 += amountIn;
140
+ reserve0 -= amountOut;
141
+ }
142
+
143
+ // Transfer out
144
+ tokenOut.transfer(msg.sender, amountOut);
145
+
146
+ emit Swap(msg.sender, amountIn, amountOut, zeroForOne);
147
+ }
148
+
149
+ function addLiquidity(uint256 amount0, uint256 amount1) external returns (uint256 liquidity) {
150
+ // Implementation...
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Price Calculation
156
+
157
+ ```solidity
158
+ // Get current spot price
159
+ function getSpotPrice() public view returns (uint256) {
160
+ return (reserve1 * 1e18) / reserve0;
161
+ }
162
+
163
+ // Get output amount for input
164
+ function getAmountOut(uint256 amountIn, bool zeroForOne) public view returns (uint256) {
165
+ (uint256 reserveIn, uint256 reserveOut) = zeroForOne
166
+ ? (reserve0, reserve1)
167
+ : (reserve1, reserve0);
168
+
169
+ uint256 amountInWithFee = amountIn * (BPS - FEE_BPS);
170
+ return (amountInWithFee * reserveOut) / (reserveIn * BPS + amountInWithFee);
171
+ }
172
+ ```
173
+
174
+ ## Flash Loans (ERC-3156)
175
+
176
+ ### Flash Loan Lender
177
+
178
+ ```solidity
179
+ import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";
180
+ import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
181
+
182
+ contract FlashLender is IERC3156FlashLender {
183
+ bytes32 private constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
184
+
185
+ uint256 public constant FEE_BPS = 9; // 0.09%
186
+
187
+ mapping(address => bool) public supportedTokens;
188
+
189
+ function flashLoan(
190
+ IERC3156FlashBorrower receiver,
191
+ address token,
192
+ uint256 amount,
193
+ bytes calldata data
194
+ ) external returns (bool) {
195
+ if (!supportedTokens[token]) revert UnsupportedToken();
196
+
197
+ uint256 fee = flashFee(token, amount);
198
+ uint256 balanceBefore = IERC20(token).balanceOf(address(this));
199
+
200
+ // Lend
201
+ IERC20(token).transfer(address(receiver), amount);
202
+
203
+ // Callback
204
+ if (receiver.onFlashLoan(msg.sender, token, amount, fee, data) != CALLBACK_SUCCESS) {
205
+ revert CallbackFailed();
206
+ }
207
+
208
+ // Verify repayment
209
+ uint256 balanceAfter = IERC20(token).balanceOf(address(this));
210
+ if (balanceAfter < balanceBefore + fee) {
211
+ revert RepaymentFailed();
212
+ }
213
+
214
+ return true;
215
+ }
216
+
217
+ function flashFee(address token, uint256 amount) public view returns (uint256) {
218
+ return (amount * FEE_BPS) / 10_000;
219
+ }
220
+
221
+ function maxFlashLoan(address token) public view returns (uint256) {
222
+ return supportedTokens[token] ? IERC20(token).balanceOf(address(this)) : 0;
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Flash Loan Borrower
228
+
229
+ ```solidity
230
+ contract FlashBorrower is IERC3156FlashBorrower {
231
+ IERC3156FlashLender public lender;
232
+
233
+ function onFlashLoan(
234
+ address initiator,
235
+ address token,
236
+ uint256 amount,
237
+ uint256 fee,
238
+ bytes calldata data
239
+ ) external returns (bytes32) {
240
+ require(msg.sender == address(lender), "Untrusted lender");
241
+ require(initiator == address(this), "Untrusted initiator");
242
+
243
+ // Do something with the flash loan
244
+ // e.g., arbitrage, liquidation, collateral swap
245
+
246
+ // Repay
247
+ IERC20(token).approve(address(lender), amount + fee);
248
+
249
+ return keccak256("ERC3156FlashBorrower.onFlashLoan");
250
+ }
251
+
252
+ function executeFlashLoan(address token, uint256 amount) external {
253
+ lender.flashLoan(this, token, amount, "");
254
+ }
255
+ }
256
+ ```
257
+
258
+ ## MEV Protection
259
+
260
+ ### Commit-Reveal Pattern
261
+
262
+ ```solidity
263
+ contract CommitRevealAuction {
264
+ struct Bid {
265
+ bytes32 commitment;
266
+ uint256 revealedAmount;
267
+ bool revealed;
268
+ }
269
+
270
+ mapping(address => Bid) public bids;
271
+ uint256 public commitDeadline;
272
+ uint256 public revealDeadline;
273
+
274
+ // Phase 1: Commit (hidden bid)
275
+ function commit(bytes32 commitment) external {
276
+ require(block.timestamp < commitDeadline, "Commit phase ended");
277
+ bids[msg.sender].commitment = commitment;
278
+ }
279
+
280
+ // Phase 2: Reveal
281
+ function reveal(uint256 amount, bytes32 salt) external {
282
+ require(block.timestamp >= commitDeadline, "Commit phase not ended");
283
+ require(block.timestamp < revealDeadline, "Reveal phase ended");
284
+
285
+ Bid storage bid = bids[msg.sender];
286
+ bytes32 expectedCommitment = keccak256(abi.encode(msg.sender, amount, salt));
287
+
288
+ require(bid.commitment == expectedCommitment, "Invalid reveal");
289
+
290
+ bid.revealedAmount = amount;
291
+ bid.revealed = true;
292
+ }
293
+ }
294
+ ```
295
+
296
+ ### Slippage Protection
297
+
298
+ ```solidity
299
+ function swap(
300
+ address tokenIn,
301
+ address tokenOut,
302
+ uint256 amountIn,
303
+ uint256 minAmountOut, // User-specified minimum
304
+ uint256 deadline // Transaction expiry
305
+ ) external {
306
+ // Deadline check - prevents stale transactions
307
+ if (block.timestamp > deadline) revert TransactionExpired();
308
+
309
+ uint256 amountOut = _calculateAmountOut(tokenIn, tokenOut, amountIn);
310
+
311
+ // Slippage check - prevents sandwich attacks
312
+ if (amountOut < minAmountOut) revert SlippageExceeded(amountOut, minAmountOut);
313
+
314
+ _executeSwap(tokenIn, tokenOut, amountIn, amountOut);
315
+ }
316
+ ```
317
+
318
+ ### Private Mempools
319
+
320
+ For sensitive transactions, use private transaction services:
321
+
322
+ ```typescript
323
+ // Frontend: Submit to Flashbots Protect
324
+ const flashbotsProvider = new ethers.providers.JsonRpcProvider(
325
+ 'https://rpc.flashbots.net'
326
+ );
327
+
328
+ // Transaction won't be visible in public mempool
329
+ const tx = await flashbotsProvider.sendTransaction(signedTx);
330
+ ```
331
+
332
+ ## Oracle Integration
333
+
334
+ ### Chainlink Price Feeds
335
+
336
+ ```solidity
337
+ import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
338
+
339
+ contract PriceConsumer {
340
+ AggregatorV3Interface internal priceFeed;
341
+
342
+ constructor(address feedAddress) {
343
+ priceFeed = AggregatorV3Interface(feedAddress);
344
+ }
345
+
346
+ function getLatestPrice() public view returns (int256 price, uint256 timestamp) {
347
+ (
348
+ /* uint80 roundID */,
349
+ price,
350
+ /* uint256 startedAt */,
351
+ timestamp,
352
+ /* uint80 answeredInRound */
353
+ ) = priceFeed.latestRoundData();
354
+
355
+ // Staleness check
356
+ if (block.timestamp - timestamp > 1 hours) {
357
+ revert StalePrice();
358
+ }
359
+
360
+ // Sanity check
361
+ if (price <= 0) {
362
+ revert InvalidPrice();
363
+ }
364
+
365
+ return (price, timestamp);
366
+ }
367
+ }
368
+ ```
369
+
370
+ ### TWAP (Time-Weighted Average Price)
371
+
372
+ ```solidity
373
+ // Uniswap V3 TWAP
374
+ import {OracleLibrary} from "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";
375
+
376
+ function getTwapPrice(address pool, uint32 twapInterval) public view returns (uint256) {
377
+ (int24 arithmeticMeanTick,) = OracleLibrary.consult(pool, twapInterval);
378
+
379
+ uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(arithmeticMeanTick);
380
+
381
+ // Convert to price
382
+ return uint256(sqrtPriceX96) ** 2 / (2 ** 192);
383
+ }
384
+ ```
385
+
386
+ ## Yield Strategies
387
+
388
+ ### Basic Yield Aggregator
389
+
390
+ ```solidity
391
+ contract YieldAggregator is ERC4626 {
392
+ struct Strategy {
393
+ address target;
394
+ uint256 allocation; // In BPS
395
+ bool active;
396
+ }
397
+
398
+ Strategy[] public strategies;
399
+ uint256 public constant TOTAL_BPS = 10_000;
400
+
401
+ function harvest() external {
402
+ uint256 totalYield;
403
+
404
+ for (uint256 i = 0; i < strategies.length; i++) {
405
+ if (strategies[i].active) {
406
+ uint256 yield = IStrategy(strategies[i].target).harvest();
407
+ totalYield += yield;
408
+ }
409
+ }
410
+
411
+ // Compound or distribute
412
+ }
413
+
414
+ function rebalance() external {
415
+ uint256 totalAssets_ = totalAssets();
416
+
417
+ for (uint256 i = 0; i < strategies.length; i++) {
418
+ Strategy memory strat = strategies[i];
419
+ if (!strat.active) continue;
420
+
421
+ uint256 targetAllocation = (totalAssets_ * strat.allocation) / TOTAL_BPS;
422
+ uint256 currentAllocation = IStrategy(strat.target).balance();
423
+
424
+ if (currentAllocation < targetAllocation) {
425
+ // Deposit more
426
+ uint256 delta = targetAllocation - currentAllocation;
427
+ IStrategy(strat.target).deposit(delta);
428
+ } else if (currentAllocation > targetAllocation) {
429
+ // Withdraw excess
430
+ uint256 delta = currentAllocation - targetAllocation;
431
+ IStrategy(strat.target).withdraw(delta);
432
+ }
433
+ }
434
+ }
435
+ }
436
+ ```
437
+
438
+ ## Liquidation Patterns
439
+
440
+ ```solidity
441
+ contract LendingProtocol {
442
+ struct Position {
443
+ uint256 collateral;
444
+ uint256 debt;
445
+ }
446
+
447
+ uint256 public constant LIQUIDATION_THRESHOLD = 8000; // 80%
448
+ uint256 public constant LIQUIDATION_BONUS = 500; // 5%
449
+
450
+ function isLiquidatable(address user) public view returns (bool) {
451
+ Position memory pos = positions[user];
452
+ uint256 collateralValue = getCollateralValue(pos.collateral);
453
+ uint256 debtValue = getDebtValue(pos.debt);
454
+
455
+ // Health factor = collateral * threshold / debt
456
+ return (collateralValue * LIQUIDATION_THRESHOLD / 10_000) < debtValue;
457
+ }
458
+
459
+ function liquidate(address user, uint256 debtToCover) external {
460
+ require(isLiquidatable(user), "Not liquidatable");
461
+
462
+ Position storage pos = positions[user];
463
+
464
+ // Calculate collateral to seize (debt + bonus)
465
+ uint256 collateralToSeize = (debtToCover * (10_000 + LIQUIDATION_BONUS)) / 10_000;
466
+ collateralToSeize = collateralToSeize * debtPrice / collateralPrice;
467
+
468
+ // Cap at user's collateral
469
+ if (collateralToSeize > pos.collateral) {
470
+ collateralToSeize = pos.collateral;
471
+ }
472
+
473
+ // Update position
474
+ pos.debt -= debtToCover;
475
+ pos.collateral -= collateralToSeize;
476
+
477
+ // Transfer
478
+ debtToken.transferFrom(msg.sender, address(this), debtToCover);
479
+ collateralToken.transfer(msg.sender, collateralToSeize);
480
+
481
+ emit Liquidation(user, msg.sender, debtToCover, collateralToSeize);
482
+ }
483
+ }
484
+ ```
485
+
486
+ ## Anti-Patterns to Avoid
487
+
488
+ ### 1. On-Chain Price Manipulation
489
+
490
+ ```solidity
491
+ // Bad: Using spot price from AMM
492
+ uint256 price = amm.getSpotPrice(); // Can be manipulated in same tx
493
+
494
+ // Good: Use TWAP or Chainlink
495
+ uint256 price = oracle.getTwapPrice(1 hours);
496
+ ```
497
+
498
+ ### 2. Unprotected External Calls
499
+
500
+ ```solidity
501
+ // Bad: No validation of external protocol
502
+ IExternalProtocol(untrustedAddress).deposit(amount);
503
+
504
+ // Good: Whitelist and validate
505
+ require(trustedProtocols[protocol], "Untrusted protocol");
506
+ IExternalProtocol(protocol).deposit(amount);
507
+ ```
508
+
509
+ ### 3. Lack of Emergency Controls
510
+
511
+ ```solidity
512
+ // Good: Emergency withdraw capability
513
+ function emergencyWithdraw() external onlyOwner {
514
+ _pause();
515
+ // Withdraw all funds from strategies
516
+ for (uint256 i = 0; i < strategies.length; i++) {
517
+ IStrategy(strategies[i]).withdrawAll();
518
+ }
519
+ }
520
+ ```