# Program Architecture

## Data Schema

### VaultAccount

Each Vault operated by PsyFinance is defined within a `VaultAccount` struct,
and has a PDA public key, derived from the Vault's strategy type, unique seed
and asset mint keys.

Specifically, a unique seed is used to generate vault PDAs that could take on
the same asset and strategy types. This enables flexibility in having vaults
operating the same stratregy at different risk levels or tenors.

The `VaultAccount` struct stores public keys of the various system roles,
`VaultAccount` owned token accounts, token account mints, public keys of on-chain
program dependencies, and current parameters and state of the Vault.

Each account passed in the instruction set
is compared to the accounts recorded in `VaultAccount` whenever possible, as
`VaultAccount` serves as the source of truth for the Vault.

### EpochHistory

The Vault operates in time periods called epochs, starting from 1 and incrementing by
1 at the end of each period. An epoch starts right after the previous epoch ends,
and ends when PsyOptions options expire and assets eld in the Tokenized Euro program
has been withdrawn back to the PsyFi Program.

The public key of an `EpochHistory` is a PDA derived from the epoch
number and `VaultAccount`. This guarantees that there can only be one `EpochHistory`
for every epoch of a Vault.

`EpochHistory` stores a vector of `OptionMarketMeta` that contains information specific
to each option market that is Vault partakes in during that epoch. This enables options
for multiple EuroMeta to be minted within the same epoch. `OptionMarketMeta` are stores
`OptionTokenSaleMarket` which is used for configuring sale prices for OTC options trade
(currently not supported by the program).

However, as of writing, we are limiting to only 1 OptionMarketMeta per epoch to simplify
implementation of the program.

Lastly, `EpochHistory` also records the state of the epoch, including
the amount of collateral asset remaining for each Vault ownership
token, at the end of an epoch. This enables payout for `WithdrawalReceipt` after epoch ends.

### Vault Ownership Token

Ownership of the Vault is represented by the Vault token, which will be proportional
to the amount of funds deposited into the Vault, and the amount of assets held by the
Vault at the time of deposit.

As Vault tokens follows the SPL Token standard, it is fungible and transferable
among users, enabling trading outside of the confinements of the Vault program.

---

## System Roles

There are three system roles, `VaultOwner`, `VaultManager` and `VaultTasker`.

- `VaultOwner` is a multisig that is authorized to modify the vault parameters such as the fee structure.
- `VaultManager` is a multisig that is authorized to set option sale markets (currently not supported),
  modify options sale allowlist and mint options.
  and will also be a multisig key for the mainnet program.
- `VaultTasker` is a regular keypair and is authorized to execute lower risk
  instruction sets including all Serum instuctions, closing of epoch and payout of receipts. Instructions approved for `VaultTasker` is intended to be executed programmatically.

---

## Deposit and Withdrawals

A user interacts with the Vault by depositing a collateral asset or withdrawing
Vault tokens. A user can perform regular deposits or withdrawal anytime during an
epoch before options are minted.

Once options are minted, a user will have to create a `DepositReceipt` or `WithdrawalReceipt`,
which are accounts recording the amount of tokens a user intends to deposit or
withdraw from the Vault, starting from the next epoch. `DepositReceipt` and `WithdrawalReceipt`
are accounts owned by the program, but has a PDA derived from the user's wallet
address, vault account key and epoch number.

Once a `DepositReceipt` or `WithdrawalReceipt` is created, further deposits or withdrawals
during the epoch will be recorded in the receipt.

At the end of the epoch, the amount of collateral held in the vault will be tallied and
the value in collateral asset for each Vault token will be calculated. Since the amount of pending
deposits is recorded in `VaultAccount`, Vault tokens for the pending deposits will be minted and stored in the `vault_ownership_token_account`.

Similarly, collateral proportional to the amount of Vault tokens to be withdrawn will be
set aside in the `withdrawal_collateral_asset_account` owned by the program. Vault tokens
pending for withdrawal will be burned when the epoch ends.

After the epoch, users will be paid Vault tokens or Collateral asset for pending
deposits or withdrawals respectively via the `payout_deposit_receipt` and \
`payout_withdrawal_receipt` instructions, that will be invoked by a crank operated and signed by `VaultTasker`. The exact amount paid out will be calculated using the `ending_collateral_per_vault_token`
recorded in `EpochHistory`.

In addition, users can withdraw from their `DepositReceipt` or `WithdrawalReceipt` in the same
epoch as when they were created, should they change their minds about depositing or withdrawing.
This is handled by the `transfer_from_deposit_receipt` and `transfer_from_withdrawal_receipt`
instructions.

---

## Fee Structure

Each Vault has three parameters - `management_fee_bps`, `performance_fee_bps` and
`withdrawal_fee_bps` which controls the amount of fees charged by the Vault. These
parameters are only modifiable by the VaultOwner.

`management_fee_bps` is applied to the total collateral assets at the end of an
epoch, excluding pending deposits and option yield.

`performance_fee_bps` is applied to the yield generated from option sale during
the epoch.

`withdrawal_fee_bps` is applied to collateral withdrawn in `withdraw` and
`payout_withdrawal_receipt` instructions.

---

## Mint Options

Options are minted with `mint_options` instruction. Prior to invoking this, two token accounts,
`writer_token_account` and `option_token_account` will have to be preinitialized, with owner
set as the `vault_authority` - an address derived from the vault_account.

`vault_authority` is
neccessary as 1) Serum does not allow a PDA storing data to be used as authority over it's account,
and 2) authority of these token accounts have to match Serum `OpenOrders` authority.

--

## Options Sale

Once options are minted via the Tokenized Euro program, they will be sold through a Serum
market that will be intialized outside of this program.

The `VaultTasker` will be responsible for initializing a Serum OpenOrders account
(required for every participant in a Serum Market), place a Serum ask order with a
limit price determined off-chain and settle the Serum order when it is fulfilled,
to retrieve the options yield.

A Serum order can also be cancelled using the `cancel_serum_order` instruction, and
have the option tokens be transfered back to the Vault via a subsequent
`settle_serum_order` instruction.

Note that each order requires a `client_order_id`. Since this id is not recorded in the
Vault program schema, it should be fixed to a standard id (e.g. 999) so it can be
referred to easily. `client_order_id` is used only for order cancel.
