syntax = "proto3";
package provlabs.vault.v1;

import "cosmos/auth/v1beta1/auth.proto";
import "cosmos/base/v1beta1/coin.proto";
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";

option go_package = "github.com/provlabs/vault/types";

// VaultAccount represents a central holding place for assets, governed by a set of rules.
// It is based on the ERC-4626 standard and builds upon the Provenance Marker module.
message VaultAccount {
  // base_account cosmos account information including address and coin holdings.
  cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true];

  // total_shares is the total number of shares that have ever been issued by the vault.
  // It serves as the canonical supply-of-record for all shares, regardless of whether
  // they are held locally on Provenance or externally (e.g., bridged).
  cosmos.base.v1beta1.Coin total_shares = 2 [(gogoproto.nullable) = false];

  // underlying_asset is the vault’s single principal collateral AND valuation/base unit.
  // - Exactly one denom.
  // - Total Vault Value (TVV) and NAV-per-share are computed and reported in this denom.
  // - Interest accrual, fees, and internal accounting are measured in this denom.
  // - Held assets acquired via settlement must have an internal NAV record priced INTO this denom.
  string underlying_asset = 3;

  // payment_denom always equals underlying_asset. Vaults are single-denom; the
  // field is inert and retained only for wire compatibility.
  //
  // Deprecated: The mixed-denom vault concept has been flattened into a single
  // underlying denom. Deletion of this field is deferred to a future major release.
  string payment_denom = 4 [deprecated = true];

  // admin is the address that has administrative privileges over the vault.
  string admin = 5 [(cosmos_proto.scalar) = "cosmos.AddressString"];

  // current_interest_rate is a decimal string (e.g., "0.9" for 90% and "0.9001353" for 90.01353%) representing the actual annual interest rate currently being applied.
  // This may be adjusted programmatically (e.g., due to lack of funds).
  string current_interest_rate = 6 [(cosmos_proto.scalar) = "cosmos.DecString"];

  // desired_interest_rate is a decimal string (e.g., "0.9" for 90% and "0.9001353" for 90.01353%) representing the target annual interest rate that the vault intends to apply.
  string desired_interest_rate = 7 [(cosmos_proto.scalar) = "cosmos.DecString"];

  // min_interest_rate is a decimal string (e.g., "0.9" for 90% and "0.9001353" for 90.01353%) representing the lowest annual interest rate the admin is allowed to set.
  // If unset (empty string), there is no lower limit.
  string min_interest_rate = 8 [(cosmos_proto.scalar) = "cosmos.DecString"];

  // max_interest_rate is a decimal string (e.g., "0.9" for 90% and "0.9001353" for 90.01353%) representing the highest annual interest rate the admin is allowed to set.
  // If unset (empty string), there is no upper limit.
  string max_interest_rate = 9 [(cosmos_proto.scalar) = "cosmos.DecString"];

  // The start time (in Unix seconds) of the current interest accrual period.
  int64 period_start = 10;

  // The expire time (in Unix seconds) of the current interest accrual period.
  int64 period_timeout = 11;

  // swap_in_enabled indicates whether users are allowed to deposit into the vault.
  bool swap_in_enabled = 12;

  // swap_out_enabled indicates whether users are allowed to withdraw from the vault.
  bool swap_out_enabled = 13;

  // withdrawal_delay_seconds is the configured time period (in seconds) that a withdrawal
  // request must wait in the pending queue before being processed.
  uint64 withdrawal_delay_seconds = 14;

  // paused indicates that all user-facing swap-in and swap-out operations are disabled.
  bool paused = 15;

  // paused_balance is the total vault value snapshot taken at the moment of pausing.
  // This value is used for all NAV calculations while the vault is paused to prevent
  // apparent devaluation during collateral rebalancing. It is cleared upon unpausing.
  // Nothing done during the pause moves it, neither a principal deposit or withdrawal
  // nor a NAV repricing; those all take effect together when the vault is unpaused.
  cosmos.base.v1beta1.Coin paused_balance = 16 [(gogoproto.nullable) = false];

  // paused_reason is a human-readable string explaining why the vault was paused, particularly for automatic pauses.
  string paused_reason = 17;

  // bridge_address is the single external address allowed to mint or burn shares on behalf
  // of this vault (e.g., for bridging to another chain). All mint/burn must flow through the
  // vault keeper, which enforces that marker supply never exceeds total_shares.
  string bridge_address = 18 [(cosmos_proto.scalar) = "cosmos.AddressString"];

  // bridge_enabled indicates whether the bridge functionality is active. If false, the
  // bridge_address has no effect and cannot mint or burn.
  bool bridge_enabled = 19;

  // asset_manager is an optional address that, when set, is authorized to manage certain
  // collateral operations alongside the admin (e.g., pausing/unpausing, depositing/withdrawing
  // principal or interest funds). If unset (empty string), only the admin may perform those actions.
  string asset_manager = 20 [(cosmos_proto.scalar) = "cosmos.AddressString"];

  // fee_period_start is the start time (in Unix seconds) of the current AUM fee collection period.
  // This is a module-managed timestamp kept in sync with the fee timeout queue machinery.
  int64 fee_period_start = 21;

  // fee_period_timeout is the end time (in Unix seconds) of the current AUM fee collection period.
  // This is a module-managed timestamp kept in sync with the fee timeout queue machinery.
  int64 fee_period_timeout = 22;

  // outstanding_aum_fee is the amount of AUM fee that has been calculated but not yet collected
  // due to insufficient liquidity in the principal marker. This amount is always denominated
  // in the vault's underlying_asset, must be preserved, and is carried into valuation computations.
  cosmos.base.v1beta1.Coin outstanding_aum_fee = 23 [(gogoproto.nullable) = false];

  // aum_fee_bips is the AUM fee rate (in basis points) for this specific vault.
  // Units: Basis Points (1 bps = 0.01%).
  // Valid Range: 0 to 10000 (0% to 100%).
  // A value of 0 disables AUM fee collection for this vault.
  // Negative values are not supported (uint32).
  uint32 aum_fee_bips = 24;

  // min_swap_in_value is a string representing the minimum value required for a deposit.
  // - The value is measured in the underlying_asset.
  // - Values must be non-negative (>= 0).
  // - If empty ("") or "0", there is no minimum limit.
  string min_swap_in_value = 25 [(cosmos_proto.scalar) = "cosmos.IntString"];

  // min_swap_out_value is a string representing the minimum value required for a withdrawal.
  // - The value is measured in the underlying_asset.
  // - Outgoing redemptions are converted to this unit before checking.
  // - Values must be non-negative (>= 0).
  // - If empty ("") or "0", there is no minimum limit.
  string min_swap_out_value = 26 [(cosmos_proto.scalar) = "cosmos.IntString"];

  // max_swap_in_value is a string representing the maximum value allowed for a deposit.
  // - The value is measured in the underlying_asset.
  // - Values must be positive (> 0).
  // - An empty string "" indicates no maximum limit.
  string max_swap_in_value = 27 [(cosmos_proto.scalar) = "cosmos.IntString"];

  // max_swap_out_value is a string representing the maximum value allowed for a withdrawal.
  // - The value is measured in the underlying_asset.
  // - Outgoing redemptions are converted to this unit before checking.
  // - Values must be positive (> 0).
  // - An empty string "" indicates no maximum limit.
  string max_swap_out_value = 28 [(cosmos_proto.scalar) = "cosmos.IntString"];

  // nav_authority is the address authorized to mutate this vault's internal NAV
  // table via MsgUpdateVaultNAV. If empty, the vault admin is treated as the NAV
  // authority. It is rotated only via MsgUpdateNAVAuthority.
  string nav_authority = 29 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// VaultNAV is a single internal net asset value entry recording the price of one
// asset denom held by a vault. The vault module is the sole source of truth for
// these values; the NAV authority maintains them via MsgUpdateVaultNAV.
message VaultNAV {
  // denom is the asset denomination this entry prices.
  string denom = 1;
  // price is the total value of `volume` units of the denom, denominated in the
  // vault's underlying asset. The per-unit value is price divided by volume.
  cosmos.base.v1beta1.Coin price = 2 [(gogoproto.nullable) = false];
  // volume is the number of units of the denom that price covers. It must be
  // positive; the per-unit value of the denom is price divided by volume.
  string volume = 3 [
    (cosmos_proto.scalar) = "cosmos.Int",
    (gogoproto.customtype) = "cosmossdk.io/math.Int",
    (gogoproto.nullable) = false
  ];
  // source identifies the origin of this NAV entry (for example an oracle name
  // or the settlement path), mirroring the Marker module's NAV source attribution.
  string source = 4;
  // updated_block_height is the block height at which this entry was last updated.
  int64 updated_block_height = 5;
  // updated_time is the block time at which this entry was last updated.
  google.protobuf.Timestamp updated_time = 6 [
    (gogoproto.stdtime) = true,
    (gogoproto.nullable) = false
  ];
}

// AccountBalance represents the coin balance of a single account.
message AccountBalance {
  option (gogoproto.equal) = false;
  option (gogoproto.goproto_getters) = false;

  // address is the account address.
  string address = 1;

  // coins is the balance of the account.
  repeated cosmos.base.v1beta1.Coin coins = 2 [
    (gogoproto.nullable) = false,
    (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
  ];
}

// PendingSwapOut are swap outs that have not yet been processed and completed.
message PendingSwapOut {
  // owner is the address initiating the swap out.
  string owner = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

  // vault_address is the address of the vault processing the withdrawal.
  string vault_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];

  // shares are the shares that were escrowed by the user.
  cosmos.base.v1beta1.Coin shares = 3 [(gogoproto.nullable) = false];

  // redeem_denom is the denomination of the asset to be redeemed. Always the
  // vault's underlying_asset; retained for wire compatibility.
  string redeem_denom = 4 [deprecated = true];

  // failure_count is the number of consecutive failed processing attempts that
  // left this request queued. Each failure re-keys the request to a later retry
  // time so it cannot hold the front of the queue. Reset when expedited.
  uint32 failure_count = 5;
}
