Skip to content

Commit

Permalink
Merge pull request lavanet#1067 from lavanet/CNS-781-plans-readme
Browse files Browse the repository at this point in the history
CNS-781: Plans README
  • Loading branch information
Yaroms authored Dec 26, 2023
2 parents 318fac7 + 4a3e670 commit b92b012
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 23 deletions.
251 changes: 251 additions & 0 deletions x/plans/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
# `x/plans`

## Abstract

This document specifies the plans module of Lava Protocol.

The plans module is responsible for managing Lava's subscription plans and handling government proposals for adding new ones. When a consumer wants to use Lava, they need to purchase a subscription. Each subscription is associated with a specific plan that sets certain limitations. The plan determines the base limitations of the subscription, such as compute unit (CU) limitations and the maximum number of providers that can be paired in each pairing session, among other things.

Note that the plans module is closely connected to the subscription and projects modules. To fully understand how subscriptions, plans, and projects work together, please also refer to their respective READMEs.

This document is focuses on the plans' technical aspects and does not include current subscription plans and prices. For more information on those, please visit Lava's official website.

## Contents

* [Concepts](#concepts)
* [Plan](#plan)
* [Policy](#policy)
* [Chain Policy](#chain-policy)
* [Geolocation](#geolocation)
* [Selected Providers](#selected-providers)
* [Parameters](#parameters)
* [Queries](#queries)
* [Transactions](#transactions)
* [Proposals](#proposals)

## Concepts

### Plan

A plan consists of limitations that are associated with a subscription. A consumer can only use Lava when they purchase a subscription that is subject to the limitations set by the plan. A plan is defined as follows:

```
struct Plan {
index string // plan unique index
block uint64 // the epoch that this plan was created
price Coin // plan price (in ulava)
allow_overuse bool // allow CU overuse flag
overuse_rate uint64 // price of CU overuse (higher price per CU)
description string // plan description (for humans)
type string // plan type (currently unused)
annual_discount uint64 // discount for buying a yearly plan (percentage)
plan_policy Policy // plan's policy
}
```
Note, the `Coin` type is from Cosmos-SDK (`cosmos.base.v1beta1.Coin`).

The plan's limitations mostly lie in its policy. As mentioned above, the plan has other fields like its unique index, price, and more. The plan's “overuse” related fields refers to a scenario where the subscription exceeds the CU limit set by the plan policy. In such cases, if CU overuse is permitted, the price of CU is higher than normal.

### Policy

A policy consists of a set of limitations that apply to a plan, a subscription, or a specific project. Each project opened using a consumer's subscription is subject to the effective policy derived from the plan policy, subscription policy, and project policy. The effective policy is calculated by selecting the strictest limitation from each policy. Overall, the policy affects the pairing between the project and providers and limits the CU that can be used by the consumer.

A policy is defined as follows:

```
struct Policy {
ChainPolicies []ChainPolicy // list of policies per chain
GeolocationProfile int32 // allowed geolocations
TotalCuLimit uint64 // CU usage limit per month
EpochCuLimit uint64 // CU usage limit per epoch
MaxProvidersToPair uint64 // max number of providers to pair
SelectedProvidersMode SELECTED_PROVIDERS_MODE // selected providers mode
SelectedProviders []string // allow list of selected providers
}
```

See below for more information regarding [chain policies](#chain-policy), [geolocation](#geolocation) and [selected providers](#selected-providers).

A plan will always have a policy, but this is not always the case for subscription or project policies, which can be nil. A plan's policy can only be changed through a government proposal to add a new plan. As for subscription and project policies, they can be modified using transactions defined in the projects module.

#### Chain Policy

A chain policy consists limitations that can be imposed on specific chains (like list of allowed APIs, requirement for advanced APIs, etc.). If a certain chain is not shown in the policy's array of chain policeis, it's regarded as not allowed by the policy (i.e. the consumer won't be able to send relays to this chain).

A chain policy is defined as follows:

```
struct ChainPolicy {
ChainId string // chain's unique index
Apis []string // allowed APIs
Requirements []ChainRequirement
}
```

A chain requirement is defined as follows:

```
struct ChainRequirement {
Collection types.CollectionData
Extensions []string
Mixed bool
}
```

The `Extensions` field is intended to enable the use of certain APIs to obtain different responses (for a modified price). Currently, the only implemented extension is the `archive` extension, which allows consumers to make archived RPC calls to retrieve data from blocks that are not stored in the chain's memory. If a regular call is made for a block that is not in the chain's memory, an error will occur. In the future, the `compliance` extension will be implemented to enable the rejection of specific APIs.

The `Mixed` field is designed to enable a combination of regular and extension/addon supporting providers. For instance, if the `archive` extension is defined but the `Mixed` field is set to `false`, the consumer's project will only be paired with providers that support the specified extensions and addons. On the other hand, if the `Mixed` field is set to `true`, the consumer's project will also be paired with providers that don't fully support the extenstion/addons.

A chain collection is defined as follows:

```
struct CollectionData {
ApiInterface string
InternalPath string
Type string
AddOn string
}
```

The `ApiInterface` field defines the API interface on which the limitations are applied. The available API interfaces for a chain are defined in the chain's spec. Overall, the API interfaces can be: `jsonrpc`, `rest`, `tendermintrpc` and `grpc`.

The `InternalPath` field is utilized for chains that have varying RPC API sets in different internal paths. Avalanche is a prime example of such a chain, consisting of three distinct subchains (or subnets) designed for different applications. For instance, Avalanche's C-Chain is dedicated to smart contracts, while Avalanche's X-Chain facilitates the sending and receiving of funds. For further information on how to define this field, please consult the Avalanche (AVAX) specification.

The `Type` field lets the user define APIs that have different functionalities depending on their type. the valid types are: `GET` and `POST`. An example of such API is Cosmos' `/cosmos/tx/v1beta1/txs` API. If it's sent as a `GET` request, it fetches transactions by event and if it's sent as a `POST` request, it sends a transaction.

The `AddOn` field lets you use additional optional APIs like debug, trace,

#### Geolocation

Geolocation profile allows consumers to get paired with providers that support these geolocations, ultimately optimizing latency and improving the quality of service for end-users. The geolocations are defined as a bitmap so the `int32` field in the policy can represent multiple geolocations.

The geolocations are defined as follows:

```
enum Geolocation {
"GLS" = 0 // Global strict
"USC" = 1 // US center
"EU" = 2 // Europe
"USE" = 4 // US east
"USW" = 8 // US west
"AF" = 16 // Africa
"AS" = 32 // Asia
"AU" = 64 // Australia
"GL" = 65535 // Global
}
```

The "GLS" geolocation means that the policy is global and not configurable.

#### Selected Providers

The selected providers feature enables consumers to pre-select providers they prefer for their pairing list by implementing an allow-list within the project policy. There several modes that determine this feature's behaviour:

```
enum SELECTED_PROVIDERS_MODE {
ALLOWED = 0 // no providers restrictions (feature is enabled but no restrictions)
MIXED = 1 // use the selected providers mixed with randomly chosen providers
EXCLUSIVE = 2 // use only the selected providers
DISABLED = 3 // selected providers feature is disabled
}
```

In the policy the user can define the desired mode and the selected providers allow-list.

## Parameters

The plans module does not contain parameters.

## Queries

The plans module supports the following queries:

| Query | Arguments | What it does |
| ---------- | --------------- | ----------------------------------------------|
| `info` | index (string) | shows a plan's info by index |
| `list` | none | show the info for all plans (latest version) |
| `params` | none | shows the module's parameters |

## Transactions

The plans module does not support any transactions.

## Proposals

The plans module supports the following proposals: `plans-add` and `plans-del`. To send a proposal and vote use the following commands:

```
lavad tx gov submit-legacy-proposal plans-add <proposal_json_1>,<proposal_json_2> --from alice <gas-flags>
lavad tx gov vote <latest_proposal_id> yes --from alice <gas-flags>
OR
lavad tx gov submit-legacy-proposal plans-del <proposal_json_1>,<proposal_json_2> --from alice <gas-flags>
lavad tx gov vote <latest_proposal_id> yes --from alice <gas-flags>
```

A valid `plans-add` JSON proposal format:

```
{
"proposal": {
"title": "Add temporary to-delete plan proposal",
"description": "A proposal of a temporary to-delete plan",
"plans": [
{
"index": "to_delete_plan",
"description": "This plan has no restrictions",
"type": "rpc",
"price": {
"denom": "ulava",
"amount": "100000"
},
"annual_discount_percentage": 20,
"allow_overuse": true,
"overuse_rate": 2,
"plan_policy": {
"chain_policies": [
{
"chain_id": "LAV1",
"apis": [
]
},
{
"chain_id": "ETH1",
"apis": [
"eth_blockNumber",
"eth_accounts"
]
}
],
"geolocation_profile": "AU",
"total_cu_limit": 1000000,
"epoch_cu_limit": 100000,
"max_providers_to_pair": 3,
"selected_providers_mode": "MIXED",
"selected_providers": [
"lava@1wvn4slrf2r7cm92fnqdhvl3x470944uev92squ"
]
}
}
]
},
"deposit": "10000000ulava"
}
```

A valid `plans-del` JSON proposal format:

```
{
"proposal": {
"title": "Delete temporary (to-delete) plan proposal",
"description": "A proposal to delete temporary (to-delete) plan",
"plans": [
"to_delete_plan"
]
},
"deposit": "10000000ulava"
}
```

51 changes: 28 additions & 23 deletions x/rewards/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
---
sidebar_position: 1
---

# `x/rewards`

## Abstract
Expand Down Expand Up @@ -40,7 +36,7 @@ The allocation pools get some of the treasury account's tokens and hold onto it.

The distribution pools use the monthly quota of funds to distribute rewards for validators and providers.

#### Validators Rewards
#### Validators Rewards Pool

In Cosmos-SDK chains, validators get rewards for creating blocks by the Cosmos' distribution module. For each new block, new tokens are minted and distributed to all the accounts that contributed to the new block creation.

Expand All @@ -52,34 +48,38 @@ The distribution pool of validators, `validators_rewards_distribution_pool`, use

The validators block reward is calculated using the following formula:

$$ Reward = \frac{{\text{{validators\_distribution\_pool\_balance}}} \cdot {\text{bonded\_target\_factor}}}{\text{{remaining\_blocks\_until\_next\_emission}}}$$

```math
Reward = \frac{{\text{{validators\_distribution\_pool\_balance}}} \cdot {\text{bonded\_target\_factor}}}{\text{{remaining\_blocks\_until\_next\_emission}}}
```
Where:
* $\text{validators\_distribution\_pool\_balance}$ - The remaining balance in the `validators_rewards_distribution_pool`.
* $\text{bonded\_target\_factor}$ - A factor calculated with the module's params (see [below](#bondedtargetfactor)).
* $\text{remaining\_blocks\_until\_next\_emission}$ - The amount of blocks until the next monthly refill of the `validators_rewards_distribution_pool`.
* $`\text{validators\_distribution\_pool\_balance}`$ - The remaining balance in the `validators_rewards_distribution_pool`.
* $`\text{bonded\_target\_factor}`$ - A factor calculated with the module's params (see [below](#bondedtargetfactor)).
* $`\text{remaining\_blocks\_until\_next\_emission}`$ - The amount of blocks until the next monthly refill of the `validators_rewards_distribution_pool`.

### Providers Rewards Pool
#### Providers Rewards Pool

Providers get rewards for their services from the funds used to buy subscriptions (see subscription module readme).

Besides these rewards, the provider also get monthly bonus rewards from a pre-allocated rewards pools. To manage this, like the validators, the providers have an allocation and distribution rewards pools. The bonus rewards exist to provide additional rewards when there is no much demand (few subscriptions).

The total monthly bonus rewards ("total spec payout") are calculated per spec by the following formula:

$$\text{Total spec payout}=\\\min\{RewardsMaxBoost\cdot\text{Total Base Payouts}, \\ \text{Spec Payout Cap}, \\ \max\{0,1.5(\text{Spec Payout Cap})-0.5(\text{Total Base Payouts})\}\}$$
```math
\text{Total spec payout}=\\\min\{RewardsMaxBoost\cdot\text{Total Base Payouts}, \\ \text{Spec Payout Cap}, \\ \max\{0,1.5(\text{Spec Payout Cap})-0.5(\text{Total Base Payouts})\}\}
```

Where:
* $\text{RewardsMaxBoost}$ - A module's parameter (see [below](#maxrewardsboost)).
* $\text{Total Base Payouts}$ - The sum of all base payouts the providers for this spec collected = $\sum_{provider_1.._n} (\text{{provider base rewards}}_i)$
* $\text{Spec Payout Cap}$ - The max value for this spec bonus rewards = $\frac{specStake\cdot specShares}{\sum_i{specStake \cdot specShares}_i}$.
* $`\text{RewardsMaxBoost}`$ - A module's parameter (see [below](#maxrewardsboost)).
* $`\text{Total Base Payouts}`$ - The sum of all base payouts the providers for this spec collected = $`\sum_{provider_1.._n} (\text{{provider base rewards}}_i)`$
* $`\text{Spec Payout Cap}`$ - The max value for this spec bonus rewards = $`\frac{specStake\cdot specShares}{\sum_i{specStake \cdot specShares}_i}`$.
* SpecStake = Total effective stake of providers in this spec.
* SpecShares = Weight factor for the spec (determined in each spec)

The total spec payout is distributed between providers proportional to the rewards they collected from subscriptions throughtout the month. Each provider will get bonus rewards according to the following formula:

$$Provider Bonus Rewards = Total Spec Payout \cdot \frac{\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j} \times \text{{adjustment}}_{i,j})}{\sum_{\text{provider}\;j'}\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j'} )}
$$
```math
Provider Bonus Rewards = Total Spec Payout \cdot \frac{\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j} \times \text{{adjustment}}_{i,j})}{\sum_{\text{provider}\;j'}\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j'} )}
```

Where:
* Adjustment - TBD
Expand All @@ -88,10 +88,13 @@ Note that some of the providers rewards are sent to the community pool (accordin

The participation fees are calculated according to the following formulas:

$$\text{Validators Participation Fee} = \frac{ValidatorsSubscriptionParticipation}{1-CommunityTax}$$

$$\text{Community Participation Fee} = ValidatorsSubscriptionParticipation + CommunityTax\\ - \text{Validators Participation Fee}$$
```math
\text{Validators Participation Fee} = \frac{ValidatorsSubscriptionParticipation}{1-CommunityTax}
```

```math
\text{Community Participation Fee} = ValidatorsSubscriptionParticipation + CommunityTax\\ - \text{Validators Participation Fee}
```
## Parameters

The rewards module contains the following parameters:
Expand Down Expand Up @@ -128,16 +131,18 @@ In Lava we wanted to make validator rewards decrease linearly with the increase

To calculate the `BondedTargetFactor` see the following formula (note that the staking module's `BondedRatio` parameter is used, which is the fraction of the staking tokens which are currently bonded):

$$\text{BondedTargetFactor}= \\\begin{cases}
```math
\text{BondedTargetFactor}= \\\begin{cases}
1 & \text{$\text{BondRatio} < \text{MinBonded}$}\\
\frac{\text{MaxBonded}-\text{BondRatio}}{\text{MaxBonded}-\text{MinBonded}} + (\text{LowFactor})\frac{\text{BondRatio}-\text{MinBonded}}{\text{MaxBonded}-\text{MinBonded}} & \text{$\text{MinBonded} < \text{BondRatio} < \text{MaxBonded}$}\\
\text{LowFactor} & \text{$\text{BondRatio} > \text{MaxBonded}$}\\
\end{cases}$$
\end{cases}
```

### MaxRewardsBoost

TBD

### ValidatorsSubscriptionParticipation

ValidatorsSubscriptionParticipation is used to calculate the providers rewards participation fees.
ValidatorsSubscriptionParticipation is used to calculate the providers rewards participation fees.

0 comments on commit b92b012

Please sign in to comment.