Aave Protocol Adapter
The Aave adapter enables the Yieldinator Facet to integrate with Aave's lending protocol, allowing vaults to earn yield by depositing assets into Aave's liquidity pools.
Overview
Aave is a decentralized non-custodial liquidity protocol where users can participate as depositors or borrowers. Depositors provide liquidity to the market to earn a passive income, while borrowers can borrow in an overcollateralized or undercollateralized way.
The Aave adapter facilitates deposits into Aave's lending pools, manages aToken balances, and harvests yield generated from lending interest.
Implementation Details
Contract: AaveAdapter.sol
AaveAdapter.solThe adapter implements the standard YieldinatorAdapter interface with Aave-specific functionality:
contract AaveAdapter is YieldinatorAdapter {
// Aave contracts
IAaveLendingPool public lendingPool;
// Mapping from underlying asset to aToken
mapping(address => address) public assetToAToken;
// Deposited amounts per token
mapping(address => uint256) public depositedAmount;
// Constructor and core functions...
}Key Functions
Asset Registration
Before using the adapter for a specific token, the asset must be registered with its corresponding aToken:
function registerAsset(address _asset, address _aToken) external onlyRole(ADAPTER_ADMIN_ROLE)Deposit
Deposits tokens into Aave's lending pool:
function deposit(address _token, uint256 _amount) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (bool)The function:
Transfers tokens from the caller to the adapter
Approves the lending pool to spend the tokens
Deposits tokens into Aave
Updates the deposited amount tracking
Withdraw
Withdraws tokens from Aave's lending pool:
function withdraw(address _token, uint256 _amount) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (bool)Harvest Yield
Harvests accrued interest without withdrawing the principal:
function harvestYield(address _token) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (uint256)The function calculates yield as the difference between the current aToken balance and the original deposited amount.
Emergency Withdraw
Provides emergency withdrawal functionality:
function emergencyWithdraw(address _token) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (uint256)APY Calculation
Returns the current APY for a token in Aave:
function getCurrentAPY(address _token) external view override returns (uint256)The APY is calculated based on Aave's liquidityRate, converted from ray (27 decimals) to a percentage with 2 decimal places (scaled by 10000).
Usage Example
// Initialize the adapter
AaveAdapter aaveAdapter = new AaveAdapter(lendingPoolAddress, adminAddress);
// Register an asset
aaveAdapter.registerAsset(daiAddress, aDaiAddress);
// Deposit tokens
aaveAdapter.deposit(daiAddress, 1000 * 1e18);
// After some time, harvest yield
uint256 harvestedYield = aaveAdapter.harvestYield(daiAddress);
// Withdraw tokens
aaveAdapter.withdraw(daiAddress, 500 * 1e18);
// In case of emergency
aaveAdapter.emergencyWithdraw(daiAddress);Security Considerations
The adapter uses OpenZeppelin's SafeERC20 for token transfers to prevent common ERC20 vulnerabilities.
Non-reentrancy guards protect against reentrancy attacks during external calls.
Role-based access control ensures only authorized addresses can call sensitive functions.
The adapter maintains accurate accounting of deposited amounts to prevent yield manipulation.
Gas Optimization
The adapter minimizes the number of external calls to Aave contracts.
Token approvals are set exactly to the amount being deposited to avoid unnecessary approvals.
Yield harvesting is designed to be gas-efficient by calculating yield based on token balances.
Integration Requirements
To use the Aave adapter, the following components are required:
An Aave lending pool address for the target network
The corresponding aToken addresses for each asset
Proper role assignments for the Yieldinator Facet