Skip to content

AaveV3Strategy

ERC-4626-shaped MSV strategy. Supplies USDC to Aave V3; holds rebasing aToken. Interest accrues in atoken.balanceOfharvest() is a no-op.

Source: khomdev-keep/src/strategies/AaveV3Strategy.vy (Vyper 0.4.x)

Consumer: MultiStrategyVault fallback / smart-routed strategy

Implementation overview

  • NAVtotalAssets = atoken.balanceOf(self) (rebasing aToken)
  • Shares — internal total_shares / shares_held; only vault deposits/withdraws
  • APR — cached apr_bps from off-chain Aave currentLiquidityRate (admin-updated)
  • Harvest/sync — no-ops; gains recognised on MSV report() via totalAssets
flowchart LR
    MSV[MultiStrategyVault] --> AAVE[AaveV3Strategy]
    AAVE -->|supply| Pool[Aave V3 Pool]
    Pool --> aToken[rebasing aToken]

Immutables

Name Role
asset Underlying USDC
vault Parent MSV
aave_pool Aave V3 pool
atoken Interest-bearing aToken

Roles

Role Powers
DEFAULT_ADMIN_ROLE APR, pause deposits, sweep stray tokens

Events

Event When
Deposit / Withdraw Vault capital flows
AprUpdated / DepositsPaused Admin config

ERC-4626 views

totalAssets

AaveV3Strategy.totalAssets() -> uint256

Strategy NAV — rebasing aToken balance (includes accrued interest).

Returns: uint256atoken.balanceOf(self).

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:120-121, _total_assets 361-365):

@external
@view
def totalAssets() -> uint256:
    return self._total_assets()

# return IERC20(atoken).balanceOf(self)

Example:

nav = aave_strategy.totalAssets()

Cross-links: convertToShares · MultiStrategyVault report

balanceOf

AaveV3Strategy.balanceOf(account) -> uint256

Internal strategy shares held by account.

Param Type Description
account address Share holder (MSV in practice)

Returns: uint256shares_held[account].

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:125-126):

@external
@view
def balanceOf(account: address) -> uint256:
    return self.shares_held[account]

Cross-links: totalSupply · convertToAssets

totalSupply

AaveV3Strategy.totalSupply() -> uint256

Total strategy shares outstanding.

Returns: uint256total_shares.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:130-131):

@external
@view
def totalSupply() -> uint256:
    return self.total_shares

Cross-links: totalAssets · balanceOf

convertToAssets

AaveV3Strategy.convertToAssets(shares) -> uint256

Shares → underlying quote (floor).

Param Type Description
shares uint256 Strategy shares

Returns: uint256 — USDC value at current aToken NAV.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:135-136):

@external
@view
def convertToAssets(shares: uint256) -> uint256:
    return self._convert_to_assets(shares, False)

Cross-links: convertToShares · previewRedeem

convertToShares

AaveV3Strategy.convertToShares(assets) -> uint256

USDC → shares quote (floor).

Param Type Description
assets uint256 USDC amount

Returns: uint256 — shares at current NAV. No virtual-share offset (vault-only depositor).

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:140-141):

@external
@view
def convertToShares(assets: uint256) -> uint256:
    return self._convert_to_shares(assets, False)

Cross-links: convertToAssets · previewDeposit

maxDeposit

AaveV3Strategy.maxDeposit(receiver) -> uint256

Max USDC depositable (ERC-4626 view).

Param Type Description
receiver address Must be vault

Returns: uint2560 if paused or receiver != vault; else max_uint256.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:145-148):

@external
@view
def maxDeposit(receiver: address) -> uint256:
    if deposits_paused or receiver != vault:
        return 0
    return max_value(uint256)

Cross-links: deposit · maxMint

maxWithdraw

AaveV3Strategy.maxWithdraw(owner) -> uint256

Max USDC withdrawable for owner.

Param Type Description
owner address Must be vault

Returns: uint256convertToAssets(shares_held[vault]); 0 if not vault.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:152-156):

@external
@view
def maxWithdraw(owner: address) -> uint256:
    if owner != vault:
        return 0
    return self._convert_to_assets(self.shares_held[owner], False)

Cross-links: withdraw · maxRedeem

previewDeposit

AaveV3Strategy.previewDeposit(assets) -> uint256

Simulate deposit — shares minted (floor).

Param Type Description
assets uint256 USDC in

Returns: uint256 — expected shares (= convertToShares).

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:160-161):

@external
@view
def previewDeposit(assets: uint256) -> uint256:
    return self._convert_to_shares(assets, False)

Cross-links: deposit · convertToShares

previewWithdraw

AaveV3Strategy.previewWithdraw(assets) -> uint256

Simulate withdraw — shares burned (ceil).

Param Type Description
assets uint256 USDC out

Returns: uint256 — shares required.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:165-166):

@external
@view
def previewWithdraw(assets: uint256) -> uint256:
    return self._convert_to_shares(assets, True)

Cross-links: withdraw · previewRedeem

previewRedeem

AaveV3Strategy.previewRedeem(shares) -> uint256

Simulate redeem — USDC out (floor).

Param Type Description
shares uint256 Shares to burn

Returns: uint256 — expected USDC (= convertToAssets).

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:170-171):

@external
@view
def previewRedeem(shares: uint256) -> uint256:
    return self._convert_to_assets(shares, False)

Cross-links: redeem · convertToAssets

maxMint

AaveV3Strategy.maxMint(receiver) -> uint256

Max shares mintable (vault-only).

Param Type Description
receiver address Must be vault

Returns: uint256 — same gates as maxDeposit.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:175-178):

@external
@view
def maxMint(receiver: address) -> uint256:
    if deposits_paused or receiver != vault:
        return 0
    return max_value(uint256)

Cross-links: mint · maxDeposit

maxRedeem

AaveV3Strategy.maxRedeem(owner) -> uint256

Max shares redeemable by owner.

Param Type Description
owner address Must be vault

Returns: uint256 — full shares_held[owner]; 0 if not vault.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:182-185):

@external
@view
def maxRedeem(owner: address) -> uint256:
    if owner != vault:
        return 0
    return self.shares_held[owner]

Cross-links: redeem · maxWithdraw

IStrategy hooks

getApr

AaveV3Strategy.getApr() -> uint256

Cached APR for MSV smart routing (off-chain Aave currentLiquidityRate → admin update).

Returns: uint256apr_bps.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:193-194):

@external
@view
def getApr() -> uint256:
    return self.apr_bps

Cross-links: set_apr_bps · Rebalancer compute_smart_targets

harvest

AaveV3Strategy.harvest() -> uint256

No-op. aToken auto-rebases — interest already in atoken.balanceOf.

Returns: uint256 — always 0.

Access: Any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:197-202):

@external
def harvest() -> uint256:
    return 0

Cross-links: totalAssets · MultiStrategyVault report

sync

AaveV3Strategy.sync()

No-op. aToken balance reflects accrued interest on every read.

Access: Any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:205-210):

@external
def sync():
    pass

Cross-links: totalAssets · harvest

deployAvailable

AaveV3Strategy.deployAvailable(amount) -> uint256

Fallback deploy capacity — always accepts full amount (vault max_debt is real cap).

Param Type Description
amount uint256 Requested USDC deployment

Returns: uint256max_uint256.

Access: view, any caller.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:219-225):

@external
@view
def deployAvailable(amount: uint256) -> uint256:
    return max_value(uint256)

Cross-links: MultiStrategyVault allocateCapital

ERC-4626 writes

deposit

AaveV3Strategy.deposit(assets, receiver) -> uint256

Vault supplies USDC to Aave V3; mints internal shares to receiver (must be vault).

Param Type Description
assets uint256 USDC amount
receiver address Share recipient (vault only)

Returns: uint256 — shares minted.

Returns / state: transferFrom vault → aave_pool.supply → receives aToken.

Access: vault only. nonreentrant. Reverts if deposits_paused.

Events: Deposit.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:234-258):

@external
@nonreentrant
def deposit(assets, receiver) -> uint256:
    self._only_vault()
    IERC20(asset).transferFrom(vault, self, assets)
    IAaveV3Pool(aave_pool).supply(asset, assets, self, 0)
    total_shares += shares; shares_held[receiver] += shares
    return shares

Cross-links: previewDeposit · withdraw

mint

AaveV3Strategy.mint(shares, receiver) -> uint256

Mint exact shares; vault pays ceil USDC → Aave supply.

Param Type Description
shares uint256 Target shares
receiver address Must be vault

Returns: uint256 — USDC pulled from vault.

Access: vault only. Same gates as deposit.

Events: Deposit.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:262-280):

@external
@nonreentrant
def mint(shares, receiver) -> uint256:
    assets = self._convert_to_assets(shares, True)
    IAaveV3Pool(aave_pool).supply(asset, assets, self, 0)
    return assets

Cross-links: deposit · maxMint

withdraw

AaveV3Strategy.withdraw(assets, receiver, owner) -> uint256

Burn shares; pull USDC from Aave to receiver.

Param Type Description
assets uint256 Target USDC
receiver address Payout address
owner address Must be vault

Returns: uint256 — shares burned. Full exit caps pull at share value (audit A3).

Access: vault only. nonreentrant.

Events: Withdraw.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:284-305):

@external
@nonreentrant
def withdraw(assets, receiver, owner) -> uint256:
    # burn shares; aave_pool.withdraw(asset, assets_to_pull, receiver)
    return shares

Cross-links: redeem · previewWithdraw

redeem

AaveV3Strategy.redeem(shares, receiver, owner) -> uint256

Burn exact shares; pull USDC from Aave to receiver.

Param Type Description
shares uint256 Shares to burn
receiver address USDC recipient
owner address Must be vault

Returns: uint256 — USDC withdrawn (assets from convertToAssets).

Access: vault only. nonreentrant.

Events: Withdraw.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:309-320):

@external
@nonreentrant
def redeem(shares, receiver, owner) -> uint256:
    assets = self._convert_to_assets(shares, False)
    IAaveV3Pool(aave_pool).withdraw(asset, assets, receiver)
    return assets

Cross-links: withdraw · previewRedeem

Admin

set_apr_bps

AaveV3Strategy.set_apr_bps(new_bps)

Update cached APR for smart routing (from off-chain Aave liquidity rate).

Param Type Description
new_bps uint256 APR bps (≤ 5000)

Access: DEFAULT_ADMIN_ROLE only.

Events: AprUpdated(new_bps).

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:327-335):

@external
def set_apr_bps(new_bps: uint256):
    access_control._check_role(DEFAULT_ADMIN_ROLE, msg.sender)
    assert new_bps <= 5_000
    self.apr_bps = new_bps

Cross-links: getApr

set_deposits_paused

AaveV3Strategy.set_deposits_paused(state)

Pause/resume vault deposits. Withdrawals always allowed.

Param Type Description
state bool True = pause deposits

Access: DEFAULT_ADMIN_ROLE only.

Events: DepositsPaused(state).

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:338-341):

@external
def set_deposits_paused(state: bool):
    access_control._check_role(DEFAULT_ADMIN_ROLE, msg.sender)
    self.deposits_paused = state

Cross-links: deposit · maxDeposit

sweep

AaveV3Strategy.sweep(token, to)

Recover stray ERC-20 (not USDC or aToken).

Param Type Description
token address Token to sweep
to address Recipient

Access: DEFAULT_ADMIN_ROLE only. Cannot sweep asset or atoken.

Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:344-353):

@external
def sweep(token: address, to: address):
    assert token != asset and token != atoken
    IERC20(token).transfer(to, IERC20(token).balanceOf(self))