AgentSkillsCN

Aave V3 Pool Operations

当用户询问“Aave 存款”“Aave 借款”“Aave 还款”“Aave 提款”“Aave 清算”“Pool.sol”“SupplyLogic”“BorrowLogic”“LiquidationLogic”,或需要理解 Aave V3 核心 Pool 操作时,应使用此技能。

SKILL.md
--- frontmatter
name: Aave V3 Pool Operations
description: This skill should be used when the user asks about "Aave supply", "Aave borrow", "Aave repay", "Aave withdraw", "Aave liquidation", "Pool.sol", "SupplyLogic", "BorrowLogic", "LiquidationLogic", or needs to understand core Aave V3 Pool operations.
version: 0.1.0

Aave V3 Pool Operations

The Pool contract is the main entry point for user interactions with Aave V3. This skill covers core operations: supply, withdraw, borrow, repay, and liquidation.

Pool Contract Overview

solidity
abstract contract Pool is VersionedInitializable, PoolStorage, IPool {
    using ReserveLogic for DataTypes.ReserveData;

    IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;

    // Core operations delegate to logic libraries
    // SupplyLogic, BorrowLogic, LiquidationLogic, FlashLoanLogic, etc.
}

Supply Operations

supply()

Deposit assets to earn interest:

solidity
function supply(
    address asset,          // Token to supply
    uint256 amount,         // Amount to supply
    address onBehalfOf,     // Recipient of aTokens
    uint16 referralCode     // Referral tracking
) public virtual;

// With EIP-2612 permit
function supplyWithPermit(
    address asset,
    uint256 amount,
    address onBehalfOf,
    uint16 referralCode,
    uint256 deadline,
    uint8 permitV,
    bytes32 permitR,
    bytes32 permitS
) public virtual;

Supply Flow

code
┌──────────────────────────────────────────────────────────────┐
│                       SUPPLY FLOW                            │
├──────────────────────────────────────────────────────────────┤
│ 1. Validate: asset active, not paused, not frozen            │
│ 2. Validate: supply cap not exceeded                         │
│ 3. Update reserve indexes (accrue interest)                  │
│ 4. Transfer underlying from user to aToken contract          │
│ 5. Mint aTokens to onBehalfOf (scaled amount)                │
│ 6. Update virtual underlying balance                         │
│ 7. Update interest rates                                     │
│ 8. Enable asset as collateral (if first supply)              │
└──────────────────────────────────────────────────────────────┘

SupplyLogic

solidity
library SupplyLogic {
    function executeSupply(
        mapping(address => DataTypes.ReserveData) storage reservesData,
        mapping(uint256 => address) storage reservesList,
        DataTypes.UserConfigurationMap storage userConfig,
        DataTypes.ExecuteSupplyParams memory params
    ) external {
        DataTypes.ReserveData storage reserve = reservesData[params.asset];
        DataTypes.ReserveCache memory reserveCache = reserve.cache();

        reserve.updateState(reserveCache);

        // Validate supply
        ValidationLogic.validateSupply(reserveCache, reserve, params.amount);

        // Update interest rates and virtual balance
        reserve.updateInterestRatesAndVirtualBalance(
            reserveCache,
            params.asset,
            params.amount,  // liquidity added
            0               // liquidity taken
        );

        // Transfer and mint
        IERC20(params.asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, params.amount);
        bool isFirstSupply = IAToken(reserveCache.aTokenAddress).mint(
            msg.sender,
            params.onBehalfOf,
            params.amount,
            reserveCache.nextLiquidityIndex
        );

        // Auto-enable as collateral on first supply
        if (isFirstSupply) {
            if (ValidationLogic.validateAutomaticUseAsCollateral(...)) {
                userConfig.setUsingAsCollateral(reserve.id, true);
            }
        }
    }
}

Withdraw Operations

withdraw()

Withdraw supplied assets:

solidity
function withdraw(
    address asset,    // Token to withdraw
    uint256 amount,   // Amount (type(uint256).max for all)
    address to        // Recipient of underlying
) public virtual returns (uint256);  // Actual amount withdrawn

Withdraw Flow

code
┌──────────────────────────────────────────────────────────────┐
│                      WITHDRAW FLOW                           │
├──────────────────────────────────────────────────────────────┤
│ 1. Update reserve indexes                                    │
│ 2. Calculate actual amount (handle max)                      │
│ 3. Validate health factor remains >= 1                       │
│ 4. Burn aTokens from user                                    │
│ 5. Transfer underlying to recipient                          │
│ 6. Update virtual balance                                    │
│ 7. Update interest rates                                     │
│ 8. Disable as collateral if balance becomes 0                │
└──────────────────────────────────────────────────────────────┘

Borrow Operations

borrow()

Borrow assets against collateral:

solidity
function borrow(
    address asset,              // Token to borrow
    uint256 amount,             // Amount to borrow
    uint256 interestRateMode,   // 2 = Variable (1 = deprecated stable)
    uint16 referralCode,        // Referral tracking
    address onBehalfOf          // Debt recipient (requires credit delegation)
) public virtual;

Borrow Flow

code
┌──────────────────────────────────────────────────────────────┐
│                       BORROW FLOW                            │
├──────────────────────────────────────────────────────────────┤
│ 1. Validate: asset active, not paused, borrowing enabled     │
│ 2. Validate: borrow cap not exceeded                         │
│ 3. Validate: health factor will remain >= 1                  │
│ 4. Validate: interest rate mode is VARIABLE                  │
│ 5. Validate: borrowable in user's eMode (if applicable)      │
│ 6. Update reserve indexes                                    │
│ 7. Mint debt tokens to onBehalfOf                            │
│ 8. Transfer underlying to msg.sender                         │
│ 9. Update interest rates                                     │
│ 10. Handle isolation mode debt ceiling                       │
└──────────────────────────────────────────────────────────────┘

BorrowLogic

solidity
library BorrowLogic {
    function executeBorrow(
        mapping(address => DataTypes.ReserveData) storage reservesData,
        mapping(uint256 => address) storage reservesList,
        mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
        DataTypes.UserConfigurationMap storage userConfig,
        DataTypes.ExecuteBorrowParams memory params
    ) public {
        DataTypes.ReserveData storage reserve = reservesData[params.asset];
        DataTypes.ReserveCache memory reserveCache = reserve.cache();

        reserve.updateState(reserveCache);

        // Comprehensive validation
        ValidationLogic.validateBorrow(
            reservesData,
            reservesList,
            eModeCategories,
            DataTypes.ValidateBorrowParams({
                reserveCache: reserveCache,
                userConfig: userConfig,
                asset: params.asset,
                userAddress: params.onBehalfOf,
                amount: params.amount,
                interestRateMode: params.interestRateMode,
                reservesCount: params.reservesCount,
                oracle: params.oracle,
                userEModeCategory: params.userEModeCategory,
                priceOracleSentinel: params.priceOracleSentinel,
                isolationModeActive: isolationModeActive,
                isolationModeCollateralAddress: isolationModeCollateralAddress,
                isolationModeDebtCeiling: isolationModeDebtCeiling
            })
        );

        // Mint debt tokens
        IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint(
            params.user,
            params.onBehalfOf,
            params.amount,
            reserveCache.nextVariableBorrowIndex
        );

        // Update rates and transfer
        reserve.updateInterestRatesAndVirtualBalance(
            reserveCache,
            params.asset,
            0,              // liquidity added
            params.amount   // liquidity taken
        );

        IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(params.user, params.amount);
    }
}

Repay Operations

repay()

Repay borrowed assets:

solidity
function repay(
    address asset,              // Token to repay
    uint256 amount,             // Amount (type(uint256).max for all)
    uint256 interestRateMode,   // 2 = Variable
    address onBehalfOf          // Debt owner to repay for
) public virtual returns (uint256);  // Actual amount repaid

// With permit
function repayWithPermit(
    address asset,
    uint256 amount,
    uint256 interestRateMode,
    address onBehalfOf,
    uint256 deadline,
    uint8 permitV,
    bytes32 permitR,
    bytes32 permitS
) public virtual returns (uint256);

// Repay using aTokens (no transfer needed)
function repayWithATokens(
    address asset,
    uint256 amount,
    uint256 interestRateMode
) public virtual returns (uint256);

Repay Flow

code
┌──────────────────────────────────────────────────────────────┐
│                        REPAY FLOW                            │
├──────────────────────────────────────────────────────────────┤
│ 1. Update reserve indexes                                    │
│ 2. Calculate actual repay amount (cap at debt)               │
│ 3. Burn debt tokens from onBehalfOf                          │
│ 4. Transfer underlying from user (or burn aTokens)           │
│ 5. Update virtual balance                                    │
│ 6. Update interest rates                                     │
│ 7. Reduce isolation mode debt if applicable                  │
└──────────────────────────────────────────────────────────────┘

Liquidation

liquidationCall()

Liquidate an undercollateralized position:

solidity
function liquidationCall(
    address collateralAsset,    // Collateral to seize
    address debtAsset,          // Debt to repay
    address user,               // User to liquidate
    uint256 debtToCover,        // Amount of debt to repay
    bool receiveAToken          // Receive aTokens or underlying
) public virtual;

Liquidation Flow

code
┌──────────────────────────────────────────────────────────────┐
│                    LIQUIDATION FLOW                          │
├──────────────────────────────────────────────────────────────┤
│ 1. Validate: user health factor < 1                          │
│ 2. Validate: liquidation grace period has passed             │
│ 3. Calculate max liquidatable debt (close factor)            │
│ 4. Calculate collateral to receive (+ liquidation bonus)     │
│ 5. Burn debt tokens from user                                │
│ 6. Transfer debt payment from liquidator                     │
│ 7. Transfer collateral to liquidator (aTokens or underlying) │
│ 8. Handle deficit if bad debt occurs                         │
│ 9. Update interest rates                                     │
└──────────────────────────────────────────────────────────────┘

LiquidationLogic

solidity
library LiquidationLogic {
    // Close factor: max 50% of debt can be liquidated per call
    uint256 internal constant DEFAULT_LIQUIDATION_CLOSE_FACTOR = 0.5e4;

    // When HF < this threshold, 100% can be liquidated
    uint256 public constant CLOSE_FACTOR_HF_THRESHOLD = 0.95e18;

    function executeLiquidationCall(
        mapping(address => DataTypes.ReserveData) storage reservesData,
        mapping(uint256 => address) storage reservesList,
        mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
        mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
        DataTypes.ExecuteLiquidationCallParams memory params
    ) external {
        // Validate liquidation is allowed
        LiquidationCallLocalVars memory vars;
        (vars.userGlobalCollateral, vars.userGlobalDebt, , , , vars.healthFactor) =
            GenericLogic.calculateUserAccountData(...);

        require(vars.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD, Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD);

        // Calculate amounts
        (vars.actualDebtToLiquidate, vars.actualCollateralToLiquidate, vars.liquidationProtocolFeeAmount) =
            _calculateAvailableCollateralToLiquidate(...);

        // Execute liquidation
        _burnDebtTokens(...);
        _liquidateCollateral(...);
    }
}

Collateral Management

setUserUseReserveAsCollateral()

Enable/disable an asset as collateral:

solidity
function setUserUseReserveAsCollateral(
    address asset,
    bool useAsCollateral
) public virtual;

Constraints:

  • Cannot disable if it would cause health factor < 1
  • Cannot disable if asset is the only collateral backing debt

Account Data

getUserAccountData()

Get user's aggregate account information:

solidity
function getUserAccountData(address user) external view returns (
    uint256 totalCollateralBase,           // Total collateral in base currency
    uint256 totalDebtBase,                 // Total debt in base currency
    uint256 availableBorrowsBase,          // Remaining borrow capacity
    uint256 currentLiquidationThreshold,   // Weighted average LT
    uint256 ltv,                           // Current LTV
    uint256 healthFactor                   // HF (< 1 means liquidatable)
);

Health Factor Calculation

solidity
// Health Factor = Σ(Collateral × LT) / Total Debt
// If HF < 1, position can be liquidated

// Example:
// Collateral: 10 ETH @ $2000 = $20,000
// LT: 82.5%
// Debt: $15,000
// HF = ($20,000 × 0.825) / $15,000 = 1.10

Interest Rate Mode

Aave V3.2+ only supports variable rate:

solidity
enum InterestRateMode {
    NONE,
    __DEPRECATED,  // Was stable rate
    VARIABLE
}

Events

solidity
event Supply(address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referralCode);
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
event Borrow(address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, DataTypes.InterestRateMode interestRateMode, uint256 borrowRate, uint16 indexed referralCode);
event Repay(address indexed reserve, address indexed user, address indexed repayer, uint256 amount, bool useATokens);
event LiquidationCall(address indexed collateralAsset, address indexed debtAsset, address indexed user, uint256 debtToCover, uint256 liquidatedCollateralAmount, address liquidator, bool receiveAToken);

Reference Files

  • src/contracts/protocol/pool/Pool.sol - Main Pool contract
  • src/contracts/protocol/libraries/logic/SupplyLogic.sol - Supply logic
  • src/contracts/protocol/libraries/logic/BorrowLogic.sol - Borrow logic
  • src/contracts/protocol/libraries/logic/LiquidationLogic.sol - Liquidation logic
  • src/contracts/protocol/libraries/logic/ValidationLogic.sol - Validation logic
  • src/contracts/protocol/libraries/logic/GenericLogic.sol - Account calculations