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 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.
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:
type Plan struct {
Index string // plan unique index
Block uint64 // the epoch that this plan was created
Price Coin // plan price (in ulava)
AllowOveruse bool // allow CU overuse flag
OveruseRate uint64 // price of CU overuse (higher price per CU)
Description string // plan description (for humans)
Type string // plan type (currently unused)
AnnualDiscountPercentage uint64 // discount for buying a yearly plan (percentage)
PlanPolicy Policy // plan's policy
ProjectsLimit uint64 // number of allowed projects
AllowedBuyers []string // list of addresses that are allowed to buy the plan (empty list -> everyone is allowed)
}
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.
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:
type Policy struct {
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, geolocation and 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.
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:
type ChainPolicy struct {
ChainId string // chain's unique index
Apis []string // allowed APIs
Requirements []ChainRequirement
}
A chain requirement is defined as follows:
type ChainRequirement struct {
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.
For more details on CollectionData
object, see the spec module's README.
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.
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.
The plans module does not contain parameters.
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 |
The plans module does not support any transactions.
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"
}
The plans module has the following events:
Event | When it happens |
---|---|
add_new_plan_to_storage |
a successful addition of a plan |
del_plan_from_storage |
a successful deletion of a plan |