Skip to content

Smart Contracts ​

KanaVault ​

The core vault contract implementing the ERC-4626 tokenized vault standard.

Key Functions ​

FunctionDescription
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_shares

As yield accrues, totalAssets() increases while totalShares stays constant, making each share worth more USDC over time.

Access Control ​

RolePermissions
OwnerSet strategy, set fees, set fee recipient, rescue tokens
StrategyReport yield, request funds
AnyoneDeposit, 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);
}
FunctionDescription
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_balance

Harvest ​

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:

  1. Claims aToken interest from Yei
  2. Claims cToken interest + COMP rewards from Takara
  3. Claims Morpho rewards via Merkl Distributor (see below)
  4. Swaps non-USDC rewards to USDC via Sailor DEX with slippage protection
  5. Reports total yield to vault
  6. 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;
ParameterDescription
tokensReward token addresses (e.g., MORPHO, wETH)
amountsClaimable amounts from Merkl tree
proofsMerkle proofs from Merkl API
minAmountsOutMinimum 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;
}
ParameterDescription
usersBeneficiary addresses (strategy address in our case)
tokensReward token addresses
amountsAmounts from the merkle tree
proofsMerkle 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 Yei
  • withdraw() → withdraws from Yei
  • harvest() → claims aToken interest
  • balanceOf() → 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

Built on SEI