Vault Contract

The Vault contract is the core primitive of Nester's savings layer. It accepts stablecoin deposits, tracks share ownership, and manages yield source allocations.

Interface

rust
#![no_std]
use soroban_sdk::{contract, contractimpl, Address, Env, Vec};

#[contract]
pub struct Vault;

#[contractimpl]
impl Vault {
    /// Initialize a new vault with admin, asset token, and strategy
    pub fn initialize(
        env: Env,
        admin: Address,
        asset: Address,       // USDC token contract
        share_token: Address, // nVault token contract
        strategy: Address,    // Allocation strategy contract
    );

    /// Deposit stablecoins and receive share tokens
    pub fn deposit(
        env: Env,
        user: Address,
        amount: i128,
    ) -> i128 {
        user.require_auth();

        let total_assets = Self::total_assets(&env);
        let total_shares = Self::total_shares(&env);

        // Calculate shares to mint
        let shares = if total_shares == 0 {
            amount  // First depositor gets 1:1 shares
        } else {
            amount * total_shares / total_assets
        };

        // Transfer USDC from user to vault
        token::transfer(&env, &user, &env.current_contract_address(), amount);

        // Mint nVault share tokens to user
        share_token::mint(&env, &user, shares);

        // Update vault totals
        Self::set_total_assets(&env, total_assets + amount);
        Self::set_total_shares(&env, total_shares + shares);

        // Emit deposit event
        env.events().publish(
            (symbol_short!("deposit"), user.clone()),
            (amount, shares),
        );

        shares
    }

    /// Withdraw stablecoins by burning share tokens
    pub fn withdraw(
        env: Env,
        user: Address,
        shares: i128,
    ) -> i128 {
        user.require_auth();

        let total_assets = Self::total_assets(&env);
        let total_shares = Self::total_shares(&env);

        // Calculate underlying amount
        let amount = shares * total_assets / total_shares;

        // Check maturity and apply penalty if early
        let penalty = Self::calculate_penalty(&env, &user, amount);
        let net_amount = amount - penalty;

        // Burn user's share tokens
        share_token::burn(&env, &user, shares);

        // Transfer USDC to user
        token::transfer(&env, &env.current_contract_address(), &user, net_amount);

        // Update vault totals (penalty stays in vault, boosting other holders)
        Self::set_total_assets(&env, total_assets - net_amount);
        Self::set_total_shares(&env, total_shares - shares);

        env.events().publish(
            (symbol_short!("withdraw"), user.clone()),
            (net_amount, shares, penalty),
        );

        net_amount
    }

    /// Get user's current position
    pub fn get_position(env: Env, user: Address) -> Position {
        let shares = share_token::balance(&env, &user);
        let total_assets = Self::total_assets(&env);
        let total_shares = Self::total_shares(&env);
        let value = shares * total_assets / total_shares;

        Position { shares, value }
    }

    /// Get vault info (for frontend display)
    pub fn get_info(env: Env) -> VaultInfo {
        VaultInfo {
            total_assets: Self::total_assets(&env),
            total_shares: Self::total_shares(&env),
            apy_estimate: Self::current_apy(&env),
            allocations: Self::get_allocations(&env),
        }
    }

    /// Rebalance vault allocations (admin only)
    pub fn rebalance(env: Env, admin: Address, new_allocations: Vec<Allocation>) {
        admin.require_auth();
        Self::verify_admin(&env, &admin);
        // Execute rebalance across yield sources
    }

    /// Emergency pause (admin only)
    pub fn pause(env: Env, admin: Address) {
        admin.require_auth();
        Self::verify_admin(&env, &admin);
        Self::set_paused(&env, true);
    }
}

Events

EventDataWhen
deposit(amount, shares)User deposits into vault
withdraw(net_amount, shares, penalty)User withdraws from vault
rebalance(new_allocations)Admin triggers rebalance
pause(admin)Vault paused for emergency

Storage Layout

rust
// Persistent storage keys
enum DataKey {
    Admin,          // Address
    Asset,          // Address (USDC token)
    ShareToken,     // Address (nVault token)
    Strategy,       // Address (allocation strategy)
    TotalAssets,    // i128
    TotalShares,    // i128
    Paused,         // bool
    Maturity(Address), // Timestamp per user
}