AaveV3Strategy¶
ERC-4626-shaped MSV strategy. Supplies USDC to Aave V3; holds rebasing aToken. Interest accrues in atoken.balanceOf — harvest() is a no-op.
Source: khomdev-keep/src/strategies/AaveV3Strategy.vy (Vyper 0.4.x)
Consumer: MultiStrategyVault fallback / smart-routed strategy
Implementation overview¶
- NAV —
totalAssets = atoken.balanceOf(self)(rebasing aToken) - Shares — internal
total_shares/shares_held; onlyvaultdeposits/withdraws - APR — cached
apr_bpsfrom off-chain AavecurrentLiquidityRate(admin-updated) - Harvest/sync — no-ops; gains recognised on MSV
report()viatotalAssets
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: uint256 — atoken.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:
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: uint256 — shares_held[account].
Access: view, any caller.
Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:125-126):
Cross-links: totalSupply · convertToAssets
totalSupply¶
AaveV3Strategy.totalSupply() -> uint256
Total strategy shares outstanding.
Returns: uint256 — total_shares.
Access: view, any caller.
Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:130-131):
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: uint256 — 0 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: uint256 — convertToAssets(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: uint256 — apr_bps.
Access: view, any caller.
Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:193-194):
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):
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):
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: uint256 — max_uint256.
Access: view, any caller.
Source (khomdev-keep/src/strategies/AaveV3Strategy.vy:219-225):
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))