Initial commit: add .gitignore and README
This commit is contained in:
310
docs/CHAIN_CONFIG.md
Normal file
310
docs/CHAIN_CONFIG.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# 🔗 Chain Configuration Guide
|
||||
|
||||
How to add and configure new chains in the DeFi Starter Kit.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
This guide walks you through adding a new blockchain network to the DeFi Starter Kit. You'll need to configure:
|
||||
|
||||
- 🔗 RPC endpoints
|
||||
- 📍 Protocol contract addresses
|
||||
- 💰 Token addresses
|
||||
- 🔧 Viem chain configuration
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Adding a New Chain
|
||||
|
||||
### 1️⃣ Create Chain Config File
|
||||
|
||||
Create a new file in `config/chains/` with your chain configuration:
|
||||
|
||||
```typescript
|
||||
// config/chains/yourchain.ts
|
||||
import type { ChainConfig } from '../types.js';
|
||||
|
||||
export const yourchain: ChainConfig = {
|
||||
chainId: 12345, // Your chain ID
|
||||
name: 'Your Chain',
|
||||
rpcUrl: process.env.YOURCHAIN_RPC_URL || 'https://rpc.yourchain.com',
|
||||
|
||||
// Aave v3
|
||||
aave: {
|
||||
poolAddressesProvider: '0x...', // Aave PoolAddressesProvider
|
||||
pool: '0x...', // Aave Pool
|
||||
},
|
||||
|
||||
// Uniswap
|
||||
uniswap: {
|
||||
swapRouter02: '0x...', // Uniswap SwapRouter02
|
||||
universalRouter: '0x...', // Uniswap Universal Router
|
||||
permit2: '0x000000000022D473030F116dDEE9F6B43aC78BA3', // Permit2 (same across chains)
|
||||
quoterV2: '0x...', // Uniswap QuoterV2
|
||||
},
|
||||
|
||||
// Protocolink
|
||||
protocolink: {
|
||||
router: '0x...', // Protocolink Router
|
||||
},
|
||||
|
||||
// Compound III
|
||||
compound3: {
|
||||
cometUsdc: '0x...', // Compound III Comet (if available)
|
||||
},
|
||||
|
||||
// Common Tokens
|
||||
tokens: {
|
||||
WETH: '0x...',
|
||||
USDC: '0x...',
|
||||
USDT: '0x...',
|
||||
DAI: '0x...',
|
||||
WBTC: '0x...',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 2️⃣ Register Chain in Addresses
|
||||
|
||||
Add your chain to `config/addresses.ts`:
|
||||
|
||||
```typescript
|
||||
import { yourchain } from './chains/yourchain.js';
|
||||
|
||||
export const chainConfigs: Record<number, ChainConfig> = {
|
||||
1: mainnet,
|
||||
8453: base,
|
||||
// ... other chains
|
||||
12345: yourchain, // Add your chain
|
||||
};
|
||||
|
||||
// Re-export
|
||||
export { yourchain };
|
||||
```
|
||||
|
||||
### 3️⃣ Add Viem Chain
|
||||
|
||||
Add your chain to `src/utils/chain-config.ts`:
|
||||
|
||||
```typescript
|
||||
import { yourChain } from 'viem/chains';
|
||||
|
||||
const viemChains = {
|
||||
1: mainnet,
|
||||
8453: base,
|
||||
// ... other chains
|
||||
12345: yourChain, // Add your chain
|
||||
};
|
||||
```
|
||||
|
||||
### 4️⃣ Update Environment Variables
|
||||
|
||||
Add RPC URL to `.env.example`:
|
||||
|
||||
```bash
|
||||
YOURCHAIN_RPC_URL=https://rpc.yourchain.com
|
||||
```
|
||||
|
||||
### 5️⃣ Update Foundry Config
|
||||
|
||||
Add RPC endpoint to `foundry.toml`:
|
||||
|
||||
```toml
|
||||
[rpc_endpoints]
|
||||
yourchain = "${YOURCHAIN_RPC_URL}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📍 Getting Official Addresses
|
||||
|
||||
### 🏦 Aave v3
|
||||
|
||||
1. 📚 Check [Aave Documentation](https://docs.aave.com/developers/deployed-contracts/deployed-contracts)
|
||||
2. 🔍 Find your chain in the deployed contracts list
|
||||
3. 📋 Get `PoolAddressesProvider` address
|
||||
4. 🔗 Use `PoolAddressesProvider.getPool()` to get Pool address
|
||||
|
||||
### 🔄 Uniswap v3
|
||||
|
||||
1. 📚 Check [Uniswap Deployments](https://docs.uniswap.org/contracts/v3/reference/deployments)
|
||||
2. 🔍 Find your chain's deployment page
|
||||
3. 📋 Get addresses for:
|
||||
- `SwapRouter02`
|
||||
- `UniversalRouter`
|
||||
- `Permit2` (same address across all chains: `0x000000000022D473030F116dDEE9F6B43aC78BA3`)
|
||||
- `QuoterV2`
|
||||
|
||||
### 🔗 Protocolink
|
||||
|
||||
1. 📚 Check [Protocolink Deployment Addresses](https://docs.protocolink.com/smart-contract/deployment-addresses)
|
||||
2. 🔍 Find your chain
|
||||
3. 📋 Get Router address
|
||||
|
||||
### 🏛️ Compound III
|
||||
|
||||
1. 📚 Check [Compound III Documentation](https://docs.compound.finance/)
|
||||
2. 🔍 Find your chain's Comet addresses
|
||||
3. 📋 Get Comet proxy address for your market
|
||||
|
||||
### 💰 Common Tokens
|
||||
|
||||
For each chain, you'll need addresses for:
|
||||
|
||||
| Token | Description |
|
||||
|-------|-------------|
|
||||
| WETH | Wrapped Ether |
|
||||
| USDC | USD Coin |
|
||||
| USDT | Tether USD |
|
||||
| DAI | Dai Stablecoin |
|
||||
| WBTC | Wrapped Bitcoin |
|
||||
|
||||
**Resources:**
|
||||
- 🔍 [Token Lists](https://tokenlists.org/)
|
||||
- 🔍 [CoinGecko](https://www.coingecko.com/)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Verifying Addresses
|
||||
|
||||
Always verify addresses from multiple sources:
|
||||
|
||||
1. ✅ Official protocol documentation
|
||||
2. ✅ Block explorer (verify contract code)
|
||||
3. ✅ Protocol GitHub repositories
|
||||
4. ✅ Community resources (Discord, forums)
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Your Configuration
|
||||
|
||||
After adding a new chain:
|
||||
|
||||
### 1. Test Chain Config Loading
|
||||
|
||||
```typescript
|
||||
import { getChainConfig } from './config/addresses.js';
|
||||
const config = getChainConfig(12345);
|
||||
console.log(config);
|
||||
```
|
||||
|
||||
### 2. Test RPC Connection
|
||||
|
||||
```typescript
|
||||
import { createRpcClient } from './src/utils/chain-config.js';
|
||||
const client = createRpcClient(12345);
|
||||
const blockNumber = await client.getBlockNumber();
|
||||
console.log('Block number:', blockNumber);
|
||||
```
|
||||
|
||||
### 3. Test Address Resolution
|
||||
|
||||
```typescript
|
||||
import { getAavePoolAddress } from './src/utils/addresses.js';
|
||||
const poolAddress = getAavePoolAddress(12345);
|
||||
console.log('Pool address:', poolAddress);
|
||||
```
|
||||
|
||||
### 4. Run Examples
|
||||
|
||||
```bash
|
||||
# Update example to use your chain ID
|
||||
tsx examples/ts/aave-supply-borrow.ts
|
||||
```
|
||||
|
||||
### 5. Run Tests
|
||||
|
||||
```bash
|
||||
# Update test to use your chain
|
||||
forge test --fork-url $YOURCHAIN_RPC_URL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Common Issues
|
||||
|
||||
### ❌ RPC URL Not Working
|
||||
|
||||
**Possible causes:**
|
||||
- ❌ RPC URL is incorrect
|
||||
- ❌ RPC provider doesn't support your chain
|
||||
- ❌ Rate limits exceeded
|
||||
|
||||
**Solutions:**
|
||||
- ✅ Verify RPC URL is correct
|
||||
- ✅ Try alternative RPC providers
|
||||
- ✅ Check rate limits
|
||||
|
||||
### ❌ Addresses Not Found
|
||||
|
||||
**Possible causes:**
|
||||
- ❌ Protocol not deployed on your chain
|
||||
- ❌ Addresses are incorrect (typos, wrong network)
|
||||
- ❌ Some protocols may not be available on all chains
|
||||
|
||||
**Solutions:**
|
||||
- ✅ Verify protocol is deployed on your chain
|
||||
- ✅ Double-check addresses for typos
|
||||
- ✅ Check protocol documentation for chain support
|
||||
|
||||
### ❌ Token Addresses Wrong
|
||||
|
||||
**Possible causes:**
|
||||
- ❌ Token addresses are incorrect
|
||||
- ❌ Token decimals differ
|
||||
- ❌ Tokens don't exist on your chain
|
||||
|
||||
**Solutions:**
|
||||
- ✅ Verify token addresses on block explorer
|
||||
- ✅ Check token decimals
|
||||
- ✅ Ensure tokens exist on your chain
|
||||
|
||||
---
|
||||
|
||||
## 📝 Chain-Specific Notes
|
||||
|
||||
### 🚀 Layer 2 Chains
|
||||
|
||||
| Consideration | Description |
|
||||
|---------------|-------------|
|
||||
| Gas costs | Typically lower than mainnet |
|
||||
| Finality times | May differ from mainnet |
|
||||
| Protocol features | Some protocols may have L2-specific features |
|
||||
|
||||
### 🧪 Testnets
|
||||
|
||||
| Consideration | Description |
|
||||
|---------------|-------------|
|
||||
| Addresses | Use testnet-specific addresses |
|
||||
| Tokens | Testnet tokens have no real value |
|
||||
| Protocol availability | Some protocols may not be available on testnets |
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
1. ✅ **Always verify addresses** - Don't trust a single source
|
||||
2. ✅ **Use environment variables** - Never hardcode RPC URLs
|
||||
3. ✅ **Test thoroughly** - Test on testnet before mainnet
|
||||
4. ✅ **Document changes** - Update documentation when adding chains
|
||||
5. ✅ **Keep addresses updated** - Protocols may upgrade contracts
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Resources
|
||||
|
||||
| Resource | Link |
|
||||
|----------|------|
|
||||
| Aave Deployed Contracts | [docs.aave.com](https://docs.aave.com/developers/deployed-contracts/deployed-contracts) |
|
||||
| Uniswap Deployments | [docs.uniswap.org](https://docs.uniswap.org/contracts/v3/reference/deployments) |
|
||||
| Protocolink Deployment Addresses | [docs.protocolink.com](https://docs.protocolink.com/smart-contract/deployment-addresses) |
|
||||
| Compound III Documentation | [docs.compound.finance](https://docs.compound.finance/) |
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 📖 [Environment Setup Guide](./ENV_SETUP.md)
|
||||
- 🔐 [Security Best Practices](./SECURITY.md)
|
||||
- 🧪 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
224
docs/ENVIRONMENT_SETUP_COMPLETE.md
Normal file
224
docs/ENVIRONMENT_SETUP_COMPLETE.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# ✅ Environment Setup - Verification Complete
|
||||
|
||||
## 🎉 All Scripts Verified
|
||||
|
||||
All scripts have been verified to properly load environment variables from `.env` files.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Scripts Checked
|
||||
|
||||
### 1. `src/strat/cli.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST before any other imports
|
||||
- ✅ Uses `getNetwork()` which lazy-loads RPC URLs from env vars
|
||||
- ✅ Validates RPC URLs and shows helpful error messages
|
||||
|
||||
### 2. `src/cli/cli.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST before any other imports
|
||||
- ✅ Uses `process.env.PRIVATE_KEY` for transaction execution
|
||||
- ✅ Uses RPC URLs from chain configs (which read from env)
|
||||
|
||||
### 3. `scripts/test-strategy.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST before any other imports
|
||||
- ✅ Reads `MAINNET_RPC_URL`, `TEST_SCENARIO`, `TEST_NETWORK` from env
|
||||
- ✅ Validates RPC URL before proceeding
|
||||
- ✅ Shows clear error messages if not configured
|
||||
|
||||
### 4. `scripts/check-env.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST
|
||||
- ✅ Verifies all RPC URLs are set and accessible
|
||||
- ✅ Tests connections to each network
|
||||
- ✅ Provides helpful feedback
|
||||
|
||||
### 5. `scripts/verify-setup.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST
|
||||
- ✅ Comprehensive verification of all setup components
|
||||
- ✅ Checks scripts, configs, and scenarios
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Network Configuration
|
||||
|
||||
### `src/strat/config/networks.ts` ✅
|
||||
|
||||
- ✅ Lazy-loads RPC URLs when `getNetwork()` is called
|
||||
- ✅ Ensures `dotenv` is loaded before reading env vars
|
||||
- ✅ Supports network-specific env vars (e.g., `MAINNET_RPC_URL`)
|
||||
- ✅ Falls back to defaults if not set
|
||||
|
||||
### `config/chains/*.ts` ✅
|
||||
|
||||
- ✅ Read `process.env` at module load time
|
||||
- ✅ Since all entry points load `dotenv` FIRST, this works correctly
|
||||
- ✅ Have sensible defaults as fallbacks
|
||||
|
||||
---
|
||||
|
||||
## 📋 Environment Variables
|
||||
|
||||
### Required
|
||||
|
||||
| Variable | Description | Status |
|
||||
|----------|-------------|--------|
|
||||
| `MAINNET_RPC_URL` | For mainnet fork testing (required for most scenarios) | ✅ |
|
||||
|
||||
### Optional
|
||||
|
||||
| Variable | Description | When Needed |
|
||||
|----------|-------------|-------------|
|
||||
| `BASE_RPC_URL` | For Base network testing | Multi-chain testing |
|
||||
| `ARBITRUM_RPC_URL` | For Arbitrum testing | Multi-chain testing |
|
||||
| `OPTIMISM_RPC_URL` | For Optimism testing | Multi-chain testing |
|
||||
| `POLYGON_RPC_URL` | For Polygon testing | Multi-chain testing |
|
||||
| `PRIVATE_KEY` | Only needed for mainnet execution (not fork testing) | Mainnet execution |
|
||||
| `TEST_SCENARIO` | Override default test scenario | Custom scenarios |
|
||||
| `TEST_NETWORK` | Override default test network | Multi-chain testing |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Validation
|
||||
|
||||
All scripts now include:
|
||||
|
||||
- ✅ RPC URL validation (checks for placeholders)
|
||||
- ✅ Clear error messages if not configured
|
||||
- ✅ Helpful suggestions (e.g., "Run 'pnpm run check:env'")
|
||||
- ✅ Fallback to defaults where appropriate
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
Run these commands to verify your setup:
|
||||
|
||||
```bash
|
||||
# 1. Check environment variables
|
||||
pnpm run check:env
|
||||
|
||||
# 2. Verify complete setup
|
||||
pnpm run verify:setup
|
||||
|
||||
# 3. Test with a scenario (requires valid RPC URL)
|
||||
pnpm run strat:test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 How It Works
|
||||
|
||||
### 1. Entry Point (CLI script or test script)
|
||||
|
||||
- 📥 Loads `dotenv.config()` FIRST
|
||||
- 📄 This reads `.env` file into `process.env`
|
||||
|
||||
### 2. Network Configuration
|
||||
|
||||
- 🔗 `getNetwork()` is called
|
||||
- ⚡ Lazy-loads RPC URLs from `process.env`
|
||||
- ✅ Returns network config with RPC URL
|
||||
|
||||
### 3. Fork Orchestrator
|
||||
|
||||
- 🔌 Uses the RPC URL from network config
|
||||
- 🌐 Connects to the RPC endpoint
|
||||
- 🍴 Creates fork if needed
|
||||
|
||||
### 4. Validation
|
||||
|
||||
- ✅ Scripts validate RPC URLs before use
|
||||
- 🔍 Check for placeholders like "YOUR_KEY"
|
||||
- 💬 Show helpful error messages if invalid
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
If environment variables aren't loading:
|
||||
|
||||
### 1. Check .env file exists
|
||||
|
||||
```bash
|
||||
ls -la .env
|
||||
```
|
||||
|
||||
### 2. Verify dotenv is loaded first
|
||||
|
||||
- ✅ Check that `import dotenv from 'dotenv'` and `dotenv.config()` are at the top
|
||||
- ✅ Before any other imports that use `process.env`
|
||||
|
||||
### 3. Test environment loading
|
||||
|
||||
```bash
|
||||
node -e "require('dotenv').config(); console.log(process.env.MAINNET_RPC_URL)"
|
||||
```
|
||||
|
||||
### 4. Run verification
|
||||
|
||||
```bash
|
||||
pnpm run verify:setup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Always load dotenv first
|
||||
|
||||
```typescript
|
||||
// ✅ Good
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
import { other } from './other.js';
|
||||
```
|
||||
|
||||
### 2. Use lazy-loading for configs
|
||||
|
||||
```typescript
|
||||
// ✅ Good - lazy load
|
||||
function getNetwork() {
|
||||
return { rpcUrl: process.env.MAINNET_RPC_URL || 'default' };
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Validate before use
|
||||
|
||||
```typescript
|
||||
// ✅ Good - validate
|
||||
if (!rpcUrl || rpcUrl.includes('YOUR_KEY')) {
|
||||
throw new Error('RPC URL not configured');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Summary
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| Scripts load `.env` files | ✅ | All scripts properly load `.env` files |
|
||||
| RPC URL validation | ✅ | All scripts validate RPC URLs before use |
|
||||
| Lazy-loading configs | ✅ | Network configs lazy-load to ensure env vars are available |
|
||||
| Clear error messages | ✅ | Clear error messages guide users to fix issues |
|
||||
| Verification scripts | ✅ | Verification scripts help diagnose problems |
|
||||
| Documentation | ✅ | Documentation explains the setup process |
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
The environment setup is complete and verified! ✅
|
||||
|
||||
All scripts are properly connected to `.env` files and handle secrets correctly. You're ready to start building DeFi strategies!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 📖 [Environment Setup Guide](./ENV_SETUP.md)
|
||||
- ✅ [Verification Summary](./ENV_VERIFICATION_SUMMARY.md)
|
||||
- 🧪 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
261
docs/ENV_SETUP.md
Normal file
261
docs/ENV_SETUP.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# ⚙️ Environment Setup Guide
|
||||
|
||||
This guide explains how to set up environment variables for the DeFi Strategy Testing Framework.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1️⃣ Copy the Example Environment File
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2️⃣ Fill in Your RPC URLs
|
||||
|
||||
```bash
|
||||
# Edit .env file
|
||||
MAINNET_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_KEY
|
||||
BASE_RPC_URL=https://base-mainnet.infura.io/v3/YOUR_INFURA_KEY
|
||||
# ... etc
|
||||
```
|
||||
|
||||
### 3️⃣ Verify Your Setup
|
||||
|
||||
```bash
|
||||
pnpm run check:env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Required Environment Variables
|
||||
|
||||
### 🔗 RPC URLs
|
||||
|
||||
These are used to connect to blockchain networks for forking and testing:
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `MAINNET_RPC_URL` | Ethereum mainnet RPC endpoint | ✅ Yes |
|
||||
| `BASE_RPC_URL` | Base network RPC endpoint | ⚠️ Optional |
|
||||
| `ARBITRUM_RPC_URL` | Arbitrum One RPC endpoint | ⚠️ Optional |
|
||||
| `OPTIMISM_RPC_URL` | Optimism network RPC endpoint | ⚠️ Optional |
|
||||
| `POLYGON_RPC_URL` | Polygon network RPC endpoint | ⚠️ Optional |
|
||||
|
||||
### 🔐 Optional Environment Variables
|
||||
|
||||
| Variable | Description | When Needed |
|
||||
|----------|-------------|-------------|
|
||||
| `PRIVATE_KEY` | Private key for executing transactions | Mainnet/testnet execution only |
|
||||
| `TEST_SCENARIO` | Override default test scenario path | Custom test scenarios |
|
||||
| `TEST_NETWORK` | Override default test network | Multi-chain testing |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Getting RPC URLs
|
||||
|
||||
### 🆓 Free Options
|
||||
|
||||
#### 1. Public RPCs (Rate-Limited)
|
||||
|
||||
| Network | Public RPC URL |
|
||||
|---------|----------------|
|
||||
| Ethereum | `https://eth.llamarpc.com` |
|
||||
| Base | `https://mainnet.base.org` |
|
||||
| Arbitrum | `https://arb1.arbitrum.io/rpc` |
|
||||
| Optimism | `https://mainnet.optimism.io` |
|
||||
| Polygon | `https://polygon-rpc.com` |
|
||||
|
||||
#### 2. Infura (Free Tier)
|
||||
|
||||
1. 📝 Sign up at [infura.io](https://infura.io)
|
||||
2. ➕ Create a project
|
||||
3. 📋 Copy your project ID
|
||||
4. 🔗 Use: `https://mainnet.infura.io/v3/YOUR_PROJECT_ID`
|
||||
|
||||
#### 3. Alchemy (Free Tier)
|
||||
|
||||
1. 📝 Sign up at [alchemy.com](https://alchemy.com)
|
||||
2. ➕ Create an app
|
||||
3. 📋 Copy your API key
|
||||
4. 🔗 Use: `https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY`
|
||||
|
||||
### 💰 Paid Options (Recommended for Production)
|
||||
|
||||
| Provider | Best For | Link |
|
||||
|----------|----------|------|
|
||||
| **Infura** | Reliable, well-known | [infura.io](https://infura.io) |
|
||||
| **Alchemy** | Fast, good free tier | [alchemy.com](https://alchemy.com) |
|
||||
| **QuickNode** | Fast, global network | [quicknode.com](https://quicknode.com) |
|
||||
| **Ankr** | Good performance | [ankr.com](https://ankr.com) |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Verification
|
||||
|
||||
### 🔍 Check Environment Variables
|
||||
|
||||
Run the environment checker:
|
||||
|
||||
```bash
|
||||
pnpm run check:env
|
||||
```
|
||||
|
||||
This will:
|
||||
- ✅ Check that all RPC URLs are set
|
||||
- ✅ Verify connections to each network
|
||||
- ✅ Show current block numbers
|
||||
- ✅ Report any issues
|
||||
|
||||
### 🧪 Test with a Scenario
|
||||
|
||||
```bash
|
||||
# Set your RPC URL
|
||||
export MAINNET_RPC_URL=https://your-rpc-url-here
|
||||
|
||||
# Run a test
|
||||
pnpm run strat:test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### ❌ "RPC URL contains placeholder"
|
||||
|
||||
**Problem:** Your `.env` file still has placeholder values like `YOUR_KEY` or `YOUR_INFURA_KEY`.
|
||||
|
||||
**Solution:** Replace placeholders with actual RPC URLs in your `.env` file.
|
||||
|
||||
### ❌ "Connection failed" or "403 Forbidden"
|
||||
|
||||
**Problem:** Your RPC endpoint is rejecting requests.
|
||||
|
||||
**Possible Causes:**
|
||||
1. ❌ Invalid API key
|
||||
2. ⏱️ Rate limiting (free tier exceeded)
|
||||
3. 🚫 IP restrictions
|
||||
4. 🔒 Infura project set to "private key only" mode
|
||||
|
||||
**Solutions:**
|
||||
1. ✅ Verify your API key is correct
|
||||
2. ✅ Check your RPC provider dashboard for rate limits
|
||||
3. ✅ Try a different RPC provider
|
||||
4. ✅ For Infura: Enable "Public Requests" in project settings
|
||||
|
||||
### ❌ "Environment variable not set"
|
||||
|
||||
**Problem:** The script can't find the required environment variable.
|
||||
|
||||
**Solutions:**
|
||||
1. ✅ Check that `.env` file exists in project root
|
||||
2. ✅ Verify variable name is correct (case-sensitive)
|
||||
3. ✅ Restart your terminal/IDE after creating `.env`
|
||||
4. ✅ Use `pnpm run check:env` to verify
|
||||
|
||||
### ❌ Module Load Order Issues
|
||||
|
||||
**Problem:** Environment variables not being loaded before modules that use them.
|
||||
|
||||
**Solution:** The framework now loads `dotenv` FIRST in all entry points. If you still have issues:
|
||||
1. ✅ Ensure `.env` file is in the project root
|
||||
2. ✅ Check that `dotenv` package is installed
|
||||
3. ✅ Verify scripts load dotenv before other imports
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
1. **Never commit `.env` files:**
|
||||
- ✅ `.env` is in `.gitignore`
|
||||
- ✅ Only commit `.env.example`
|
||||
|
||||
2. **Use different keys for different environments:**
|
||||
- 🧪 Development: Free tier or public RPCs
|
||||
- 🚀 Production: Paid RPC providers
|
||||
|
||||
3. **Rotate keys regularly:**
|
||||
- 🔄 Especially if keys are exposed
|
||||
- 📝 Update `.env` file with new keys
|
||||
|
||||
### 🗂️ Organization
|
||||
|
||||
4. **Use environment-specific files:**
|
||||
- 📁 `.env.local` - Local development (gitignored)
|
||||
- 📁 `.env.production` - Production (gitignored)
|
||||
- 📁 `.env.example` - Template (committed)
|
||||
|
||||
5. **Validate on startup:**
|
||||
- ✅ Use `pnpm run check:env` before running tests
|
||||
- ✅ Scripts will warn if RPC URLs are not configured
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security Notes
|
||||
|
||||
> ⚠️ **IMPORTANT**:
|
||||
> - ⛔ **Never commit `.env` files** - They may contain private keys
|
||||
> - 🔑 **Don't share RPC keys** - They may have rate limits or costs
|
||||
> - 🔄 **Use separate keys** for development and production
|
||||
> - 🔐 **Rotate keys** if they're exposed or compromised
|
||||
|
||||
---
|
||||
|
||||
## 📝 Example .env File
|
||||
|
||||
```bash
|
||||
# RPC Endpoints
|
||||
MAINNET_RPC_URL=https://mainnet.infura.io/v3/your-infura-project-id
|
||||
BASE_RPC_URL=https://base-mainnet.infura.io/v3/your-infura-project-id
|
||||
ARBITRUM_RPC_URL=https://arbitrum-mainnet.infura.io/v3/your-infura-project-id
|
||||
OPTIMISM_RPC_URL=https://optimism-mainnet.infura.io/v3/your-infura-project-id
|
||||
POLYGON_RPC_URL=https://polygon-mainnet.infura.io/v3/your-infura-project-id
|
||||
|
||||
# Private Keys (only for mainnet execution, not fork testing)
|
||||
# PRIVATE_KEY=0x...
|
||||
|
||||
# Test Configuration (optional)
|
||||
# TEST_SCENARIO=scenarios/aave/leveraged-long.yml
|
||||
# TEST_NETWORK=mainnet
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
After setting up your environment:
|
||||
|
||||
### 1. Verify Setup
|
||||
|
||||
```bash
|
||||
pnpm run check:env
|
||||
```
|
||||
|
||||
### 2. Run a Test Scenario
|
||||
|
||||
```bash
|
||||
pnpm run strat:test
|
||||
```
|
||||
|
||||
### 3. Run a Scenario with CLI
|
||||
|
||||
```bash
|
||||
pnpm run strat run scenarios/aave/leveraged-long.yml
|
||||
```
|
||||
|
||||
### 4. Try Fuzzing
|
||||
|
||||
```bash
|
||||
pnpm run strat fuzz scenarios/aave/leveraged-long.yml --iters 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 📖 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
- 🔗 [Chain Configuration](./CHAIN_CONFIG.md)
|
||||
- 🔐 [Security Best Practices](./SECURITY.md)
|
||||
147
docs/ENV_VERIFICATION_SUMMARY.md
Normal file
147
docs/ENV_VERIFICATION_SUMMARY.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# ✅ Environment Setup Verification - Complete
|
||||
|
||||
## 🎉 Verification Results
|
||||
|
||||
All scripts have been verified to properly connect to `.env` files and handle secrets correctly.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Scripts Verified
|
||||
|
||||
### 1. `src/strat/cli.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST (line 14-15)
|
||||
- ✅ Before any other imports
|
||||
- ✅ Validates RPC URLs before use
|
||||
- ✅ Shows helpful error messages
|
||||
|
||||
### 2. `src/cli/cli.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST (line 13-15)
|
||||
- ✅ Before any other imports
|
||||
- ✅ Uses `PRIVATE_KEY` from env for execution
|
||||
- ✅ Validates private key before use
|
||||
|
||||
### 3. `scripts/test-strategy.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST (line 18-19)
|
||||
- ✅ Before any other imports
|
||||
- ✅ Reads `MAINNET_RPC_URL`, `TEST_SCENARIO`, `TEST_NETWORK`
|
||||
- ✅ Validates RPC URL with placeholder checks
|
||||
- ✅ Shows clear error messages
|
||||
|
||||
### 4. `scripts/check-env.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST
|
||||
- ✅ Tests all RPC URL connections
|
||||
- ✅ Validates environment setup
|
||||
- ✅ Provides detailed feedback
|
||||
|
||||
### 5. `scripts/verify-setup.ts` ✅
|
||||
|
||||
- ✅ Loads `dotenv` FIRST
|
||||
- ✅ Comprehensive setup verification
|
||||
- ✅ Checks all components
|
||||
|
||||
---
|
||||
|
||||
## ✅ Configuration Verified
|
||||
|
||||
### 1. `src/strat/config/networks.ts` ✅
|
||||
|
||||
- ✅ Lazy-loads RPC URLs when `getNetwork()` is called
|
||||
- ✅ Ensures `dotenv` is loaded before reading env vars
|
||||
- ✅ Supports all network-specific env vars
|
||||
- ✅ Has sensible fallbacks
|
||||
|
||||
### 2. `config/chains/*.ts` ✅
|
||||
|
||||
- ✅ Read `process.env` at module load
|
||||
- ✅ Work correctly because entry points load dotenv first
|
||||
- ✅ Have default fallbacks
|
||||
|
||||
---
|
||||
|
||||
## 📋 Environment Variables
|
||||
|
||||
### Required
|
||||
|
||||
| Variable | Description | Status |
|
||||
|----------|-------------|--------|
|
||||
| `MAINNET_RPC_URL` | Required for mainnet fork testing | ✅ |
|
||||
|
||||
### Optional
|
||||
|
||||
| Variable | Description | When Needed |
|
||||
|----------|-------------|-------------|
|
||||
| `BASE_RPC_URL` | Base network RPC endpoint | Multi-chain testing |
|
||||
| `ARBITRUM_RPC_URL` | Arbitrum One RPC endpoint | Multi-chain testing |
|
||||
| `OPTIMISM_RPC_URL` | Optimism network RPC endpoint | Multi-chain testing |
|
||||
| `POLYGON_RPC_URL` | Polygon network RPC endpoint | Multi-chain testing |
|
||||
| `PRIVATE_KEY` | Private key for executing transactions | Mainnet/testnet execution only |
|
||||
| `TEST_SCENARIO` | Override default test scenario path | Custom test scenarios |
|
||||
| `TEST_NETWORK` | Override default test network | Multi-chain testing |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Validation Features
|
||||
|
||||
All scripts include:
|
||||
|
||||
- ✅ RPC URL validation (checks for placeholders like "YOUR_KEY")
|
||||
- ✅ Clear error messages if not configured
|
||||
- ✅ Helpful suggestions (e.g., "Run 'pnpm run check:env'")
|
||||
- ✅ Fallback to defaults where appropriate
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Verification Commands
|
||||
|
||||
```bash
|
||||
# Check environment variables and RPC connections
|
||||
pnpm run check:env
|
||||
|
||||
# Verify complete setup
|
||||
pnpm run verify:setup
|
||||
|
||||
# Test with a scenario
|
||||
pnpm run strat:test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| `.env` in `.gitignore` | ✅ | `.env` file is in `.gitignore` |
|
||||
| `.env.example` template | ✅ | `.env.example` provides template |
|
||||
| Private keys protection | ✅ | Private keys only used when explicitly needed |
|
||||
| RPC URL validation | ✅ | RPC URLs validated before use |
|
||||
| No hardcoded secrets | ✅ | No hardcoded secrets |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Test Results
|
||||
|
||||
Running `pnpm run verify:setup` shows:
|
||||
|
||||
- ✅ All scripts load dotenv correctly
|
||||
- ✅ Network config loads correctly
|
||||
- ✅ Scenario files exist
|
||||
- ✅ Environment variables are accessible
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
All scripts are properly connected to `.env` files and handle secrets correctly. The setup is complete and ready for use!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Next Steps
|
||||
|
||||
1. ✅ Run `pnpm run check:env` to verify your environment
|
||||
2. ✅ Run `pnpm run verify:setup` for comprehensive verification
|
||||
3. ✅ Test with `pnpm run strat:test`
|
||||
4. ✅ Start building DeFi strategies!
|
||||
320
docs/INTEGRATION_GUIDE.md
Normal file
320
docs/INTEGRATION_GUIDE.md
Normal file
@@ -0,0 +1,320 @@
|
||||
# 🔌 Integration Guide
|
||||
|
||||
> Step-by-step guide for integrating DeFi protocols into your application.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
1. [Aave v3 Integration](#-aave-v3-integration)
|
||||
2. [Uniswap v3 Integration](#-uniswap-v3-integration)
|
||||
3. [Protocolink Integration](#-protocolink-integration)
|
||||
4. [Compound III Integration](#-compound-iii-integration)
|
||||
5. [Cross-Protocol Strategies](#-cross-protocol-strategies)
|
||||
|
||||
---
|
||||
|
||||
## 🏦 Aave v3 Integration
|
||||
|
||||
### 1️⃣ Setup
|
||||
|
||||
```typescript
|
||||
import { createWalletRpcClient } from '../src/utils/chain-config.js';
|
||||
import { getAavePoolAddress } from '../src/utils/addresses.js';
|
||||
|
||||
const CHAIN_ID = 1; // Mainnet
|
||||
const walletClient = createWalletRpcClient(CHAIN_ID, privateKey);
|
||||
const poolAddress = getAavePoolAddress(CHAIN_ID);
|
||||
```
|
||||
|
||||
### 2️⃣ Supply Collateral
|
||||
|
||||
```typescript
|
||||
// 1. Approve token
|
||||
await walletClient.writeContract({
|
||||
address: tokenAddress,
|
||||
abi: ERC20_ABI,
|
||||
functionName: 'approve',
|
||||
args: [poolAddress, amount],
|
||||
});
|
||||
|
||||
// 2. Supply
|
||||
await walletClient.writeContract({
|
||||
address: poolAddress,
|
||||
abi: POOL_ABI,
|
||||
functionName: 'supply',
|
||||
args: [asset, amount, account, 0],
|
||||
});
|
||||
|
||||
// 3. Enable as collateral
|
||||
await walletClient.writeContract({
|
||||
address: poolAddress,
|
||||
abi: POOL_ABI,
|
||||
functionName: 'setUserUseReserveAsCollateral',
|
||||
args: [asset, true],
|
||||
});
|
||||
```
|
||||
|
||||
### 3️⃣ Borrow
|
||||
|
||||
```typescript
|
||||
// Note: Use variable rate (2), stable rate is deprecated in v3.3+
|
||||
await walletClient.writeContract({
|
||||
address: poolAddress,
|
||||
abi: POOL_ABI,
|
||||
functionName: 'borrow',
|
||||
args: [debtAsset, borrowAmount, 2, 0, account],
|
||||
});
|
||||
```
|
||||
|
||||
### 4️⃣ Flash Loans
|
||||
|
||||
#### Single Asset
|
||||
|
||||
```typescript
|
||||
await walletClient.writeContract({
|
||||
address: poolAddress,
|
||||
abi: POOL_ABI,
|
||||
functionName: 'flashLoanSimple',
|
||||
args: [receiverAddress, asset, amount, params, 0],
|
||||
});
|
||||
```
|
||||
|
||||
#### Multi-Asset
|
||||
|
||||
```typescript
|
||||
await walletClient.writeContract({
|
||||
address: poolAddress,
|
||||
abi: POOL_ABI,
|
||||
functionName: 'flashLoan',
|
||||
args: [receiverAddress, assets, amounts, modes, account, params, 0],
|
||||
});
|
||||
```
|
||||
|
||||
> ⚠️ **Important**: Your flash loan receiver contract must:
|
||||
> 1. ✅ Receive the loaned tokens
|
||||
> 2. ✅ Perform desired operations
|
||||
> 3. ✅ Approve the pool for `amount + premium`
|
||||
> 4. ✅ Return `true` from `executeOperation`
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Uniswap v3 Integration
|
||||
|
||||
### 1️⃣ Setup
|
||||
|
||||
```typescript
|
||||
import { getUniswapSwapRouter02 } from '../src/utils/addresses.js';
|
||||
|
||||
const routerAddress = getUniswapSwapRouter02(CHAIN_ID);
|
||||
```
|
||||
|
||||
### 2️⃣ Get Quote
|
||||
|
||||
```typescript
|
||||
// Use QuoterV2 contract to get expected output
|
||||
const quote = await publicClient.readContract({
|
||||
address: quoterAddress,
|
||||
abi: QUOTER_ABI,
|
||||
functionName: 'quoteExactInputSingle',
|
||||
args: [{
|
||||
tokenIn: tokenInAddress,
|
||||
tokenOut: tokenOutAddress,
|
||||
fee: 3000, // 0.3% fee tier
|
||||
amountIn: amountIn,
|
||||
sqrtPriceLimitX96: 0,
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
### 3️⃣ Execute Swap
|
||||
|
||||
```typescript
|
||||
// 1. Approve token
|
||||
await walletClient.writeContract({
|
||||
address: tokenInAddress,
|
||||
abi: ERC20_ABI,
|
||||
functionName: 'approve',
|
||||
args: [routerAddress, amountIn],
|
||||
});
|
||||
|
||||
// 2. Execute swap
|
||||
await walletClient.writeContract({
|
||||
address: routerAddress,
|
||||
abi: SWAP_ROUTER_ABI,
|
||||
functionName: 'exactInputSingle',
|
||||
args: [{
|
||||
tokenIn: tokenInAddress,
|
||||
tokenOut: tokenOutAddress,
|
||||
fee: 3000,
|
||||
recipient: account,
|
||||
deadline: BigInt(Math.floor(Date.now() / 1000) + 600),
|
||||
amountIn: amountIn,
|
||||
amountOutMinimum: amountOutMin, // Apply slippage protection
|
||||
sqrtPriceLimitX96: 0,
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
### 4️⃣ TWAP Oracle
|
||||
|
||||
```typescript
|
||||
// Always use TWAP, not spot prices, to protect against manipulation
|
||||
// See examples/ts/uniswap-v3-oracle.ts for implementation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Protocolink Integration
|
||||
|
||||
### 1️⃣ Setup
|
||||
|
||||
```typescript
|
||||
import * as api from '@protocolink/api';
|
||||
import * as common from '@protocolink/common';
|
||||
|
||||
const CHAIN_ID = common.ChainId.mainnet;
|
||||
```
|
||||
|
||||
### 2️⃣ Build Logics
|
||||
|
||||
```typescript
|
||||
// Swap logic
|
||||
const swapQuotation = await api.protocols.uniswapv3.getSwapTokenQuotation(CHAIN_ID, {
|
||||
input: { token: USDC, amount: '1000' },
|
||||
tokenOut: WBTC,
|
||||
slippage: 100,
|
||||
});
|
||||
const swapLogic = api.protocols.uniswapv3.newSwapTokenLogic(swapQuotation);
|
||||
|
||||
// Supply logic
|
||||
const supplyQuotation = await api.protocols.aavev3.getSupplyQuotation(CHAIN_ID, {
|
||||
input: swapQuotation.output,
|
||||
});
|
||||
const supplyLogic = api.protocols.aavev3.newSupplyLogic(supplyQuotation);
|
||||
```
|
||||
|
||||
### 3️⃣ Execute
|
||||
|
||||
```typescript
|
||||
const routerData = await api.router.getRouterData(CHAIN_ID, {
|
||||
account,
|
||||
logics: [swapLogic, supplyLogic],
|
||||
});
|
||||
|
||||
await walletClient.sendTransaction({
|
||||
to: routerData.router,
|
||||
data: routerData.data,
|
||||
value: BigInt(routerData.estimation.value || '0'),
|
||||
gas: BigInt(routerData.estimation.gas),
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ Compound III Integration
|
||||
|
||||
### 1️⃣ Setup
|
||||
|
||||
```typescript
|
||||
import { getCompound3Comet } from '../src/utils/addresses.js';
|
||||
|
||||
const cometAddress = getCompound3Comet(CHAIN_ID);
|
||||
```
|
||||
|
||||
### 2️⃣ Supply Collateral
|
||||
|
||||
```typescript
|
||||
// 1. Approve collateral
|
||||
await walletClient.writeContract({
|
||||
address: collateralAddress,
|
||||
abi: ERC20_ABI,
|
||||
functionName: 'approve',
|
||||
args: [cometAddress, amount],
|
||||
});
|
||||
|
||||
// 2. Supply
|
||||
await walletClient.writeContract({
|
||||
address: cometAddress,
|
||||
abi: COMET_ABI,
|
||||
functionName: 'supply',
|
||||
args: [collateralAddress, amount],
|
||||
});
|
||||
```
|
||||
|
||||
### 3️⃣ Borrow Base Asset
|
||||
|
||||
```typescript
|
||||
// In Compound III, you "borrow" by withdrawing the base asset
|
||||
const baseToken = await publicClient.readContract({
|
||||
address: cometAddress,
|
||||
abi: COMET_ABI,
|
||||
functionName: 'baseToken',
|
||||
});
|
||||
|
||||
await walletClient.writeContract({
|
||||
address: cometAddress,
|
||||
abi: COMET_ABI,
|
||||
functionName: 'withdraw',
|
||||
args: [baseToken, borrowAmount],
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Cross-Protocol Strategies
|
||||
|
||||
### ⚡ Flash Loan Arbitrage
|
||||
|
||||
**Strategy Flow:**
|
||||
|
||||
1. ⚡ Flash loan asset from Aave
|
||||
2. 🔄 Swap on Uniswap (or other DEX)
|
||||
3. 🔄 Swap on different DEX/pool
|
||||
4. ✅ Repay flash loan + premium
|
||||
5. 💰 Keep profit
|
||||
|
||||
> 📖 See `examples/ts/flashloan-arbitrage.ts` for conceptual example.
|
||||
|
||||
### 📈 Supply-Borrow-Swap
|
||||
|
||||
**Strategy Flow:**
|
||||
|
||||
1. 💰 Supply collateral to Aave
|
||||
2. 💸 Borrow asset
|
||||
3. 🔄 Swap borrowed asset
|
||||
4. 💰 Supply swapped asset back to Aave
|
||||
|
||||
> 📖 See `examples/ts/supply-borrow-swap.ts` for implementation.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
| Practice | Description | Status |
|
||||
|----------|-------------|--------|
|
||||
| 🛡️ **Slippage Protection** | Always set minimum output amounts | ✅ |
|
||||
| ⛽ **Gas Costs** | Check gas costs for complex transactions | ✅ |
|
||||
| 🔮 **TWAP Oracles** | Never rely on spot prices alone | ✅ |
|
||||
| 🧪 **Test on Testnets** | Always test before mainnet | ✅ |
|
||||
| ⚠️ **Error Handling** | Handle errors gracefully | ✅ |
|
||||
| 📊 **Monitor Positions** | Track liquidation risks | ✅ |
|
||||
| 🔐 **Use Permit2** | Save gas on approvals when possible | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
- 📖 Review [Security Best Practices](./SECURITY.md)
|
||||
- 🔗 Check [Chain Configuration](./CHAIN_CONFIG.md) for adding new chains
|
||||
- 📜 Explore example contracts in `contracts/examples/`
|
||||
- 🧪 Run tests in `test/`
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 🔐 [Security Best Practices](./SECURITY.md)
|
||||
- 🔗 [Chain Configuration](./CHAIN_CONFIG.md)
|
||||
- 🧪 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
- ⚙️ [Environment Setup](./ENV_SETUP.md)
|
||||
324
docs/SECURITY.md
Normal file
324
docs/SECURITY.md
Normal file
@@ -0,0 +1,324 @@
|
||||
# 🔐 Security Best Practices
|
||||
|
||||
> Comprehensive security checklist for DeFi integration.
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ General Security Principles
|
||||
|
||||
### 🔒 1. Access Control
|
||||
|
||||
- ✅ Use access control modifiers for sensitive functions
|
||||
- ✅ Implement owner/admin roles properly
|
||||
- ✅ Never hardcode private keys or mnemonics
|
||||
- ✅ Use environment variables for sensitive data
|
||||
|
||||
### ✅ 2. Input Validation
|
||||
|
||||
- ✅ Validate all user inputs
|
||||
- ✅ Check for zero addresses
|
||||
- ✅ Validate amounts (no zero, no overflow)
|
||||
- ✅ Check token decimals
|
||||
|
||||
### 🔄 3. Reentrancy Protection
|
||||
|
||||
- ✅ Use ReentrancyGuard for external calls
|
||||
- ✅ Follow checks-effects-interactions pattern
|
||||
- ✅ Be extra careful with flash loans
|
||||
|
||||
### ⚠️ 4. Error Handling
|
||||
|
||||
- ✅ Use require/assert appropriately
|
||||
- ✅ Provide clear error messages
|
||||
- ✅ Handle edge cases
|
||||
- ✅ Test error conditions
|
||||
|
||||
---
|
||||
|
||||
## 🏦 Protocol-Specific Security
|
||||
|
||||
### 🏦 Aave v3
|
||||
|
||||
#### ⚡ Flash Loans
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| ⚠️ **Critical** | ✅ | Always repay flash loan + premium in `executeOperation` |
|
||||
| ⚠️ **Critical** | ✅ | Verify `msg.sender == pool` in `executeOperation` |
|
||||
| ⚠️ **Critical** | ✅ | Verify `initiator == address(this)` in `executeOperation` |
|
||||
| ✅ | ✅ | Calculate premium correctly: `amount + premium` |
|
||||
| ✅ | ✅ | Handle multi-asset flash loans carefully |
|
||||
| ✅ | ✅ | Test repayment failure scenarios |
|
||||
|
||||
#### 💰 Interest Rate Modes
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| ⚠️ **Deprecated** | ✅ | Stable rate borrowing is deprecated in v3.3+ |
|
||||
| ✅ | ✅ | Always use variable rate (mode = 2) for new integrations |
|
||||
| ✅ | ✅ | Understand interest rate risks |
|
||||
|
||||
#### 🛡️ Collateral Management
|
||||
|
||||
- ✅ Check liquidation thresholds
|
||||
- ✅ Monitor health factor
|
||||
- ✅ Handle eMode/isolation mode restrictions
|
||||
- ✅ Verify collateral can be enabled
|
||||
|
||||
### 🔄 Uniswap v3
|
||||
|
||||
#### 🛡️ Slippage Protection
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| ⚠️ **Critical** | ✅ | Always set `amountOutMinimum` with slippage tolerance |
|
||||
| ✅ | ✅ | Use TWAP oracles, not spot prices |
|
||||
| ✅ | ✅ | Account for price impact in large swaps |
|
||||
| ✅ | ✅ | Consider using UniswapX for better execution |
|
||||
|
||||
#### 🔮 Oracle Security
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| ⚠️ **Critical** | ✅ | Never use spot prices for critical operations |
|
||||
| ✅ | ✅ | Use TWAP with sufficient observation window |
|
||||
| ✅ | ✅ | Verify observation cardinality |
|
||||
| ✅ | ✅ | Protect against oracle manipulation |
|
||||
|
||||
#### 🔐 Permit2
|
||||
|
||||
- ✅ Verify signature validity
|
||||
- ✅ Check expiration (deadline)
|
||||
- ✅ Verify nonce (prevent replay)
|
||||
- ✅ Protect against signature theft (verify spender)
|
||||
|
||||
### 🔗 Protocolink
|
||||
|
||||
#### ✅ Route Validation
|
||||
|
||||
- ✅ Verify all logics in the route
|
||||
- ✅ Check token addresses
|
||||
- ✅ Validate amounts
|
||||
- ✅ Verify slippage settings
|
||||
|
||||
#### ⚡ Execution
|
||||
|
||||
- ✅ Check gas estimates
|
||||
- ✅ Handle execution failures
|
||||
- ✅ Verify router address
|
||||
- ✅ Monitor transaction status
|
||||
|
||||
### 🏛️ Compound III
|
||||
|
||||
#### 💰 Borrowing
|
||||
|
||||
| Check | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| ⚠️ **Important** | ✅ | Understand base asset vs collateral |
|
||||
| ✅ | ✅ | Check borrow limits |
|
||||
| ✅ | ✅ | Monitor collateral ratio |
|
||||
| ✅ | ✅ | Handle liquidation risks |
|
||||
|
||||
---
|
||||
|
||||
## 📜 Smart Contract Security
|
||||
|
||||
### ⚡ Flash Loan Receivers
|
||||
|
||||
```solidity
|
||||
// ✅ Good: Verify caller and initiator
|
||||
function executeOperation(
|
||||
address asset,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
address initiator,
|
||||
bytes calldata params
|
||||
) external override returns (bool) {
|
||||
require(msg.sender == address(pool), "Invalid caller");
|
||||
require(initiator == address(this), "Invalid initiator");
|
||||
|
||||
// Your logic here
|
||||
|
||||
// ✅ Good: Approve repayment
|
||||
IERC20(asset).approve(address(pool), amount + premium);
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### 🔄 Reentrancy Protection
|
||||
|
||||
```solidity
|
||||
// ✅ Good: Use ReentrancyGuard
|
||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||
|
||||
contract MyContract is ReentrancyGuard {
|
||||
function withdraw() external nonReentrant {
|
||||
// Safe withdrawal logic
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🔒 Access Control
|
||||
|
||||
```solidity
|
||||
// ✅ Good: Use access control
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
contract MyContract is Ownable {
|
||||
function sensitiveFunction() external onlyOwner {
|
||||
// Owner-only logic
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Security
|
||||
|
||||
### 🧪 Foundry Tests
|
||||
|
||||
- ✅ Test all edge cases
|
||||
- ✅ Test error conditions
|
||||
- ✅ Test reentrancy attacks
|
||||
- ✅ Test flash loan scenarios
|
||||
- ✅ Test with fork tests
|
||||
- ✅ Test gas limits
|
||||
|
||||
### 📊 Test Coverage
|
||||
|
||||
- ✅ Unit tests for all functions
|
||||
- ✅ Integration tests
|
||||
- ✅ Fork tests on mainnet
|
||||
- ✅ Fuzz tests for inputs
|
||||
- ✅ Invariant tests
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Deployment Security
|
||||
|
||||
### 🔍 Pre-Deployment
|
||||
|
||||
- ✅ Get professional security audit
|
||||
- ✅ Review all dependencies
|
||||
- ✅ Test on testnets extensively
|
||||
- ✅ Verify all addresses
|
||||
- ✅ Check contract sizes
|
||||
|
||||
### 🔐 Post-Deployment
|
||||
|
||||
- ✅ Monitor transactions
|
||||
- ✅ Set up alerts
|
||||
- ✅ Keep private keys secure
|
||||
- ✅ Use multisig for admin functions
|
||||
- ✅ Have an emergency pause mechanism
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Common Vulnerabilities
|
||||
|
||||
### 1. Reentrancy
|
||||
|
||||
❌ **Bad**: External call before state update
|
||||
|
||||
```solidity
|
||||
function withdraw() external {
|
||||
msg.sender.call{value: balance}("");
|
||||
balance = 0; // Too late!
|
||||
}
|
||||
```
|
||||
|
||||
✅ **Good**: State update before external call
|
||||
|
||||
```solidity
|
||||
function withdraw() external nonReentrant {
|
||||
uint256 amount = balance;
|
||||
balance = 0;
|
||||
msg.sender.call{value: amount}("");
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Integer Overflow
|
||||
|
||||
❌ **Bad**: No overflow protection
|
||||
|
||||
```solidity
|
||||
uint256 total = amount1 + amount2;
|
||||
```
|
||||
|
||||
✅ **Good**: Use SafeMath or Solidity 0.8+
|
||||
|
||||
```solidity
|
||||
uint256 total = amount1 + amount2; // Safe in Solidity 0.8+
|
||||
```
|
||||
|
||||
### 3. Access Control
|
||||
|
||||
❌ **Bad**: No access control
|
||||
|
||||
```solidity
|
||||
function withdraw() external {
|
||||
// Anyone can call
|
||||
}
|
||||
```
|
||||
|
||||
✅ **Good**: Proper access control
|
||||
|
||||
```solidity
|
||||
function withdraw() external onlyOwner {
|
||||
// Only owner can call
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Resources
|
||||
|
||||
| Resource | Link |
|
||||
|----------|------|
|
||||
| OpenZeppelin Security | [docs.openzeppelin.com](https://docs.openzeppelin.com/contracts/security) |
|
||||
| Consensys Best Practices | [consensys.github.io](https://consensys.github.io/smart-contract-best-practices/) |
|
||||
| Aave Security | [docs.aave.com](https://docs.aave.com/developers/guides/security-best-practices) |
|
||||
| Uniswap Security | [docs.uniswap.org](https://docs.uniswap.org/contracts/v4/concepts/security) |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Security Audit Checklist
|
||||
|
||||
Before deploying to production:
|
||||
|
||||
- [ ] 🔍 Professional security audit completed
|
||||
- [ ] 📦 All dependencies reviewed
|
||||
- [ ] 🔒 Access control implemented
|
||||
- [ ] 🔄 Reentrancy protection added
|
||||
- [ ] ✅ Input validation implemented
|
||||
- [ ] ⚠️ Error handling comprehensive
|
||||
- [ ] 🧪 Tests cover edge cases
|
||||
- [ ] ⛽ Gas optimization reviewed
|
||||
- [ ] ⏸️ Emergency pause mechanism
|
||||
- [ ] 👥 Multisig for admin functions
|
||||
- [ ] 📊 Monitoring and alerts set up
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Reporting Security Issues
|
||||
|
||||
If you discover a security vulnerability, please report it responsibly:
|
||||
|
||||
1. ⛔ **DO NOT** open a public issue
|
||||
2. 📧 Email security details to the maintainers
|
||||
3. ⏰ Allow time for the issue to be addressed
|
||||
4. 🔒 Follow responsible disclosure practices
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Disclaimer
|
||||
|
||||
This security guide is for educational purposes. Always get professional security audits before deploying to production.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 📖 [Integration Guide](./INTEGRATION_GUIDE.md)
|
||||
- 🔗 [Chain Configuration](./CHAIN_CONFIG.md)
|
||||
- 🧪 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
587
docs/STRATEGY_TESTING.md
Normal file
587
docs/STRATEGY_TESTING.md
Normal file
@@ -0,0 +1,587 @@
|
||||
# 🧪 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 <scenario-file> [options]
|
||||
```
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| `--network <network>` | Network name or chain ID | `mainnet` |
|
||||
| `--report <file>` | Output JSON report path | - |
|
||||
| `--html <file>` | Output HTML report path | - |
|
||||
| `--junit <file>` | Output JUnit XML report path | - |
|
||||
| `--rpc <url>` | 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>` | Number of iterations | `100` |
|
||||
| `--seed <number>` | Random seed for reproducibility | - |
|
||||
| `--report <file>` | 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<number, Record<string, Address>> = {
|
||||
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<RuntimeAddresses>;
|
||||
actions: Record<string, (ctx: StepContext, args: any) => Promise<StepResult>>;
|
||||
invariants?: Array<(ctx: StepContext) => Promise<void>>;
|
||||
views?: Record<string, (ctx: ViewContext, args?: any) => Promise<any>>;
|
||||
}
|
||||
```
|
||||
|
||||
### Example Implementation
|
||||
|
||||
```typescript
|
||||
export class MyProtocolAdapter implements ProtocolAdapter {
|
||||
name = 'my-protocol';
|
||||
|
||||
async discover(network: Network): Promise<RuntimeAddresses> {
|
||||
return {
|
||||
contract: '0x...',
|
||||
};
|
||||
}
|
||||
|
||||
actions = {
|
||||
myAction: async (ctx: StepContext, args: any): Promise<StepResult> => {
|
||||
// Implement action
|
||||
return { success: true };
|
||||
},
|
||||
};
|
||||
|
||||
views = {
|
||||
myView: async (ctx: ViewContext): Promise<any> => {
|
||||
// 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
|
||||
299
docs/STRATEGY_TESTING_COMPLETE.md
Normal file
299
docs/STRATEGY_TESTING_COMPLETE.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# 🎉 DeFi Strategy Testing Framework - Implementation Complete
|
||||
|
||||
## ✅ Completed Features
|
||||
|
||||
### 🔧 Core Engine
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Fork Orchestrator | ✅ | Anvil/Hardhat support |
|
||||
| Scenario Runner | ✅ | Step-by-step execution |
|
||||
| Assertion Evaluator | ✅ | Protocol view support |
|
||||
| Failure Injector | ✅ | Oracle shocks, time travel, etc. |
|
||||
| Fuzzer | ✅ | Parameterized inputs |
|
||||
| Whale Registry | ✅ | Automatic token funding |
|
||||
|
||||
### 🔌 Protocol Adapters
|
||||
|
||||
#### 🏦 Aave v3 Adapter ✅
|
||||
|
||||
- ✅ Supply, withdraw, borrow, repay
|
||||
- ✅ Flash loans (simple)
|
||||
- ✅ Health factor monitoring
|
||||
- ✅ User account data views
|
||||
|
||||
#### 🔄 Uniswap v3 Adapter ✅
|
||||
|
||||
- ✅ Exact input/output swaps
|
||||
- ✅ Slippage handling
|
||||
|
||||
#### 🏛️ Compound v3 Adapter ✅
|
||||
|
||||
- ✅ Supply collateral
|
||||
- ✅ Borrow base asset (withdraw)
|
||||
- ✅ Repay debt (supply base asset)
|
||||
- ✅ Borrow and collateral balance views
|
||||
|
||||
#### 💰 ERC20 Adapter ✅
|
||||
|
||||
- ✅ Token approvals
|
||||
- ✅ Balance queries
|
||||
|
||||
### 💥 Failure Injection
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Oracle shocks | ✅ | Storage manipulation attempt |
|
||||
| Time travel | ✅ | Advance time |
|
||||
| Set block timestamp | ✅ | Set block timestamp |
|
||||
| Liquidity shocks | ✅ | Move liquidity |
|
||||
| Gas price manipulation | ✅ | Set gas price |
|
||||
| Reserve pause simulation | ✅ | Pause reserves |
|
||||
| Cap exhaustion simulation | ✅ | Simulate cap exhaustion |
|
||||
|
||||
### 📊 Reporting
|
||||
|
||||
| Format | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| JSON Reporter | ✅ | Machine-readable |
|
||||
| HTML Reporter | ✅ | Human-readable |
|
||||
| JUnit XML Reporter | ✅ | CI integration |
|
||||
|
||||
### 📝 DSL & Configuration
|
||||
|
||||
- ✅ YAML/JSON scenario loader
|
||||
- ✅ Schema validation with Zod
|
||||
- ✅ Network configuration
|
||||
- ✅ Oracle feed registry
|
||||
- ✅ Token metadata resolution
|
||||
|
||||
### 🖥️ CLI Commands
|
||||
|
||||
| Command | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| `fork up` | ✅ | Start/manage forks |
|
||||
| `run` | ✅ | Execute scenarios |
|
||||
| `fuzz` | ✅ | Fuzz test scenarios |
|
||||
| `failures` | ✅ | List failure injections |
|
||||
| `compare` | ✅ | Compare run reports |
|
||||
| `assert` | ✅ | Re-check assertions (placeholder) |
|
||||
|
||||
### 📚 Example Scenarios
|
||||
|
||||
- ✅ Aave leveraged long strategy
|
||||
- ✅ Aave liquidation drill
|
||||
- ✅ Compound v3 supply/borrow
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- ✅ Comprehensive strategy testing guide
|
||||
- ✅ Scenario format documentation
|
||||
- ✅ API documentation
|
||||
- ✅ Examples and usage guides
|
||||
|
||||
### 🧪 Testing Infrastructure
|
||||
|
||||
- ✅ Test script for real fork testing
|
||||
- ✅ Whale impersonation for token funding
|
||||
- ✅ Snapshot/revert for fast iterations
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Key Features
|
||||
|
||||
### 🐋 Automatic Token Funding
|
||||
|
||||
The framework automatically funds test accounts by:
|
||||
|
||||
1. 📋 Looking up whale addresses from the registry
|
||||
2. 🎭 Impersonating whales on the fork
|
||||
3. 💸 Transferring tokens to test accounts
|
||||
4. ✅ Verifying balances
|
||||
|
||||
### 🔮 Enhanced Oracle Shocks
|
||||
|
||||
Oracle shocks attempt to modify Chainlink aggregator storage:
|
||||
|
||||
1. 🔍 Resolve aggregator address from feed name
|
||||
2. 📊 Read current price and round ID
|
||||
3. 🧮 Calculate new price based on percentage delta
|
||||
4. 💾 Attempt to modify storage slot (with fallback warnings)
|
||||
5. 📝 Log detailed information for verification
|
||||
|
||||
### 🎲 Fuzzing Support
|
||||
|
||||
Fuzzing runs scenarios with randomized parameters:
|
||||
|
||||
- ✅ Amounts vary by ±20%
|
||||
- ✅ Oracle shock percentages vary within ranges
|
||||
- ✅ Fee tiers randomly selected
|
||||
- ✅ Slippage parameters varied
|
||||
- ✅ Each iteration runs on a fresh snapshot
|
||||
|
||||
### 🔌 Multi-Protocol Support
|
||||
|
||||
The framework supports multiple protocols:
|
||||
|
||||
| Protocol | Features | Status |
|
||||
|----------|----------|--------|
|
||||
| Aave v3 | Lending/borrowing | ✅ |
|
||||
| Uniswap v3 | Swaps | ✅ |
|
||||
| Compound v3 | Lending/borrowing | ✅ |
|
||||
| ERC20 tokens | Approvals, balances | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Usage Examples
|
||||
|
||||
### Basic Scenario Run
|
||||
|
||||
```bash
|
||||
pnpm run strat run scenarios/aave/leveraged-long.yml
|
||||
```
|
||||
|
||||
### Fuzz Testing
|
||||
|
||||
```bash
|
||||
pnpm run strat fuzz scenarios/aave/leveraged-long.yml --iters 100 --seed 42
|
||||
```
|
||||
|
||||
### With Reports
|
||||
|
||||
```bash
|
||||
pnpm run strat run scenarios/aave/leveraged-long.yml \
|
||||
--report out/run.json \
|
||||
--html out/report.html \
|
||||
--junit out/junit.xml
|
||||
```
|
||||
|
||||
### Test Script
|
||||
|
||||
```bash
|
||||
export MAINNET_RPC_URL=https://mainnet.infura.io/v3/YOUR_KEY
|
||||
pnpm run strat:test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technical Implementation
|
||||
|
||||
### 🍴 Fork Orchestration
|
||||
|
||||
- ✅ Supports Anvil (Foundry) and Hardhat
|
||||
- ✅ Snapshot/revert for fast iterations
|
||||
- ✅ Account impersonation for whale funding
|
||||
- ✅ Storage manipulation for oracle overrides
|
||||
- ✅ Time travel for interest accrual testing
|
||||
|
||||
### 🔌 Protocol Adapters
|
||||
|
||||
- ✅ Clean interface for adding new protocols
|
||||
- ✅ Automatic address discovery
|
||||
- ✅ View functions for assertions
|
||||
- ✅ Invariant checking after each step
|
||||
|
||||
### 💥 Failure Injection
|
||||
|
||||
- ✅ Protocol-agnostic failures (oracle, time, gas)
|
||||
- ✅ Protocol-specific failures (pause, caps)
|
||||
- ✅ Storage manipulation where possible
|
||||
- ✅ Fallback warnings when manipulation fails
|
||||
|
||||
### 🐋 Token Funding
|
||||
|
||||
- ✅ Whale registry for known addresses
|
||||
- ✅ Automatic impersonation
|
||||
- ✅ Transfer execution
|
||||
- ✅ Balance verification
|
||||
- ✅ Graceful degradation on failure
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps (Future Enhancements)
|
||||
|
||||
While the core framework is complete, future enhancements could include:
|
||||
|
||||
### 🔌 More Protocol Adapters
|
||||
|
||||
- [ ] Maker DAO
|
||||
- [ ] Curve
|
||||
- [ ] Balancer
|
||||
- [ ] Lido
|
||||
|
||||
### 💥 Enhanced Failure Injection
|
||||
|
||||
- [ ] More reliable oracle manipulation
|
||||
- [ ] Protocol-specific failure modes
|
||||
- [ ] Custom failure scenarios
|
||||
|
||||
### 🎲 Advanced Fuzzing
|
||||
|
||||
- [ ] Property-based testing
|
||||
- [ ] Mutation testing
|
||||
- [ ] Coverage-guided fuzzing
|
||||
|
||||
### 🔗 Integration
|
||||
|
||||
- [ ] Tenderly backend
|
||||
- [ ] CI/CD integration
|
||||
- [ ] Dashboard/UI
|
||||
|
||||
### 📊 Analysis
|
||||
|
||||
- [ ] Gas profiling
|
||||
- [ ] Risk margin calculators
|
||||
- [ ] Historical backtesting
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
### 🔮 Oracle Manipulation
|
||||
|
||||
Oracle storage manipulation is complex and may not work on all forks. The framework attempts the manipulation and logs warnings if it fails. For production use, consider:
|
||||
|
||||
- ✅ Using mock oracles
|
||||
- ✅ Deploying custom aggregators
|
||||
- ✅ Using Tenderly's simulation capabilities
|
||||
|
||||
### 🐋 Token Funding
|
||||
|
||||
Token funding relies on:
|
||||
|
||||
- ✅ Whale addresses having sufficient balances
|
||||
- ✅ Fork supporting account impersonation
|
||||
- ✅ RPC endpoint allowing custom methods
|
||||
|
||||
If funding fails, accounts can be manually funded or alternative methods used.
|
||||
|
||||
### 🍴 Fork Requirements
|
||||
|
||||
For best results, use:
|
||||
|
||||
- ✅ Anvil (Foundry) for local forks
|
||||
- ✅ RPC endpoints that support custom methods
|
||||
- ✅ Sufficient block history for protocol state
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
The DeFi Strategy Testing Framework is now complete with:
|
||||
|
||||
- ✅ Full protocol adapter support (Aave, Uniswap, Compound)
|
||||
- ✅ Comprehensive failure injection
|
||||
- ✅ Fuzzing capabilities
|
||||
- ✅ Automatic token funding
|
||||
- ✅ Multiple report formats
|
||||
- ✅ Complete documentation
|
||||
|
||||
The framework is ready for use in testing DeFi strategies against local mainnet forks with both success and failure scenarios.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- 📖 [Strategy Testing Guide](./STRATEGY_TESTING.md)
|
||||
- ⚙️ [Environment Setup](./ENV_SETUP.md)
|
||||
- 🔗 [Chain Configuration](./CHAIN_CONFIG.md)
|
||||
- 🔐 [Security Best Practices](./SECURITY.md)
|
||||
Reference in New Issue
Block a user