Appearance
Smart Contracts ​
KanaVault ​
The core vault contract implementing the ERC-4626 tokenized vault standard.
Key Functions ​
| Function | Description |
|---|---|
deposit(uint256 assets, address receiver) | Deposit USDC, receive kUSDC shares |
withdraw(uint256 assets, address receiver, address owner) | Burn kUSDC, receive USDC |
redeem(uint256 shares, address receiver, address owner) | Burn exact shares, receive USDC |
totalAssets() | Total USDC managed (idle + deployed) |
setStrategy(IStrategy newStrategy) | Migrate to a new strategy |
harvest() | Claim and compound yield (backward compatible, no slippage protection) |
harvestWithSlippage(uint256 takaraMinOut, uint256 morphoMinOut) | Harvest with slippage protection on reward swaps |
setPerformanceFee(uint256 fee) | Update fee (max 20%) |
setFeeRecipient(address recipient) | Update fee recipient |
rescueToken(address token) | Recover stuck tokens |
Share Accounting ​
shares = deposit_amount × total_shares / total_assets
assets = shares × total_assets / total_sharesAs yield accrues, totalAssets() increases while totalShares stays constant, making each share worth more USDC over time.
Access Control ​
| Role | Permissions |
|---|---|
| Owner | Set strategy, set fees, set fee recipient, rescue tokens |
| Strategy | Report yield, request funds |
| Anyone | Deposit, withdraw, view balances |
IStrategy Interface ​
The interface that all strategies must implement:
solidity
interface IStrategy {
function deposit(uint256 amount) external;
function withdraw(uint256 amount) external returns (uint256);
function harvest() external;
function harvestWithSlippage(uint256 takaraMinOut, uint256 morphoMinOut) external;
function balanceOf() external view returns (uint256);
function asset() external view returns (address);
}| Function | Description |
|---|---|
deposit(uint256) | Receive USDC from vault, deploy to protocols |
withdraw(uint256) | Pull USDC from protocols, return to vault |
harvest() | Claim rewards, compound yield (backward compatible, no slippage protection) |
harvestWithSlippage(uint256, uint256) | Claim rewards with slippage protection on swaps |
balanceOf() | Total USDC value across all positions |
asset() | The managed asset address (USDC) |
USDCStrategy ​
The multi-protocol strategy that splits USDC across Yei Finance, Takara, and Morpho.
Allocation Management ​
Allocations are set in basis points (total must equal 10,000):
solidity
// Example: 40% Yei, 35% Takara, 25% Morpho
strategy.setAllocations([4000, 3500, 2500]);Deposit Logic ​
On deposit, USDC is split according to allocation weights and supplied to each protocol.
Withdrawal Logic ​
On withdrawal, funds are pulled proportionally from all protocols:
withdrawal_from_yei = amount × yei_balance / total_balance
withdrawal_from_takara = amount × takara_balance / total_balance
withdrawal_from_morpho = amount × morpho_balance / total_balanceHarvest ​
The harvest() function is backward compatible but offers no slippage protection. The recommended approach is harvestWithSlippage():
solidity
function harvestWithSlippage(
uint256 takaraMinOut, // Min USDC from Takara reward swaps
uint256 morphoMinOut // Min USDC from Morpho reward swaps
) external;Harvest flow:
- Claims aToken interest from Yei
- Claims cToken interest + COMP rewards from Takara
- Claims Morpho rewards via Merkl Distributor (see below)
- Swaps non-USDC rewards to USDC via Sailor DEX with slippage protection
- Reports total yield to vault
- Redeposits compounded USDC
Slippage protection: If the actual swap output is less than the specified minAmountOut, the transaction reverts. This prevents MEV attacks and sandwich bots from extracting value during reward swaps.
Morpho Rewards via Merkl ​
Morpho rewards are distributed through the Merkl Distributor contract at 0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae. The strategy includes a dedicated function for claiming:
solidity
function claimMorphoRewards(
address[] calldata tokens,
uint256[] calldata amounts,
bytes32[][] calldata proofs,
uint256[] calldata minAmountsOut
) external;| Parameter | Description |
|---|---|
tokens | Reward token addresses (e.g., MORPHO, wETH) |
amounts | Claimable amounts from Merkl tree |
proofs | Merkle proofs from Merkl API |
minAmountsOut | Minimum USDC out per token swap (slippage protection) |
The keeper fetches merkle proofs from https://api.merkl.xyz/v4/claim?user={strategyAddress}&chainId=1329 and passes them to this function. After claiming, tokens are swapped to USDC and re-deployed to lending protocols.
IMerklDistributor ​
The Merkl Distributor interface used for claiming Morpho protocol rewards:
solidity
interface IMerklDistributor {
function claim(
address[] calldata users,
address[] calldata tokens,
uint256[] calldata amounts,
bytes32[][] calldata proofs
) external;
}| Parameter | Description |
|---|---|
users | Beneficiary addresses (strategy address in our case) |
tokens | Reward token addresses |
amounts | Amounts from the merkle tree |
proofs | Merkle proofs validating the claim |
Merkl distributor address: 0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae
The USDCStrategy wraps this interface in its claimMorphoRewards() function, adding automatic swap-to-USDC logic and slippage protection.
YeiOnlyStrategy ​
A simpler strategy for initial deployment that only uses Yei Finance (Aave V3 fork).
Why? ​
- Simpler — single protocol, fewer failure modes
- Battle-tested — Aave V3 is the most proven lending protocol
- Stepping stone — deploy with YeiOnly first, migrate to USDCStrategy later
Functions ​
Same IStrategy interface but with a single protocol:
deposit()→ supplies all USDC to Yeiwithdraw()→ withdraws from Yeiharvest()→ claims aToken interestbalanceOf()→ returns Yei aToken balance
Migration Path ​
1. Deploy with YeiOnlyStrategy
2. Test in production, build confidence
3. Deploy USDCStrategy
4. Call vault.setStrategy(usdcStrategy)
5. Funds automatically migrate