diff --git a/readme-docs/gather-docs.sh b/readme-docs/gather-docs.sh index e15469cfd7..fbbb7df970 100644 --- a/readme-docs/gather-docs.sh +++ b/readme-docs/gather-docs.sh @@ -1,8 +1,14 @@ -for f in $(find "./x" -type f -name "*.md" \ # -not -path "deps/*" - -not -path "scripts/*" \ - -not -path "readme-docs/*" - ) +#!/bin/bash +for f in $(find "./x" \ + -type f \ + -name "*.md" ) + # -not -path "scripts/*" \ + # -not -path "readme-docs/*"\ + # ) do echo $f - cp $f readme-docs/md + start=$(echo $f | cut -d'/' -f3- | cut -d/ -f1) + filename=$(echo $f | cut -d'/' -f3- | cut -d/ -f2) + newfilename=$start"_"$filename + cp $f readme-docs/md/$newfilename done \ No newline at end of file diff --git a/readme-docs/md/01_concepts.md b/readme-docs/md/01_concepts.md deleted file mode 100644 index dcc05c86ae..0000000000 --- a/readme-docs/md/01_concepts.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "Claim Module: Overview" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - - -# Concepts - -In Stride, users are required to claim their airdrop by participating in core network activities. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: - -* 20% vesting over 3 months by staking -* 60% vesting over 3 months by liquid staking - -At initial, module stores all airdrop users with amounts from genesis inside KVStore. - -Airdrop users are eligible to claim their vesting or free amount only once in the initial period of 3 months and after the initial period, users can claim tokens monthly not in vesting format. diff --git a/readme-docs/md/02_state.md b/readme-docs/md/02_state.md deleted file mode 100644 index df0e6a3364..0000000000 --- a/readme-docs/md/02_state.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "Claim Module: State" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# State - -### Claim Records - -```protobuf -// A Claim Records is the metadata of claim data per address -message ClaimRecord { - // address of claim user - string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; - - // weight that represent the portion from total allocations - double weight = 2; - - // true if action is completed - // index of bool in array refers to action enum # - repeated bool action_completed = 3 [ - (gogoproto.moretags) = "yaml:\"action_completed\"" - ]; -} -``` -When a user get airdrop for his/her action, claim record is created to prevent duplicated actions on future actions. - -### State - -```protobuf -message GenesisState { - // params defines all the parameters of the module. - Params params = 2 [ - (gogoproto.moretags) = "yaml:\"params\"", - (gogoproto.nullable) = false - ]; - - // list of claim records, one for every airdrop recipient - repeated ClaimRecord claim_records = 3 [ - (gogoproto.moretags) = "yaml:\"claim_records\"", - (gogoproto.nullable) = false - ]; -} -``` - -Claim module's state consists of `params`, and `claim_records`. diff --git a/readme-docs/md/03_end_epoch.md b/readme-docs/md/03_end_epoch.md deleted file mode 100644 index 5a9cf541d7..0000000000 --- a/readme-docs/md/03_end_epoch.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "Mint Module: End Epoch" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Begin-Epoch - -Minting parameters are recalculated and inflation -paid at the beginning of each epoch. An epoch is signalled by x/epochs - -## NextEpochProvisions - -The target epoch provision is recalculated on each reduction period (default 3 years). -At the time of reduction, the current provision is multiplied by reduction factor (default `2/3`), -to calculate the provisions for the next epoch. Consequently, the rewards of the next period -will be lowered by `1 - reduction factor`. - -```go -func (m Minter) NextEpochProvisions(params Params) sdk.Dec { - return m.EpochProvisions.Mul(params.ReductionFactor) -} -``` - -## EpochProvision - -Calculate the provisions generated for each epoch based on current epoch provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount`. These rewards are transferred to a `FeeCollector`, which handles distributing the rewards per the chains needs. (See TODO.md for details) This fee collector is specified as the `auth` module's `FeeCollector` `ModuleAccount`. - -```go -func (m Minter) EpochProvision(params Params) sdk.Coin { - provisionAmt := m.EpochProvisions.QuoInt(sdk.NewInt(int64(params.EpochsPerYear))) - return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()) -} -``` diff --git a/readme-docs/md/03_events.md b/readme-docs/md/03_events.md deleted file mode 100644 index 6f4c86f2ae..0000000000 --- a/readme-docs/md/03_events.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "Claim Module: Events" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - -# Events - -## External module hooks - -`claim` module emits the following events at the time of hooks: - -| Type | Attribute Key | Attribute Value | -| ----- | ------------- | --------------- | -| claim | sender | {receiver} | -| claim | amount | {claim_amount} | - diff --git a/readme-docs/md/04_keeper.md b/readme-docs/md/04_keeper.md deleted file mode 100644 index e27cb057a5..0000000000 --- a/readme-docs/md/04_keeper.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Claim Module: Keeper" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Keepers - -## Keeper functions - -Claim keeper module provides utility functions to manage epochs. - -```go - GetModuleAccountAddress(ctx sdk.Context) sdk.AccAddress - GetDistributorAccountBalance(ctx sdk.Context) sdk.Coin - EndAirdrop(ctx sdk.Context) error - GetClaimRecord(ctx sdk.Context, addr sdk.AccAddress) (types.ClaimRecord, error) - GetClaimRecords(ctx sdk.Context) []types.ClaimRecord - SetClaimRecord(ctx sdk.Context, claimRecord types.ClaimRecord) error - SetClaimRecords(ctx sdk.Context, claimRecords []types.ClaimRecord) error - GetClaimableAmountForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action, includeClaimed bool) (sdk.Coins, error) - GetUserTotalClaimable(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) - ClaimCoinsForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action) (sdk.Coins, error) - clearInitialClaimables(ctx sdk.Context) - fundRemainingsToCommunity(ctx sdk.Context) error -``` diff --git a/readme-docs/md/04_params.md b/readme-docs/md/04_params.md deleted file mode 100644 index 31a8e43bb0..0000000000 --- a/readme-docs/md/04_params.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: "Mint Module: Params" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Parameters - -The minting module contains the following parameters: - -| Key | Type | Example | -| ------------------------------------------ | ------------ | -------------------------------------- | -| mint_denom | string | "uosmo" | -| genesis_epoch_provisions | string (dec) | "500000000" | -| epoch_identifier | string | "weekly" | -| reduction_period_in_epochs | int64 | 156 | -| reduction_factor | string (dec) | "0.6666666666666" | -| distribution_proportions.staking | string (dec) | "0.4" | -| distribution_proportions.pool_incentives | string (dec) | "0.3" | -| distribution_proportions.developer_rewards | string (dec) | "0.2" | -| distribution_proportions.community_pool | string (dec) | "0.1" | -| weighted_developer_rewards_receivers | array | [{"address": "osmoxx", "weight": "1"}] | -| minting_rewards_distribution_start_epoch | int64 | 10 | - -**Notes** -1. `mint_denom` defines denom for minting token - uosmo -2. `genesis_epoch_provisions` provides minting tokens per epoch at genesis. -3. `epoch_identifier` defines the epoch identifier to be used for mint module e.g. "weekly" -4. `reduction_period_in_epochs` defines the number of epochs to pass to reduce mint amount -5. `reduction_factor` defines the reduction factor of tokens at every `reduction_period_in_epochs` -6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distribute tokens to community pool. -7. `weighted_developer_rewards_receivers` provides the addresses that receives developer rewards by weight -8. `minting_rewards_distribution_start_epoch` defines the start epoch of minting to make sure minting start after initial pools are set diff --git a/readme-docs/md/05_events.md b/readme-docs/md/05_events.md deleted file mode 100644 index 65dbdc5a93..0000000000 --- a/readme-docs/md/05_events.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "Mint Module: Events" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - - -# Events - -The minting module emits the following events: - -## End of Epoch - -| Type | Attribute Key | Attribute Value | -| ---- | ---------------- | ----------------- | -| mint | epoch_number | {epochNumber} | -| mint | epoch_provisions | {epochProvisions} | -| mint | amount | {amount} | diff --git a/readme-docs/md/05_react_hooks.md b/readme-docs/md/05_react_hooks.md deleted file mode 100644 index bdc9ec7cfd..0000000000 --- a/readme-docs/md/05_react_hooks.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Claim Module: React Hooks" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# React Hooks - -Claim module react on following hooks of external modules. - -20% of airdrop is sent to a vesting account when `staking.AfterDelegationModified` hook is triggered. -20% of airdrop is sent to a vesting account when `stakeibc.AfterLiquidStake` hook is triggered. - -When airdrop is claimed for specific hook type, it can't be claimed double. diff --git a/readme-docs/md/06_queries.md b/readme-docs/md/06_queries.md deleted file mode 100644 index b32d518e12..0000000000 --- a/readme-docs/md/06_queries.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: "Claim Module: Queries" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Queries - -## GRPC queries - -Claim module provides below GRPC queries to query claim status - -```protobuf -service Query { - rpc DistributorAccountBalance(QueryDistributorAccountBalanceRequest) returns (QueryDistributorAccountBalanceResponse) {} - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {} - rpc ClaimRecord(QueryClaimRecordRequest) returns (QueryClaimRecordResponse) {} - rpc ClaimableForAction(QueryClaimableForActionRequest) returns (QueryClaimableForActionResponse) {} - rpc TotalClaimable(QueryTotalClaimableRequest) returns (QueryTotalClaimableResponse) {} -} -``` - -## CLI commands - -For the following commands, you can change `$(strided keys show -a {your key name})` with the address directly. - -Query the claim record for a given address - -```sh -strided query claim claim-record $(strided keys show -a {your key name}) -``` - -Query the claimable amount that would be earned if a specific action is completed right now. - -```sh - -strided query claim claimable-for-action $(strided keys show -a {your key name}) ActionAddLiquidity -``` - -Query the total claimable amount that would be earned if all remaining actions were completed right now. - -```sh -strided query claim total-claimable $(strided keys show -a {your key name}) ActionAddLiquidity -``` diff --git a/readme-docs/md/07_params.md b/readme-docs/md/07_params.md deleted file mode 100644 index 3082b14cf4..0000000000 --- a/readme-docs/md/07_params.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Claim Module: Params" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Params - -Claim module provides below params - -```protobuf -// Params defines the claim module's parameters. -message Params { - google.protobuf.Timestamp airdrop_start_time = 1 [ - (gogoproto.stdtime) = true, - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"airdrop_start_time\"" - ]; - google.protobuf.Timestamp airdrop_duration = 2 [ - (gogoproto.nullable) = false, - (gogoproto.stdduration) = true, - (gogoproto.jsontag) = "airdrop_duration,omitempty", - (gogoproto.moretags) = "yaml:\"airdrop_duration\"" - ]; - // denom of claimable asset - string claim_denom = 3; - // airdrop distribution account - string distributor_address = 4; -} -``` - -1. `airdrop_start_time` refers to the time when user can start to claim airdrop. -2. `airdrop_duration` refers to the duration from start time to end time. -3. `claim_denom` refers to the denomination of claiming tokens. As a default, it's `ustrd`. -4. `distributor_address` refers to the address of distribution account. \ No newline at end of file diff --git a/readme-docs/md/README.md b/readme-docs/md/README.md deleted file mode 100644 index 9a859bb99d..0000000000 --- a/readme-docs/md/README.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: "Claim Module" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - -# Claims module - -## Abstract - -The Stride claims module has users claim higher percentages as they perform certain tasks on-chain. -Furthermore, these claimable assets 'expire' if not claimed. -Users have three months (`AirdropDuration`) to claim their full airdrop amount -After three months from launch, all unclaimed tokens get sent to the community pool. - -## Contents - -1. **[Concept](01_concepts.md)** -2. **[State](02_state.md)** -3. **[Events](03_events.md)** -4. **[Keeper](04_keeper.md)** -5. **[React Hooks](05_react_hooks.md)** -6. **[Queries](06_queries.md)** -7. **[Params](07_params.md)** - -## Genesis State - -## Actions - -There are 2 types of actions, each of which release another 50% of the airdrop allocation. -The 2 actions are as follows: - -```golang -ActionLiquidStake Action = 0 -ActionDelegateStake Action = 1 -``` - -These actions are monitored by registring claim **hooks** to the stakeibc, and staking modules. -This means that when you perform an action, the claims module will immediately unlock those coins if they are applicable. -These actions can be performed in any order. - -The code is structured by separating out a segment of the tokens as "claimable", indexed by each action type. -So if Alice delegates tokens, the claims module will move the 50% of the claimables associated with staking to her liquid balance. -If she delegates again, there will not be additional tokens given, as the relevant action has already been performed. -Every action must be performed to claim the full amount. - -## ClaimRecords - -A claim record is a struct that contains data about the claims process of each airdrop recipient. - -It contains an address, the initial claimable airdrop amount, and an array of bools representing -whether each action has been completed. The position in the array refers to enum number of the action. - -So for example, `[true, true]` means that `ActionLiquidStake` and `ActionDelegateStake` are completed. - -```golang -type ClaimRecord struct { - // address of claim user - Address string - // weight that represent the portion from total allocation - Weight sdk.Dec - // true if action is completed - // index of bool in array refers to action enum # - ActionCompleted []bool -} - -``` - - -## Params - -The airdrop logic has 4 parameters: - -```golang -type Params struct { - // Time that marks the beginning of the airdrop disbursal, - // should be set to chain launch time. - AirdropStartTime time.Time - AirdropDuration time.Duration - // denom of claimable asset - ClaimDenom string - // address of distributor account - DistributorAddress string -} -``` diff --git a/readme-docs/md/README.md_README.md b/readme-docs/md/README.md_README.md new file mode 100644 index 0000000000..1b7e781ec5 --- /dev/null +++ b/readme-docs/md/README.md_README.md @@ -0,0 +1,33 @@ +--- +title: "Stride Modules" +excerpt: "" +category: 62c5c5ff03a5bf069004def2 +--- + +## Stride Modules + +`stakeibc` - Manages minting and burning of stAssets, staking and unstaking of native assets across chains. +`icacallbacks` - Callbacks for interchain accounts. +`records` - IBC middleware wrapping the transfer module, does record keeping on IBC transfers and ICA calls +`claim` - airdrop logic for Stride's rolling, task-based airdrop +`interchainquery` - Issues queries between IBC chains, verifies state proof and executes callbacks. +`epochs` - Makes on-chain timers which other modules can execute code during. +`mint` - Controls token supply emissions, and what modules they are directed to. + +### Attribution + +Stride is proud to be an open-source project, and we welcome all other projects to use our repo. We use modules from the cosmos-sdk and other open source projects. + +We operate under the Apache 2.0 License, and have used the following modules from fellow Cosmos projects. Huge thank you to these projects! + +We use the following modules from [Osmosis](https://github.com/osmosis-labs/osmosis) provided under [this License](https://github.com/osmosis-labs/osmosis/blob/main/LICENSE): +``` +x/epochs +x/mint +``` +We use the following module (marketed as public infra) from [Quicksilver](https://github.com/ingenuity-build/quicksilver) provided under [this License](https://github.com/ingenuity-build/quicksilver/blob/main/LICENSE): +``` +x/interchainqueries +``` + +Relevant licenses with full attribution can be found in the relevant repo subdirectories. \ No newline at end of file diff --git a/readme-docs/md/claim_README.md b/readme-docs/md/claim_README.md new file mode 100644 index 0000000000..1ab120ca93 --- /dev/null +++ b/readme-docs/md/claim_README.md @@ -0,0 +1,217 @@ +--- +title: "Claim" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The Claim Module + +Users are required participate in core network activities to claim their airdrop. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: +* 20% vesting over 3 months by staking +* 60% vesting over 3 months by liquid staking + +These claimable assets 'expire' if not claimed. Users have three months (`AirdropDuration`) to claim their full airdrop amount. After three months from launch, all unclaimed tokens get sent to the community pool. At initialization, module stores all airdrop users with amounts from genesis inside KVStore. Airdrop users are eligible to claim their vesting or free amount only once in the initial period of 3 months. After the initial period, users can claim tokens monthly. + +## Actions + +There are 2 types of actions, each of which release another 50% of the airdrop allocation. +The 2 actions are as follows: + +```golang +ActionLiquidStake Action = 0 +ActionDelegateStake Action = 1 +``` + +These actions are monitored by registring claim **hooks** to the stakeibc, and staking modules. +This means that when you perform an action, the claims module will immediately unlock those coins if they are applicable. +These actions can be performed in any order. + +The code is structured by separating out a segment of the tokens as "claimable", indexed by each action type. +So if Alice delegates tokens, the claims module will move the 50% of the claimables associated with staking to her liquid balance. +If she delegates again, there will not be additional tokens given, as the relevant action has already been performed. +Every action must be performed to claim the full amount. + +## ClaimRecords + +A claim record is a struct that contains data about the claims process of each airdrop recipient. + +It contains an address, the initial claimable airdrop amount, and an array of bools representing +whether each action has been completed. The position in the array refers to enum number of the action. + +So for example, `[true, true]` means that `ActionLiquidStake` and `ActionDelegateStake` are completed. + +```golang +type ClaimRecord struct { + // address of claim user + Address string + // weight that represent the portion from total allocation + Weight sdk.Dec + // true if action is completed + // index of bool in array refers to action enum # + ActionCompleted []bool +} + +``` + +## Params + +The airdrop logic has 4 parameters: + +```golang +type Params struct { + // Time that marks the beginning of the airdrop disbursal, + // should be set to chain launch time. + AirdropStartTime time.Time + AirdropDuration time.Duration + // denom of claimable asset + ClaimDenom string + // address of distributor account + DistributorAddress string +} +``` + +## Keeper functions + +Claim keeper module provides utility functions to manage epochs. + +```go + GetModuleAccountAddress(ctx sdk.Context) sdk.AccAddress + GetDistributorAccountBalance(ctx sdk.Context) sdk.Coin + EndAirdrop(ctx sdk.Context) error + GetClaimRecord(ctx sdk.Context, addr sdk.AccAddress) (types.ClaimRecord, error) + GetClaimRecords(ctx sdk.Context) []types.ClaimRecord + SetClaimRecord(ctx sdk.Context, claimRecord types.ClaimRecord) error + SetClaimRecords(ctx sdk.Context, claimRecords []types.ClaimRecord) error + GetClaimableAmountForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action, includeClaimed bool) (sdk.Coins, error) + GetUserTotalClaimable(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) + ClaimCoinsForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action) (sdk.Coins, error) + clearInitialClaimables(ctx sdk.Context) + fundRemainingsToCommunity(ctx sdk.Context) error +``` + +## React Hooks + +The claim module reacts on the following hooks, executed in external modules. + +20% of airdrop is sent to a vesting account when `staking.AfterDelegationModified` hook is triggered. +20% of airdrop is sent to a vesting account when `stakeibc.AfterLiquidStake` hook is triggered. + +Once the airdrop is claimed for a specific hook type, it can't be claimed again. + +### Claim Records + +```protobuf +// A Claim Records is the metadata of claim data per address +message ClaimRecord { + // address of claim user + string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; + + // weight that represent the portion from total allocations + double weight = 2; + + // true if action is completed + // index of bool in array refers to action enum # + repeated bool action_completed = 3 [ + (gogoproto.moretags) = "yaml:\"action_completed\"" + ]; +} +``` +When a user get airdrop for his/her action, claim record is created to prevent duplicated actions on future actions. + +### State + +```protobuf +message GenesisState { + // params defines all the parameters of the module. + Params params = 2 [ + (gogoproto.moretags) = "yaml:\"params\"", + (gogoproto.nullable) = false + ]; + + // list of claim records, one for every airdrop recipient + repeated ClaimRecord claim_records = 3 [ + (gogoproto.moretags) = "yaml:\"claim_records\"", + (gogoproto.nullable) = false + ]; +} +``` + +Claim module's state consists of `params`, and `claim_records`. + + +Claim module provides below params + +```protobuf +// Params defines the claim module's parameters. +message Params { + google.protobuf.Timestamp airdrop_start_time = 1 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"airdrop_start_time\"" + ]; + google.protobuf.Timestamp airdrop_duration = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "airdrop_duration,omitempty", + (gogoproto.moretags) = "yaml:\"airdrop_duration\"" + ]; + // denom of claimable asset + string claim_denom = 3; + // airdrop distribution account + string distributor_address = 4; +} +``` + +1. `airdrop_start_time` refers to the time when user can start to claim airdrop. +2. `airdrop_duration` refers to the duration from start time to end time. +3. `claim_denom` refers to the denomination of claiming tokens. As a default, it's `ustrd`. +4. `distributor_address` refers to the address of distribution account. + +## Queries + +### GRPC queries + +Claim module provides below GRPC queries to query claim status + +```protobuf +service Query { + rpc DistributorAccountBalance(QueryDistributorAccountBalanceRequest) returns (QueryDistributorAccountBalanceResponse) {} + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {} + rpc ClaimRecord(QueryClaimRecordRequest) returns (QueryClaimRecordResponse) {} + rpc ClaimableForAction(QueryClaimableForActionRequest) returns (QueryClaimableForActionResponse) {} + rpc TotalClaimable(QueryTotalClaimableRequest) returns (QueryTotalClaimableResponse) {} +} +``` + +### CLI commands + +For the following commands, you can change `$(strided keys show -a {your key name})` with the address directly. + +Query the claim record for a given address + +```sh +strided query claim claim-record $(strided keys show -a {your key name}) +``` + +Query the claimable amount that would be earned if a specific action is completed right now. + +```sh + +strided query claim claimable-for-action $(strided keys show -a {your key name}) ActionAddLiquidity +``` + +Query the total claimable amount that would be earned if all remaining actions were completed right now. + +```sh +strided query claim total-claimable $(strided keys show -a {your key name}) ActionAddLiquidity +``` + +## Events + +`claim` module emits the following events at the time of hooks: + +| Type | Attribute Key | Attribute Value | +| ----- | ------------- | --------------- | +| claim | sender | {receiver} | +| claim | amount | {claim_amount} | + diff --git a/readme-docs/md/epochs_README.md b/readme-docs/md/epochs_README.md new file mode 100644 index 0000000000..3f8f774a4c --- /dev/null +++ b/readme-docs/md/epochs_README.md @@ -0,0 +1,183 @@ +--- +title: "Epochs" +excerpt: "" +category: 6392913957c533007128548e +--- + + +# Epochs + +## Abstract
+ +While using the SDK, we often want to run certain code periodically. The `epochs` module allows other modules to be configured such that they are signaled once every period. So another module can specify it wants to execute code once a week, starting at UTC-time = x. `epochs` creates a generalized epoch interface to other modules so that they can easily be signalled upon such events. + +## Contents + +1. **[Concepts](#concepts)** +2. **[State](#state)** +3. **[Events](#events)** +4. **[Keeper](#keeper)** +5. **[Hooks](#hooks)** +6. **[Queries](#queries)** +7. **[Future Improvements](#future-improvements)** + +## Concepts + +Epochs are on-chain timers that have timer ticks at specific time intervals, triggering the execution of certain logic that is constrained by a specific epoch. The purpose of the `epochs` module is to provide a generalized epoch interface to other modules so that they can easily implement epochs without keeping their own code for epochs. + +Every epoch has a unique identifier. Every epoch will have a start time, and an end time, where `end_time = start_time + duration`. +When an epoch triggers the execution of code, that code is executed at the first block whose blocktime is greater than `end_time`. It follows that the `start_time` of the following epoch will be the `end_time` of the previous epoch. + +Stride uses three epoch identifiers as found in `x/epochs/genesis.go` + +1. `DAY_EPOCH`: this identifies an epoch that lasts 24 hours. +2. `STRIDE_EPOCH`: this identifies an epoch that lasts 5 minutes on local mode tesnet (although this may be changed) and longer on public testnet and mainnet, and is used in the `x/stakeibc/` module as a time interval in accordance with which the Stride app chain performs certain functions, such as autocompound stakig rewards. + +## State + +The `epochs` module keeps `EpochInfo` objects and modifies the information as epoch info changes. +Epochs are initialized as part of genesis initialization, and modified on begin blockers or end blockers. + +### Epoch information type + +```protobuf +message EpochInfo { + string identifier = 1; + google.protobuf.Timestamp start_time = 2 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"start_time\"" + ]; + google.protobuf.Duration duration = 3 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "duration,omitempty", + (gogoproto.moretags) = "yaml:\"duration\"" + ]; + int64 current_epoch = 4; + google.protobuf.Timestamp current_epoch_start_time = 5 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"current_epoch_start_time\"" + ]; + bool epoch_counting_started = 6; + reserved 7; + int64 current_epoch_start_height = 8; +} +``` + +`EpochInfo` keeps `identifier`, `start_time`,`duration`, `current_epoch`, `current_epoch_start_time`, `epoch_counting_started`, `current_epoch_start_height`. + +1. `identifier` keeps epoch identification string. +2. `start_time` keeps epoch counting start time, if block time passes `start_time`, `epoch_counting_started` is set. +3. `duration` keeps target epoch duration. +4. `current_epoch` keeps current active epoch number. +5. `current_epoch_start_time` keeps the start time of current epoch. +6. `epoch_number` is counted only when `epoch_counting_started` flag is set. +7. `current_epoch_start_height` keeps the start block height of current epoch. + +--- + +## Events + +The `epochs` module emits the following events: + +### BeginBlocker + +| Type | Attribute Key | Attribute Value | +| ----------- | ------------- | --------------- | +| epoch_start | epoch_number | {epoch_number} | +| epoch_start | start_time | {start_time} | + +### EndBlocker + +| Type | Attribute Key | Attribute Value | +| --------- | ------------- | --------------- | +| epoch_end | epoch_number | {epoch_number} | + +## Keeper + +### Keeper Functions + +`epochs/keeper/` module provides utility functions to manage epochs. + +```go +// Keeper is the interface for lockup module keeper +type Keeper interface { + // GetEpochInfo returns epoch info by identifier + GetEpochInfo(ctx sdk.Context, identifier string) types.EpochInfo + // SetEpochInfo set epoch info + SetEpochInfo(ctx sdk.Context, epoch types.EpochInfo) + // DeleteEpochInfo delete epoch info + DeleteEpochInfo(ctx sdk.Context, identifier string) + // IterateEpochInfo iterate through epochs + IterateEpochInfo(ctx sdk.Context, fn func(index int64, epochInfo types.EpochInfo) (stop bool)) + // Get all epoch infos + AllEpochInfos(ctx sdk.Context) []types.EpochInfo +} +``` + +## Hooks + +```go + // the first block whose timestamp is after the duration is counted as the end of the epoch + AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) + // new epoch is next block of epoch end block + BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) +``` + +The `BeforeEpochStart` hook does different things depending on the identifier. + +If in a `day` identifier it: + +1. begins unbondings +2. sweeps unbonded tokens to the redemption account +3. cleans up old records +4. creates empty epoch unbonding records for the next day + +If in a `stride_epoch` identifier it: 5. creates and deposits records on each host zone 6. sets withdrawal addresses 7. updates redemption rates (if the epoch coincides with the correct interval) 8. processes `TRANSFER_QUEUE` deposit records to the delegation Interchain Account (if the epoch coincides with the correct interval) 9. processes `DELEGATION_QUEUE` deposit records to the delegation Interchain Account (if the epoch coincides with the correct interval) 10. Query the rewards account using interchain queries, with the transfer callback to a delegation account as a staked record (if at proper interval) + +### How modules receive hooks + +On the hook receiver functions of other modules, they need to filter `epochIdentifier` and execute for only a specific `epochIdentifier`. +Filtering `epochIdentifier` could be in `Params` of other modules so that they can be modified by governance. +Governance can change an epoch from `week` to `day` as needed. + +## Queries + +`epochs` module provides the below queries to check the module's state + +```protobuf +service Query { + // EpochInfos provide running epochInfos + rpc EpochInfos(QueryEpochsInfoRequest) returns (QueryEpochsInfoResponse) {} + // CurrentEpoch provide current epoch of specified identifier + rpc CurrentEpoch(QueryCurrentEpochRequest) returns (QueryCurrentEpochResponse) {} +} +``` + +## Future Improvements + +### Lack point using this module + +In current design each epoch should be at least 2 blocks as start block should be different from endblock. +Because of this, each epoch time will be `max(blocks_time x 2, epoch_duration)`. +If epoch_duration is set to `1s`, and `block_time` is `5s`, actual epoch time should be `10s`. +We definitely recommend configure epoch_duration as more than 2x block_time, to use this module correctly. +If you enforce to set it to 1s, it's same as 10s - could make module logic invalid. + +TODO for postlaunch: We should see if we can architect things such that the receiver doesn't have to do this filtering, and the epochs module would pre-filter for them. + +### Block-time drifts problem + +This implementation has block time drift based on block time. +For instance, we have an epoch of 100 units that ends at t=100, if we have a block at t=97 and a block at t=104 and t=110, this epoch ends at t=104. +And new epoch start at t=110. There are time drifts here, for around 1-2 blocks time. +It will slow down epochs. + +It's going to slow down epoch by 10-20s per week when epoch duration is 1 week. This should be resolved after launch. diff --git a/readme-docs/md/icacallbacks_README.md b/readme-docs/md/icacallbacks_README.md new file mode 100644 index 0000000000..7ae0869300 --- /dev/null +++ b/readme-docs/md/icacallbacks_README.md @@ -0,0 +1,61 @@ +--- +title: "Icacallbacks" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The ICACallbacks Module + +Add `icacallbacks` module. Interchain accounts are very useful, but ICA calls triggered by automated logic on Stride are limited in functionality and difficult to work with due to a lack of callbacks. Most of Stride's interchain account logic is triggered epochly from the `BeginBlocker`, and state updates on Stride must be made after ICA calls are issued, based on the success / failure of those calls. + +The challenges faced before creating the icacallbacks modules were: +(1) Messages must be handled one-off (by matching on message type) - really what we want to do is update state in acks based on the _transaction_ sent +(2) Message responses are almost always empty, e.g. `MsgDelegateResponse`, which leads to +(3) Matching processed messages to state on the controller is very challenging (sometimes impossible) based on the attributes of the message sent. For example, given the following type +``` +type Gift struct { + from string + to string + amount int + reason string +} +``` +two ICA bank sends associated with gifts that have the same `from`, `to` and `amount` but _different_ `reasons` are indistinguishable today in acks. + +`icacontroller` solves the issues as follows +- Callbacks can be registered to process data associated with a particular IBC packet, per module (solves 1) +- ICA auth modules can store callback data using `icacallbacks`, passing in both a callback and args +- Arguments to the callback can be (un)marshaled and contain arbitrary keys, allowing for updates to data on the controller chain based on the success / failure of the ICA call (solves 2 / 3) + +### Technical notes +- Callbacks are uniquely identifiable through `portId/channelId/sequence` keys +- Only modules that have registered callbacks can invoke them +- `icacallbacks` doesn't have a message server / handler (it can only be called by other modules) +- `icacallbacks` does authentication by fetching the module associated with a packet (containing the registered callbacks) by calling `ChannelKeeper.LookupModuleByChannel` (it's permissioned at the module level) +- `icacallbacks` is an interchain account auth module, although it's possible this design could be generalized to work with other IBC modules +- in case of a timeout, callbacks are still executed with the ack set to an empty byte array +- We're using protos to serialize / deserialize callback arguments + +The flow to add callbacks is to call `ICACallbacksKeeper.SetCallbackData` after sending an IBC transaction. When the ack returns +- the callback is fetched using the callback key +- the module is fetched using the portId / channelId +and the callback is invoked and deleted. + +The middleware structure is as follows +![middleware](https://user-images.githubusercontent.com/1331345/183272460-5225d67d-95ee-47e2-8200-11de013a0695.png) + +### Invariants +- `portId, channelId` pair map to a unique module (important for fetching the correct `CallbackHandler` from a received packet) +- callback ids are unique within modules (they don't have to be unique between modules, because `CallICACallback` is scoped to a module) + +## Keeper functions +- `CallRegisteredICACallback()`: invokes the relevant callback asssociated with an ICA + +## State +- `CallbackData`: stores the callback type, arguments and associated packet +- `CallbackHandler` +- `Callbacks` +- `Callback` + +## Events +The `icacallbacks` module does not currently emit any events. diff --git a/readme-docs/md/interchainquery_README.md b/readme-docs/md/interchainquery_README.md new file mode 100644 index 0000000000..284af092d6 --- /dev/null +++ b/readme-docs/md/interchainquery_README.md @@ -0,0 +1,102 @@ +--- +title: "Interchainquery" +excerpt: "" +category: 6392913957c533007128548e +--- + + + +# Interchain Query + +## Abstract +Stride uses interchain queries and interchain accounts to perform multichain liquid staking. The `interchainquery` module creates a framework that allows other modules to query other appchains using IBC. The `interchainquery` module is used to make bank balance ICQ queries to withdrawal account every N. The callback triggers ICA bank sends for 90% of the rewards to the delegation account and 10% to the stride hostzone revenue account. The ICA bank send logic is in x/stakeibc/keeper/callbacks.go. + +## Contents + +1. **[Concepts](#concepts)** +2. **[State](#state)** +3. **[Events](#events)** +4. **[Keeper](#keeper)** +5. **[Msgs](#msgs)** + +## State + +The `interchainquery` module keeps `Query` objects and modifies the information from query to query, as defined in `proto/interchainquery/v1/genesis.proto` + +### InterchainQuery information type + +`Query` has information types that pertain to the query itself. `Query` keeps the following: + +1. `id` keeps the query identification string. +2. `connection_id` keeps the id of the channel or connection between the controller and host chain. +3. `chain_id` keeps the id of the queried chain. +4. `query_type` keeps the type of interchain query +5. `request` keeps an bytecode encoded version of the interchain query +6. `period` TODO +7. `last_height` keeps the blockheight of the last block before the query was made +8. `callback_id` keeps the function that will be called by the interchain query +9. `ttl` TODO +10. `height` keeps the height at which the ICQ query should execute on the host zone. This is often `0`, meaning the query should execute at the latest height on the host zone. + +`DataPoint` has information types that pertain to the data that is queried. `DataPoint` keeps the following: + +1. `id` keeps the identification string of the datapoint +2. `remote_height` keeps the block height of the queried chain +3. `local_height` keeps the block height of the querying chain +4. `value` keeps the bytecode value of the data retrieved by the Query + +## Events + +The `interchainquery` module emits an event at the end of every 3 `stride_epoch`s (e.g. 15 minutes on local testnet). + +The purpose of this event is to send interchainqueries that query data about staking rewards, which Stride uses to reinvest (aka autocompound) staking rewards. + +```go + event := sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeyAction, types.AttributeValueQuery), + sdk.NewAttribute(types.AttributeKeyQueryId, queryInfo.Id), + sdk.NewAttribute(types.AttributeKeyChainId, queryInfo.ChainId), + sdk.NewAttribute(types.AttributeKeyConnectionId, queryInfo.ConnectionId), + sdk.NewAttribute(types.AttributeKeyType, queryInfo.QueryType), + // TODO: add height to request type + sdk.NewAttribute(types.AttributeKeyHeight, "0"), + sdk.NewAttribute(types.AttributeKeyRequest, hex.EncodeToString(queryInfo.Request)), + ) +``` + +## Keeper + +### Keeper Functions +`interchainquery/keeper/` module provides utility functions to manage ICQs + +```go +// GetQuery returns query +GetQuery(ctx sdk.Context, id string) (types.Query, bool) +// SetQuery set query info +SetQuery(ctx sdk.Context, query types.Query) +// DeleteQuery delete query info +DeleteQuery(ctx sdk.Context, id string) +// IterateQueries iterate through queries +IterateQueries(ctx sdk.Context, fn func(index int64, queryInfo types.Query) (stop bool)) +// AllQueries returns every queryInfo in the store +AllQueries(ctx sdk.Context) []types.Query +``` + +## Msgs + +`interchainquery` has a `Msg` service that passes messages between chains. + +```protobuf +service Msg { + // SubmitQueryResponse defines a method for submiting query responses. + rpc SubmitQueryResponse(MsgSubmitQueryResponse) returns (MsgSubmitQueryResponseResponse) +} +``` + diff --git a/readme-docs/md/mint_README.md b/readme-docs/md/mint_README.md new file mode 100644 index 0000000000..b2b93b3a13 --- /dev/null +++ b/readme-docs/md/mint_README.md @@ -0,0 +1,131 @@ +--- +title: "Mint" +excerpt: "" +category: 6392913957c533007128548e +--- + + + +# The Mint Module + +The `x/mint` module mints tokens at the end of epochs. + +The `x/distribution` module is responsible for allocating tokens to stakers, community pool, etc. + +The mint module uses time basis epochs from the `x/epochs` module. + +The `x/mint` module is designed by Osmosis. It is used to handle the regular printing of new tokens within a chain. Its core function is to: +- Mint new tokens once per epoch (default one week) +- Have a "Reductioning factor" every period, which reduces the amount of rewards per epoch. + (default: period is 3 years, where a year is 52 epochs. The next period's rewards are 2/3 of the prior period's rewards) + +## Params + +Minting params are held in the global params store. + +```go +type Params struct { + MintDenom string // type of coin to mint + GenesisEpochProvisions sdk.Dec // initial epoch provisions at genesis + EpochIdentifier string // identifier of epoch + ReductionPeriodInEpochs int64 // number of epochs between reward reductions + ReductionFactor sdk.Dec // reduction multiplier to execute on each period + DistributionProportions DistributionProportions // distribution_proportions defines the proportion of the minted denom + WeightedDeveloperRewardsReceivers []WeightedAddress // address to receive developer rewards + MintingRewardsDistributionStartEpoch int64 // start epoch to distribute minting rewards +} +``` + +The minting module contains the following parameters: + +| Key | Type | Example | +| ------------------------------------------ | ------------ | -------------------------------------- | +| mint_denom | string | "uosmo" | +| genesis_epoch_provisions | string (dec) | "500000000" | +| epoch_identifier | string | "weekly" | +| reduction_period_in_epochs | int64 | 156 | +| reduction_factor | string (dec) | "0.6666666666666" | +| distribution_proportions.staking | string (dec) | "0.4" | +| distribution_proportions.pool_incentives | string (dec) | "0.3" | +| distribution_proportions.developer_rewards | string (dec) | "0.2" | +| distribution_proportions.community_pool | string (dec) | "0.1" | +| weighted_developer_rewards_receivers | array | [{"address": "osmoxx", "weight": "1"}] | +| minting_rewards_distribution_start_epoch | int64 | 10 | + + + +## EpochProvision + +Calculate the provisions generated for each epoch based on current epoch provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount`. These rewards are transferred to a `FeeCollector`, which handles distributing the rewards per the chains needs. (See TODO.md for details) This fee collector is specified as the `auth` module's `FeeCollector` `ModuleAccount`. + +```go +func (m Minter) EpochProvision(params Params) sdk.Coin { + provisionAmt := m.EpochProvisions.QuoInt(sdk.NewInt(int64(params.EpochsPerYear))) + return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()) +} +``` + +**Notes** +1. `mint_denom` defines denom for minting token - uosmo +2. `genesis_epoch_provisions` provides minting tokens per epoch at genesis. +3. `epoch_identifier` defines the epoch identifier to be used for mint module e.g. "weekly" +4. `reduction_period_in_epochs` defines the number of epochs to pass to reduce mint amount +5. `reduction_factor` defines the reduction factor of tokens at every `reduction_period_in_epochs` +6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distribute tokens to community pool. +7. `weighted_developer_rewards_receivers` provides the addresses that receives developer rewards by weight +8. `minting_rewards_distribution_start_epoch` defines the start epoch of minting to make sure minting start after initial pools are set + + +## Begin-Epoch + +Minting parameters are recalculated and inflation +paid at the beginning of each epoch. An epoch is signalled by x/epochs + +## NextEpochProvisions + +The target epoch provision is recalculated on each reduction period (default 3 years). +At the time of reduction, the current provision is multiplied by reduction factor (default `2/3`), +to calculate the provisions for the next epoch. Consequently, the rewards of the next period +will be lowered by `1 - reduction factor`. + +```go +func (m Minter) NextEpochProvisions(params Params) sdk.Dec { + return m.EpochProvisions.Mul(params.ReductionFactor) +} +``` +## Reductioning factor + +This is a generalization over the Bitcoin style halvenings. +Every year, the amount of rewards issued per week will reduce by a governance specified factor, instead of a fixed `1/2`. +So `RewardsPerEpochNextPeriod = ReductionFactor * CurrentRewardsPerEpoch)`. +When `ReductionFactor = 1/2`, the Bitcoin halvenings are recreated. +We default to having a reduction factor of `2/3`, and thus reduce rewards at the end of every year by `33%`. + +The implication of this is that the total supply is finite, according to the following formula: + +$$Total\ Supply = InitialSupply + EpochsPerPeriod * \frac{InitialRewardsPerEpoch}{1 - ReductionFactor} $$ + +## Events + +The minting module emits the following events: + +### End of Epoch + +| Type | Attribute Key | Attribute Value | +| ---- | ---------------- | ----------------- | +| mint | epoch_number | {epochNumber} | +| mint | epoch_provisions | {epochProvisions} | +| mint | amount | {amount} | + + +## Minter + +The minter is a space for holding current rewards information. + +```go +type Minter struct { + EpochProvisions sdk.Dec // Rewards for the current epoch +} +``` \ No newline at end of file diff --git a/readme-docs/md/records_README.md b/readme-docs/md/records_README.md new file mode 100644 index 0000000000..76ebb12aa9 --- /dev/null +++ b/readme-docs/md/records_README.md @@ -0,0 +1,73 @@ +--- +title: "Records" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The Records Module + +The records module handles record keeping and accounting for the Stride blockchain. + +It is [IBC middleware](https://ibc.cosmos.network/main/ibc/middleware/develop.html). IBC middleware wraps core IBC modules and other middlewares. Specifically, the records module adds a middleware stack to `app.go` with the following structure: `records -> transfer`. All ibc packets routed to the `transfer` module will first pass through `records`, where we can apply custom logic (record keeping) before passing messages to the underlying `transfer` module. + +Note: +- The middleware stack is added in `app.go` +- The custom handler logic is added in `ibc_module.go` by implementing the IBCModule interface + +## Keeper functions + +Deposit Records +- `GetDepositRecordCount()` +- `SetDepositRecordCount()` +- `AppendDepositRecord()` +- `SetDepositRecord()` +- `GetDepositRecord()` +- `RemoveDepositRecord()` +- `GetAllDepositRecord()` +- `GetDepositRecordByEpochAndChain()` + +Epoch Unbonding Records +- `SetEpochUnbondingRecord()` +- `GetEpochUnbondingRecord()` +- `RemoveEpochUnbondingRecord()` +- `GetAllEpochUnbondingRecord()` +- `GetAllPreviousEpochUnbondingRecords()` +- `GetHostZoneUnbondingByChainId()` +- `AddHostZoneToEpochUnbondingRecord()` +- `SetHostZoneUnbondings()` + +User Redemption Records +- `SetUserRedemptionRecord()` +- `GetUserRedemptionRecord()` +- `RemoveUserRedemptionRecord()` +- `GetAllUserRedemptionRecord()` +- `IterateUserRedemptionRecords()` + +## State + +Callbacks +- `TransferCallback` + +Genesis +- `UserRedemptionRecord` +- `Params` +- `RecordsPacketData` +- `NoData` +- `DepositRecord` +- `HostZoneUnbonding` +- `EpochUnbondingRecord` +- `GenesisState` + +## Queries + +- `Params` +- `GetDepositRecord` +- `AllDepositRecord` +- `GetUserRedemptionRecord` +- `AllUserRedemptionRecord` +- `AllUserRedemptionRecordForUser` +- `GetEpochUnbondingRecord` +- `AllEpochUnbondingRecord` + +## Events +The `records` module emits does not currently emit any events. diff --git a/readme-docs/md/stakeibc_README.md b/readme-docs/md/stakeibc_README.md new file mode 100644 index 0000000000..fc86c835e4 --- /dev/null +++ b/readme-docs/md/stakeibc_README.md @@ -0,0 +1,120 @@ +--- +title: "StakeIBC" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The StakeIBC Module + +The StakeIBC Module contains Stride's main app logic: +- it exposes core liquid staking entry points to the user (liquid staking and redeeming) +- it executes automated beginBlocker and endBlocker logic to stake funds on relevant host zones using Interchain Accounts +- it handles registering new host zones and adjusting host zone validator sets and weights +- it defines Stride's core data structures (e.g. hostZone) +- it defines all the callbacks used when issuing Interchain Account logic + +Nearly all of Stride's functionality is built using interchain accounts (ICAs), which are a new functionality in Cosmos, and a critical component of IBC. ICAs allow accounts on Zone A to be controlled by Zone B. ICAs communicate with one another using Interchain Queries (ICQs), which involve Zone A querying Zone B for relevant information. + +Two Zones communicate via a connection and channel. All communications between the Controller Zone (the chain that is querying) and the Host Zone (the chain that is being queried) is done through a dedicated IBC channel between the two chains, which is opened the first time the two chains interact. + +For context, ICS standards define that each channel is associated with a particular connection, and a connection may have any number of associated channels. + +## Params +``` +DepositInterval (default uint64 = 1) +DelegateInterval (default uint64 = 1) +ReinvestInterval (default uint64 = 1) +RewardsInterval (default uint64 = 1) +RedemptionRateInterval (default uint64 = 1) +StrideCommission (default uint64 = 10) +ValidatorRebalancingThreshold (default uint64 = 100) +ICATimeoutNanos(default uint64 = 600000000000) +BufferSize (default uint64 = 5) +IbcTimeoutBlocks (default uint64 = 300) +FeeTransferTimeoutNanos (default uint64 = 1800000000000 +SafetyMinRedemptionRateThreshold (default uint64 = 90) +SafetyMaxRedemptionRateThreshold (default uint64 = 150) +MaxStakeICACallsPerEpoch (default uint64 = 100) +IBCTransferTimeoutNanos (default uint64 = 1800000000000) +SafetyNumValidators (default uint64 = 35) +``` + +## Keeper functions + +- `LiquidStake()` +- `RedeemStake()` +- `ClaimUndelegatedTokens()` +- `RebalanceValidators()` +- `AddValidator()` +- `ChangeValidatorWeight()` +- `DeleteValidator()` +- `RegisterHostZone()` +- `ClearBalance()` +- `RestoreInterchainAccount()` +- `UpdateValidatorSharesExchRate()` + +## State + +Callbacks +- `SplitDelegation` +- `DelegateCallback` +- `ClaimCallback` +- `ReinvestCallback` +- `UndelegateCallback` +- `RedemptionCallback` +- `Rebalancing` +- `RebalanceCallback` + +HostZone +- `HostZone` +- `ICAAccount` +- `MinValidatorRequirements` + +Host Zone Validators +- `Validator` +- `ValidatorExchangeRate` + +Misc +- `GenesisState` +- `EpochTracker` +- `Delegation` + +Governance +- `AddValidatorProposal` + +## Queries + +- `QueryInterchainAccountFromAddressRequest` +- `QueryInterchainAccountFromAddressResponse` +- `QueryParamsRequest` +- `QueryParamsResponse` +- `QueryGetValidatorsRequest` +- `QueryGetValidatorsResponse` +- `QueryGetICAAccountRequest` +- `QueryGetICAAccountResponse` +- `QueryGetHostZoneRequest` +- `QueryGetHostZoneResponse` +- `QueryAllHostZoneRequest` +- `QueryAllHostZoneResponse` +- `QueryModuleAddressRequest` +- `QueryModuleAddressResponse` +- `QueryGetEpochTrackerRequest` +- `QueryGetEpochTrackerResponse` +- `QueryAllEpochTrackerRequest` +- `QueryAllEpochTrackerResponse` + +## Events + +`stakeibc` module emits the following events: + +Type: Attribute Key → Attribute Value +-------------------------------------------------- +registerHostZone: module → stakeibc +registerHostZone: connectionId → connectionId +registerHostZone: chainId → chainId +submitHostZoneUnbonding: hostZone → chainId +submitHostZoneUnbonding: newAmountUnbonding → totalAmtToUnbond +stakeExistingDepositsOnHostZone: hostZone → chainId +stakeExistingDepositsOnHostZone: newAmountStaked → amount +onAckPacket (IBC): module → moduleName +onAckPacket (IBC): ack → ackInfo diff --git a/x/README.md b/x/README.md index a3a9bb6a8d..1b7e781ec5 100644 --- a/x/README.md +++ b/x/README.md @@ -3,17 +3,31 @@ title: "Stride Modules" excerpt: "" category: 62c5c5ff03a5bf069004def2 --- -# Stride modules -Stride implements the following custom modules: -* `epochs` - Makes on-chain timers which other modules can execute code during. -* `mint` - Controls token supply emissions, and what modules they are directed to. -* `interchainquery` - Issues queries between IBC chains, verifies state proof and executes callbacks. -* `records` - IBC middleware wrapping the transfer module, does record keeping on IBC transfers and ICA calls -* `stakeibc` - Manages minting and burning of `stAssets`, staking and unstaking of native assets across chains. -* `icacallbacks` - Callbacks for interchain accounts. +## Stride Modules -This is done in addition to updates to several modules within the SDK. +`stakeibc` - Manages minting and burning of stAssets, staking and unstaking of native assets across chains. +`icacallbacks` - Callbacks for interchain accounts. +`records` - IBC middleware wrapping the transfer module, does record keeping on IBC transfers and ICA calls +`claim` - airdrop logic for Stride's rolling, task-based airdrop +`interchainquery` - Issues queries between IBC chains, verifies state proof and executes callbacks. +`epochs` - Makes on-chain timers which other modules can execute code during. +`mint` - Controls token supply emissions, and what modules they are directed to. -* `gov` - {Voting period changes} -* `vesting` - {vesting changes} +### Attribution + +Stride is proud to be an open-source project, and we welcome all other projects to use our repo. We use modules from the cosmos-sdk and other open source projects. + +We operate under the Apache 2.0 License, and have used the following modules from fellow Cosmos projects. Huge thank you to these projects! + +We use the following modules from [Osmosis](https://github.com/osmosis-labs/osmosis) provided under [this License](https://github.com/osmosis-labs/osmosis/blob/main/LICENSE): +``` +x/epochs +x/mint +``` +We use the following module (marketed as public infra) from [Quicksilver](https://github.com/ingenuity-build/quicksilver) provided under [this License](https://github.com/ingenuity-build/quicksilver/blob/main/LICENSE): +``` +x/interchainqueries +``` + +Relevant licenses with full attribution can be found in the relevant repo subdirectories. \ No newline at end of file diff --git a/x/claim/README.md b/x/claim/README.md new file mode 100644 index 0000000000..1ab120ca93 --- /dev/null +++ b/x/claim/README.md @@ -0,0 +1,217 @@ +--- +title: "Claim" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The Claim Module + +Users are required participate in core network activities to claim their airdrop. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: +* 20% vesting over 3 months by staking +* 60% vesting over 3 months by liquid staking + +These claimable assets 'expire' if not claimed. Users have three months (`AirdropDuration`) to claim their full airdrop amount. After three months from launch, all unclaimed tokens get sent to the community pool. At initialization, module stores all airdrop users with amounts from genesis inside KVStore. Airdrop users are eligible to claim their vesting or free amount only once in the initial period of 3 months. After the initial period, users can claim tokens monthly. + +## Actions + +There are 2 types of actions, each of which release another 50% of the airdrop allocation. +The 2 actions are as follows: + +```golang +ActionLiquidStake Action = 0 +ActionDelegateStake Action = 1 +``` + +These actions are monitored by registring claim **hooks** to the stakeibc, and staking modules. +This means that when you perform an action, the claims module will immediately unlock those coins if they are applicable. +These actions can be performed in any order. + +The code is structured by separating out a segment of the tokens as "claimable", indexed by each action type. +So if Alice delegates tokens, the claims module will move the 50% of the claimables associated with staking to her liquid balance. +If she delegates again, there will not be additional tokens given, as the relevant action has already been performed. +Every action must be performed to claim the full amount. + +## ClaimRecords + +A claim record is a struct that contains data about the claims process of each airdrop recipient. + +It contains an address, the initial claimable airdrop amount, and an array of bools representing +whether each action has been completed. The position in the array refers to enum number of the action. + +So for example, `[true, true]` means that `ActionLiquidStake` and `ActionDelegateStake` are completed. + +```golang +type ClaimRecord struct { + // address of claim user + Address string + // weight that represent the portion from total allocation + Weight sdk.Dec + // true if action is completed + // index of bool in array refers to action enum # + ActionCompleted []bool +} + +``` + +## Params + +The airdrop logic has 4 parameters: + +```golang +type Params struct { + // Time that marks the beginning of the airdrop disbursal, + // should be set to chain launch time. + AirdropStartTime time.Time + AirdropDuration time.Duration + // denom of claimable asset + ClaimDenom string + // address of distributor account + DistributorAddress string +} +``` + +## Keeper functions + +Claim keeper module provides utility functions to manage epochs. + +```go + GetModuleAccountAddress(ctx sdk.Context) sdk.AccAddress + GetDistributorAccountBalance(ctx sdk.Context) sdk.Coin + EndAirdrop(ctx sdk.Context) error + GetClaimRecord(ctx sdk.Context, addr sdk.AccAddress) (types.ClaimRecord, error) + GetClaimRecords(ctx sdk.Context) []types.ClaimRecord + SetClaimRecord(ctx sdk.Context, claimRecord types.ClaimRecord) error + SetClaimRecords(ctx sdk.Context, claimRecords []types.ClaimRecord) error + GetClaimableAmountForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action, includeClaimed bool) (sdk.Coins, error) + GetUserTotalClaimable(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) + ClaimCoinsForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action) (sdk.Coins, error) + clearInitialClaimables(ctx sdk.Context) + fundRemainingsToCommunity(ctx sdk.Context) error +``` + +## React Hooks + +The claim module reacts on the following hooks, executed in external modules. + +20% of airdrop is sent to a vesting account when `staking.AfterDelegationModified` hook is triggered. +20% of airdrop is sent to a vesting account when `stakeibc.AfterLiquidStake` hook is triggered. + +Once the airdrop is claimed for a specific hook type, it can't be claimed again. + +### Claim Records + +```protobuf +// A Claim Records is the metadata of claim data per address +message ClaimRecord { + // address of claim user + string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; + + // weight that represent the portion from total allocations + double weight = 2; + + // true if action is completed + // index of bool in array refers to action enum # + repeated bool action_completed = 3 [ + (gogoproto.moretags) = "yaml:\"action_completed\"" + ]; +} +``` +When a user get airdrop for his/her action, claim record is created to prevent duplicated actions on future actions. + +### State + +```protobuf +message GenesisState { + // params defines all the parameters of the module. + Params params = 2 [ + (gogoproto.moretags) = "yaml:\"params\"", + (gogoproto.nullable) = false + ]; + + // list of claim records, one for every airdrop recipient + repeated ClaimRecord claim_records = 3 [ + (gogoproto.moretags) = "yaml:\"claim_records\"", + (gogoproto.nullable) = false + ]; +} +``` + +Claim module's state consists of `params`, and `claim_records`. + + +Claim module provides below params + +```protobuf +// Params defines the claim module's parameters. +message Params { + google.protobuf.Timestamp airdrop_start_time = 1 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"airdrop_start_time\"" + ]; + google.protobuf.Timestamp airdrop_duration = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "airdrop_duration,omitempty", + (gogoproto.moretags) = "yaml:\"airdrop_duration\"" + ]; + // denom of claimable asset + string claim_denom = 3; + // airdrop distribution account + string distributor_address = 4; +} +``` + +1. `airdrop_start_time` refers to the time when user can start to claim airdrop. +2. `airdrop_duration` refers to the duration from start time to end time. +3. `claim_denom` refers to the denomination of claiming tokens. As a default, it's `ustrd`. +4. `distributor_address` refers to the address of distribution account. + +## Queries + +### GRPC queries + +Claim module provides below GRPC queries to query claim status + +```protobuf +service Query { + rpc DistributorAccountBalance(QueryDistributorAccountBalanceRequest) returns (QueryDistributorAccountBalanceResponse) {} + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {} + rpc ClaimRecord(QueryClaimRecordRequest) returns (QueryClaimRecordResponse) {} + rpc ClaimableForAction(QueryClaimableForActionRequest) returns (QueryClaimableForActionResponse) {} + rpc TotalClaimable(QueryTotalClaimableRequest) returns (QueryTotalClaimableResponse) {} +} +``` + +### CLI commands + +For the following commands, you can change `$(strided keys show -a {your key name})` with the address directly. + +Query the claim record for a given address + +```sh +strided query claim claim-record $(strided keys show -a {your key name}) +``` + +Query the claimable amount that would be earned if a specific action is completed right now. + +```sh + +strided query claim claimable-for-action $(strided keys show -a {your key name}) ActionAddLiquidity +``` + +Query the total claimable amount that would be earned if all remaining actions were completed right now. + +```sh +strided query claim total-claimable $(strided keys show -a {your key name}) ActionAddLiquidity +``` + +## Events + +`claim` module emits the following events at the time of hooks: + +| Type | Attribute Key | Attribute Value | +| ----- | ------------- | --------------- | +| claim | sender | {receiver} | +| claim | amount | {claim_amount} | + diff --git a/x/claim/spec/01_concepts.md b/x/claim/spec/01_concepts.md deleted file mode 100644 index dcc05c86ae..0000000000 --- a/x/claim/spec/01_concepts.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "Claim Module: Overview" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - - -# Concepts - -In Stride, users are required to claim their airdrop by participating in core network activities. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: - -* 20% vesting over 3 months by staking -* 60% vesting over 3 months by liquid staking - -At initial, module stores all airdrop users with amounts from genesis inside KVStore. - -Airdrop users are eligible to claim their vesting or free amount only once in the initial period of 3 months and after the initial period, users can claim tokens monthly not in vesting format. diff --git a/x/claim/spec/02_state.md b/x/claim/spec/02_state.md deleted file mode 100644 index df0e6a3364..0000000000 --- a/x/claim/spec/02_state.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "Claim Module: State" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# State - -### Claim Records - -```protobuf -// A Claim Records is the metadata of claim data per address -message ClaimRecord { - // address of claim user - string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; - - // weight that represent the portion from total allocations - double weight = 2; - - // true if action is completed - // index of bool in array refers to action enum # - repeated bool action_completed = 3 [ - (gogoproto.moretags) = "yaml:\"action_completed\"" - ]; -} -``` -When a user get airdrop for his/her action, claim record is created to prevent duplicated actions on future actions. - -### State - -```protobuf -message GenesisState { - // params defines all the parameters of the module. - Params params = 2 [ - (gogoproto.moretags) = "yaml:\"params\"", - (gogoproto.nullable) = false - ]; - - // list of claim records, one for every airdrop recipient - repeated ClaimRecord claim_records = 3 [ - (gogoproto.moretags) = "yaml:\"claim_records\"", - (gogoproto.nullable) = false - ]; -} -``` - -Claim module's state consists of `params`, and `claim_records`. diff --git a/x/claim/spec/03_events.md b/x/claim/spec/03_events.md deleted file mode 100644 index 6f4c86f2ae..0000000000 --- a/x/claim/spec/03_events.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "Claim Module: Events" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - -# Events - -## External module hooks - -`claim` module emits the following events at the time of hooks: - -| Type | Attribute Key | Attribute Value | -| ----- | ------------- | --------------- | -| claim | sender | {receiver} | -| claim | amount | {claim_amount} | - diff --git a/x/claim/spec/04_keeper.md b/x/claim/spec/04_keeper.md deleted file mode 100644 index e27cb057a5..0000000000 --- a/x/claim/spec/04_keeper.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Claim Module: Keeper" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Keepers - -## Keeper functions - -Claim keeper module provides utility functions to manage epochs. - -```go - GetModuleAccountAddress(ctx sdk.Context) sdk.AccAddress - GetDistributorAccountBalance(ctx sdk.Context) sdk.Coin - EndAirdrop(ctx sdk.Context) error - GetClaimRecord(ctx sdk.Context, addr sdk.AccAddress) (types.ClaimRecord, error) - GetClaimRecords(ctx sdk.Context) []types.ClaimRecord - SetClaimRecord(ctx sdk.Context, claimRecord types.ClaimRecord) error - SetClaimRecords(ctx sdk.Context, claimRecords []types.ClaimRecord) error - GetClaimableAmountForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action, includeClaimed bool) (sdk.Coins, error) - GetUserTotalClaimable(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) - ClaimCoinsForAction(ctx sdk.Context, addr sdk.AccAddress, action types.Action) (sdk.Coins, error) - clearInitialClaimables(ctx sdk.Context) - fundRemainingsToCommunity(ctx sdk.Context) error -``` diff --git a/x/claim/spec/05_react_hooks.md b/x/claim/spec/05_react_hooks.md deleted file mode 100644 index bdc9ec7cfd..0000000000 --- a/x/claim/spec/05_react_hooks.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Claim Module: React Hooks" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# React Hooks - -Claim module react on following hooks of external modules. - -20% of airdrop is sent to a vesting account when `staking.AfterDelegationModified` hook is triggered. -20% of airdrop is sent to a vesting account when `stakeibc.AfterLiquidStake` hook is triggered. - -When airdrop is claimed for specific hook type, it can't be claimed double. diff --git a/x/claim/spec/06_queries.md b/x/claim/spec/06_queries.md deleted file mode 100644 index b32d518e12..0000000000 --- a/x/claim/spec/06_queries.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: "Claim Module: Queries" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Queries - -## GRPC queries - -Claim module provides below GRPC queries to query claim status - -```protobuf -service Query { - rpc DistributorAccountBalance(QueryDistributorAccountBalanceRequest) returns (QueryDistributorAccountBalanceResponse) {} - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {} - rpc ClaimRecord(QueryClaimRecordRequest) returns (QueryClaimRecordResponse) {} - rpc ClaimableForAction(QueryClaimableForActionRequest) returns (QueryClaimableForActionResponse) {} - rpc TotalClaimable(QueryTotalClaimableRequest) returns (QueryTotalClaimableResponse) {} -} -``` - -## CLI commands - -For the following commands, you can change `$(strided keys show -a {your key name})` with the address directly. - -Query the claim record for a given address - -```sh -strided query claim claim-record $(strided keys show -a {your key name}) -``` - -Query the claimable amount that would be earned if a specific action is completed right now. - -```sh - -strided query claim claimable-for-action $(strided keys show -a {your key name}) ActionAddLiquidity -``` - -Query the total claimable amount that would be earned if all remaining actions were completed right now. - -```sh -strided query claim total-claimable $(strided keys show -a {your key name}) ActionAddLiquidity -``` diff --git a/x/claim/spec/07_params.md b/x/claim/spec/07_params.md deleted file mode 100644 index 757a4cbf3d..0000000000 --- a/x/claim/spec/07_params.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Claim Module: Params" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Params :) - -Claim module provides below params - -```protobuf -// Params defines the claim module's parameters. -message Params { - google.protobuf.Timestamp airdrop_start_time = 1 [ - (gogoproto.stdtime) = true, - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"airdrop_start_time\"" - ]; - google.protobuf.Timestamp airdrop_duration = 2 [ - (gogoproto.nullable) = false, - (gogoproto.stdduration) = true, - (gogoproto.jsontag) = "airdrop_duration,omitempty", - (gogoproto.moretags) = "yaml:\"airdrop_duration\"" - ]; - // denom of claimable asset - string claim_denom = 3; - // airdrop distribution account - string distributor_address = 4; -} -``` - -1. `airdrop_start_time` refers to the time when user can start to claim airdrop. -2. `airdrop_duration` refers to the duration from start time to end time. -3. `claim_denom` refers to the denomination of claiming tokens. As a default, it's `ustrd`. -4. `distributor_address` refers to the address of distribution account. \ No newline at end of file diff --git a/x/claim/spec/README.md b/x/claim/spec/README.md deleted file mode 100644 index 9a859bb99d..0000000000 --- a/x/claim/spec/README.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: "Claim Module" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - -# Claims module - -## Abstract - -The Stride claims module has users claim higher percentages as they perform certain tasks on-chain. -Furthermore, these claimable assets 'expire' if not claimed. -Users have three months (`AirdropDuration`) to claim their full airdrop amount -After three months from launch, all unclaimed tokens get sent to the community pool. - -## Contents - -1. **[Concept](01_concepts.md)** -2. **[State](02_state.md)** -3. **[Events](03_events.md)** -4. **[Keeper](04_keeper.md)** -5. **[React Hooks](05_react_hooks.md)** -6. **[Queries](06_queries.md)** -7. **[Params](07_params.md)** - -## Genesis State - -## Actions - -There are 2 types of actions, each of which release another 50% of the airdrop allocation. -The 2 actions are as follows: - -```golang -ActionLiquidStake Action = 0 -ActionDelegateStake Action = 1 -``` - -These actions are monitored by registring claim **hooks** to the stakeibc, and staking modules. -This means that when you perform an action, the claims module will immediately unlock those coins if they are applicable. -These actions can be performed in any order. - -The code is structured by separating out a segment of the tokens as "claimable", indexed by each action type. -So if Alice delegates tokens, the claims module will move the 50% of the claimables associated with staking to her liquid balance. -If she delegates again, there will not be additional tokens given, as the relevant action has already been performed. -Every action must be performed to claim the full amount. - -## ClaimRecords - -A claim record is a struct that contains data about the claims process of each airdrop recipient. - -It contains an address, the initial claimable airdrop amount, and an array of bools representing -whether each action has been completed. The position in the array refers to enum number of the action. - -So for example, `[true, true]` means that `ActionLiquidStake` and `ActionDelegateStake` are completed. - -```golang -type ClaimRecord struct { - // address of claim user - Address string - // weight that represent the portion from total allocation - Weight sdk.Dec - // true if action is completed - // index of bool in array refers to action enum # - ActionCompleted []bool -} - -``` - - -## Params - -The airdrop logic has 4 parameters: - -```golang -type Params struct { - // Time that marks the beginning of the airdrop disbursal, - // should be set to chain launch time. - AirdropStartTime time.Time - AirdropDuration time.Duration - // denom of claimable asset - ClaimDenom string - // address of distributor account - DistributorAddress string -} -``` diff --git a/x/epochs/README.md b/x/epochs/README.md index 67a6f70f86..3f8f774a4c 100644 --- a/x/epochs/README.md +++ b/x/epochs/README.md @@ -1,7 +1,7 @@ --- -title: "Epochs Module" +title: "Epochs" excerpt: "" -category: 62c5c5ff03a5bf069004def2 +category: 6392913957c533007128548e --- + +# The Mint Module + +The `x/mint` module mints tokens at the end of epochs. + +The `x/distribution` module is responsible for allocating tokens to stakers, community pool, etc. + +The mint module uses time basis epochs from the `x/epochs` module. + +The `x/mint` module is designed by Osmosis. It is used to handle the regular printing of new tokens within a chain. Its core function is to: +- Mint new tokens once per epoch (default one week) +- Have a "Reductioning factor" every period, which reduces the amount of rewards per epoch. + (default: period is 3 years, where a year is 52 epochs. The next period's rewards are 2/3 of the prior period's rewards) + +## Params + +Minting params are held in the global params store. + +```go +type Params struct { + MintDenom string // type of coin to mint + GenesisEpochProvisions sdk.Dec // initial epoch provisions at genesis + EpochIdentifier string // identifier of epoch + ReductionPeriodInEpochs int64 // number of epochs between reward reductions + ReductionFactor sdk.Dec // reduction multiplier to execute on each period + DistributionProportions DistributionProportions // distribution_proportions defines the proportion of the minted denom + WeightedDeveloperRewardsReceivers []WeightedAddress // address to receive developer rewards + MintingRewardsDistributionStartEpoch int64 // start epoch to distribute minting rewards +} +``` + +The minting module contains the following parameters: + +| Key | Type | Example | +| ------------------------------------------ | ------------ | -------------------------------------- | +| mint_denom | string | "uosmo" | +| genesis_epoch_provisions | string (dec) | "500000000" | +| epoch_identifier | string | "weekly" | +| reduction_period_in_epochs | int64 | 156 | +| reduction_factor | string (dec) | "0.6666666666666" | +| distribution_proportions.staking | string (dec) | "0.4" | +| distribution_proportions.pool_incentives | string (dec) | "0.3" | +| distribution_proportions.developer_rewards | string (dec) | "0.2" | +| distribution_proportions.community_pool | string (dec) | "0.1" | +| weighted_developer_rewards_receivers | array | [{"address": "osmoxx", "weight": "1"}] | +| minting_rewards_distribution_start_epoch | int64 | 10 | + + + +## EpochProvision + +Calculate the provisions generated for each epoch based on current epoch provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount`. These rewards are transferred to a `FeeCollector`, which handles distributing the rewards per the chains needs. (See TODO.md for details) This fee collector is specified as the `auth` module's `FeeCollector` `ModuleAccount`. + +```go +func (m Minter) EpochProvision(params Params) sdk.Coin { + provisionAmt := m.EpochProvisions.QuoInt(sdk.NewInt(int64(params.EpochsPerYear))) + return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()) +} +``` + +**Notes** +1. `mint_denom` defines denom for minting token - uosmo +2. `genesis_epoch_provisions` provides minting tokens per epoch at genesis. +3. `epoch_identifier` defines the epoch identifier to be used for mint module e.g. "weekly" +4. `reduction_period_in_epochs` defines the number of epochs to pass to reduce mint amount +5. `reduction_factor` defines the reduction factor of tokens at every `reduction_period_in_epochs` +6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distribute tokens to community pool. +7. `weighted_developer_rewards_receivers` provides the addresses that receives developer rewards by weight +8. `minting_rewards_distribution_start_epoch` defines the start epoch of minting to make sure minting start after initial pools are set + + +## Begin-Epoch + +Minting parameters are recalculated and inflation +paid at the beginning of each epoch. An epoch is signalled by x/epochs + +## NextEpochProvisions + +The target epoch provision is recalculated on each reduction period (default 3 years). +At the time of reduction, the current provision is multiplied by reduction factor (default `2/3`), +to calculate the provisions for the next epoch. Consequently, the rewards of the next period +will be lowered by `1 - reduction factor`. + +```go +func (m Minter) NextEpochProvisions(params Params) sdk.Dec { + return m.EpochProvisions.Mul(params.ReductionFactor) +} +``` +## Reductioning factor + +This is a generalization over the Bitcoin style halvenings. +Every year, the amount of rewards issued per week will reduce by a governance specified factor, instead of a fixed `1/2`. +So `RewardsPerEpochNextPeriod = ReductionFactor * CurrentRewardsPerEpoch)`. +When `ReductionFactor = 1/2`, the Bitcoin halvenings are recreated. +We default to having a reduction factor of `2/3`, and thus reduce rewards at the end of every year by `33%`. + +The implication of this is that the total supply is finite, according to the following formula: + +$$Total\ Supply = InitialSupply + EpochsPerPeriod * \frac{InitialRewardsPerEpoch}{1 - ReductionFactor} $$ + +## Events + +The minting module emits the following events: + +### End of Epoch + +| Type | Attribute Key | Attribute Value | +| ---- | ---------------- | ----------------- | +| mint | epoch_number | {epochNumber} | +| mint | epoch_provisions | {epochProvisions} | +| mint | amount | {amount} | + + +## Minter + +The minter is a space for holding current rewards information. + +```go +type Minter struct { + EpochProvisions sdk.Dec // Rewards for the current epoch +} +``` \ No newline at end of file diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md deleted file mode 100644 index 6a79334919..0000000000 --- a/x/mint/spec/01_concepts.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Mint Module: Concepts" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Concepts - -The `x/mint` module is designed to handle the regular printing of new tokens within a chain. -The design taken within Osmosis is to - -- Mint new tokens once per epoch (default one week) -- To have a "Reductioning factor" every period, which reduces the amount of rewards per epoch. - (default: period is 3 years, where a year is 52 epochs. The next period's rewards are 2/3 of the prior period's rewards) - -## Reductioning factor - -This is a generalization over the Bitcoin style halvenings. -Every year, the amount of rewards issued per week will reduce by a governance specified factor, instead of a fixed `1/2`. -So `RewardsPerEpochNextPeriod = ReductionFactor * CurrentRewardsPerEpoch)`. -When `ReductionFactor = 1/2`, the Bitcoin halvenings are recreated. -We default to having a reduction factor of `2/3`, and thus reduce rewards at the end of every year by `33%`. - -The implication of this is that the total supply is finite, according to the following formula: - -$$Total\ Supply = InitialSupply + EpochsPerPeriod * \frac{InitialRewardsPerEpoch}{1 - ReductionFactor} $$ diff --git a/x/mint/spec/02_state.md b/x/mint/spec/02_state.md deleted file mode 100644 index b6afbd7c44..0000000000 --- a/x/mint/spec/02_state.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -# docs: https://docs.readme.com/main/docs/preview-and-publish-pages#markdown-directory-format -title: "Mint Module: State" # -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# State - -## Minter - -The minter is a space for holding current rewards information. - -```go -type Minter struct { - EpochProvisions sdk.Dec // Rewards for the current epoch -} -``` - -## Params - -Minting params are held in the global params store. - -```go -type Params struct { - MintDenom string // type of coin to mint - GenesisEpochProvisions sdk.Dec // initial epoch provisions at genesis - EpochIdentifier string // identifier of epoch - ReductionPeriodInEpochs int64 // number of epochs between reward reductions - ReductionFactor sdk.Dec // reduction multiplier to execute on each period - DistributionProportions DistributionProportions // distribution_proportions defines the proportion of the minted denom - WeightedDeveloperRewardsReceivers []WeightedAddress // address to receive developer rewards - MintingRewardsDistributionStartEpoch int64 // start epoch to distribute minting rewards -} -``` - -## LastHalvenEpoch - -Last halven epoch stores the epoch number when the last reduction of coin mint amount per epoch has happened. - -**TODO:** -- Update the name to LastReductionEpoch as the reduction amount could be set by governance. \ No newline at end of file diff --git a/x/mint/spec/03_end_epoch.md b/x/mint/spec/03_end_epoch.md deleted file mode 100644 index 5a9cf541d7..0000000000 --- a/x/mint/spec/03_end_epoch.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "Mint Module: End Epoch" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Begin-Epoch - -Minting parameters are recalculated and inflation -paid at the beginning of each epoch. An epoch is signalled by x/epochs - -## NextEpochProvisions - -The target epoch provision is recalculated on each reduction period (default 3 years). -At the time of reduction, the current provision is multiplied by reduction factor (default `2/3`), -to calculate the provisions for the next epoch. Consequently, the rewards of the next period -will be lowered by `1 - reduction factor`. - -```go -func (m Minter) NextEpochProvisions(params Params) sdk.Dec { - return m.EpochProvisions.Mul(params.ReductionFactor) -} -``` - -## EpochProvision - -Calculate the provisions generated for each epoch based on current epoch provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount`. These rewards are transferred to a `FeeCollector`, which handles distributing the rewards per the chains needs. (See TODO.md for details) This fee collector is specified as the `auth` module's `FeeCollector` `ModuleAccount`. - -```go -func (m Minter) EpochProvision(params Params) sdk.Coin { - provisionAmt := m.EpochProvisions.QuoInt(sdk.NewInt(int64(params.EpochsPerYear))) - return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()) -} -``` diff --git a/x/mint/spec/04_params.md b/x/mint/spec/04_params.md deleted file mode 100644 index 31a8e43bb0..0000000000 --- a/x/mint/spec/04_params.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: "Mint Module: Params" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# Parameters - -The minting module contains the following parameters: - -| Key | Type | Example | -| ------------------------------------------ | ------------ | -------------------------------------- | -| mint_denom | string | "uosmo" | -| genesis_epoch_provisions | string (dec) | "500000000" | -| epoch_identifier | string | "weekly" | -| reduction_period_in_epochs | int64 | 156 | -| reduction_factor | string (dec) | "0.6666666666666" | -| distribution_proportions.staking | string (dec) | "0.4" | -| distribution_proportions.pool_incentives | string (dec) | "0.3" | -| distribution_proportions.developer_rewards | string (dec) | "0.2" | -| distribution_proportions.community_pool | string (dec) | "0.1" | -| weighted_developer_rewards_receivers | array | [{"address": "osmoxx", "weight": "1"}] | -| minting_rewards_distribution_start_epoch | int64 | 10 | - -**Notes** -1. `mint_denom` defines denom for minting token - uosmo -2. `genesis_epoch_provisions` provides minting tokens per epoch at genesis. -3. `epoch_identifier` defines the epoch identifier to be used for mint module e.g. "weekly" -4. `reduction_period_in_epochs` defines the number of epochs to pass to reduce mint amount -5. `reduction_factor` defines the reduction factor of tokens at every `reduction_period_in_epochs` -6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distribute tokens to community pool. -7. `weighted_developer_rewards_receivers` provides the addresses that receives developer rewards by weight -8. `minting_rewards_distribution_start_epoch` defines the start epoch of minting to make sure minting start after initial pools are set diff --git a/x/mint/spec/05_events.md b/x/mint/spec/05_events.md deleted file mode 100644 index 65dbdc5a93..0000000000 --- a/x/mint/spec/05_events.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "Mint Module: Events" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - - -# Events - -The minting module emits the following events: - -## End of Epoch - -| Type | Attribute Key | Attribute Value | -| ---- | ---------------- | ----------------- | -| mint | epoch_number | {epochNumber} | -| mint | epoch_provisions | {epochProvisions} | -| mint | amount | {amount} | diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md deleted file mode 100644 index e005cc25ad..0000000000 --- a/x/mint/spec/README.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: "Mint Module" -excerpt: "" -category: 62c5c5ff03a5bf069004def2 ---- - - - -# `mint` - -Mint module mint OSMO tokens at the end of epochs. -On the other hand, module allocate tokens to OSMO stakers, pool incentives, developer rewards, and community pool. - -Module uses time basis epochs supported by `epochs` module. - -## Contents - -1. **[Concept](01_concepts.md)** -2. **[State](02_state.md)** -3. **[End Epoch](03_end_epoch.md)** -4. **[Parameters](04_params.md)** -5. **[Events](05_events.md)** - diff --git a/x/records/README.md b/x/records/README.md new file mode 100644 index 0000000000..76ebb12aa9 --- /dev/null +++ b/x/records/README.md @@ -0,0 +1,73 @@ +--- +title: "Records" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The Records Module + +The records module handles record keeping and accounting for the Stride blockchain. + +It is [IBC middleware](https://ibc.cosmos.network/main/ibc/middleware/develop.html). IBC middleware wraps core IBC modules and other middlewares. Specifically, the records module adds a middleware stack to `app.go` with the following structure: `records -> transfer`. All ibc packets routed to the `transfer` module will first pass through `records`, where we can apply custom logic (record keeping) before passing messages to the underlying `transfer` module. + +Note: +- The middleware stack is added in `app.go` +- The custom handler logic is added in `ibc_module.go` by implementing the IBCModule interface + +## Keeper functions + +Deposit Records +- `GetDepositRecordCount()` +- `SetDepositRecordCount()` +- `AppendDepositRecord()` +- `SetDepositRecord()` +- `GetDepositRecord()` +- `RemoveDepositRecord()` +- `GetAllDepositRecord()` +- `GetDepositRecordByEpochAndChain()` + +Epoch Unbonding Records +- `SetEpochUnbondingRecord()` +- `GetEpochUnbondingRecord()` +- `RemoveEpochUnbondingRecord()` +- `GetAllEpochUnbondingRecord()` +- `GetAllPreviousEpochUnbondingRecords()` +- `GetHostZoneUnbondingByChainId()` +- `AddHostZoneToEpochUnbondingRecord()` +- `SetHostZoneUnbondings()` + +User Redemption Records +- `SetUserRedemptionRecord()` +- `GetUserRedemptionRecord()` +- `RemoveUserRedemptionRecord()` +- `GetAllUserRedemptionRecord()` +- `IterateUserRedemptionRecords()` + +## State + +Callbacks +- `TransferCallback` + +Genesis +- `UserRedemptionRecord` +- `Params` +- `RecordsPacketData` +- `NoData` +- `DepositRecord` +- `HostZoneUnbonding` +- `EpochUnbondingRecord` +- `GenesisState` + +## Queries + +- `Params` +- `GetDepositRecord` +- `AllDepositRecord` +- `GetUserRedemptionRecord` +- `AllUserRedemptionRecord` +- `AllUserRedemptionRecordForUser` +- `GetEpochUnbondingRecord` +- `AllEpochUnbondingRecord` + +## Events +The `records` module emits does not currently emit any events. diff --git a/x/stakeibc/README.md b/x/stakeibc/README.md new file mode 100644 index 0000000000..fc86c835e4 --- /dev/null +++ b/x/stakeibc/README.md @@ -0,0 +1,120 @@ +--- +title: "StakeIBC" +excerpt: "" +category: 6392913957c533007128548e +--- + +# The StakeIBC Module + +The StakeIBC Module contains Stride's main app logic: +- it exposes core liquid staking entry points to the user (liquid staking and redeeming) +- it executes automated beginBlocker and endBlocker logic to stake funds on relevant host zones using Interchain Accounts +- it handles registering new host zones and adjusting host zone validator sets and weights +- it defines Stride's core data structures (e.g. hostZone) +- it defines all the callbacks used when issuing Interchain Account logic + +Nearly all of Stride's functionality is built using interchain accounts (ICAs), which are a new functionality in Cosmos, and a critical component of IBC. ICAs allow accounts on Zone A to be controlled by Zone B. ICAs communicate with one another using Interchain Queries (ICQs), which involve Zone A querying Zone B for relevant information. + +Two Zones communicate via a connection and channel. All communications between the Controller Zone (the chain that is querying) and the Host Zone (the chain that is being queried) is done through a dedicated IBC channel between the two chains, which is opened the first time the two chains interact. + +For context, ICS standards define that each channel is associated with a particular connection, and a connection may have any number of associated channels. + +## Params +``` +DepositInterval (default uint64 = 1) +DelegateInterval (default uint64 = 1) +ReinvestInterval (default uint64 = 1) +RewardsInterval (default uint64 = 1) +RedemptionRateInterval (default uint64 = 1) +StrideCommission (default uint64 = 10) +ValidatorRebalancingThreshold (default uint64 = 100) +ICATimeoutNanos(default uint64 = 600000000000) +BufferSize (default uint64 = 5) +IbcTimeoutBlocks (default uint64 = 300) +FeeTransferTimeoutNanos (default uint64 = 1800000000000 +SafetyMinRedemptionRateThreshold (default uint64 = 90) +SafetyMaxRedemptionRateThreshold (default uint64 = 150) +MaxStakeICACallsPerEpoch (default uint64 = 100) +IBCTransferTimeoutNanos (default uint64 = 1800000000000) +SafetyNumValidators (default uint64 = 35) +``` + +## Keeper functions + +- `LiquidStake()` +- `RedeemStake()` +- `ClaimUndelegatedTokens()` +- `RebalanceValidators()` +- `AddValidator()` +- `ChangeValidatorWeight()` +- `DeleteValidator()` +- `RegisterHostZone()` +- `ClearBalance()` +- `RestoreInterchainAccount()` +- `UpdateValidatorSharesExchRate()` + +## State + +Callbacks +- `SplitDelegation` +- `DelegateCallback` +- `ClaimCallback` +- `ReinvestCallback` +- `UndelegateCallback` +- `RedemptionCallback` +- `Rebalancing` +- `RebalanceCallback` + +HostZone +- `HostZone` +- `ICAAccount` +- `MinValidatorRequirements` + +Host Zone Validators +- `Validator` +- `ValidatorExchangeRate` + +Misc +- `GenesisState` +- `EpochTracker` +- `Delegation` + +Governance +- `AddValidatorProposal` + +## Queries + +- `QueryInterchainAccountFromAddressRequest` +- `QueryInterchainAccountFromAddressResponse` +- `QueryParamsRequest` +- `QueryParamsResponse` +- `QueryGetValidatorsRequest` +- `QueryGetValidatorsResponse` +- `QueryGetICAAccountRequest` +- `QueryGetICAAccountResponse` +- `QueryGetHostZoneRequest` +- `QueryGetHostZoneResponse` +- `QueryAllHostZoneRequest` +- `QueryAllHostZoneResponse` +- `QueryModuleAddressRequest` +- `QueryModuleAddressResponse` +- `QueryGetEpochTrackerRequest` +- `QueryGetEpochTrackerResponse` +- `QueryAllEpochTrackerRequest` +- `QueryAllEpochTrackerResponse` + +## Events + +`stakeibc` module emits the following events: + +Type: Attribute Key → Attribute Value +-------------------------------------------------- +registerHostZone: module → stakeibc +registerHostZone: connectionId → connectionId +registerHostZone: chainId → chainId +submitHostZoneUnbonding: hostZone → chainId +submitHostZoneUnbonding: newAmountUnbonding → totalAmtToUnbond +stakeExistingDepositsOnHostZone: hostZone → chainId +stakeExistingDepositsOnHostZone: newAmountStaked → amount +onAckPacket (IBC): module → moduleName +onAckPacket (IBC): ack → ackInfo