Overview
The StrategyAaveLeverage contract implements a sophisticated leveraged yield strategy on Aave V3. It recursively borrows WETH against supplied collateral, swaps to the underlying asset, and re-supplies to amplify returns. This strategy multiplies exposure but also increases risk.
Implements: IStrategy
Risk Level: High (uses leverage, liquidation risk)
Strategy Flow:
- Supply LINK as collateral
- Borrow WETH against LINK
- Swap WETH → LINK via DEX
- Supply newly acquired LINK
- Repeat (controlled by
maxDepth)
State Variables
Immutable. The underlying asset token (e.g., LINK).
Immutable. Address of the Vault contract.
Immutable. Address of the StrategyRouter.
Immutable. Aave V3 Pool contract.
dataProvider
IProtocolDataProvider
required
Immutable. Aave Protocol Data Provider.
Immutable. UniswapV2-style DEX router for token swaps.
Immutable. WETH token address.
Immutable. Price oracle for WETH/LINK conversions.
Total principal deposited by vault (tracking).
Total WETH borrowed (approximate tracking).
Maximum leverage loop iterations (default: 3, max: 6).
Borrow amount per loop in basis points (default: 6000 = 60%).
Events
InvestedLeveraged
event InvestedLeveraged(
uint256 initial,
uint8 depth,
uint256 finalSupplied,
uint256 borrowedWETH
)
Number of leverage loops executed
Total amount supplied after leverage
Deleveraged
event Deleveraged(uint256 repaidWETH, uint256 redeemedLINK)
Harvested
event Harvested(uint256 profit)
PauseToggled
event PauseToggled(bool paused)
LeverageParamsUpdated
event LeverageParamsUpdated(uint8 maxDepth, uint256 borrowFactor)
Constructor
constructor(
address _asset,
address _vault,
address _router,
address _pool,
address _dataProvider,
address _swapRouter,
address _weth,
address _oracle
)
Underlying asset (e.g., LINK)
Aave Protocol Data Provider address
UniswapV2-compatible router address
Initialization:
- Approves pool to spend unlimited tokens
- Approves swap router to spend unlimited WETH
- Sets all immutable references
Core Strategy Functions
invest
function invest(uint256 amount) external override onlyRouter
Invest with leverage by recursively borrowing and re-supplying.
Initial amount to invest (already transferred to strategy)
Requirements:
- Strategy must not be paused
- Strategy must hold sufficient token balance
- Only callable by router
Process:
- Supply initial
amount as collateral
- Loop up to
maxDepth times:
- Calculate safe borrow amount (limited by pool liquidity)
- Borrow WETH from Aave
- Swap WETH → LINK via DEX
- Supply received LINK as additional collateral
- Update bookkeeping (
deposited, borrowedWETH)
Safety Features:
- Caps borrow to small amounts (0.001 WETH or 1% of pool) to avoid liquidity issues
- Uses try/catch on all external calls (borrow, swap, supply)
- Stops looping if any operation fails
- Attempts to repay borrowed WETH if swap fails
Example:
// Invest 1000 LINK with 3x leverage loops
// Loop 1: Supply 1000 LINK, borrow 0.001 WETH, swap to ~0.1 LINK, supply 0.1 LINK
// Loop 2: Borrow 0.001 WETH, swap to ~0.1 LINK, supply 0.1 LINK
// Loop 3: Borrow 0.001 WETH, swap to ~0.1 LINK, supply 0.1 LINK
// Total supplied: ~1000.3 LINK
// Total borrowed: ~0.003 WETH
router.moveFundsToStrategy(address(strategy), 1000e18);
strategy.invest(1000e18);
withdrawToVault
function withdrawToVault(uint256 amount) external override onlyRouter returns(uint256)
Withdraw underlying assets from Aave position.
Amount of underlying to withdraw
Actual amount withdrawn and sent to vault
Warning: Withdrawing may fail if position is too leveraged. Call deleverageAll() first if needed.
Process:
- Attempts to withdraw
amount from Aave
- Transfers received tokens to vault
- Updates
deposited tracker
harvest
function harvest() external override onlyRouter
Harvest accrued interest and send profits to vault.
Process:
- Gets current aToken balance (collateral including interest)
- Calculates profit:
aBal - deposited
- Withdraws profit amount from Aave
- Transfers profit to vault
Note: Keeps principal deposited; only harvests profits above deposited amount.
deleverageAll
function deleverageAll(uint256 maxLoops) external onlyRouter
Unwind leverage by repaying borrowed WETH.
Maximum iterations to prevent excessive gas usage
Process (each loop):
- Check current WETH debt
- Calculate LINK needed to repay (using oracle price + 5% buffer)
- Withdraw LINK from Aave collateral
- Swap LINK → WETH via DEX
- Repay WETH debt to Aave
- Update bookkeeping
- Repeat until debt is zero or maxLoops reached
Use Cases:
- Before large withdrawals
- Risk management during volatility
- Emergency deleveraging
Example:
// Reduce leverage before withdrawing
strategy.deleverageAll(5); // Up to 5 iterations
// Now safe to withdraw
strategy.withdrawToVault(500e18);
strategyBalance
function strategyBalance() public view override returns (uint256)
Get net asset value of the leveraged position.
Net value (collateral + idle - debt)
Calculation:
collateral = Aave supplied amount
idle = Token balance on contract
debtValue = WETH debt converted to LINK using oracle
netValue = collateral + idle - debtValue
Example:
// Position:
// Supplied: 1000 LINK
// Borrowed: 0.003 WETH (= 0.3 LINK at oracle price)
// strategyBalance() = 1000 - 0.3 = 999.7 LINK
Configuration Functions
setLeverageParams
function setLeverageParams(uint8 _maxDepth, uint256 _borrowFactor) external onlyRouter
Update leverage parameters.
Maximum loop iterations (1-6)
Borrow percentage in basis points (max 8000 = 80%)
Safety Limits:
_maxDepth 6 (gas limit protection)
_borrowFactor 8000 (80% max to maintain safe LTV)
Example:
// Set conservative leverage: 2 loops, 50% borrow
strategy.setLeverageParams(2, 5000);
// Set aggressive leverage: 5 loops, 70% borrow (risky!)
strategy.setLeverageParams(5, 7000);
togglePause
function togglePause() external onlyRouter
Pause or unpause the strategy (emergency control).
When Paused:
invest() reverts
deleverageAll() reverts
harvest() and withdrawToVault() still work (for emergency exits)
View Functions
getLeverageState
function getLeverageState()
external view
returns (
uint256 deposited_,
uint256 borrowed_,
uint256 netExposure,
uint256 loops,
uint8 maxDepth_
)
Get complete leverage state.
Total deposited principal
Net exposure (deposited - borrowed in asset terms)
getLTV
function getLTV() external view returns (uint256)
Get current Loan-to-Value ratio.
LTV ratio scaled by 1e18 (1e18 = 100%)
Formula: borrowedWETH * 1e18 / deposited
Example:
uint256 ltv = strategy.getLTV();
if (ltv > 0.7e18) { // If LTV > 70%
// Position is highly leveraged, consider deleveraging
router.triggerDeleverage(address(strategy), 3);
}
isAtRisk
function isAtRisk(uint256 maxSafeLTV) external view returns (bool)
Check if position exceeds safe LTV threshold.
Maximum safe LTV in 1e18 scale (e.g., 0.75e18 = 75%)
True if current LTV exceeds maxSafeLTV
Example:
// Check if position is at risk of liquidation
// Aave LINK LTV might be 80%, use 70% for safety
if (strategy.isAtRisk(0.70e18)) {
// Emergency deleverage
strategy.deleverageAll(10);
}
Integration Example
// 1. Deploy leveraged strategy
StrategyAaveLeverage strategy = new StrategyAaveLeverage(
address(link), // asset
address(vault), // vault
address(router), // router
aavePool, // Aave V3 Pool
aaveDataProvider, // Data Provider
uniswapRouter, // Swap router
address(weth), // WETH
priceOracle // Oracle
);
// 2. Configure leverage parameters
strategy.setLeverageParams(
3, // 3 leverage loops
6000 // Borrow 60% at each loop
);
// 3. Add to router
address[] memory strats = new address[](2);
strats[0] = address(safeStrategy); // 70% allocation
strats[1] = address(strategy); // 30% allocation
uint256[] memory allocations = new uint256[](2);
allocations[0] = 7000;
allocations[1] = 3000;
router.setStrategies(strats, allocations);
// 4. Invest with leverage
router.moveFundsToStrategy(address(strategy), 1000e18);
// Strategy now has leveraged position
// 5. Monitor position
(uint256 dep, uint256 borr, uint256 net, , ) = strategy.getLeverageState();
uint256 ltv = strategy.getLTV();
console.log("Deposited:", dep);
console.log("Borrowed:", borr);
console.log("LTV:", ltv / 1e16, "%"); // Convert to percentage
// 6. Risk management
if (strategy.isAtRisk(0.70e18)) {
router.triggerDeleverage(address(strategy), 5);
}
// 7. Harvest profits
router.harvestAll();
// 8. Safe withdrawal (deleverage first)
router.triggerDeleverage(address(strategy), 10);
strategy.withdrawToVault(500e18);
Risk Management
Liquidation Risk
// Monitor LTV continuously
uint256 aaveLinkLTV = 8000; // 80% from Aave docs
uint256 safeLTV = 7000; // 70% safety buffer
if (strategy.getLTV() > safeLTV * 1e18 / 10000) {
// Approaching liquidation threshold
strategy.deleverageAll(5);
}
Market Volatility
// During high volatility, reduce leverage
if (volatilityIndex > threshold) {
// Reduce to 1 loop (minimal leverage)
strategy.setLeverageParams(1, 5000);
// Deleverage existing position
strategy.deleverageAll(10);
}
Emergency Procedures
// Emergency pause
strategy.togglePause();
// Emergency deleverage
strategy.deleverageAll(20); // High loop count for full unwind
// Emergency withdraw
uint256 balance = strategy.strategyBalance();
strategy.withdrawToVault(balance);
Gas Costs (approximate per loop):
invest(): ~500k gas (3 loops = ~1.5M gas)
deleverageAll(): ~400k gas per loop
withdrawToVault(): ~250k gas
strategyBalance(): ~50k gas (view)
Yield Amplification:
- 3 loops with 60% borrow: ~1.8x exposure
- Base APY 5% → Effective ~9% (before borrow costs)
- Must subtract WETH borrow APY
Risks:
- Liquidation if LTV exceeds Aave threshold
- DEX slippage on swaps
- Oracle manipulation risk
- Smart contract risk (Aave, DEX, Oracle)
Security Considerations
- Liquidation: Monitor LTV closely. Aave liquidates at ~80-85% LTV.
- Oracle Risk: Relies on oracle for deleverage calculations. Oracle failure could cause incorrect swaps.
- DEX Risk: Swaps use
amountOutMin = 0 (no slippage protection in current implementation).
- Flash Loan Risk: Vulnerable to oracle manipulation via flash loans.
- Pause Mechanism: Router can pause strategy to prevent new investments during crises.
AI Agent Integration
// AI monitors market and adjusts leverage
function aiOptimizeLeverage() external onlyAI {
uint256 currentAPY = strategy.estimateAPY();
uint256 volatility = getMarketVolatility();
if (volatility > 50) {
// High volatility: reduce leverage
strategy.setLeverageParams(1, 4000);
router.triggerDeleverage(address(strategy), 5);
} else if (currentAPY > 15 && volatility < 20) {
// Good opportunity: increase leverage
strategy.setLeverageParams(4, 6500);
}
// Continuous LTV monitoring
if (strategy.isAtRisk(0.72e18)) {
// Emergency deleverage
strategy.deleverageAll(10);
emit AIRiskMitigation("High LTV detected");
}
}
See Also