# ๐Ÿงช DeFi Strategy Testing Framework > A comprehensive CLI tool for testing DeFi strategies against local mainnet forks with support for success paths and controlled failure scenarios. --- ## ๐Ÿ“‹ Overview The DeFi Strategy Testing Framework allows you to: - โœ… Run **repeatable, deterministic simulations** of DeFi strategies on local mainnet forks - ๐Ÿ’ฅ Test both **success** and **failure** cases: liquidations, oracle shocks, cap limits, slippage, approvals, paused assets, etc. - โœ… Provide **clear pass/fail assertions** (e.g., Aave Health Factor >= 1 after each step; exact token deltas; gas ceilings) - ๐Ÿ“Š Produce **auditable reports** (JSON + HTML) suitable for CI - ๐ŸŽฒ **Fuzz test** strategies with parameterized inputs - ๐Ÿ‹ **Automatically fund** test accounts via whale impersonation --- ## ๐Ÿ—๏ธ Architecture ``` /defi-strat-cli /src/strat /core # ๐Ÿ”ง Engine: fork control, scenario runner, assertions, reporting - fork-orchestrator.ts # ๐Ÿด Fork management (Anvil/Hardhat) - scenario-runner.ts # โ–ถ๏ธ Executes scenarios step by step - assertion-evaluator.ts # โœ… Evaluates assertions - failure-injector.ts # ๐Ÿ’ฅ Injects failure scenarios - fuzzer.ts # ๐ŸŽฒ Fuzz testing with parameterized inputs - whale-registry.ts # ๐Ÿ‹ Whale addresses for token funding /adapters # ๐Ÿ”Œ Protocol adapters /aave-v3-adapter.ts # ๐Ÿฆ Aave v3 operations /uniswap-v3-adapter.ts # ๐Ÿ”„ Uniswap v3 swaps /compound-v3-adapter.ts # ๐Ÿ›๏ธ Compound v3 operations /erc20-adapter.ts # ๐Ÿ’ฐ ERC20 token operations /dsl # ๐Ÿ“ Strategy/Scenario schema + loader - scenario-loader.ts # ๐Ÿ“„ YAML/JSON parser /reporters # ๐Ÿ“Š Report generators - json-reporter.ts # ๐Ÿ“„ JSON reports - html-reporter.ts # ๐ŸŒ HTML reports - junit-reporter.ts # ๐Ÿ”ง JUnit XML for CI /config # โš™๏ธ Configuration - networks.ts # ๐ŸŒ Network configurations - oracle-feeds.ts # ๐Ÿ”ฎ Oracle feed addresses /scenarios # ๐Ÿ“š Example strategies /aave - leveraged-long.yml - liquidation-drill.yml /compound3 - supply-borrow.yml ``` --- ## ๐Ÿš€ Quick Start ### ๐Ÿ“ฆ Installation ```bash # Install dependencies pnpm install ``` ### โ–ถ๏ธ Run a Scenario ```bash # Run a scenario pnpm run strat run scenarios/aave/leveraged-long.yml # Run with custom network pnpm run strat run scenarios/aave/leveraged-long.yml --network base # Generate reports pnpm run strat run scenarios/aave/leveraged-long.yml \ --report out/run.json \ --html out/report.html \ --junit out/junit.xml ``` ### ๐Ÿงช Test Script For comprehensive testing with a real fork: ```bash # Set your RPC URL export MAINNET_RPC_URL=https://mainnet.infura.io/v3/YOUR_KEY # Run test script pnpm run strat:test ``` --- ## ๐Ÿ–ฅ๏ธ CLI Commands ### ๐Ÿด `fork up` Start or attach to a fork instance. ```bash pnpm run strat fork up --network mainnet --block 18500000 ``` ### โ–ถ๏ธ `run` Run a scenario file. ```bash pnpm run strat run [options] ``` | Option | Description | Default | |--------|-------------|---------| | `--network ` | Network name or chain ID | `mainnet` | | `--report ` | Output JSON report path | - | | `--html ` | Output HTML report path | - | | `--junit ` | Output JUnit XML report path | - | | `--rpc ` | Custom RPC URL | - | ### ๐ŸŽฒ `fuzz` Fuzz test a scenario with parameterized inputs. ```bash pnpm run strat fuzz scenarios/aave/leveraged-long.yml --iters 100 --seed 42 ``` | Option | Description | Default | |--------|-------------|---------| | `--iters ` | Number of iterations | `100` | | `--seed ` | Random seed for reproducibility | - | | `--report ` | Output JSON report path | - | ### ๐Ÿ’ฅ `failures` List available failure injection methods. ```bash pnpm run strat failures [protocol] ``` ### ๐Ÿ“Š `compare` Compare two run reports. ```bash pnpm run strat compare out/run1.json out/run2.json ``` --- ## ๐Ÿ“ Writing Scenarios Scenarios are defined in YAML or JSON format: ```yaml version: 1 network: mainnet protocols: [aave-v3, uniswap-v3] assumptions: baseCurrency: USD slippageBps: 30 minHealthFactor: 1.05 accounts: trader: funded: - token: WETH amount: "5" steps: - name: Approve WETH to Aave Pool action: erc20.approve args: token: WETH spender: aave-v3:Pool amount: "max" - name: Supply WETH action: aave-v3.supply args: asset: WETH amount: "5" onBehalfOf: $accounts.trader assert: - aave-v3.healthFactor >= 1.5 - name: Borrow USDC action: aave-v3.borrow args: asset: USDC amount: "6000" rateMode: variable - name: Swap USDC->WETH action: uniswap-v3.exactInputSingle args: tokenIn: USDC tokenOut: WETH fee: 500 amountIn: "3000" - name: Oracle shock (-12% WETH) action: failure.oracleShock args: feed: CHAINLINK_WETH_USD pctDelta: -12 - name: Check HF still safe action: assert args: expression: "aave-v3.healthFactor >= 1.05" ``` --- ## ๐Ÿ”Œ Supported Actions ### ๐Ÿฆ Aave v3 | Action | Description | Status | |--------|-------------|--------| | `aave-v3.supply` | Supply assets to Aave | โœ… | | `aave-v3.withdraw` | Withdraw assets from Aave | โœ… | | `aave-v3.borrow` | Borrow assets from Aave | โœ… | | `aave-v3.repay` | Repay borrowed assets | โœ… | | `aave-v3.flashLoanSimple` | Execute a flash loan | โœ… | **Views:** - `aave-v3.healthFactor`: Get user health factor - `aave-v3.userAccountData`: Get full user account data ### ๐Ÿ›๏ธ Compound v3 | Action | Description | Status | |--------|-------------|--------| | `compound-v3.supply` | Supply collateral to Compound v3 | โœ… | | `compound-v3.withdraw` | Withdraw collateral or base asset | โœ… | | `compound-v3.borrow` | Borrow base asset (withdraws base asset) | โœ… | | `compound-v3.repay` | Repay debt (supplies base asset) | โœ… | **Views:** - `compound-v3.borrowBalance`: Get borrow balance - `compound-v3.collateralBalance`: Get collateral balance for an asset ### ๐Ÿ”„ Uniswap v3 | Action | Description | Status | |--------|-------------|--------| | `uniswap-v3.exactInputSingle` | Execute an exact input swap | โœ… | | `uniswap-v3.exactOutputSingle` | Execute an exact output swap | โœ… | ### ๐Ÿ’ฐ ERC20 | Action | Description | Status | |--------|-------------|--------| | `erc20.approve` | Approve token spending | โœ… | **Views:** - `erc20.balanceOf`: Get token balance ### ๐Ÿ’ฅ Failure Injection | Action | Description | Status | |--------|-------------|--------| | `failure.oracleShock` | Inject an oracle price shock (attempts storage manipulation) | โœ… | | `failure.timeTravel` | Advance time | โœ… | | `failure.setTimestamp` | Set block timestamp | โœ… | | `failure.liquidityShock` | Move liquidity | โœ… | | `failure.setBaseFee` | Set gas price | โœ… | | `failure.pauseReserve` | Pause a reserve (Aave) | โœ… | | `failure.capExhaustion` | Simulate cap exhaustion | โœ… | --- ## โœ… Assertions Assertions can be added to any step: ```yaml steps: - name: Check health factor action: assert args: expression: "aave-v3.healthFactor >= 1.05" ``` ### Supported Operators | Operator | Description | Example | |----------|-------------|---------| | `>=` | Greater than or equal | `aave-v3.healthFactor >= 1.05` | | `<=` | Less than or equal | `amount <= 1000` | | `>` | Greater than | `balance > 0` | | `<` | Less than | `gasUsed < 1000000` | | `==` | Equal to | `status == "success"` | | `!=` | Not equal to | `error != null` | --- ## ๐Ÿ“Š Reports ### ๐Ÿ“„ JSON Report Machine-readable JSON format with full run details. **Features:** - โœ… Complete step-by-step execution log - โœ… Assertion results - โœ… Gas usage metrics - โœ… Error messages and stack traces - โœ… State deltas ### ๐ŸŒ HTML Report Human-readable HTML report with: - โœ… Run summary (pass/fail status, duration, gas) - โœ… Step-by-step execution details - โœ… Assertion results with visual indicators - โœ… Gas usage charts - โœ… Error messages with syntax highlighting ### ๐Ÿ”ง JUnit XML CI-friendly XML format for integration with test runners. **Features:** - โœ… Compatible with Jenkins, GitLab CI, GitHub Actions - โœ… Test suite and case structure - โœ… Pass/fail status - โœ… Error messages and stack traces --- ## ๐Ÿด Fork Orchestration The framework supports: | Backend | Status | Features | |---------|--------|----------| | **Anvil** (Foundry) | โœ… | Fast, rich custom RPC methods | | **Hardhat** | โœ… | Wider familiarity | | **Tenderly** | ๐Ÿšง Coming soon | Optional remote simulation backend | ### ๐ŸŽฏ Fork Features - โœ… **Snapshot/revert** - Fast test loops - ๐Ÿ‹ **Account impersonation** - Fund/borrow from whales - โฐ **Time travel** - Advance time, set timestamp - ๐Ÿ’พ **Storage manipulation** - Oracle overrides - โ›ฝ **Gas price control** - Test gas scenarios --- ## ๐Ÿ‹ Token Funding The framework automatically funds test accounts via whale impersonation. Known whale addresses are maintained in the whale registry for common tokens. ### How It Works 1. ๐Ÿ“‹ Look up whale address from registry 2. ๐ŸŽญ Impersonate whale on the fork 3. ๐Ÿ’ธ Transfer tokens to test account 4. โœ… Verify balance ### Adding New Whales ```typescript // src/strat/core/whale-registry.ts export const WHALE_REGISTRY: Record> = { 1: { YOUR_TOKEN: '0x...' as Address, }, }; ``` --- ## ๐Ÿ”Œ Protocol Adapters ### Adding a New Adapter Implement the `ProtocolAdapter` interface: ```typescript export interface ProtocolAdapter { name: string; discover(network: Network): Promise; actions: Record Promise>; invariants?: Array<(ctx: StepContext) => Promise>; views?: Record Promise>; } ``` ### Example Implementation ```typescript export class MyProtocolAdapter implements ProtocolAdapter { name = 'my-protocol'; async discover(network: Network): Promise { return { contract: '0x...', }; } actions = { myAction: async (ctx: StepContext, args: any): Promise => { // Implement action return { success: true }; }, }; views = { myView: async (ctx: ViewContext): Promise => { // Implement view return value; }, }; } ``` --- ## ๐Ÿ’ฅ Failure Injection ### ๐Ÿ”ฎ Oracle Shocks Inject price changes to test liquidation scenarios. The framework attempts to modify Chainlink aggregator storage: ```yaml - name: Oracle shock action: failure.oracleShock args: feed: CHAINLINK_WETH_USD pctDelta: -12 # -12% price drop # aggregatorAddress: 0x... # Optional, auto-resolved if not provided ``` > โš ๏ธ **Note:** Oracle storage manipulation requires precise slot calculation and may not work on all forks. The framework will attempt the manipulation and log warnings if it fails. ### โฐ Time Travel Advance time for interest accrual, maturity, etc.: ```yaml - name: Advance time action: failure.timeTravel args: seconds: 86400 # 1 day ``` ### ๐Ÿ’ง Liquidity Shocks Move liquidity to test pool utilization: ```yaml - name: Liquidity shock action: failure.liquidityShock args: token: WETH whale: 0x... amount: "1000" ``` --- ## ๐ŸŽฒ Fuzzing Fuzz testing runs scenarios with parameterized inputs: ```bash pnpm run strat fuzz scenarios/aave/leveraged-long.yml --iters 100 --seed 42 ``` ### What Gets Fuzzed | Parameter | Variation | Description | |-----------|-----------|-------------| | Amounts | ยฑ20% | Randomly vary token amounts | | Oracle shocks | Within range | Vary oracle shock percentages | | Fee tiers | Random selection | Test different fee tiers | | Slippage | Variable | Vary slippage parameters | ### Features - โœ… Each iteration runs on a fresh snapshot - โœ… Failures don't affect subsequent runs - โœ… Reproducible with seed parameter - โœ… Detailed report for all iterations --- ## ๐ŸŒ Network Support | Network | Chain ID | Status | |---------|----------|--------| | Ethereum Mainnet | 1 | โœ… | | Base | 8453 | โœ… | | Arbitrum One | 42161 | โœ… | | Optimism | 10 | โœ… | | Polygon | 137 | โœ… | > ๐Ÿ’ก Or use chain IDs directly: `--network 1` for mainnet. --- ## ๐Ÿ” Security & Safety > โš ๏ธ **IMPORTANT**: This tool is for **local forks and simulations only**. Do **not** use real keys or send transactions on mainnet from this tool. Testing "oracle shocks", liquidations, and admin toggles are **defensive simulations** to validate strategy resilience, **not** instructions for real-world exploitation. --- ## ๐Ÿ“š Examples See the `scenarios/` directory for example scenarios: | Scenario | Description | Path | |----------|-------------|------| | **Leveraged Long** | Leveraged long strategy with Aave and Uniswap | `aave/leveraged-long.yml` | | **Liquidation Drill** | Test liquidation scenarios with oracle shocks | `aave/liquidation-drill.yml` | | **Supply & Borrow** | Compound v3 supply and borrow example | `compound3/supply-borrow.yml` | --- ## ๐Ÿ”ง Troubleshooting ### โŒ Token Funding Fails If token funding fails, check: 1. โœ… Whale address has sufficient balance on the fork 2. โœ… Fork supports account impersonation (Anvil) 3. โœ… RPC endpoint allows custom methods ### โŒ Oracle Shocks Don't Work Oracle storage manipulation is complex and may fail if: 1. โŒ Storage slot calculation is incorrect 2. โŒ Fork doesn't support storage manipulation 3. โŒ Aggregator uses a different storage layout > ๐Ÿ’ก The framework will log warnings and continue - verify price changes manually if needed. ### โŒ Fork Connection Issues If the fork fails to start: 1. โœ… Check RPC URL is correct and accessible 2. โœ… Verify network configuration 3. โœ… Check if fork block number is valid --- ## ๐Ÿš€ Future Enhancements - [ ] ๐ŸŽฏ Tenderly backend integration - [ ] โ›ฝ Gas profiling & diffing - [ ] ๐Ÿ“Š Risk margin calculators - [ ] ๐Ÿ“ˆ HTML charts for HF over time - [ ] ๐Ÿ”Œ More protocol adapters (Maker, Curve, Balancer, etc.) - [ ] โšก Parallel execution of scenarios - [ ] ๐Ÿ“ Scenario templates and generators --- ## ๐Ÿค Contributing Contributions welcome! Please: 1. ๐Ÿด Fork the repository 2. ๐ŸŒฟ Create a feature branch 3. โœ๏ธ Make your changes 4. ๐Ÿงช Add tests 5. ๐Ÿ“ค Submit a pull request --- ## ๐Ÿ“„ License MIT