Skip to content

Commit

Permalink
added protos for val-set-preference
Browse files Browse the repository at this point in the history
  • Loading branch information
stackman27 committed Sep 22, 2022
1 parent b888f88 commit d992ac6
Show file tree
Hide file tree
Showing 8 changed files with 3,811 additions and 0 deletions.
30 changes: 30 additions & 0 deletions proto/osmosis/validator-preference/v1beta1/query.proto
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 ];
}
39 changes: 39 additions & 0 deletions proto/osmosis/validator-preference/v1beta1/state.proto
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
];
}
100 changes: 100 additions & 0 deletions proto/osmosis/validator-preference/v1beta1/tx.proto
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 {}
148 changes: 148 additions & 0 deletions x/validator-preference/README.md
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)
Loading

0 comments on commit d992ac6

Please sign in to comment.