# Definitions

- Staking Token: The SPL Token users stake to receive rewards.
- Reward Token: The SPL Token users receive in exchange for staking.
- Reward Unit: The base unit for pro-rated distribution of reward tokens.
- Epoch: A time period for staking.
- Stakers: Users that stake tokens into the program for rewards.

# Data Structures

## StakePool

Each StakePool is associated to one staking token. StakePool maintains a clock used by other data strcutures and instructions to determine reward emission via `current_epoch`, `epoch_duration` and `next_epoch_start_time`. StakePool also records the `total_reward_units`, which is the sum of all reward units for stakers in the StakePool. StakePool also stores `inactive_epoch_vec` and `starting_epoch_vec`, which are vectors containing the epoch in which associated RewardPool starts or becomes inactive.

## RewardPool

Each RewardPool is associated to one reward token that will be distributed to stakers, and a StakePool. Each StakePool can have multiple RewardPool distributing the same reward token. A RewardPool records the distribution strategy and amount to emit per epoch, as well as the current state of the RewardPool - whether it's active and which epoch it should start emitting rewards in.

Each RewardPool owns two token accounts - a `reward_token_account` storing reward tokens yet to be allocated for distribution, and a `allocated_token_account` storing reward tokens that are allocated and yet to be claimed.

## RewardRecord

Each epoch, a RewardRecord will be created for a RewardPool that has started and is not inactive. RewardRecord is associated to a RewardPool, and thereby a StakePool. Each RewardRecord stores the amount of tokens to be distributed for that epoch, per reward unit, in `epoch_reward`, and the cummulative amount of `epoch_reward` since the first RewardRecord.

## StakingRecord

To participate in staking, a user has to create one StakingRecord for every StakePool they would like to stake in. StakingRecord stores the reward units, amount of tokens stakedm lockup period expiry timestamp and a vector of the last epoch in which each RewardPool was claimed for.

# Roles and Responsibilites of Users.

## StakePool Operators

StakePool operators will be responsible for creating StakePools with `create_stake_pool` , and RewardPools with the `create_reward_pool` instructions. At time of initialization, they will be responsible for determining the start time of the StakePool, epoch duration, and which epoch should a RewardPool start in, as well as the initial distribution strategy. They will also determine the fidelity of epoch rewards with `epoch_reward_decimals`.

## Reward Providers (reward_pool_authority)

Reward providers will provide incentives for staking a particular token by transferring tokens directly to the `reward_token_account` of a RewardPool. If the reward provider is given access to the `reward_pool_authority` private key, they can also dictate on the reward distribution strategy with the `update_reward_pool` instruction.

Reward providers can also choose to wind-down a RewardPool by turning it inactive, or increment the reward rate by transferring more tokens into the `reward_token_account` and changing the distribution strategy.

## Permissionless Cranks

Cranks are responsible for maintaining the state of the program by calling `update_stake_pool_epoch` every epoch to increment the epoch number on StakePool, `create_reward_record` to create a new RewardRecord for each active RewardPool every epoch and `update_reward_record` to recompute the `epoch_reward` as the `total_reward_units` of a StakePool changes during an epoch when users stake and unstake their tokens.

## Stakers

Stakers will invoke `create_staking_record` to initialize a StakingRecord to participate in a StakePool, `stake_token` to stake their tokens with the desired lock-up period, and `unstake_token` when the lock-up period has ended. They can also call `claim_reward` to redeem RewardTokens after each epoch has passed.

## PsyFi Vault Program

The Vault Program is authorized to invoke `claim_reward_by_vault` to claim reward tokens for a staker to be transferred to staker-owned associated token account, and `stake_by_vault` to stake tokens on behalf of a staker, to be recorded in their StakingRecord.

# Limitations

- Since `total_reward_units` will include both reward units that are eligible to claim for the current epoch and reward units that are ineligible, `epoch_reward`, which is calculated based on that, will not be precise.
  - This will result in a lower `epoch_reward` (reward token per reward unit), resulting in current participants being able to claim less tokens than what they might have expected.
- If `RewardRecord` is not created for an epoch that has passed, then users would not be able to stake additional tokens or unstake from Vault, since staking or unstaking requires all eligible rewards to be claimed.
- Max. number of RewardPool constrained by size of `last_epoch_claimed_vec`.
- Since `current_epoch` is a `u16` with max value of 65536, the minimum allowed epoch duration is 4 hours to enable 30 year equivalent of epochs to be recorded.
- Once a RewardPool is inactive, it will not be allowed to be switched back to active again as RewardRecords for the intermediary epochs would not have been created.
- Reward multipliers and lock up periods are fixed at the program level.
- Since `cummulative_reward` is of size `u64`, there is a need to pre plan how large `epoch_decimals` should be or it will reach the max limit very quickly.
  For instance:
  - If each epoch last for a day, and a RewardPool is intended to last for 3 years at least, then each `epoch_reward` should be less than `(2^64 / 1000) = 1.8e16`.
    - If `epoch_decimals` is 10, then the ratio of emissions per day to reward units must not be more than `1.8e6`.
- Worst case scenario, one can always start a new RewardPool and deprecate the existing one, under the same StakePool.
