> For the complete documentation index, see [llms.txt](https://docs.satay.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.satay.finance/technical-overview/vault-module.md).

# Vault Module

## Overview

The `satay::vault` module contains the code for vault logic within the Satay protocol. This module manages vault creation, deposits, withdrawals, strategy integration, and overall vault state.

## Structs

### Vault

The `Vault` struct represents a vault in the protocol. It holds essential information about the vault's assets, state, and associated strategies.

```rust
struct Vault has key {
    total_debt: u64,
    is_paused: bool,
    total_idle: u64,
    deposit_limit: Option<u64>,
    total_debt_limit: Option<u64>,
    base_metadata: Object<Metadata>,
    shares_metadata: Object<Metadata>,
    last_report: u64,
    total_locked: u64,
    lock_duration: u64,
    manager: address,
    strategies: SimpleMap<Object<BaseStrategy>, StrategyState>,
    management_fee: Option<u64>,
    performance_fee: Option<u64>
}
```

### VaultController

The `VaultController` struct holds the vault's extend ref.

```rust
struct VaultController has key {
    extend_ref: ExtendRef
}
```

### RegistryInfo

Tracks all vaults and strategies registered within the protocol.

```rust
struct RegistryInfo has key {
    vaults: vector<Object<Vault>>,
    strategies: vector<Object<BaseStrategy>>,
}
```

### WithdrawalRequest

Represents a request to withdraw assets from a vault.

```rust
struct WithdrawalRequest {
    remaining: u64,
    account: address,
    to_withdraw: u64,
    vault: Object<Vault>,
    to_burn: FungibleAsset,
    withdrawn: FungibleAsset,
    losses: SimpleMap<Object<BaseStrategy>, u64>,
    debt_offsets: SimpleMap<Object<BaseStrategy>, u64>,
}
```

## Events

* **VaultCreated**: Emitted when a new vault is created.
* **Deposit**: Emitted when assets are deposited into a vault.
* **Withdraw**: Emitted when assets are withdrawn from a vault.
* **RegistryInitialized**: Emitted when the registry is initialized.
* **VaultPaused**: Emitted when a vault is paused.
* **VaultUnpaused**: Emitted when a vault is unpaused.
* **SetDepositLimit**: Emitted when the deposit limit of a vault is set.
* **SetPerformanceFee**: Emitted when the performance fee of a vault is set.
* **SetManagementFee**: Emitted when the management fee of a vault is set.
* **BaseStrategyAdded**: Emitted when a strategy is added to a vault.
* **BaseStrategyRemoved**: Emitted when a strategy is removed from a vault.
* **BaseStrategySharesDeposit**: Emitted when strategy shares are deposited into a vault.
* **BaseStrategySharesWithdraw**: Emitted when strategy shares are withdrawn from a vault.
* **SetLockDuration**: Emitted when the lock duration is set.

## Constants

* `MAX_PERFORMANCE_FEE: u64 = 2000` – Maximum performance fee in basis points.
* `MAX_MANAGEMENT_FEE: u64 = 300` – Maximum management fee in basis points.
* `MIN_LOCK_DURATION: u64 = 604_800` – Minimum profit lock duration, expressed in seconds.
* `MAX_LOCK_DURATION: u64 = 2_419_200` – Maximum profit lock duration, expressed in seconds.
* `MAX_BPS: u64 = 10_000` – Maximum basis points.
* `U64_MAX: u64 = 18446744073709551615` – Maximum u64 value.
* `DEBT_RATIO_MAX: u64 = 10_000` – Maximum debt ratio in basis points.
* `SECONDS_PER_YEAR: u64 = 31_556_952`  – Number of seconds in a year.
* `DEFAULT_LOCK_DURATION: u64 = 1_209_600` – Default profit lock duration, expressed in seconds.

## Error Codes

* `ENOT_AUTHORIZED:` Unauthorized signer or capability.
* `EALREADY_INITIALIZED`: Resource already initialized.
* `EINVALID_DEBT_LIMIT`: Invalid debt limit (too much or too low).
* `EINVALID_DEPOSIT_LIMIT`: Invalid deposit limit (too much or too low).
* `EINVALID_FEE`: Invalid performance fee (too much or too low).
* `EVAULT_BASE_ASSET_MISMATCH`: Asset metadata does not match the vault base assets.
* `EINSUFFICIENT_BALANCE`: Insufficient balance to perform action.
* `EVAULT_NOT_PAUSED`: Vault has not been paused.
* `EVAULT_ALREADY_PAUSED`: Vault has already been paused.
* `ESTRATEGY_ALREADY_ADDED`: BaseStrategy has already been added to vault.
* `EVAULT_SHARES_ASSET_MISMATCH`: Asset metadata does not match the vault shares assets.
* `ESTRATEGY_INSUFFICIENT_DEBT`: BaseStrategy does not have sufficient debt.
* `EVAULT_STRATEGY_MISMATCH`: BaseStrategy does not belong or match the vault it's being used with.
* `EINVALID_DEPOSIT_AMOUNT`: Deposit too much and exceeds the set limit.
* `ESTRATEGY_HAS_DEBT`: BaseStrategy still has unpaid debt.
* `EVAULT_INSUFFICIENT_DEBT`: Vault does not have sufficient debt.
* `EINVALID_WITHDRAWAL_AMOUNT`: Invalid withdrawal amount.
* `EVAULT_PAUSED`: Vault is currently paused.
* `ESTRATEGY_SHARES_METADATA_MISMATCH`: BaseStrategy shares metadata does not match asset metadata.
* `ESTRATEGY_WITNESS_MISMATCH`: BaseStrategy witness does not match the provided witness.
* `EINVALID_SHARES_FACTORS`: Invalid shares conversion factors.
* `EVAULT_INSUFFICIENT_ASSETS`: Insufficient vault assets.
* `EINVALID_DEBT_AMOUNT`: Invalid amount of debt to take.
* `EINVALID_REPORT_TIME`: Invalid report time.
* `EWITHDRAWAL_ACCOUNT_MISMATCH`: Withdrawal account mismatch.
* `EASSET_STORE_ALREADY_EXISTS`: Asset store already exists.
* `EASSET_STORE_DOES_NOT_EXISTS`: Asset store does not exists.
* `EINVALID_AMOUNT`: Invalid amount.
* `EINVARIANT_VIOLATION`: Total withdrawn does not match the expected amount.
* `ETOO_MUCH_LOSS`: Too much loss.
* `EINVALID_LOCK_DURATION`: Invalid lock duration.
* `ECANNOT_SWEEP_BASE_ASSET`: Can not sweep base asset.
* `ECANNOT_SWEEP_ASSOCIATED_ASSET`: Can not sweep asset associated with vault.

## Functions

**Initialization**

* `initialize(account: &signer)`: Initializes the registry. Can only be called by the governance account. Emits `RegistryInitialized` event.

**Vault Management**

* `create(account: &signer, deposit_limit: Option<u64>, total_debt_limit: Option<u64>, base_metadata: Object<Metadata>): Object<Vault>`: Creates a new vault with specified parameters. Can only be called by the governance account. Emits `VaultCreated` event.
* `pause(account: &signer, vault: Object<Vault>)`: Pauses a vault, preventing deposits but allowing withdrawals. Can only be called by the governance account. Emits `VaultPaused` event.
* `unpause(account: &signer, vault: Object<Vault>)`: Unpauses a vault, allowing deposits again. Can only be called by the governance account. Emits `VaultUnpaused` event.
* `set_deposit_limit(account: &signer, vault: Object<Vault>, deposit_limit: Option<u64>)`: Sets the deposit limit for a vault. Can only be called by the governance account. Emits `SetDepositLimit` event.
* `set_performance_fee(account: &signer, vault: Object<Vault>, fee: Option<u64>)`: Sets the performance fee for a vault. Can only be called by the governance account. Emits `SetPerformanceFee` event.
* `set_management_fee(account: &signer, vault: Object<Vault>, fee: Option<u64>)`: Sets the management fee for a vault. Can only be called by the governance account. Emits `SetManagementFee` event.
* `set_lock_duration(account: &signer, vault: Object<Vault>, duration: u64):` Sets the lock duration for a vault. Can only be called by the governance account. Emits `SetLockDuration` event.

**Deposits and Withdrawals**

* `deposit(vault: Object<Vault>, asset: FungibleAsset): FungibleAsset`: Deposits assets into the vault, minting shares for the depositor. Emits `Deposit` event.
* `initialize_withdrawal(account: &signer, vault: Object<Vault>, shares_asset: FungibleAsset): WithdrawalRequest`: Initializes a withdrawal request by specifying the shares to burn.
* `withdraw(account: &signer, request: &mut WithdrawalRequest)`: Processes a withdrawal request by burning shares and preparing assets for withdrawal.
* `complete_withdrawal(account: &signer, request: WithdrawalRequest, max_loss: Option<u64>): FungibleAsset`: Completes a withdrawal request and returns the withdrawn assets. Emits `Withdraw` event.
* `complete_withdrawal_coin<C>( account: &signer, request: WithdrawalRequest, max_loss: Option<u64> ): Coin<C>:` Completes a withdrawal request and returns the withdrawn coin.
* `report(account: &signer, vault: Object<Vault>, strategy: Object<BaseStrategy>): (u64, u64):`This function is called by the strategy to report its performance and collect fees. Returns two values indicating profit and loss.

**Strategy Management**

* `add_strategy(account: &signer, vault: Object<Vault>, strategy: Object<BaseStrategy>, debt_limit: u64)`: Adds a strategy to the vault. Can only be called by the governance account. Emits `StrategyAdded` event.
* `remove_strategy(account: &signer, vault: Object<Vault>, strategy: Object<BaseStrategy>, force: bool)`: Removes a strategy from the vault. Can only be called by the governance account. Emits `StrategyRemoved` event.
* `update_strategy_debt_limit(account: &signer, vault: Object<Vault>, strategy: Object<BaseStrategy>, debt_limit: u64)`: Updates the debt limit for a strategy. Can only be called by the governance account.
* `sweep( account: &signer, vault: Object, metadata: Object, amount: u64 ):` Sweeps a specified amount of a fungible asset from the vault to the governance address. Can only be called by the governance account.

**Debt Management**

* `create_debt_fa(account: &signer, vault: Object<Vault>, auth_ref: &AuthRef, amount: u64): FungibleAsset`: Creates debt for a strategy by transferring assets from the vault to the strategy. Can only be called by the governance account.
* `create_debt_coin<C>(account: &signer, vault: Object<Vault>, auth_ref: &AuthRef, amount: u64): Coin<C>`: Creates debt for a strategy by transferring coins from the vault to the strategy. Can only be called by the governance account.

**Strategy Shares Management**

* `deposit_strategy_shares(vault: Object<Vault>, strategy: Object<BaseStrategy>, asset: FungibleAsset)`: Deposits strategy shares into the vault. Emits `StrategySharesDeposit` event.
* `withdraw_strategy_shares<T>(vault: Object<Vault>, auth_ref: &AuthRef, amount: u64, _: &T): FungibleAsset`: Withdraws strategy shares from the vault. Emits `StrategySharesWithdraw` event.

**Withdrawal Processing**

* `apply_strategy_withdrawal(request: &mut WithdrawalRequest, strategy: Object<BaseStrategy>, asset: FungibleAsset)`: Applies a strategy withdrawal to the withdrawal request.
* `apply_strategy_loss(request: &mut WithdrawalRequest, strategy: Object<BaseStrategy>, amount: u64)`: Applies a strategy loss to the withdrawal request.
* `add_debt_offset(request: &mut WithdrawalRequest, strategy: Object<BaseStrategy>, amount: u64)`: Adds a debt offset for a strategy in the withdrawal request.
* `withdrawn_amount(request: &WithdrawalRequest): u64`: Retrieves the total amount withdrawn in the request.
* `withdrawn_asset(request: &WithdrawalRequest): &FungibleAsset`: Retrieves the asset withdrawn in the request.

**Helpers**

* `get_total_assets(vault: &Vault): u64:` Retrieves total assets (idle + debs).
* `convert_amount_to_shares(vault: &Vault, amount: u64): u64`: Converts an amount of base assets to vault shares.
* `convert_shares_to_amount(vault: &Vault, shares: u64): u64`: Converts vault shares back to base asset amount.
* `get_total_shares(vault: &Vault): u128:`Returns the total supply of shares issued by the vault. If no shares exist, returns 0.
* `get_locked_profit(vault: &Vault): u64:`Calculates the amount of profit currently locked in the vault based on the lock duration and time elapsed since last report. Returns 0 if vault is paused or lock period has expired.
* `get_free_funds(vault: &Vault): u64:`Calculates the total available funds in the vault by subtracting locked profits from total assets. Returns 0 if locked profits exceed total assets.
* `max_deposit(vault: &Vault): u64:`Calculates the maximum amount that can be deposited into the vault based on deposit limit and current total assets. Returns maximum u64 minus total assets if no limit is set.
* `withdrawal_amount(request: &WithdrawalRequest): u64:`Returns the total amount of assets requested for withdrawal.
* `withdrawal_remaining(request: &WithdrawalRequest): u64:`Returns the remaining amount of assets yet to be withdrawn.
* `withdrawal_account(request: &WithdrawalRequest): address:`Returns the address of the account that initiated the withdrawal request.
* `withdrawal_vault(request: &WithdrawalRequest): Object<Vault>:`Returns the vault object associated with the withdrawal request.
* `withdrawal_to_burn(request: &WithdrawalRequest): &FungibleAsset:`Returns a reference to the shares asset that will be burned during withdrawal.
* `withdrawal_withdrawn(request: &WithdrawalRequest): &FungibleAsset:`Returns a reference to the assets that have been withdrawn so far.
* `withdrawal_debt_offsets(request: &WithdrawalRequest): &SimpleMap<Object<BaseStrategy>, u64> :`Returns a reference to the map of strategy debt offsets made during withdrawal.
* `withdrawal_losses(request: &WithdrawalRequest): &SimpleMap<Object<BaseStrategy>, u64>:`Returns a reference to the map of losses realized by strategies during withdrawal.
* `get_signer_for_router(vault: Object<Vault>, ref: &RouterRef): signer :` Generates a signer for router operations after validating the router reference. Only authorized routers can obtain a signer.

### **View Functions**

1. **Vault Information**
   * `vaults(): vector<Object<Vault>>`: Retrieves all vaults registered in the protocol.
   * `base_metadata(vault: Object<Vault>): Object<Metadata>`:  Retrieves the base asset metadata of the vault
   * `shares_metadata(vault: Object<Vault>): Object<Metadata>:` Retrieves the shares asset metadata of the vault
   * `total_debt_limit(vault: Object<Vault>): Option<u64>:` Retrieves the total debt limit of the vault (if set)
   * `total_idle(vault: Object<Vault>): u64`: Retrieves the total idle assets in a vault.
   * `total_debt(vault: Object<Vault>): u64`: Retrieves the total debt of a vault.
   * `total_assets(vault: Object<Vault>): u64`: Retrieves the total assets managed by a vault.
   * `total_shares(vault: Object<Vault>): u64`: Retrieves the total shares issued by a vault.
   * `is_paused(vault: Object<Vault>): bool`: Checks if a vault is paused.
   * `deposit_limit(vault: Object<Vault>): Option<u64>`: Retrieves the deposit limit of a vault.
   * `manager(vault: Object<Vault>): address`: Retrieves the manager address of a vault.
   * `lock_duration(vault: Object<Vault>): u64:` Retrieves the lock duration for profits
   * `total_locked(vault: Object<Vault>): u64: Retrieves`the total amount of locked profits
   * `performance_fee(vault: Object<Vault>): u64:` Retrieves the performance fee of the vault.
   * `management_fee(vault: Object<Vault>): u64:` Retrieves the management fee of the vault.
2. **Strategy Information**
   * `strategies(): vector<Object<BaseStrategy>>`: Retrieves all strategies registered in the protocol.
   * `vault_strategies(vault: Object<Vault>): vector<Object<BaseStrategy>>`: Retrieves all strategies associated with a vault.
   * `strategy_debt(vault: Object<Vault>, strategy: Object<BaseStrategy>): u64`: Retrieves the current debt of a strategy in a vault.
   * `get_strategy_shares_balance(vault: Object<Vault>, strategy: Object<BaseStrategy>): u64`: Retrieves the balance of strategy shares held by the vault.
   * `strategy_total_loss(vault: Object, strategy: Object): u64:` Retrieves the total loss incurred by a strategy
   * `strategy_total_profit(vault: Object, strategy: Object): u64:` Retrieves the total profit generated by a strategy
   * `strategy_last_report(vault: Object, strategy: Object): u64:` Retrieves the timestamp of the last report from a strategy
   * `strategy_debt_limit(vault: Object, strategy: Object): u64:` Retrieves the debt limit set for a strategy

#### Internal Functions

* `deposit_internal(vault: Object<Vault>, asset: FungibleAsset): FungibleAsset:` Handles the core deposit logic - adds assets to vault's idle balance and mints corresponding shares.
* `create_shares_asset(vault_signer: &signer, base_metadata: Object<`Metadata>`): Object<`Metadata>`:` Creates a new shares token for the vault with "vs" prefix (e.g. vsBTC) based on the base asset metadata.
* `get_strategy_returns(vault: Object<`Vault>`, strategy: Object<BaseStrategy>): (u64, u64)` Calculates a strategy's profit or loss by comparing current assets to debt.
* `assess_fee(vault: Object<Vault>, strategy: Object<Vault>, profit: u64): (u64, u64):` Calculates management and performance fees based on strategy performance and time elapsed.
* `handle_loss(vault: Object<Vault, strategy: Object<BaseStrategy>, loss: u64):` Updates vault and strategy state to account for realized losses.
* `handle_profit(vault: Object<Vault, strategy: Object<BaseStrategy>, profit: u64):`Updates vault and strategy state to account for realized profits.
* `create_debt_internal(account: &signer, vault: Object<Vault>, auth_ref: &AuthRef, amount: u64):` Core logic for creating new strategy debt - validates limits and updates vault/strategy debt tracking.
* `create_internal( constructor_ref: &ConstructorRef, manager: address, deposit_limit: Option<u64>, total_debt_limit: Option<u64>, base_metadata: Object<Metadata>, shares_metadata: Object<Metadata>): (Vault, VaultController)` Initializes a new vault with given parameters and creates required controller objects.
* `is_signer_authorized(account: &signer, vault: Object<Vault>): bool:` Checks if an account has permission to perform privileged vault operations.

## Access Control

* **Governance Only**: Certain functions are restricted to the governance account, such as initializing the registry, creating vaults, pausing/unpausing vaults, setting deposit limits, setting protocol fees, adding/removing strategies, updating strategy debt limits, and creating debts.
* **Governance or Manager**: Functions that can be performed by either the governance account or the vault manager.
* **Friend Functions**: The `satay::satay` and `satay::vault_tests` modules are friends of `satay::vault`, giving them access to certain internal protocol functions.&#x20;
