An ERC-4626 tokenized vault that allocates deposits across multiple DeFi yield strategies (Aave V3, Compound V3, and extensible to any protocol).
Depositors ──> MultiStrategyVault (ERC-4626) ──> Strategy A (Aave V3)
| ──> Strategy B (Compound V3)
| ──> Strategy C (custom)
v
Vault Shares (msUSDC)
Core contracts:
| Contract | Description |
|---|---|
MultiStrategyVault |
ERC-4626 vault with timelocked strategy management, rebalancing, and performance fees |
AaveV3Strategy |
Deposits into Aave V3 lending pool, yield via aToken rebasing |
CompoundV3Strategy |
Supplies to Compound V3 (Comet) markets |
IStrategy |
Interface for building custom yield strategies |
- Timelocked strategy additions -- 2-day delay between proposal and execution prevents instant rug
- Allocation caps -- Total strategy allocation cannot exceed 100% (10,000 bps)
- Reentrancy protection -- All state-changing externals use OpenZeppelin
ReentrancyGuard - Emergency withdrawal -- Owner can pull all funds from all strategies; tolerates individual strategy failures
- Pausable -- Deposits can be paused while withdrawals remain active
- Performance fee cap -- Maximum 20% (2,000 bps), enforced at contract level
forge buildforge test # Run all tests
forge test -vvv # Verbose output with traces
forge test --gas-report # Gas usage report28 tests including:
- Unit tests for deposits, withdrawals, strategy management
- Access control tests
- Emergency scenario tests (reverting strategies)
- Fuzz tests for deposit/redeem invariants
# Set environment
export PRIVATE_KEY=0x...
export RPC_URL=https://eth-mainnet.g.alchemy.com/v2/...
# Deploy
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcastImplement IStrategy:
contract MyStrategy is IStrategy {
function asset() external view returns (IERC20);
function totalAssets() external view returns (uint256);
function deposit(uint256 amount) external;
function withdraw(uint256 amount) external returns (uint256);
function harvest() external returns (uint256);
}Then propose it via the vault:
vault.proposeStrategy(address(myStrategy));
// Wait 2 days...
vault.executeAddStrategy(3000); // 30% allocationMIT