Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dividends): module scaffolding #686

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
45 changes: 45 additions & 0 deletions proto/dividends/events.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
syntax = "proto3";
package rollapp.dividends;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "dividends/gauge.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/dividends/types";

message EventUpdateParams {
string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
Params new_params = 2 [ (gogoproto.nullable) = false ];
Params old_params = 3 [ (gogoproto.nullable) = false ];
}

message EventCreateGauge {
// gauge_id is the ID of the gauge to update
uint64 gauge_id = 1;
// approved_denoms is a list of allowed tokens
repeated string approved_denoms = 2;
// query_condition is *where* the gauge rewards are distributed to
QueryCondition query_condition = 3 [ (gogoproto.nullable) = false ];
// vesting_condition is *how long* the gauge rewards are distributed to
VestingCondition vesting_condition = 4 [ (gogoproto.nullable) = false ];
// vesting_condition is *how frequent* the gauge rewards are distributed to
VestingFrequency vesting_frequency = 5;
}

message EventUpdateGauge {
// gauge_id is the ID of the gauge to update
uint64 gauge_id = 1;
// approved_denoms is a list of allowed tokens
repeated string approved_denoms = 2;
// query_condition is *where* the gauge rewards are distributed to
QueryCondition query_condition = 3 [ (gogoproto.nullable) = false ];
// vesting_condition is *how long* the gauge rewards are distributed to
VestingCondition vesting_condition = 4 [ (gogoproto.nullable) = false ];
// vesting_condition is *how frequent* the gauge rewards are distributed to
VestingFrequency vesting_frequency = 5;
}

message EventDeactivateGauge {
// gauge_id is the ID of the gauge to update
uint64 gauge_id = 1;
}
77 changes: 77 additions & 0 deletions proto/dividends/gauge.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
syntax = "proto3";
package rollapp.dividends;

import "gogoproto/gogo.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/dividends/types";

// Params holds parameters for the incentives module
message Params {
// distr_epoch_identifier is what epoch type distribution will be triggered by
// (day, week, etc.)
string distr_epoch_identifier = 1;
}

// Gauge is an object that stores and distributes yields to recipients who
// satisfy certain conditions.
message Gauge {
// id is the unique ID of a gauge
uint64 id = 1;
// address is a bech32-formatted address that holds the tokens to allocate
string address = 2;
// active is a flag to show if the gauge is active
bool active = 3;
// approved_denoms is a list of allowed tokens: only gov can approve tokens
// that can be used for dividends
repeated string approved_denoms = 4;
// query_condition is *where* the gauge rewards are distributed to
QueryCondition query_condition = 5 [ (gogoproto.nullable) = false ];
// vesting_condition is *how long* the gauge rewards are distributed to
VestingCondition vesting_condition = 6 [ (gogoproto.nullable) = false ];
// vesting_condition is *how frequent* the gauge rewards are distributed to
VestingFrequency vesting_frequency = 7;
}

message QueryCondition {
oneof condition {
QueryConditionStakers stakers = 1;
}
}

message VestingCondition {
oneof condition {
VestingConditionPerpetual perpetual = 1;
VestingConditionLimited limited = 2;
}
}

enum VestingFrequency {
VESTING_FREQUENCY_UNSPECIFIED = 0;
VESTING_FREQUENCY_BLOCK = 1;
VESTING_FREQUENCY_EPOCH = 2;
}

// QueryConditionStakers queries the stakers
message QueryConditionStakers {}

// VestingConditionPerpetual is a vesting condition that distributes rewards
// infinitely. Perpetual gauges distribute all their tokens at a single time
// and only distribute their tokens again once the gauge is refilled.
//
// Non-perpetual gauges distribute their tokens equally per period while the
// gauge is in the active period. Perpetual gauges distribute all their tokens
// at a single time and only distribute their tokens again once the gauge is
// refilled.
message VestingConditionPerpetual {}

// VestingConditionLimited is a vesting condition that distributes rewards over
// the specified time. Non-perpetual gauges distribute their tokens equally per
// period while the gauge is in the active period.
message VestingConditionLimited {
// num_units is the number of total epochs/blocks distribution will be
// completed over
int64 num_units = 1;
// filled_epochs is the number of epochs/blocks distribution has been
// completed on already
int64 filled_units = 2;
}
19 changes: 19 additions & 0 deletions proto/dividends/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
syntax = "proto3";
package rollapp.dividends;

import "gogoproto/gogo.proto";
import "dividends/gauge.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/dividends/types";

// GenesisState defines the incentives module's various parameters when first
// initialized
message GenesisState {
// params are all the parameters of the module
Params params = 1 [ (gogoproto.nullable) = false ];
// gauges are all gauges that should exist at genesis
repeated Gauge gauges = 2 [ (gogoproto.nullable) = false ];
// last_gauge_id is what the gauge number will increment from when creating
// the next gauge after genesis
uint64 last_gauge_id = 3;
}
47 changes: 47 additions & 0 deletions proto/dividends/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
syntax = "proto3";
package rollapp.dividends;

import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "dividends/gauge.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/dividends/types";

// Query defines the gRPC querier service
service Query {
rpc GaugeByID(GaugeByIDRequest) returns (GaugeByIDResponse) {
option (google.api.http).get = "/rollapp/dividends/gauge_by_id/{id}";
}

rpc Gauges(GaugesRequest) returns (GaugesResponse) {
option (google.api.http).get = "/rollapp/dividends/gauges";
}

rpc Params(ParamsRequest) returns (ParamsResponse) {
option (google.api.http).get = "/rollapp/dividends/params";
}
}

message GaugeByIDRequest {
uint64 id = 1;
}

message GaugeByIDResponse {
Gauge gauge = 1 [ (gogoproto.nullable) = false ];
}

message GaugesRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

message GaugesResponse {
repeated Gauge data = 1 [ (gogoproto.nullable) = false ];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

message ParamsRequest {}

message ParamsResponse {
Params params = 1 [ (gogoproto.nullable) = false ];
}
75 changes: 75 additions & 0 deletions proto/dividends/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
syntax = "proto3";
package rollapp.dividends;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/msg/v1/msg.proto";
import "cosmos/base/v1beta1/coin.proto";
import "dividends/gauge.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/dividends/types";

service Msg {
rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);
rpc CreateGauge(MsgCreateGauge) returns (MsgCreateGaugeResponse);
rpc UpdateGauge(MsgUpdateGauge) returns (MsgUpdateGaugeResponse);
rpc DeactivateGauge(MsgDeactivateGauge) returns (MsgDeactivateGaugeResponse);
}

// MsgCreateGauge creates a gauge to distribute rewards to users
message MsgCreateGauge {
option (cosmos.msg.v1.signer) = "authority";

// Authority is the address that controls the module.
string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// approved_denoms is a list of allowed tokens: only gov can approve tokens
// that can be used for dividends
repeated string approved_denoms = 2;
// query_condition is *where* the gauge rewards are distributed to
QueryCondition query_condition = 3 [ (gogoproto.nullable) = false ];
// vesting_condition is *how long* the gauge rewards are distributed to
VestingCondition vesting_condition = 4 [ (gogoproto.nullable) = false ];
// vesting_condition is *how frequent* the gauge rewards are distributed to
VestingFrequency vesting_frequency = 5;
}

message MsgCreateGaugeResponse {}

// MsgUpdateGauge updates a gauge
message MsgUpdateGauge {
option (cosmos.msg.v1.signer) = "authority";

// Authority is the address that controls the module.
string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// gauge_id is the ID of the gauge to update
uint64 gauge_id = 2;
// approved_denoms is a list of allowed tokens: only gov can approve tokens
// that can be used for dividends
repeated string approved_denoms = 3;
}

message MsgUpdateGaugeResponse {}

// MsgDeactivateGauge deactivates a gauge
message MsgDeactivateGauge {
option (cosmos.msg.v1.signer) = "authority";

// Authority is the address that controls the module.
string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// gauge_id is the ID of the gauge to deactivate
uint64 gauge_id = 2;
}

message MsgDeactivateGaugeResponse {}

// MsgUpdateParams allows to update module params.
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";

// Authority is the address that controls the module.
string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// NewParams should be fully populated.
Params new_params = 2 [ (gogoproto.nullable) = false ];
}

message MsgUpdateParamsResponse {}
1 change: 1 addition & 0 deletions swagger-proto/third_party/cosmos_tmp
Submodule cosmos_tmp added at c7b003
30 changes: 26 additions & 4 deletions testutil/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ import (
epochskeeper "github.com/dymensionxyz/dymension-rdk/x/epochs/keeper"
epochstypes "github.com/dymensionxyz/dymension-rdk/x/epochs/types"

"github.com/dymensionxyz/dymension-rdk/x/dividends"
dividendskeeper "github.com/dymensionxyz/dymension-rdk/x/dividends/keeper"
dividendstypes "github.com/dymensionxyz/dymension-rdk/x/dividends/types"

"github.com/dymensionxyz/dymension-rdk/x/gasless"
gaslessclient "github.com/dymensionxyz/dymension-rdk/x/gasless/client"
gaslesskeeper "github.com/dymensionxyz/dymension-rdk/x/gasless/keeper"
Expand Down Expand Up @@ -151,6 +155,7 @@ var kvstorekeys = []string{
epochstypes.StoreKey, hubgentypes.StoreKey, hubtypes.StoreKey,
ibctransfertypes.StoreKey, capabilitytypes.StoreKey, gaslesstypes.StoreKey, wasmtypes.StoreKey,
tokenfactorytypes.StoreKey, rollappparamstypes.StoreKey, timeupgradetypes.StoreKey,
dividendstypes.StoreKey,
}

func getGovProposalHandlers() []govclient.ProposalHandler {
Expand Down Expand Up @@ -198,6 +203,7 @@ var (
wasm.AppModuleBasic{},
tokenfactory.NewAppModuleBasic(),
rollappparams.AppModuleBasic{},
dividends.AppModuleBasic{},
)

// module account permissions
Expand All @@ -214,6 +220,7 @@ var (
wasmtypes.ModuleName: {authtypes.Burner},
rollappparamstypes.ModuleName: nil,
tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner},
dividendstypes.ModuleName: nil,
}
)

Expand Down Expand Up @@ -249,6 +256,7 @@ type App struct {
HubKeeper hubkeeper.Keeper
HubGenesisKeeper hubgenkeeper.Keeper
RollappParamsKeeper rollappparamskeeper.Keeper
DividendsKeeper dividendskeeper.Keeper
UpgradeKeeper upgradekeeper.Keeper
ParamsKeeper paramskeeper.Keeper
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
Expand Down Expand Up @@ -381,9 +389,7 @@ func NewRollapp(
authtypes.FeeCollectorName,
)
app.MintKeeper.SetHooks(
minttypes.NewMultiMintHooks(
// insert mint hooks receivers here
),
minttypes.NewMultiMintHooks(),
)

app.DistrKeeper = distrkeeper.NewKeeper(
Expand All @@ -409,6 +415,18 @@ func NewRollapp(
authtypes.NewModuleAddress(timeupgradetypes.ModuleName).String(),
)

app.DividendsKeeper = dividendskeeper.NewKeeper(
appCodec,
keys[dividendstypes.StoreKey],
&stakingKeeper,
app.AccountKeeper,
app.DistrKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

app.DividendsKeeper.SetGetBalanceFunc(app.DividendsKeeper.GetBalanceFunc())

// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.StakingKeeper = *stakingKeeper.SetHooks(app.DistrKeeper.Hooks())
Expand Down Expand Up @@ -459,7 +477,7 @@ func NewRollapp(

app.GovKeeper = *govKeeper.SetHooks(
govtypes.NewMultiGovHooks(
// register the governance hooks
// register the governance hooks
),
)

Expand Down Expand Up @@ -609,6 +627,7 @@ func NewRollapp(
hubgenesis.NewAppModule(appCodec, app.HubGenesisKeeper),
gasless.NewAppModule(appCodec, app.GaslessKeeper),
rollappparams.NewAppModule(appCodec, app.RollappParamsKeeper),
dividends.NewAppModule(app.DividendsKeeper),
}

app.mm = module.NewManager(modules...)
Expand Down Expand Up @@ -639,6 +658,7 @@ func NewRollapp(
tokenfactorytypes.ModuleName,
gaslesstypes.ModuleName,
rollappparamstypes.ModuleName,
dividendstypes.ModuleName,
}
app.mm.SetOrderBeginBlockers(beginBlockersList...)

Expand All @@ -663,6 +683,7 @@ func NewRollapp(
tokenfactorytypes.ModuleName,
gaslesstypes.ModuleName,
rollappparamstypes.ModuleName,
dividendstypes.ModuleName,
}
app.mm.SetOrderEndBlockers(endBlockersList...)

Expand Down Expand Up @@ -693,6 +714,7 @@ func NewRollapp(
tokenfactorytypes.ModuleName,
gaslesstypes.ModuleName,
rollappparamstypes.ModuleName,
dividendstypes.ModuleName,
}
app.mm.SetOrderInitGenesis(initGenesisList...)

Expand Down
Loading
Loading