-
Notifications
You must be signed in to change notification settings - Fork 611
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b888f88
commit d992ac6
Showing
8 changed files
with
3,811 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
syntax = "proto3"; | ||
package osmosis.validatorpreference.v1beta1; | ||
|
||
import "gogoproto/gogo.proto"; | ||
import "google/api/annotations.proto"; | ||
import "osmosis/validator-preference/v1beta1/state.proto"; | ||
|
||
option go_package = "github.com/osmosis-labs/osmosis/v12/x/validator-preference/client/queryproto"; | ||
option (gogoproto.goproto_getters_all) = false; | ||
|
||
// Query defines the gRPC querier service. | ||
service Query { | ||
// Returns the list of ValidatorPreferences for the user. | ||
rpc UserValidatorPreferences(QueryUserValidatorPreferences) | ||
returns (QueryUserValidatorPreferenceResponse) { | ||
option (google.api.http).get = | ||
"/osmosis/validator-preference/v1beta1/{user}"; | ||
} | ||
} | ||
|
||
// Request type for UserValidatorPreferences. | ||
message QueryUserValidatorPreferences { | ||
// user account address | ||
string user = 2; | ||
} | ||
|
||
// Response type the QueryUserValidatorPreferences query request | ||
message QueryUserValidatorPreferenceResponse { | ||
repeated ValidatorPreference preferences = 1 [ (gogoproto.nullable) = false ]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
syntax = "proto3"; | ||
package osmosis.validatorpreference.v1beta1; | ||
|
||
import "gogoproto/gogo.proto"; | ||
import "google/api/annotations.proto"; | ||
|
||
option go_package = "github.com/osmosis-labs/osmosis/v12/x/validator-preference/types"; | ||
option (gogoproto.goproto_getters_all) = false; | ||
|
||
// ValidatorPreference defines the message structure for CreateValidatorSetPreference. | ||
// It allows a user to set {val_addr, weight} in state. | ||
// If a user does not have a validator set preference list set, and has | ||
// staked, make their preference list default to their current staking | ||
// distribution. | ||
message ValidatorPreference { | ||
// val_oper_address holds the validator address the user wants to delegate | ||
// funds to. | ||
string val_oper_address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; | ||
// weight is decimal between 0 and 1, and they all sum to 1. | ||
string weight = 2 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", | ||
(gogoproto.nullable) = false | ||
]; | ||
} | ||
|
||
// ValidatorSetPreferences is a wrapper that holds a list of {valAddr, weights}. | ||
// The weights are arranged in decimal notation from 0 to 1 and must add up to 1. | ||
// A delegator can only have one validator-set and they have the ability to modify | ||
// the weights and the validator. | ||
message ValidatorSetPreferences { | ||
// delegator is the address of the user who created the validator-set. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
|
||
// preference holds {valAddr, weight} for the user who created it. | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
syntax = "proto3"; | ||
package osmosis.validatorpreference.v1beta1; | ||
|
||
import "gogoproto/gogo.proto"; | ||
import "cosmos/base/v1beta1/coin.proto"; | ||
import "osmosis/validator-preference/v1beta1/state.proto"; | ||
|
||
option go_package = "github.com/osmosis-labs/osmosis/v12/x/validator-preference/types"; | ||
|
||
// Msg defines the validator-preference modules's gRPC message service. | ||
service Msg { | ||
// CreateValidatorSetPreference creates a set of validator preference. | ||
rpc CreateValidatorSetPreference(MsgCreateValidatorSetPreference) | ||
returns (MsgCreateValidatorSetPreferenceResponse); | ||
|
||
// UpdateValidatorSetPreference updates an existing set of validator preference. | ||
rpc UpdateValidatorSetPreference(MsgUpdateValidatorSetPreference) | ||
returns (MsgUpdateValidatorSetPreferenceResponse); | ||
|
||
// StakeToValidatorSet gets the owner, coins and stakes to a validator-set. | ||
rpc StakeToValidatorSet(MsgStakeToValidatorSet) | ||
returns (MsgStakeToValidatorSetResponse); | ||
|
||
// UnStakeFromValidatorSet gets the owner and coins and unstakes from | ||
// validator-set. The unbonding logic will follow the `Undelegate` logic from the sdk. | ||
rpc UnStakeFromValidatorSet(MsgUnStakeFromValidatorSet) | ||
returns (MsgUnStakeFromValidatorSetResponse); | ||
|
||
// WithdrawDelegationRewards allows users to claim rewards from the validator-set. | ||
rpc WithdrawDelegationRewards(MsgWithdrawDelegationRewards) | ||
returns (MsgWithdrawDelegationRewardsResponse); | ||
} | ||
|
||
// MsgCreateValidatorSetPreference is a list that holds validator-set. | ||
message MsgCreateValidatorSetPreference { | ||
// delegator is the user who is trying to create a validator-set. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
|
||
// list of {valAddr, weight} to delegate to | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
} | ||
|
||
message MsgCreateValidatorSetPreferenceResponse {} | ||
|
||
// MsgCreateValidatorSetPreference is a set of list that holds validator-preference. | ||
message MsgUpdateValidatorSetPreference { | ||
// delegator is the user who is trying to update a validator-set. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
|
||
// updated list of delegators validator-set {valAddr, weight} | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
} | ||
|
||
message MsgUpdateValidatorSetPreferenceResponse {} | ||
|
||
// MsgStakeToValidatorSet allows users to stake to an existing validator-set | ||
message MsgStakeToValidatorSet { | ||
// delegator is the user who is trying to stake. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
|
||
// the amount of tokens the user is trying to stake. | ||
// For ex: UnStake 10osmo with validator-set {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2} | ||
// our unstake logic would attempt to stake 5osmo to A , 3osmo to B, 2osmo to C. | ||
cosmos.base.v1beta1.Coin coin = 2 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin" | ||
]; | ||
} | ||
|
||
message MsgStakeToValidatorSetResponse {} | ||
|
||
message MsgUnStakeFromValidatorSet { | ||
// delegator is the user who is trying to unstake. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
|
||
// the amount the user wants to unstake | ||
// For ex: UnStake 10osmo with validator-set {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2} | ||
// our unstake logic would attempt to unstake 5osmo from A , 3osmo from B, 2osmo from C | ||
cosmos.base.v1beta1.Coin coin = 3 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin" | ||
]; | ||
} | ||
|
||
message MsgUnStakeFromValidatorSetResponse {} | ||
|
||
// MsgWithdrawDelegationRewards allows user to claim staking rewards from the validator set. | ||
// This message | ||
message MsgWithdrawDelegationRewards { | ||
// delegator is the user who is trying to claim staking rewards. | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
} | ||
|
||
message MsgWithdrawDelegationRewardsResponse {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
# Validator Set Preference | ||
|
||
## Abstract | ||
|
||
Validator-Set preference is a new module which gives users and contracts a | ||
better UX for staking to a set of validators. For example: a one click button | ||
that stakes to multiple validators. Then the user can set (or realistically a frontend provides) | ||
a list of recommended defaults (Ex: governoors, wosmongton, chain/stack contributors etc). | ||
Currently this can be done on-chain with frontends, but having a preference list stored locally | ||
eases frontend code burden. | ||
|
||
## Design | ||
|
||
How does this module work? | ||
|
||
- Allow an user to set a list of {val-addr, weight} in state, called their validator-set preference. | ||
- Give users a single message to stake {X} tokens, according to their validator set preference distribution. | ||
- Give users a single message to unstake {X} tokens, according to their validator set preference distribution. | ||
- Give users a single message to claim rewards from everyone on their preference list. | ||
- If a user does not have a validator set preference list set, and has staked do the following; | ||
- Make their preference list default to their current staking distribution. | ||
- If a user has no preference list and no staking, then return error for messages. | ||
|
||
## Calculations | ||
|
||
Staking Calculation | ||
|
||
- The user provides an amount to stake and our `MsgStakeToValidatorSet` divides the amount based on validator weight distribution. | ||
For ex: Stake 100osmo with validator-set {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2} | ||
our stake logic will attempt to stake (100 * 0.5) 50osmo for ValA , (100 * 0.3) 30osmo from ValB and (100 * 0.2) 20osmo from ValC. | ||
|
||
UnStaking Calculation | ||
|
||
- The user provides an amount to unstake and our `MsgUnStakeFromValidatorSet` divides the amount based on validator weight distribution. | ||
- Here, the user can either unstake the entire amount or partial amount | ||
- Entire amount unstaking: UnStake 100osmo from validator-set {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2}, | ||
our unstake logic will attempt to unstake 50osmo from ValA , 30osmo from ValB, 20osmo from ValC | ||
- Partial amount unstaking: UnStake 27osmo from validator-set {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2}, | ||
our unstake logic will attempt to unstake (27 * 0.5) 13.5osmos from ValA, (27 * 0.3), 8.1osmo from ValB, | ||
and (50 * 0.2) 5.4smo from ValC where 13.5osmo + 8.1osmo + 5.4osmo = 27osmo | ||
- The user will then have 73osmo remaining with unchanged weights {ValA -> 0.5, ValB -> 0.3, ValC -> 0.2}, | ||
|
||
## Messages | ||
|
||
### CreateValidatorSetPreference | ||
|
||
Creates a validator-set of `{valAddr, Weight}` given the delegator address | ||
and preferences. The weights are in decimal format from 0 to 1 and must add up to 1. | ||
|
||
```go | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
``` | ||
|
||
**State Modifications:** | ||
|
||
- Safety Checks | ||
- check if the user already has a validator-set created. | ||
- check if the validator exist and is valid. | ||
- check if the validator-set add up to 1. | ||
- Add owner address to the `KVStore`, where a state of validator-set is stored | ||
|
||
### UpdateValidatorSetPreference | ||
|
||
Updates a validator-set of `{valAddr, Weight}` given the delegator address | ||
and existing preferences. The weights calculations follow the same rule as `CreateValidatorSetPreference`. | ||
|
||
```go | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
``` | ||
|
||
**State Modifications:** | ||
|
||
- Follows the same rule as `CreateValidatorSetPreference` except for the following | ||
- Update the `KVStore` value for the specific owner address key | ||
|
||
### StakeToValidatorSet | ||
|
||
Gets the existing validator-set of the delegator and stakes the given amount. The given amount | ||
will be divided based on the weights distributed to the validators. The weights will be unchanged! | ||
|
||
```go | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
``` | ||
|
||
**State Modifications:** | ||
|
||
- Check if the user has a validator-set and if so, get the users validator-set from `KVStore` | ||
- Safety Checks | ||
- check if the user has enough funds to delegate. | ||
- check overflow/underflow since `Delegate` method takes `sdk.Int` as tokenAmount | ||
- use the [Delegate](https://github.com/cosmos/cosmos-sdk/blob/main/x/staking/keeper/delegation.go#L614) method from the cosmos-sdk to handle delegation | ||
|
||
### UnStakeFromValidatorSet | ||
|
||
Gets the existing validator-set of the delegator and unstake the given amount. The amount to unstake will | ||
will be divided based on the weights distributed to the validators. The weights will be unchanged! | ||
|
||
The given amount will be divided based on the weights distributed to the validators. | ||
|
||
```go | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
repeated ValidatorPreference preferences = 2 [ | ||
(gogoproto.moretags) = "yaml:\"preferences\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
``` | ||
|
||
**State Modifications:** | ||
|
||
- Check if the user has a validator-set and if so, get the users validator-set from `KVStore` | ||
- The unbonding logic will be follow the `UnDelegate` logic from the cosmos-sdk. | ||
- Safety Checks | ||
- check that the amount of funds to undelegate is <= to the funds the user has in the address. | ||
- `UnDelegate` method takes `sdk.Dec` as tokenAmount, so check if overflow/underflow case is relevant | ||
- use the [UnDelegate](https://github.com/cosmos/cosmos-sdk/blob/main/x/staking/keeper/delegation.go#L614) method from the cosmos-sdk to handle delegation | ||
|
||
### WithdrawDelegationRewards | ||
|
||
Allows the user to claim rewards based from the existing validator-set. The user can claim rewards from all the validators at once. | ||
|
||
```go | ||
string delegator = 1 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; | ||
``` | ||
|
||
## Code Layout | ||
|
||
The Code Layout is very similar to TWAP module. | ||
|
||
- client/* - Implementation of GRPC and CLI queries | ||
- types/* - Implement ValidatorSetPreference, GenesisState. Define the interface and setup keys. | ||
- twapmodule/validatorsetpreference.go - SDK AppModule interface implementation. | ||
- api.go - Public API, that other users / modules can/should depend on | ||
- listeners.go - Defines hooks & calls to logic.go, for triggering actions on | ||
- keeper.go - generic SDK boilerplate (defining a wrapper for store keys + params) | ||
- msg_server.go - handle messages request from client and process responses. | ||
- store.go - Managing logic for getting and setting things to underlying stores (KVStore) |
Oops, something went wrong.