Files
staking-reward-streamer/docs/MathSpec.md
Filip Pajic 1f9e9f678c docs: minor latex and typo fixes
* MPMaximum Latex syntax fix

* Update T_RATE to reflect block time on SN Sepolia

* Pending Latex syntax fix

* Global Reward Latex syntax fix

* NewIndex Latex syntax fix

* reward example value typo fix

* format MathSpec table

* explicitly state T_RATE is chain dependent value
2025-08-19 12:55:55 +02:00

1065 lines
30 KiB
Markdown

## Table of Contents
## Mathematical Specification of Staking Protocol
<!-- prettier-ignore -->
> [!IMPORTANT]
> All values in this document are expressed as unsigned integers.
### Summary
### Constants
| Symbol | Source | Value | Unit | Description |
| --------------------------- | ----------------------------------------------------------------------- | ----------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------- |
| $SCALE_{FACTOR}$ | | $\pu{1 \times 10^{18}}$ | (1) | Scaling factor to maintain precision in calculations. |
| $M_{MAX}$ | | $\pu{4 \mathrm{(1)}}$ | (1) | Maximum multiplier of annual percentage yield. |
| $\mathtt{APY}$ | | 100 | percent | Annual percentage yield for multiplier points. |
| $\mathsf{MPY}$ | $M_{MAX} \times \mathtt{APY}$ | 400 | percent | Multiplier points accrued maximum percentage yield. |
| $\mathsf{MPY}^\mathit{abs}$ | $100 + (2 \times M_{\text{MAX}} \times \mathtt{APY})$ | 900 | percent | Multiplier points absolute maximum percentage yield. |
| $T_{RATE}$ | (minimal blocktime) | 2 (chain dependent) | seconds | The accrue rate period of time over which multiplier points are calculated. |
| $T_{DAY}$ | | 86400 | seconds | One day. |
| $T_{YEAR}$ | $\lfloor365.242190 \times T_{DAY}\rfloor$ | 31556925 | seconds | One (mean) tropical year. |
| $A_{MIN}$ | $\lceil\tfrac{T_{YEAR} \times 100}{T_{RATE} \times \mathtt{APY}}\rceil$ | 2629744 | tokens per period | Minimal value to generate 1 multiplier point in the accrue rate period ($T_{RATE}$). ($A_{MIN} \propto T_{RATE}$) |
| $A_{MAX}$ | $\frac{2^{256} - 1}{\text{APY} \times T_{\text{RATE}}}$ | | tokens per period | Maximum value to not overflow unsigned integer of 256 bits. |
| $T_{MIN}$ | $90 \times T_{DAY}$ | 7776000 | seconds | Minimum lockup period, equivalent to 90 days. |
| $T_{MAX}$ | $M_{MAX} \times T_{YEAR}$ | 126227700 | seconds | Maximum of lockup period. |
### Variables
#### System and User Parameters
##### $\Delta a\rightarrow$ Amount Difference
Difference in amount, can be either reduced or increased depending on context.
---
##### $\Delta t\rightarrow$ Time Difference of Last Accrual
---
The time difference defined as:
$$
\Delta t = t_{now} - t_{last}, \quad \text{where} \Delta t > T_{RATE}
$$
---
##### $t_{lock}\rightarrow$ Time Lock Duration
A user-defined duration for which $a_{bal}$ remains locked.
---
##### $t_{now}\rightarrow$ Time Now
The current timestamp seconds since the Unix epoch (January 1, 1970).
---
##### $t_{lock, \Delta}\rightarrow$ Time Lock Remaining Duration
Seconds $a_{bal}$ remains locked, expressed as:
$$
\begin{align} &t_{lock, \Delta} = max(t_{lock,end},t_{now}) - t_{now} \\
\text{ where: }\quad & t_{lock, \Delta} = 0\text{ or }T_{MIN} \le t_{lock, \Delta} \le (M_{MAX} \times T_{YEAR})\end{align}
$$
---
#### State Related
##### $a_{bal}\rightarrow$ Amount of Balance
Amount of tokens in balance, where $a_{bal} \ge A_{MIN}$.
---
##### $t_{lock,end}\rightarrow$ Time Lock End
Timestamp marking the end of the lock period, its state can be defined as:
$$
t_{lock,end} = \max(t_{now}, t_{lock,end}) + t_{lock}
$$
The value of $t_{lock,end}$ can be updated only within the functions:
- $\mathcal{f}^{stake}(\mathbb{Acc}, \Delta a, \Delta t_{lock})$;
- $\mathcal{f}^{lock}(\mathbb{Acc}, \Delta t_{lock})$;
---
##### $t_{last}\rightarrow$ Time of Accrual
Timestamp of the last accrued time, its state can be defined as:
$$
t_{last} = t_{now}
$$
The value of $t_{last}$ is updated by all functions that change state:
- $f^{accrue}(\mathbb{Acc}, a_{bal},\Delta t)$,
- $\mathcal{f}^{stake}(\mathbb{Acc}, \Delta a, \Delta t_{lock})$;
- $\mathcal{f}^{lock}(\mathbb{Acc}, \Delta t_{lock})$;
- $\mathcal{f}^{unstake}(\mathbb{Acc}, \Delta a)$;
---
##### $mp_\mathcal{M}\rightarrow$ Maximum Multiplier Points
Maximum value that $mp_\Sigma$ can reach.
Relates as $mp_\mathcal{M} \propto a_{bal} \cdot (t_{lock} + \mathsf{MPY})$.
Altered by functions that change the account state:
- $\mathcal{f}^{stake}(\mathbb{Acc}, \Delta a, \Delta t_{lock})$;
- $\mathcal{f}^{lock}(\mathbb{Acc}, \Delta t_{lock})$;
- $\mathcal{f}^{unstake}(\mathbb{Acc}, \Delta a)$.
It's state can be expressed as the following state changes:
###### Increase in Balance and Lock
$$
\begin{aligned}
mp_\mathcal{M} &= mp_\mathcal{M} + mp_\mathcal{A}(\Delta a, M_{MAX} \times T_{YEAR}) \\
&\quad + mp_\mathcal{B}(\Delta a, t_{lock,\Delta} + t_{lock}) \\
&\quad + mp_\mathcal{B}(a_{bal}, t_{lock}) \\
&\quad + mp_\mathcal{I}(\Delta a)
\end{aligned}
$$
###### Increase in Balance only
$$
\begin{aligned}
mp_\mathcal{M} &= mp_\mathcal{M} + mp_\mathcal{A}(\Delta a, M_{MAX} \times T_{YEAR}) \\
&\quad + mp_\mathcal{B}(\Delta a, t_{lock,\Delta}) \\
&\quad + mp_\mathcal{I}(\Delta a)
\end{aligned}
$$
###### Increase in Lock only
$$
mp_\mathcal{M} = mp_\mathcal{M} + mp_\mathcal{B}(a_{bal}, t_{lock})
$$
###### Decrease in Balance
$$
mp_\mathcal{M} = mp_\mathcal{M} - mp_\mathcal{R}(mp_\mathcal{M}, a_{bal}, \Delta a)
$$
---
##### $mp_{\Sigma}\rightarrow$ Total Multiplier Points
Altered by all functions that change state:
- $\mathcal{f}^{stake}( \mathbb{Acc}, Delta a, t_{lock}) \longrightarrow$ Stake Amount With Lock
- $\mathcal{f}^{lock}(\mathbb{Acc}, t_{lock}) \longrightarrow$ Increase Lock;
- $\mathcal{f}^{unstake}( \mathbb{Acc}, Delta a)\longrightarrow$ Unstake Amount Unlocked;
- $\mathcal{f}^{accrue}(\mathbb{Acc}) \longrightarrow$ Accrue Multiplier Points.
The state can be expressed as the following state changes:
###### For every $T_{RATE}$
$$
mp_{\Sigma} = min(\mathcal{f}mp_\mathcal{A}(a_{bal},\Delta t), mp_\mathcal{M} - mp_\Sigma)
$$
###### Increase in Balance and Lock
$$
\begin{aligned}
mp_{\Sigma} &= mp_{\Sigma} + mp_\mathcal{B}(\Delta a, t_{lock, \Delta} + t_{lock}) \\
&\quad + mp_\mathcal{B}(a_{bal}, t_{lock}) \\
&\quad + mp_\mathcal{I}(\Delta a)
\end{aligned}
$$
###### Increase in Balance only
$$
mp_{\Sigma} = mp_{\Sigma} + mp_\mathcal{B}(\Delta a, t_{lock, \Delta}) + mp_\mathcal{I}(\Delta a)
$$
###### Increase in Lock only
$$
mp_{\Sigma} = mp_{\Sigma} + mp_\mathcal{B}(a_{bal}, t_{lock})
$$
###### Decrease in Balance
$$
mp_{\Sigma} = mp_{\Sigma} - mp_\mathcal{R}(mp_{\Sigma}, a_{bal}, \Delta a)
$$
---
##### $\mathbb{Acc}\rightarrow$ Account Storage Schema
Defined as following:
$$
\begin{gather}
\mathbb{Acc} \\
\overbrace{
\begin{align}
a_{bal} & : \text{balance}, \\
t_{lock,end} & : \text{lock end}, \\
t_{last} & : \text{last accrual}, \\
mp_\Sigma & : \text{total MPs}, \\
mp_\mathcal{M} & : \text{maximum MPs}
\end{align}
}
\end{gather}
$$
---
##### $\mathbb{Acc} \cdot W \rightarrow$ Account Weight
The **account weight** for an individual account $j$ combines its staked balance and accumulated Multiplier Points. This
weight determines the proportion of rewards the account is entitled to.
$$
\mathbb{Acc} \cdot W = \mathbb{Acc} \cdot a_{\text{bal}} + \mathbb{Acc} \cdot mp_{\Sigma}
$$
Where:
- $\mathbb{Acc} \cdot a_{\text{bal}}$: Staked balance of account $j$.
- $\mathbb{Acc} \cdot mp_{\Sigma}$: Total Multiplier Points of account $j$.
##### $\mathbb{System}\rightarrow$ System Storage Schema
Defined as following:
$$
\begin{gather}
\mathbb{Sys} \\
\overbrace{
\begin{align}
\mathbb{Acc}\mathrm{[]} & : \text{accounts}, \\
a_{bal} & : \text{total staked}, \\
mp_\Sigma & : \text{MP supply}, \\
mp_\mathcal{M} & : \text{MP supply max}
\end{align}
}
\end{gather}
$$
---
##### $\mathbb{Sys} \cdot W \rightarrow$ Total Weight
The **total weight** of the system is the aggregate of all staked tokens and Multiplier Points (MP) across all accounts.
It serves as the denominator in reward distribution calculations.
$$
\mathbb{Sys} \cdot W = \mathbb{Sys} \cdot a_{\text{bal}} + \mathbb{Sys} \cdot mp_{\Sigma}
$$
Where:
- $\mathbb{Sys} \cdot a_{\text{bal}}$: Total tokens staked in the system.
- $\mathbb{Sys} \cdot mp_{\Sigma}$: Total Multiplier Points accumulated in the system.
---
##### $R_i \rightarrow$ Cumulative Reward Index
The **reward index** represents the cumulative rewards distributed per unit of total weight (staked balance plus
Multiplier Points) in the system. It is a crucial component for calculating individual rewards.
$$
R_i = R_i + \left( \frac{R_{\text{new}} \times SCALE_{FACTOR}}{\mathbb{Sys} \cdot W} \right)
$$
Where:
- $R_{\text{new}}$: The amount of new rewards added to the system.
- $\mathbb{Sys} \cdot W$: The total weight in the system, calculated as the sum of all staked balances and total
Multiplier Points.
- $SCALE_{FACTOR}$: Scaling factor to maintain precision.
---
### Pure Mathematical Functions
<!-- prettier-ignore -->
> [!NOTE]
> This function definitions represent direct mathematical input -> output methods, which don't change state.
#### $\mathcal{f}{mp_\mathcal{I}}(\Delta a) \longrightarrow$ Initial Multiplier Points
Calculates the initial multiplier points based on the balance change $\Delta a$. The result is equal to the amount of
balance added.
$$
\boxed{
\begin{equation}
\mathcal{f}{mp_\mathcal{I}}(\Delta a) = \Delta a
\end{equation}
}
$$
Where
- **$\Delta a$**: Represents the change in balance.
---
#### $\mathcal{f}{mp_\mathcal{A}}(a_{bal}, \Delta t) \longrightarrow$ Accrue Multiplier Points
Calculates the accrued multiplier points over a time period **$\Delta t$**, based on the account balance **$a_{bal}$**
and the annual percentage yield $\mathtt{APY}$.
$$
\boxed{
\begin{equation}
\mathcal{f}mp_\mathcal{A}(a_{bal}, \Delta t) = \dfrac{a_{bal} \times \Delta t \times \mathtt{APY}}{100 \times T_{YEAR}}
\end{equation}
}
$$
Where
- **$a_{bal}$**: Represents the current account balance.
- **$\Delta t$**: The time difference or the duration over which the multiplier points are accrued, expressed in the
same time units as the year (typically days or months).
- **$T_{YEAR}$**: A constant representing the duration of a full year, used to normalize the time difference
**$\Delta t$**.
- **$\mathtt{APY}$**: The Annual Percentage Yield (APY) expressed as a percentage, which determines how much the balance
grows over a year.
---
#### $\mathcal{f}{mp_\mathcal{B}}(\Delta a, t_{lock}) \longrightarrow$ Bonus Multiplier Points
Calculates the bonus multiplier points earned when a balance **$\Delta a$** is locked for a specified duration
$t_{lock}$. It is equivalent to the $\mathcal{f}{mp_\mathcal{A}}(a_{bal}, \Delta t) \longrightarrow$ Accrue Multiplier
Points but specifically applied in the context of a locked balance, using $\Delta t$ as $t_{lock}$.
$$
\begin{aligned}
&\mathcal{f}mp_\mathcal{B}(\Delta a, t_{lock}) = \mathcal{f}mp_\mathcal{A}(\Delta a, t_{lock}) \\
&\boxed{
\begin{equation}
\mathcal{f}mp_\mathcal{B}(\Delta a, t_{lock}) = \dfrac{\Delta a \times t_{lock} \times \mathtt{APY}}{100 \times T_{YEAR}}
\end{equation}
}
\end{aligned}
$$
Where:
- **$\Delta a$**: Represents the amount of the balance that is locked.
- **$t_{lock}$**: The duration for which the balance **$\Delta a$** is locked, measured in units of seconds.
- **$T_{YEAR}$**: A constant representing the length of a year, used to normalize the lock period **$t_{lock}$** as a
fraction of a full year.
- **$\mathtt{APY}$**: The Annual Percentage Yield (APY), expressed as a percentage, which indicates the yearly interest
rate applied to the locked balance.
---
#### $\mathcal{f}{mp_\mathcal{R}}(mp, a_{bal}, \Delta a) \longrightarrow$ Reduce Multiplier Points
Calculates the reduction in multiplier points when a portion of the balance **$\Delta a$** is removed from the total
balance **$a_{bal}$**. The reduction is proportional to the ratio of the removed balance to the total balance, applied
to the current multiplier points **$mp$**.
$$
\boxed{
\begin{equation}
\mathcal{f}{mp_\mathcal{R}}(mp, a_{bal}, \Delta a) = \dfrac{mp \times \Delta a}{ a_{bal}}
\end{equation}
}
$$
Where:
- **$mp$**: Represents the current multiplier points.
- **$a_{bal}$**: The total account balance before the removal of **$\Delta a$**.
- **$\Delta a$**: The amount of balance being removed or deducted.
---
### State Functions
These function definitions represent methods that modify the state of both **$\mathbb{System}$** and **$\mathbb{Acc}$**.
They perform various pure mathematical operations to implement the specified state changes, affecting either the system
as a whole and the individual account states.
#### $\mathcal{f}^{stake}(\mathbb{Acc},\Delta a, t_{lock}) \longrightarrow$ Stake Amount With Lock
_Purpose:_ Allows a user to stake an amount $\Delta a$ with an optional lock duration $t_{lock}$.
```mermaid
---
title: Stake Storage Access Flowchart
---
flowchart LR
BonusMP{{Bonus MP}}
InitialMP{{Initial MP}}
Balance
LockEnd[Lock End]
TotalMP[Total MPs]
MaxMP[Maximum MPs]
FBonusMP{Calc Bonus MP}
FMaxMP{Calc Max Accrue MP}
M_MAX([MAX MULTIPLIER])
Balance --> InitialMP
Balance --> FMaxMP
M_MAX --> FMaxMP
InitialMP --> TotalMP
InitialMP --> MaxMP
BonusMP --> TotalMP
BonusMP --> MaxMP
FMaxMP --> MaxMP
LockEnd --> FBonusMP
Balance --> FBonusMP
FBonusMP --> BonusMP
```
##### Steps
###### Accrue Existing Multiplier Points (MPs)
Call the $\mathcal{f}^{accrue}(\mathbb{Account}) \longrightarrow$ Accrue Multiplier Points function to update MPs and
last accrual time.
###### Calculate the New Remaining Lock Period ($\Delta t_{lock}$)
$$
\Delta t_{lock} = max(\mathbb{Acc} \cdot t_{lock,end}, t_{now}) + t_{lock} - t_{now}
$$
###### Verify Constraints
Ensure new balance ($a_{bal}$ + $\Delta a$) meets the minimum amount ($A_{MIN}$):
$$
\mathbb{Acc} \cdot a_{bal} + \Delta a > A_{MIN}
$$
Ensure the New Remaining Lock Period ($\Delta t_{lock}$) is within Allowed Limits
$$
\Delta t_{lock} = 0 \lor T_{MIN} \le \Delta t_{lock} \le T_{MAX}
$$
###### Calculate Increased Bonus MPs
For the new amount ($\Delta a$) with the New Remaining Lock Period ($\Delta t_{lock}$):
$$
\Delta \hat{mp}^\mathcal{B} = \mathcal{f}mp_\mathcal{B}(\Delta a, \Delta t_{lock})
$$
For extending the lock ($t_{lock}$) on the existing balance ($\mathbb{Acc} \cdot a_{bal}$):
$$
\Delta \hat{mp}^\mathcal{B} = \Delta \hat{mp}^\mathcal{B} + \mathcal{f}mp_\mathcal{B}(\mathbb{Acc} \cdot a_{bal}, t_{lock})
$$
###### Calculate Increased Maximum MPs ($\Delta mp_\mathcal{M}$)
$$
\Delta mp_\mathcal{M} = \mathcal{f}mp_\mathcal{I}(\Delta a) + \Delta \hat{mp}^\mathcal{B} + \mathcal{f}mp_\mathcal{A}(\Delta a, M_{MAX} \times T_{YEAR})
$$
###### Calculate Increased Total MPs ($\Delta mp_\Sigma$)
$$
\Delta mp_\Sigma = \mathcal{f}mp_\mathcal{I}(\Delta a) + \Delta \hat{mp}^\mathcal{B}
$$
###### Verify Constraints
Ensure the New Maximum MPs ($\mathbb{Acc} \cdot mp_\mathcal{M} + \Delta mp_\mathcal{M}$) is within the Absolute Maximum
MPs:
$$
\mathbb{Acc} \cdot mp_\mathcal{M} + \Delta mp_\mathcal{M} \le \frac{a_{bal} \times \mathsf{MPY}^\mathit{abs}}{100}
$$
###### Update account State
Maximum MPs:
$$
\mathbb{Acc} \cdot mp_\mathcal{M} = \mathbb{Acc}\cdot mp_\mathcal{M} + \Delta mp_\mathcal{M}
$$
Total MPs:
$$
\mathbb{Acc} \cdot mp_\Sigma = \mathbb{Acc} \cdot mp_\Sigma + \Delta mp_\Sigma
$$
Balance:
$$
\mathbb{Acc} \cdot a_{bal} = \mathbb{Acc} \cdot a_{bal} + \Delta a
$$
Lock end time:
$$
\mathbb{Acc} \cdot t_{lock,end} = max(\mathbb{Acc} \cdot t_{lock,end}, t_{now}) + t_{lock}
$$
###### Update System State
Maximum MPs:
$$
\mathbb{Sys} \cdot mp_\mathcal{M} = \mathbb{Sys} \cdot mp_\mathcal{M} + \Delta mp_\mathcal{M}
$$
Total MPs:
$$
\mathbb{Sys} \cdot mp_\Sigma = \mathbb{Sys} \cdot mp_\Sigma + \Delta mp_\Sigma
$$
Total staked amount:
$$
\mathbb{Sys} \cdot a_{bal} = \mathbb{Sys} \cdot a_{bal} + \Delta a
$$
---
#### $\mathcal{f}^{lock}(\mathbb{Acc}, t_{lock}) \longrightarrow$ Increase Lock
<!-- prettier-ignore -->
> [!NOTE]
> Equivalent to:
> ```math
> \mathcal{f}_{stake}(\mathbb{Acc},0, t_{lock})
> ```
_Purpose:_ Allows a user to lock the $\mathbb{Acc} \cdot a_{bal}$ with a lock duration $t_{lock}$.
```mermaid
---
title: Lock Storage Access Flowchart
---
flowchart LR
BonusMP{{Bonus MP}}
LockEnd[Lock End]
TotalMP[Total MPs]
MaxMP[Maximum MPs]
FBonusMP{Calc Bonus MP}
BonusMP --> TotalMP
BonusMP --> MaxMP
LockEnd --> FBonusMP
Balance --> FBonusMP
FBonusMP --> BonusMP
```
##### Steps
###### Accrue Existing Multiplier Points (MPs)
Call the $\mathcal{f}^{accrue}(\mathbb{Account}) \longrightarrow$ Accrue Multiplier Points function to update MPs and
last accrual time.
###### Calculate the New Remaining Lock Period ($\Delta t_{lock}$)
$$
\Delta t_{lock} = max(\mathbb{Acc} \cdot t_{lock,end}, t_{now}) + t_{lock} - t_{now}
$$
###### Verify Constraints
Ensure the New Remaining Lock Period ($\Delta t_{lock}$) is within allowed limits:
$$
\Delta t_{lock} = 0 \lor T_{MIN} \le \Delta t_{lock} \le T_{MAX}
$$
###### Calculate Bonus MPs for the Increased Lock Period
$$
\Delta \hat{mp}^\mathcal{B} = mp_\mathcal{B}(\mathbb{Acc} \cdot a_{bal}, t_{lock})
$$
###### Verify Constraints
Ensure the New Maximum MPs ($\mathbb{Acc} \cdot mp_\mathcal{M} + \Delta \hat{mp}^\mathcal{B}$) is within the Absolute
Maximum MPs:
$$
\mathbb{Acc} \cdot mp_\mathcal{M} + \Delta \hat{mp}^\mathcal{B} \le \frac{a_{bal} \times \mathsf{MPY}^\mathit{abs}}{100}
$$
###### Update account State
Maximum MPs:
$$
\mathbb{Acc} \cdot mp_\mathcal{M} = \mathbb{Acc} \cdot mp_\mathcal{M} + \Delta \hat{mp}^\mathcal{B}
$$
Total MPs:
$$
\mathbb{Acc} \cdot mp_\Sigma = \mathbb{Acc} \cdot mp_\Sigma + \Delta \hat{mp}^\mathcal{B}
$$
Lock end time:
$$
\mathbb{Acc} \cdot t_{lock,end} = max(\mathbb{Acc} \cdot t_{lock,end}, t_{now}) + t_{lock}
$$
###### Update System State
Maximum MPs:
$$
\mathbb{Sys} \cdot mp_\mathcal{M} = \mathbb{Sys} \cdot mp_\mathcal{M} + \Delta mp_\mathcal{B}
$$
Total MPs:
$$
\mathbb{Sys} \cdot mp_\Sigma = \mathbb{Sys} \cdot mp_\Sigma + \Delta mp_\mathcal{B}
$$
---
#### $\mathcal{f}^{unstake}(\mathbb{Acc}, \Delta a) \longrightarrow$ Unstake Amount Unlocked
Purpose: Allows a user to unstake an amount $\Delta a$.
```mermaid
---
title: Unstake Storage Access Flowchart
---
flowchart LR
Balance
TotalMP[Total MPs]
MaxMP[Maximum MPs]
FReduceMP{Calc Reduced MP}
TotalMP --> FReduceMP
MaxMP --> FReduceMP
Balance --> FReduceMP
FReduceMP --> Balance
FReduceMP --> TotalMP
FReduceMP --> MaxMP
```
##### Steps
###### Accrue Existing Multiplier Points (MPs)
Call the $\mathcal{f}^{accrue}(\mathbb{Account}) \longrightarrow$ Accrue Multiplier Points function to update MPs and
last accrual time.
###### Verify Constraints
Ensure the account is not locked:
$$
\mathbb{Acc} \cdot t_{lock,end} < t_{now}
$$
Ensure that account have enough balance:
$$
\mathbb{Acc} \cdot a_{bal} > \Delta a
$$
Ensure that new balance ($\mathbb{Acc} \cdot a_{bal} - \Delta a$) will be zero or more than minimum allowed:
$$
\mathbb{Acc} \cdot a_{bal} - \Delta a = 0 \lor \mathbb{Acc} \cdot a_{bal} - \Delta a > A_{MIN}
$$
###### Calculate Reduced Amounts
Maximum MPs:
$$
\Delta mp_\mathcal{M} =\mathcal{f}mp_\mathcal{R}(\mathbb{Acc} \cdot mp_\mathcal{M}, \mathbb{Acc} \cdot a_{bal}, \Delta a)
$$
Total MPs:
$$
\Delta mp_\Sigma = \mathcal{f}mp_\mathcal{R}(\mathbb{Acc} \cdot mp_\Sigma, \mathbb{Acc} \cdot a_{bal}, \Delta a)
$$
###### Update account State
Maximum MPs:
$$
\mathbb{Acc} \cdot mp_\mathcal{M} = \mathbb{Acc} \cdot mp_\mathcal{M} - \Delta mp_\mathcal{M}
$$
Total MPs:
$$
\mathbb{Acc} \cdot mp_\Sigma = \mathbb{Acc} \cdot mp_\Sigma - \Delta mp_\Sigma
$$
Balance:
$$
\mathbb{Acc} \cdot a_{bal} = \mathbb{Acc} \cdot a_{bal} - \Delta a
$$
###### Update System State
Maximum MPs:
$$
\mathbb{Sys} \cdot mp_\mathcal{M} = \mathbb{Sys} \cdot mp_\mathcal{M} - \Delta mp_\mathcal{M}
$$
Total MPs:
$$
\mathbb{Sys} \cdot mp_\Sigma = \mathbb{Sys} \cdot mp_\Sigma - \Delta mp_\Sigma
$$
Total staked amount:
$$
\mathbb{Sys} \cdot a_{bal} = \mathbb{Sys} \cdot a_{bal} - \Delta a
$$
---
#### $\mathcal{f}^{accrue}(\mathbb{Acc}) \longrightarrow$ Accrue Multiplier Points
Purpose: Accrue multiplier points (MPs) for the account based on the elapsed time since the last accrual.
```mermaid
---
title: Accrue Storage Access Flowchart
---
flowchart LR
AccruedMP{{Accrued MP}}
Balance
LastMint[Last Mint]
TotalMP[Total MPs] --> MAX{max}
MaxMP[Maximum MPs] --> MAX
FAccruedMP{Calc Accrued MP}
NOW((NOW)) --> FAccruedMP
FAccruedMP --> LastMint
LastMint --> FAccruedMP
Balance --> FAccruedMP
FAccruedMP --> AccruedMP
AccruedMP --> MAX
MAX --> TotalMP
```
##### Steps
###### Calculate the time Period since Last Accrual
$$
\Delta t = t_{now} - \mathbb{Acc} \cdot t_{last}
$$
###### Verify Constraints
Ensure the accrual period is greater than the minimum rate period:
$$
\Delta t > T_{RATE}
$$
###### Calculate Accrued MP for the Accrual Period
$$
\Delta \hat{mp}^\mathcal{A} = min(\mathcal{f}mp_\mathcal{A}(\mathbb{Acc} \cdot a_{bal},\Delta t) ,\mathbb{Acc} \cdot mp_\mathcal{M} - \mathbb{Acc} \cdot mp_\Sigma)
$$
###### Update account State
Total MPs:
$$
\mathbb{Acc} \cdot mp_\Sigma = \mathbb{Acc} \cdot mp_\Sigma + \Delta \hat{mp}^\mathcal{A}
$$
Last accrual time:
$$
\mathbb{Acc} \cdot t_{last} = t_{now}
$$
###### Update System State
Total MPs:
$$
\mathbb{Sys} \cdot mp_\Sigma = \mathbb{Sys} \cdot mp_\Sigma + \Delta \hat{mp}^\mathcal{A}
$$
---
#### Reward Index Update
The **reward index** is updated whenever new rewards are added to the system. This update ensures that rewards are
accurately tracked and distributed based on the current total weight.
1. **Calculate New Rewards:**
$$
R_{\text{new}} = R_{\text{bal}} - R_{\text{accounted}}
$$
Where:
- $R_{\text{bal}}$: Current balance of reward tokens in the contract.
- $R_{\text{accounted}}$: Total rewards that have already been accounted for.
2. **Update Reward Index:**
$$
R_i = R_i + \left( \frac{R_\text{new} \times SCALE_{FACTOR}}{\mathbb{Sys} \cdot W} \right)
$$
3. **Account for Distributed Rewards:**
$$
R_\text{accounted} = R_\text{accounted} + R_\text{new}
$$
---
#### Reward Calculation for Accounts
Each account's rewards are calculated based on the difference between the current reward index and the account's last
recorded reward index. This ensures that rewards are distributed proportionally and accurately.
1. **Calculate Reward Index Difference:**
$$
\Delta \mathbb{Acc} \cdot R_i = \mathbb{Sys} \cdot R_i - \mathbb{Acc} \cdot R_i
$$
2. **Calculate Reward for Account $j$:**
$$
\text{reward}^j = \frac{\mathbb{Acc} \cdot W \times \Delta \mathbb{Acc} \cdot R_i}{SCALE_{FACTOR}}
$$
3. **Update Account Reward Index:**
$$
\mathbb{Acc} \cdot R_i = R_i
$$
---
#### Distribute Rewards
When distributing rewards to an account, ensure that the reward does not exceed the contract's available balance. Adjust
the accounted rewards accordingly to maintain consistency.
1. **Determine Transfer Amount:**
$$
\text{amount} = \min(\text{reward}^j, R_{\text{bal}})
$$
1. **Adjust Accounted Rewards:**
$$
R_{\text{accounted}} = R_{\text{accounted}} - \text{amount}
$$
3. **Transfer Reward Tokens:**
$$
\text{RewardToken.transfer}(j, \text{amount})
$$
#### Reward Calculation
At any given point, the **total reward** accumulated by an account $j$ is calculated as follows:
$$
\text{reward}^j = \frac{(\mathbb{Acc} \cdot a_{\text{bal}} + \mathbb{Acc} \cdot mp_{\Sigma}) \times (R_i - \mathbb{Acc} \cdot R_i)}{SCALE_{FACTOR}}
$$
This formula ensures that rewards are distributed proportionally based on both the staked tokens and the accrued
Multiplier Points, adjusted by the changes in the global reward index since the last reward calculation for the account.
---
#### $\mathcal{f}^{\text{updateRewardIndex}}(\mathbb{Sys}) \longrightarrow$ Update Reward Index
Calculates and updates the global reward index based on newly added rewards and the current total weight in the system.
$$
\boxed{
\begin{equation}
\mathcal{f}^{\text{updateRewardIndex}}(\mathbb{Sys}) = R_i + \left( \frac{R_{\text{new}} \times SCALE_{FACTOR}}{\mathbb{Sys} \cdot W} \right)
\end{equation}
}
$$
Where:
- $R_{\text{new}}$: Calculated as $R_{\text{bal}} - R_{\text{accounted}}$.
- $\mathbb{Sys} \cdot W$: Defined as $\mathbb{Sys} \cdot a_{\text{bal}} + \mathbb{Sys} \cdot mp_{\Sigma}$.
---
#### $\mathcal{f}^{\text{calculateReward}}(\mathbb{Acc} \cdot a_{\text{bal}}, \mathbb{Acc} \cdot mp_{\Sigma}, R_i, \mathbb{Acc} \cdot R_i) \longrightarrow$ Calculate Account Reward
Calculates the reward for an account $j$ based on its staked balance, Multiplier Points, and the change in the global
reward index.
$$
\boxed{
\begin{equation}
\mathcal{f}^{\text{calculateReward}}(\mathbb{Acc} \cdot a_{\text{bal}}, \mathbb{Acc} \cdot mp_{\Sigma}, R_i, \mathbb{Acc} \cdot R_i) = \frac{(\mathbb{Acc} \cdot a_{\text{bal}} + \mathbb{Acc} \cdot mp_{\Sigma}) \times (R_i - \mathbb{Acc} \cdot R_i)}{SCALE_{FACTOR}}
\end{equation}
}
$$
Where:
- $\mathbb{Acc} \cdot a_{\text{bal}}$: Staked balance of account $j$.
- $\mathbb{Acc} \cdot mp_{\Sigma}$: Total Multiplier Points of account $j$.
- $R_i$: Current cumulative reward index.
- $\mathbb{Acc} \cdot R_i$: Reward index at the last update for account $j$.
- $SCALE_{FACTOR}$: Scaling factor to maintain precision.
---
### Support Functions
#### Maximum Total Multiplier Points
The maximum total multiplier points that can be generated for a determined amount of balance and lock duration.
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}mp_{\mathcal{M}}(a_{bal}, t_{\text{lock}}) = a_{bal} + \frac{a_{bal} \times \mathtt{APY} \times \left( T_{\text{MAX}} + t_{\text{lock}} \right)}{100 \times T_{\text{YEAR}}}
\end{equation}
}
$$
#### Maximum Accrued Multiplier Points
The maximum multiplier points that can be accrued over time for a determined amount of balance. It's
$\mathcal{f}{mp_\mathcal{A}}(a_{bal}, Delta t) \longrightarrow$ Accrue Multiplier Points using
$\Delta t = M_{MAX} \times T_{YEAR}$
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}mp_{A}^{max}(a_{bal}) = \frac{a_{bal} \times \mathsf{MPY}}{100}
\end{equation}
}
$$
#### Maximum Absolute Multiplier Points
The absolute maximum multiplier points that some balance could have, which is the sum of the maximum lockup time bonus
and the maximum accrued multiplier points.
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}mp_\mathcal{M}^\mathit{abs}(a_{bal}) = \frac{a_{bal} \times \mathsf{MPY}^\mathit{abs}}{100}
\end{equation}
}
$$
#### Retrieve Bonus Multiplier Points
Returns the Bonus Multiplier Points from the Maximum Multiplier Points and Balance.
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}\hat{mp}^\mathcal{B}(mp_\mathcal{M}, a_{bal}) = mp_\mathcal{M} - \left(a_{\text{bal}} + \hat{\mathcal{f}}mp_{A}^{max}(a_{bal}) \right)
\end{equation}
}
$$
#### Retrieve Accrued Multiplier Points
Returns the accrued multiplier points from Total Multiplier Points, Maximum Multiplier Points and Balance.
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}\hat{mp}^\mathcal{A}(mp_\Sigma, mp_\mathcal{M}, a_{bal}) = mp_\Sigma + \hat{\mathcal{f}}mp_{A}^{max}(a_{bal}) - mp_\mathcal{M}
\end{equation}
}
$$
#### Time to Accrue Multiplier Points
Retrieves how much seconds to a certain $a_{bal}$ would reach a certain $mp$
$$
\boxed{
\begin{equation}
t_{rem}(a_{bal},mp_ {target}) = \frac{mp_{target} \times 100 \times T_{YEAR}}{a_{bal} \times \mathtt{APY}}
\end{equation}
}
$$
#### Locked Time ($t_{lock}$)
<!-- prettier-ignore -->
> [!CAUTION]
> Use for reference only. If implemented with integers, for $a_{bal} < T_{YEAR}$, due precision loss, the result may be an approximation.
Estimates the time an account set as locked time.
$$
\boxed{
\begin{equation}
\hat{\mathcal{f}}\tilde{t}_ {lock}(mp_{\mathcal{M}}, a_{bal}) \approx \left\lceil \frac{(mp_{\mathcal{M}} - a_{bal}) \times 100 \times T_{YEAR}}{a_{bal} \times \mathtt{APY}}\right\rceil - T_{\text{MAX}}
\end{equation}
}
$$
Where:
- $mp_{\mathcal{M}}$: Maximum multiplier points calculated the $a_{bal}$
- $a_{bal}$: Account balance used to calculate the $mp_{\mathcal{M}}$
#### Remaining Time Lock Available to Increase
<!-- prettier-ignore -->
> [!CAUTION]
> Use for reference only. If implemented with integers, for $a_{bal} < T_{YEAR}$, due precision loss, the result may be an approximation.
Retrieves how much time lock can be increased for an account.
$$
\boxed{
\begin{equation}
t_{rem}^{lock}(a_{bal},mp_\mathcal{M}) \approx \frac{\left(\hat{\mathcal{f}}mp_\mathcal{M}^\mathit{abs}(a_{bal}) - mp_\mathcal{M}\right)\times T_{YEAR}}{a_{bal}}
\end{equation}
}
$$