diff --git a/app/app.go b/app/app.go index 0a0077eba7..481cfc281f 100644 --- a/app/app.go +++ b/app/app.go @@ -126,6 +126,9 @@ import ( appparams "github.com/umee-network/umee/v4/app/params" "github.com/umee-network/umee/v4/swagger" "github.com/umee-network/umee/v4/util/genmap" + "github.com/umee-network/umee/v4/x/incentive" + incentivekeeper "github.com/umee-network/umee/v4/x/incentive/keeper" + incentivemodule "github.com/umee-network/umee/v4/x/incentive/module" "github.com/umee-network/umee/v4/x/leverage" leveragekeeper "github.com/umee-network/umee/v4/x/leverage/keeper" leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" @@ -186,6 +189,7 @@ func init() { // ibcfee.AppModuleBasic{}, gravity.AppModuleBasic{}, leverage.AppModuleBasic{}, + incentivemodule.AppModuleBasic{}, oracle.AppModuleBasic{}, bech32ibc.AppModuleBasic{}, uibcmodule.AppModuleBasic{}, @@ -210,6 +214,7 @@ func init() { icatypes.ModuleName: nil, gravitytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, leveragetypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + incentive.ModuleName: nil, oracletypes.ModuleName: nil, uibc.ModuleName: nil, } @@ -260,6 +265,7 @@ type UmeeApp struct { ICAHostKeeper icahostkeeper.Keeper GravityKeeper gravitykeeper.Keeper LeverageKeeper leveragekeeper.Keeper + IncentiveKeeper incentivekeeper.Keeper OracleKeeper oraclekeeper.Keeper bech32IbcKeeper bech32ibckeeper.Keeper UIbcQuotaKeeper uibcquotakeeper.Keeper @@ -324,8 +330,8 @@ func New( authzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey, ibchost.StoreKey, ibctransfertypes.StoreKey, icahosttypes.StoreKey, gravitytypes.StoreKey, - leveragetypes.StoreKey, oracletypes.StoreKey, bech32ibctypes.StoreKey, - uibc.StoreKey, + leveragetypes.StoreKey, incentive.StoreKey, oracletypes.StoreKey, + bech32ibctypes.StoreKey, uibc.StoreKey, } if Experimental { storeKeys = append(storeKeys, wasm.StoreKey) @@ -466,11 +472,14 @@ func New( app.OracleKeeper, cast.ToBool(appOpts.Get(leveragetypes.FlagEnableLiquidatorQuery)), ) - app.LeverageKeeper = *app.LeverageKeeper.SetHooks( - leveragetypes.NewMultiHooks( - app.OracleKeeper.Hooks(), - ), + app.IncentiveKeeper = incentivekeeper.NewKeeper( + appCodec, + keys[incentive.StoreKey], + app.BankKeeper, + app.LeverageKeeper, ) + app.LeverageKeeper.SetTokenHooks(app.OracleKeeper.Hooks()) + app.LeverageKeeper.SetBondHooks(app.IncentiveKeeper.BondHooks()) app.GravityKeeper = gravitykeeper.NewKeeper( keys[gravitytypes.StoreKey], @@ -674,6 +683,7 @@ func New( ica.NewAppModule(nil, &app.ICAHostKeeper), gravity.NewAppModule(app.GravityKeeper, app.BankKeeper), leverage.NewAppModule(appCodec, app.LeverageKeeper, app.AccountKeeper, app.BankKeeper), + incentivemodule.NewAppModule(appCodec, app.IncentiveKeeper, app.BankKeeper, app.LeverageKeeper), oracle.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper), bech32ibc.NewAppModule(appCodec, app.bech32IbcKeeper), uibcmodule.NewAppModule(appCodec, app.UIbcQuotaKeeper), @@ -703,6 +713,7 @@ func New( paramstypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, // ibcfeetypes.ModuleName, leveragetypes.ModuleName, + incentive.ModuleName, oracletypes.ModuleName, gravitytypes.ModuleName, bech32ibctypes.ModuleName, @@ -721,6 +732,7 @@ func New( paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, // ibcfeetypes.ModuleName, leveragetypes.ModuleName, + incentive.ModuleName, gravitytypes.ModuleName, bech32ibctypes.ModuleName, uibc.ModuleName, @@ -743,6 +755,7 @@ func New( oracletypes.ModuleName, leveragetypes.ModuleName, + incentive.ModuleName, gravitytypes.ModuleName, bech32ibctypes.ModuleName, uibc.ModuleName, @@ -758,6 +771,7 @@ func New( oracletypes.ModuleName, leveragetypes.ModuleName, + incentive.ModuleName, gravitytypes.ModuleName, bech32ibctypes.ModuleName, uibc.ModuleName, @@ -794,10 +808,12 @@ func New( simStateModules := genmap.Pick( app.mm.Modules, - []string{stakingtypes.ModuleName, authtypes.ModuleName, oracletypes.ModuleName, - ibchost.ModuleName}, + []string{ + stakingtypes.ModuleName, authtypes.ModuleName, oracletypes.ModuleName, + ibchost.ModuleName, + }, ) - // TODO: Ensure x/leverage implements simulator and add it here: + // TODO: Ensure x/leverage, x/incentive implement simulator and add it here: simTestModules := genmap.Pick(simStateModules, []string{oracletypes.ModuleName, ibchost.ModuleName}) diff --git a/app/upgrades.go b/app/upgrades.go index 61bb09455f..fab4b4a0da 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -23,6 +23,7 @@ import ( "github.com/umee-network/umee/v4/app/upgradev3" "github.com/umee-network/umee/v4/app/upgradev3x3" + "github.com/umee-network/umee/v4/x/incentive" leveragekeeper "github.com/umee-network/umee/v4/x/leverage/keeper" leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" oraclekeeper "github.com/umee-network/umee/v4/x/oracle/keeper" @@ -47,6 +48,18 @@ func (app UmeeApp) RegisterUpgradeHandlers(bool) { app.registerUpgrade4_1(upgradeInfo) app.registerUpgrade4_2(upgradeInfo) app.registerUpgrade4_3(upgradeInfo) + app.registerUpgrade4_4(upgradeInfo) +} + +// performs upgrade from v4.3 to v4.4 +func (app *UmeeApp) registerUpgrade4_4(upgradeInfo upgradetypes.Plan) { + const planName = "v4.4" + app.UpgradeKeeper.SetUpgradeHandler(planName, onlyModuleMigrations(app, planName)) + app.storeUpgrade(planName, upgradeInfo, storetypes.StoreUpgrades{ + Added: []string{ + incentive.ModuleName, + }, + }) } // performs upgrade from v4.2 to v4.3 @@ -97,7 +110,6 @@ func (app *UmeeApp) registerUpgrade4_3(upgradeInfo upgradetypes.Plan) { icahosttypes.StoreKey, }, }) - } // performs upgrade from v4.1 to v4.2 diff --git a/proto/umee/incentive/v1/genesis.proto b/proto/umee/incentive/v1/genesis.proto index 2d0a9326fa..28fc058d52 100644 --- a/proto/umee/incentive/v1/genesis.proto +++ b/proto/umee/incentive/v1/genesis.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package umeenetwork.umee.incentive.v1; +package umee.incentive.v1; option go_package = "github.com/umee-network/umee/v4/x/incentive"; @@ -11,7 +11,7 @@ import "umee/incentive/v1/incentive.proto"; message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; uint32 next_program_id = 2; - uint64 last_rewards_time = 3; + int64 last_rewards_time = 3; repeated RewardTracker reward_trackers = 4 [(gogoproto.nullable) = false]; repeated RewardAccumulator reward_accumulators = 5 [(gogoproto.nullable) = false]; repeated IncentiveProgram upcoming_programs = 6 [(gogoproto.nullable) = false]; @@ -21,59 +21,55 @@ message GenesisState { repeated AccountUnbondings account_unbondings = 10 [(gogoproto.nullable) = false]; } -// TotalBond tracks the amount of coins of one uToken denomination bonded to a -// given reward tier by all accounts. Used by queries TotalBonded and TotalUnbonding. -message TotalBond { - uint32 tier = 1; - cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false]; -} - -// Bond tracks the amount of coins of one uToken denomination bonded to a -// given reward tier by a single account. +// Bond tracks the amount of coins of one uToken denomination bonded +// by a single account. message Bond { string account = 1; - uint32 tier = 2; - cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false]; + cosmos.base.v1beta1.Coin uToken = 2 [(gogoproto.nullable) = false]; } -// RewardTracker tracks the value of a given tier and lock denom's RewardAccumulator -// at the last time a specific account calculated pending rewards for it. When calculating +// RewardTracker tracks the value of a given lock denom's RewardAccumulator at the +// last time a specific account calculated pending rewards for it. When calculating // available rewards, this value is used to determine the difference between the current -// RewardAccumulator for a tier and the last value at which the user updated bonds or claimed +// RewardAccumulator for a uToken and the last value at which the user updated bonds or claimed // tokens. Their pending rewards increase by only the rewards accrued in that time period. message RewardTracker { - string account = 1; - uint32 tier = 2; - string denom = 3; - repeated cosmos.base.v1beta1.DecCoin reward_tracker = 4 [ + string account = 1; + string uToken = 2; + repeated cosmos.base.v1beta1.DecCoin rewards = 3 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" ]; } // RewardAccumulator is a global reward tracking struct that indicates the amount -// of rewards that a single unit of denom would have accumulated if it was bonded -// at a given tier since genesis. +// of rewards that a reference amount of a bonded uToken denom would have accumulated +// if it was bonded since genesis. To prevent rounding issues, the reference amount is +// 10^exponent of the uToken's smallest possible amount, generally matching the exponent +// of the associated base token registered with the leverage module. message RewardAccumulator { - uint32 tier = 1; - string denom = 2; - repeated cosmos.base.v1beta1.DecCoin reward_tracker = 3 [ + string uToken = 1; + repeated cosmos.base.v1beta1.DecCoin rewards = 2 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" ]; + uint32 exponent = 3; } // Unbonding is a structure that tracks an in-progress token unbonding. +// It tracks both its start time and end time, so that if the module's +// unbonding time changes, the unbonding can complete at the earlier of +// its original end time or its new one based on the new parameter. message Unbonding { - uint64 end = 1; - cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false]; + int64 start = 1; + int64 end = 2; + cosmos.base.v1beta1.Coin uToken = 3 [(gogoproto.nullable) = false]; } // AccountUnbondings is a structure that is used to store all of an account's unbondings -// for a single bonded uToken denom and and unbonding tier in both KVStore and genesis state. +// for a single bonded uToken denom in both KVStore and genesis state. message AccountUnbondings { string account = 1; - string denom = 2; - uint32 tier = 3; - repeated Unbonding unbondings = 4 [(gogoproto.nullable) = false]; -} + string uToken = 2; + repeated Unbonding unbondings = 3 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/umee/incentive/v1/incentive.proto b/proto/umee/incentive/v1/incentive.proto index f384797aaf..97839032a5 100644 --- a/proto/umee/incentive/v1/incentive.proto +++ b/proto/umee/incentive/v1/incentive.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package umeenetwork.umee.incentive.v1; +package umee.incentive.v1; import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; @@ -10,43 +10,19 @@ option go_package = "github.com/umee-network/umee/v4/x/incentive"; message Params { option (gogoproto.equal) = true; - // max_unbondings defines the maximum amount of concurrent unbondings an address can have - // on each unbonding tier of each bonded uToken denom. + // max_unbondings is the maximum amount of concurrent unbondings an address can have + // of each bonded uToken denom. Zero is interpreted as no limit. uint32 max_unbondings = 1; - // unbonding_duration_long defines the unbonding duration (in seconds) of the long tier. - uint64 unbonding_duration_long = 2; + // unbonding_duration is the unbonding duration (in seconds). + int64 unbonding_duration = 2; - // unbonding_duration_middle defines the unbonding duration (in seconds) of the middle tier. - uint64 unbonding_duration_middle = 3; - - // unbonding_duration_short defines the unbonding duration (in seconds) of the short tier. - uint64 unbonding_duration_short = 4; - - // tier_weight_short defines the proportion of rewards which assets bonded - // in the short unbonding duration receive compared to what the same amount - // would receive bonded to the long tier. - // valid values: [0;1] - string tier_weight_short = 5 [ + // emergency_unbond_fee is the portion of a bond that is paid when it is instantly + // released using MsgEmergencyUnbond. For example, 0.01 is a 1% fee. Ranges 0-1. + string emergency_unbond_fee = 3 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - - // tier_weight_middle defines the proportion of rewards which assets bonded - // in the middle unbonding duration receive compared to what the same amount - // would receive bonded to the long tier. - // valid values: [0;1] - string tier_weight_middle = 6 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - - // community_fund_address is the address from which all incentive programs - // proposed with "from_community_fund = true" will receive their funding. - // Since funds are withdrawn automatically when an incentive program passes - // governance, this account should always contain sufficient balance to - // cover incentive programs which are being voted upon. - string community_fund_address = 7; } // IncentiveProgram defines a liquidity mining incentive program on a single @@ -62,13 +38,13 @@ message IncentiveProgram { // start_time is the unix time (in seconds) at which the incentives begin. // If a program is passed after its intended start time, its start time // will be increased to the current time, with program duration unchanged. - uint64 start_time = 2; + int64 start_time = 2; // duration is the length of the incentive program from start time to // completion in seconds. - uint64 duration = 3; + int64 duration = 3; - // uToken is the incentivized uToken collateral. Suppliers who collateralize + // uToken is the incentivized uToken collateral denom. Suppliers who collateralize // this asset then bond it to the incentive module are eligible for this program's // rewards. string uToken = 4; diff --git a/proto/umee/incentive/v1/query.proto b/proto/umee/incentive/v1/query.proto index a51aff9e5e..92a664b706 100644 --- a/proto/umee/incentive/v1/query.proto +++ b/proto/umee/incentive/v1/query.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package umeenetwork.umee.incentive.v1; +package umee.incentive.v1; import "cosmos/base/query/v1beta1/pagination.proto"; import "google/api/annotations.proto"; @@ -17,28 +17,22 @@ service Query { option (google.api.http).get = "/umee/incentive/v1/params"; } - // TotalBonded queries the sum of all bonded collateral uTokens, separated by tier. + // TotalBonded queries the sum of all bonded collateral uTokens. rpc TotalBonded(QueryTotalBonded) returns (QueryTotalBondedResponse) { - option (google.api.http).get = "/umee/incentive/v1/total_bonded/{denom}"; + option (google.api.http).get = "/umee/incentive/v1/total_bonded"; } - // TotalUnbonding queries the sum of all unbonding collateral uTokens, separated by tier. + // TotalUnbonding queries the sum of all unbonding collateral uTokens. rpc TotalUnbonding(QueryTotalUnbonding) returns (QueryTotalUnbondingResponse) { - option (google.api.http).get = "/umee/incentive/v1/total_unbonding/{denom}"; + option (google.api.http).get = "/umee/incentive/v1/total_unbonding"; } - // Bonded queries all bonded collateral uTokens associated with an account. - rpc Bonded(QueryBonded) - returns (QueryBondedResponse) { - option (google.api.http).get = "/umee/incentive/v1/bonded/{address}/{denom}"; - } - - // Unbondings queries all current uToken unbondings associated with an account. - rpc Unbondings(QueryUnbondings) - returns (QueryUnbondingsResponse) { - option (google.api.http).get = "/umee/incentive/v1/unbondings/{address}"; + // AccountBonds queries all bonded collateral and unbondings associated with an account. + rpc AccountBonds(QueryAccountBonds) + returns (QueryAccountBondsResponse) { + option (google.api.http).get = "/umee/incentive/v1/account_bonds/{address}"; } // PendingRewards queries unclaimed incentive rewards associated with an account. @@ -73,6 +67,14 @@ service Query { returns (QueryIncentiveProgramResponse) { option (google.api.http).get = "/umee/incentive/v1/incentive_program/{id}"; } + + // CurrentRates queries the hypothetical return of a bonded uToken denomination + // if current incentive rewards continued for one year. The response is an sdk.Coins + // of base token rewards, per reference amount (usually 10^exponent of the uToken.) + rpc CurrentRates(QueryCurrentRates) + returns (QueryCurrentRatesResponse) { + option (google.api.http).get = "/umee/incentive/v1/current_rates"; + } } // QueryParams defines the request structure for the Params gRPC service @@ -98,26 +100,22 @@ message QueryPendingRewardsResponse { ]; } -// QueryBonded defines the request structure for the Bonded gRPC service handler. -message QueryBonded { +// QueryAccountBonds defines the request structure for the AccountBonds gRPC service handler. +message QueryAccountBonds { string address = 1; - // denom is an optional field which causes the query to return the totals of only one uToken - string denom = 2; -} - -// QueryBondedResponse defines the response structure for the Bonded gRPC service handler. -message QueryBondedResponse { - repeated TotalBond bonded = 1 [(gogoproto.nullable) = false]; } -// QueryUnbondings defines the request structure for the Unbondings gRPC service handler. -message QueryUnbondings { - string address = 1; -} - -// QueryUnbondingsResponse defines the response structure for the Unbondings gRPC service handler. -message QueryUnbondingsResponse { - repeated Unbonding unbondings = 1 [(gogoproto.nullable) = false]; +// QueryAccountBondsResponse defines the response structure for the AccountBonds gRPC service handler. +message QueryAccountBondsResponse { + repeated cosmos.base.v1beta1.Coin bonded = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + repeated cosmos.base.v1beta1.Coin unbonding = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + repeated Unbonding unbondings = 3 [(gogoproto.nullable) = false]; } // QueryTotalBonded defines the request structure for the TotalBonded gRPC service handler. @@ -128,7 +126,10 @@ message QueryTotalBonded { // QueryTotalBondedResponse defines the response structure for the TotalBonded gRPC service handler. message QueryTotalBondedResponse { - repeated TotalBond bonded = 1 [(gogoproto.nullable) = false]; + repeated cosmos.base.v1beta1.Coin bonded = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; } // QueryTotalUnbonding defines the request structure for the TotalUnbonding gRPC service handler. @@ -139,7 +140,10 @@ message QueryTotalUnbonding { // QueryTotalUnbondingResponse defines the response structure for the TotalUnbonding gRPC service handler. message QueryTotalUnbondingResponse { - repeated TotalBond unbonding = 1 [(gogoproto.nullable) = false]; + repeated cosmos.base.v1beta1.Coin unbonding = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; } // QueryUpcomingIncentivePrograms defines the request structure for the @@ -191,3 +195,26 @@ message QueryIncentiveProgram { message QueryIncentiveProgramResponse { IncentiveProgram program = 1 [(gogoproto.nullable) = false]; } + +// QueryCurrentRates defines the request structure for the CurrentRates gRPC service handler. +message QueryCurrentRates { + // uToken is the uToken denomination whose current annual rate of rewards is being queried + string uToken = 1; +} + +// QueryCurrentRatesResponse defines the response structure for the CurrentRates gRPC service handler. +message QueryCurrentRatesResponse { + // Reference Bond is an amount of bonded uTokens (usually 10^exponent) whose current rewards are being + // calculated. This amount can be used to compute an individual user's rewards: for example, if a user has + // 2.5x the reference amount currently bonded, then they would receive 2.5x the rewards below annually + // at current rates. + cosmos.base.v1beta1.Coin reference_bond = 1 [ + (gogoproto.nullable) = false + ]; + // Rewards are the amount of base token rewards that the reference amount of bonded uTokens would earn + // if current rates continued for a full year. + repeated cosmos.base.v1beta1.Coin rewards = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} \ No newline at end of file diff --git a/proto/umee/incentive/v1/tx.proto b/proto/umee/incentive/v1/tx.proto index 9811d9dc5a..828413b71a 100644 --- a/proto/umee/incentive/v1/tx.proto +++ b/proto/umee/incentive/v1/tx.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package umeenetwork.umee.incentive.v1; +package umee.incentive.v1; import "cosmos/base/v1beta1/coin.proto"; import "cosmos_proto/cosmos.proto"; @@ -14,12 +14,17 @@ service Msg { // Claim defines a method for claiming any pending incentive rewards. rpc Claim(MsgClaim) returns (MsgClaimResponse); - // Bond defines a method for bonding uToken collateral into reward tier. + // Bond defines a method for bonding uToken collateral. rpc Bond(MsgBond) returns (MsgBondResponse); // BeginUnbonding defines a method for starting to unbond uToken collateral. + // Only max_unbondings unbondings can be active at per user, per denom, at once. rpc BeginUnbonding(MsgBeginUnbonding) returns (MsgBeginUnbondingResponse); + // EmergencyUnbond defines a method for instantly unbonding uToken collateral in exchange for a fee. + // This can finish existing unbondings or unbond bonded tokens, and is not restricted by max_unbondings. + rpc EmergencyUnbond(MsgEmergencyUnbond) returns (MsgEmergencyUnbondResponse); + // Sponsor defines a permissionless method for sponsoring an upcoming, not yet funded incentive program. // The sponsor must be a single account and the MsgSponsor must fully cover the expected program rewards. rpc Sponsor(MsgSponsor) returns (MsgSponsorResponse); @@ -47,8 +52,7 @@ message MsgClaimResponse { // MsgBond represents a account's request to bond uToken collateral. message MsgBond { string account = 1; - uint32 tier = 2; - cosmos.base.v1beta1.Coin asset = 3 [(gogoproto.nullable) = false]; + cosmos.base.v1beta1.Coin uToken = 2 [(gogoproto.nullable) = false]; } // MsgBondResponse defines the Msg/Lock response type. @@ -57,21 +61,28 @@ message MsgBondResponse {} // MsgBeginUnbonding represents a account's request to begin unbonding uToken collateral. message MsgBeginUnbonding { string account = 1; - uint32 tier = 2; - cosmos.base.v1beta1.Coin asset = 3 [(gogoproto.nullable) = false]; + cosmos.base.v1beta1.Coin uToken = 2 [(gogoproto.nullable) = false]; } // MsgBeginUnbondingResponse defines the Msg/BeginUnbonding response type. message MsgBeginUnbondingResponse {} +// MsgEmergencyUnbond represents a account's request to instantly unbond uToken collateral for a fee. +message MsgEmergencyUnbond { + string account = 1; + cosmos.base.v1beta1.Coin uToken = 2 [(gogoproto.nullable) = false]; +} + +// MsgEmergencyUnbondResponse defines the Msg/EmergencyUnbond response type. +message MsgEmergencyUnbondResponse {} + // MsgSponsor represents a sponsor's request to fund rewards for an incentive program. // The program must have been passed by governance, not yet started, and not yet funded. // Funded assets must be the full amount required by the program. message MsgSponsor { // Sponsor bech32 account address - string sponsor = 1; - uint32 program = 2; - cosmos.base.v1beta1.Coin asset = 3 [(gogoproto.nullable) = false]; + string sponsor = 1; + uint32 program = 2; } // MsgSponsorResponse defines the Msg/Sponsor response type. diff --git a/util/coin/coin.go b/util/coin/coin.go index 8e969fe10e..7adc96a914 100644 --- a/util/coin/coin.go +++ b/util/coin/coin.go @@ -22,7 +22,7 @@ func Normalize(cs sdk.Coins) sdk.Coins { return cs } -// New creates a mkCoin with a given base denom and amount +// New creates a Coin with a given base denom and amount func New(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } diff --git a/util/keys/keys.go b/util/keys/keys.go new file mode 100644 index 0000000000..64ce7a2fda --- /dev/null +++ b/util/keys/keys.go @@ -0,0 +1,59 @@ +package keys + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ExtractAddress extracts addr from a key of the form of +// ... | lengthPrefixed(addr) | ... +// starting at a given index. Also returns the index of the first byte following the address. +func ExtractAddress(startIndex int, key []byte) (addr sdk.AccAddress, nextIndex int, err error) { + if len(key) <= startIndex { + return sdk.AccAddress{}, 0, fmt.Errorf("key too short to contain address after startIndex") + } + // interpret, as 0-255, the byte after the prefix + addrLen := int(key[startIndex]) + if len(key) < startIndex+1+addrLen { + return sdk.AccAddress{}, 0, fmt.Errorf("key too short to contain specified address length after prefix") + } + addr = key[startIndex+1 : startIndex+1+addrLen] + return addr, startIndex + 1 + addrLen, nil +} + +// ExtractString extracts a null-terminated string from a key of the form of +// ... | bytes(string) | 0x0 | ... +// starting at a given index. Also returns the index of the first byte following the null terminator. +func ExtractString(startIndex int, key []byte) (s string, nextIndex int, err error) { + if len(key) <= startIndex+1 { + return "", 0, fmt.Errorf("key too short to contain non-empty null terminated string after startIndex") + } + if key[startIndex] == 0 { + return "", 0, fmt.Errorf("empty null-terminated string not allowed in key") + } + // find the first 0x00 after prefix + for i, b := range key[startIndex:] { + if b == 0 { + s = string(key[startIndex : startIndex+i]) + nextIndex = startIndex + i + 1 + return s, nextIndex, nil + } + } + return "", 0, fmt.Errorf("null terminator not found") +} + +// ExtractAddressAndString extracts addr and a null-terminated string from a key of the form of +// ... | lengthPrefixed(addr) | bytes(string) | 0x0 | ... +// starting at a given index. Also returns the index of the first byte following the null terminator. +func ExtractAddressAndString(startIndex int, key []byte) (addr sdk.AccAddress, s string, nextIndex int, err error) { + // first parse leading address + addr, nextIndex, err = ExtractAddress(startIndex, key) + if err != nil { + return addr, "", 0, err + } + + // continue parsing key from where we left off + s, nextIndex, err = ExtractString(nextIndex, key) + return addr, s, nextIndex, err +} diff --git a/util/keys/keys_test.go b/util/keys/keys_test.go new file mode 100644 index 0000000000..8e8ebc6e02 --- /dev/null +++ b/util/keys/keys_test.go @@ -0,0 +1,302 @@ +package keys + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestExtractAddressAndString(t *testing.T) { + testCases := []struct { + name string + startIndex int + key []byte + expectErr string + addr []byte + s string + nextIndex int + }{ + { + "typical case", + 2, + []byte{2, 2, 1, 4, 97, 98, 99, 0}, + "", + []byte{4}, + "abc", + 8, + }, + { + "trailing data", + 2, + []byte{2, 2, 1, 4, 97, 98, 99, 0, 1, 2, 3}, + "", + []byte{4}, + "abc", + 8, + }, + { + "no prefix", + 0, + []byte{1, 4, 97, 98, 99, 0}, + "", + []byte{4}, + "abc", + 6, + }, + { + "zero length address, correctly prefixed", + 2, + []byte{2, 2, 0, 97, 98, 99, 0}, + "", + []byte{}, + "abc", + 7, + }, + { + "empty string, properly terminated", + 2, + []byte{2, 2, 1, 4, 0}, + "key too short to contain non-empty null terminated string after startIndex", + []byte{4}, + "", + 0, + }, + { + "null terminator before string", + 2, + []byte{2, 2, 1, 4, 0, 0}, + "empty null-terminated string not allowed in key", + []byte{}, + "", + 0, + }, + { + "key too short (empty)", + 2, + []byte{}, + "key too short", + []byte{}, + "", + 0, + }, + { + "key too short (prefix only)", + 2, + []byte{2, 2}, + "key too short", + []byte{}, + "", + 0, + }, + { + "key too short (no addr)", + 2, + []byte{2, 2, 1}, + "key too short", + []byte{}, + "", + 0, + }, + { + "key too short (big addr len prefix)", + 2, + []byte{2, 2, 42, 4, 4, 4, 97, 98, 99, 0}, + "key too short", + []byte{}, + "", + 0, + }, + { + "non-terminated string", + 2, + []byte{2, 2, 1, 4, 97, 98, 99}, + "null terminator not found", + []byte{}, + "", + 0, + }, + } + + for _, tc := range testCases { + addr, denom, read, err := ExtractAddressAndString(tc.startIndex, tc.key) + if tc.expectErr != "" { + assert.ErrorContains(t, err, tc.expectErr) + } else { + assert.Equal(t, denom, tc.s, tc.name) + assert.Equal(t, read, tc.nextIndex, tc.name) + assert.DeepEqual(t, []byte(addr), tc.addr) + } + } +} + +func TestExtractAddress(t *testing.T) { + testCases := []struct { + name string + startIndex int + key []byte + expectErr string + addr []byte + nextIndex int + }{ + { + "typical case", + 2, + []byte{2, 2, 1, 4}, + "", + []byte{4}, + 4, + }, + { + "trailing data", + 2, + []byte{2, 2, 1, 4, 97, 98, 99, 0, 1, 2, 3}, + "", + []byte{4}, + 4, + }, + { + "no prefix", + 0, + []byte{1, 4}, + "", + []byte{4}, + 2, + }, + { + "zero length address, correctly prefixed", + 2, + []byte{2, 2, 0, 97, 98, 99, 0}, + "", + []byte{}, + 3, + }, + { + "key too short (empty)", + 2, + []byte{}, + "key too short", + []byte{}, + 0, + }, + { + "key too short (prefix only)", + 2, + []byte{2, 2}, + "key too short", + []byte{}, + 0, + }, + { + "key too short (no addr)", + 2, + []byte{2, 2, 1}, + "key too short", + []byte{}, + 0, + }, + { + "key too short (big addr len prefix)", + 2, + []byte{2, 2, 42, 4, 4, 4, 97, 98, 99, 0}, + "key too short", + []byte{}, + 0, + }, + } + + for _, tc := range testCases { + addr, read, err := ExtractAddress(tc.startIndex, tc.key) + if tc.expectErr != "" { + assert.ErrorContains(t, err, tc.expectErr) + } else { + assert.Equal(t, read, tc.nextIndex, tc.name) + assert.DeepEqual(t, []byte(addr), tc.addr) + } + } +} + +func TestExtractString(t *testing.T) { + testCases := []struct { + name string + startIndex int + key []byte + expectErr string + s string + nextIndex int + }{ + { + "typical case", + 2, + []byte{2, 2, 97, 98, 99, 0}, + "", + "abc", + 6, + }, + { + "trailing data", + 2, + []byte{2, 2, 97, 98, 99, 0, 1, 2, 3}, + "", + "abc", + 6, + }, + { + "no prefix", + 0, + []byte{97, 98, 99, 0}, + "", + "abc", + 4, + }, + { + "empty string, properly terminated", + 2, + []byte{2, 2, 0}, + "key too short to contain non-empty null terminated string after startIndex", + "", + 0, + }, + { + "null terminator before string", + 2, + []byte{2, 2, 0, 9, 9}, + "empty null-terminated string not allowed in key", + "", + 0, + }, + { + "key too short (empty)", + 2, + []byte{}, + "key too short", + "", + 0, + }, + { + "key too short (prefix only)", + 2, + []byte{2, 2}, + "key too short", + "", + 0, + }, + { + "non-terminated string", + 2, + []byte{2, 2, 97, 98, 99}, + "null terminator not found", + "", + 0, + }, + } + + for _, tc := range testCases { + denom, read, err := ExtractString(tc.startIndex, tc.key) + if tc.expectErr != "" { + assert.ErrorContains(t, err, tc.expectErr) + } else { + assert.Equal(t, denom, tc.s, tc.name) + assert.Equal(t, read, tc.nextIndex, tc.name) + } + } +} diff --git a/util/store/store.go b/util/store/store.go index 0b7f2296fa..91a868f22b 100644 --- a/util/store/store.go +++ b/util/store/store.go @@ -22,23 +22,42 @@ import ( "fmt" sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" gogotypes "github.com/gogo/protobuf/types" ) +// GetObject gets and unmarshals a structure from KVstore. Panics on failure to decode, and returns a boolean +// indicating whether any data was found. If the return is false, the object might not be initialized with +// valid zero values for its type. +func GetObject(store sdk.KVStore, cdc codec.Codec, key []byte, object codec.ProtoMarshaler, errField string) bool { + if bz := store.Get(key); len(bz) > 0 { + err := cdc.Unmarshal(bz, object) + if err != nil { + panic(errField + " could not be unmarshaled: " + err.Error()) + } + return true + } + // No stored bytes at key: return false + return false +} + +// SetObject marshals and sets a structure in KVstore. Returns error on failure to encode. +func SetObject(store sdk.KVStore, cdc codec.Codec, key []byte, object codec.ProtoMarshaler, errField string) error { + bz, err := cdc.Marshal(object) + if err != nil { + return fmt.Errorf("failed to encode %s, %s", errField, err.Error()) + } + store.Set(key, bz) + return nil +} + // GetInt retrieves an sdkmath.Int from a KVStore, or returns zero if no value is stored. // It panics if a stored value fails to unmarshal or is negative. // Accepts an additional string which should describe the field being retrieved in custom error messages. func GetInt(store sdk.KVStore, key []byte, errField string) sdkmath.Int { if bz := store.Get(key); len(bz) > 0 { - val := sdk.ZeroInt() - if err := val.Unmarshal(bz); err != nil { - panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) - } - if val.IsNegative() { - panic(fmt.Sprintf("%s: retrieved negative %s", val, errField)) - } - return val + return Int(bz, errField) } // No stored bytes at key: return zero return sdk.ZeroInt() @@ -68,14 +87,7 @@ func SetInt(store sdk.KVStore, key []byte, val sdkmath.Int, errField string) err // Accepts an additional string which should describe the field being retrieved in custom error messages. func GetDec(store sdk.KVStore, key []byte, errField string) sdk.Dec { if bz := store.Get(key); len(bz) > 0 { - val := sdk.ZeroDec() - if err := val.Unmarshal(bz); err != nil { - panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) - } - if val.IsNegative() { - panic(fmt.Sprintf("%s: retrieved negative %s", val, errField)) - } - return val + return Dec(bz, errField) } // No stored bytes at key: return zero return sdk.ZeroDec() @@ -105,11 +117,7 @@ func SetDec(store sdk.KVStore, key []byte, val sdk.Dec, errField string) error { // Accepts an additional string which should describe the field being retrieved in custom error messages. func GetUint32(store sdk.KVStore, key []byte, errField string) uint32 { if bz := store.Get(key); len(bz) > 0 { - val := gogotypes.UInt32Value{} - if err := val.Unmarshal(bz); err != nil { - panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) - } - return val.Value + return Uint32(bz, errField) } // No stored bytes at key: return zero return 0 @@ -137,17 +145,13 @@ func SetUint32(store sdk.KVStore, key []byte, val uint32, errField string) error // Accepts an additional string which should describe the field being retrieved in custom error messages. func GetUint64(store sdk.KVStore, key []byte, errField string) uint64 { if bz := store.Get(key); len(bz) > 0 { - val := gogotypes.UInt64Value{} - if err := val.Unmarshal(bz); err != nil { - panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) - } - return val.Value + return Uint64(bz, errField) } // No stored bytes at key: return zero return 0 } -// SetUint64 stores a uint32 in a KVStore, or clears if setting to zero. +// SetUint64 stores a uint64 in a KVStore, or clears if setting to zero. // Uses gogoproto Uint64Value for marshaling, and returns an error on failure to encode. // Accepts an additional string which should describe the field being set in custom error messages. func SetUint64(store sdk.KVStore, key []byte, val uint64, errField string) error { @@ -164,6 +168,36 @@ func SetUint64(store sdk.KVStore, key []byte, val uint64, errField string) error return nil } +// GetInt64 retrieves an int64 from a KVStore, or returns zero if no value is stored. +// Uses gogoproto Int64Value for unmarshaling, and panics if a stored value fails to unmarshal. +// Accepts an additional string which should describe the field being retrieved in custom error messages. +// Allows negative values. +func GetInt64(store sdk.KVStore, key []byte, errField string) int64 { + if bz := store.Get(key); len(bz) > 0 { + return Int64(bz, errField) + } + // No stored bytes at key: return zero + return 0 +} + +// SetInt64 stores an int64 in a KVStore, or clears if setting to zero. +// Uses gogoproto Int64Value for marshaling, and returns an error on failure to encode. +// Accepts an additional string which should describe the field being set in custom error messages. +// Allows negative values. +func SetInt64(store sdk.KVStore, key []byte, val int64, errField string) error { + if val == 0 { + store.Delete(key) + } else { + v := &gogotypes.Int64Value{Value: val} + bz, err := v.Marshal() + if err != nil { + return fmt.Errorf("error while setting %s: %s", errField, err) + } + store.Set(key, bz) + } + return nil +} + // GetAddress retrieves an sdk.AccAddress from a KVStore, or an empty address if no value is stored. // Panics if a non-empty address fails sdk.VerifyAddressFormat, so non-empty returns are always valid. // Accepts an additional string which should describe the field being retrieved in custom error messages. diff --git a/util/store/unmarshal.go b/util/store/unmarshal.go new file mode 100644 index 0000000000..72579d71f3 --- /dev/null +++ b/util/store/unmarshal.go @@ -0,0 +1,65 @@ +package store + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + gogotypes "github.com/gogo/protobuf/types" +) + +// Int converts bytes to sdk.Int, and panics on failure or negative value +// with a message which includes the name of the value being retrieved +func Int(bz []byte, errField string) sdkmath.Int { + val := sdk.ZeroInt() + if err := val.Unmarshal(bz); err != nil { + panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) + } + if val.IsNegative() { + panic(fmt.Sprintf("%s: retrieved negative %s", val, errField)) + } + return val +} + +// Dec converts bytes to sdk.Dec, and panics on failure or negative value +// with a message which includes the name of the value being retrieved +func Dec(bz []byte, errField string) sdk.Dec { + val := sdk.ZeroDec() + if err := val.Unmarshal(bz); err != nil { + panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) + } + if val.IsNegative() { + panic(fmt.Sprintf("%s: retrieved negative %s", val, errField)) + } + return val +} + +// Uint32 converts bytes to a uint64 using gogotypes.Uint32Value, and panics on failure +// with a message which includes the name of the value being retrieved +func Uint32(bz []byte, errField string) uint32 { + val := gogotypes.UInt32Value{} + if err := val.Unmarshal(bz); err != nil { + panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) + } + return val.Value +} + +// Int64 converts bytes to an int64 using gogotypes.Int64Value, and panics on failure +// with a message which includes the name of the value being retrieved +func Int64(bz []byte, errField string) int64 { + val := gogotypes.Int64Value{} + if err := val.Unmarshal(bz); err != nil { + panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) + } + return val.Value +} + +// Uint64 converts bytes to a uint64 using gogotypes.Uint64Value, and panics on failure +// with a message which includes the name of the value being retrieved +func Uint64(bz []byte, errField string) uint64 { + val := gogotypes.UInt64Value{} + if err := val.Unmarshal(bz); err != nil { + panic(fmt.Sprintf("error unmarshaling %s into %T: %s", errField, val, err)) + } + return val.Value +} diff --git a/x/incentive/README.md b/x/incentive/README.md new file mode 100644 index 0000000000..3dd2fe0b3b --- /dev/null +++ b/x/incentive/README.md @@ -0,0 +1,10 @@ +# Incentive Module + +## Abstract + +This document specifies the `x/incentive` module of the Umee chain. + +The incentive module allows users to `Bond` collateral `uTokens` from the `x/leverage` module, and governance to create and fund `Incentive Programs` which distribute rewards to users with bonded uTokens over time. Users can `Unbond` tokens over a period of time, after which they can be withdrawn. + +The incentive module depends on the `x/leverage` module for information about users' bonded collateral, and also requires that the leverage module prevent bonded or currently unbonding collateral from being withdrawn. +There are also a few more advanced interactions, such as instantly unbonding collateral when it is liquidated, and registering an `exponent` when a uToken denom is incentivized for the first time. \ No newline at end of file diff --git a/x/incentive/client/cli/query.go b/x/incentive/client/cli/query.go index 5d4c0cfa4e..a1d46a1dd4 100644 --- a/x/incentive/client/cli/query.go +++ b/x/incentive/client/cli/query.go @@ -29,9 +29,10 @@ func GetQueryCmd() *cobra.Command { cmd.AddCommand( GetCmdQueryParams(), - GetCmdQueryUnbondings(), - GetCmdQueryBonded(), + GetCmdQueryAccountBonds(), + GetCmdQueryCurrentRates(), GetCmdQueryTotalBonded(), + GetCmdQueryTotalUnbonding(), GetCmdQueryPendingRewards(), GetCmdQueryUpcomingIncentivePrograms(), GetCmdQueryOngoingIncentivePrograms(), @@ -65,12 +66,12 @@ func GetCmdQueryParams() *cobra.Command { return cmd } -// GetCmdQueryUnbondings creates a Cobra command to query all unbondings associated with a single account. -func GetCmdQueryUnbondings() *cobra.Command { +// GetCmdQueryAccountBonds creates a Cobra command to query all bonds and unbondings associated with a single account. +func GetCmdQueryAccountBonds() *cobra.Command { cmd := &cobra.Command{ - Use: "unbondings [address]", + Use: "account-bonds [address]", Args: cobra.ExactArgs(1), - Short: fmt.Sprintf("Query all %s module unbondings associated with a single account", incentive.ModuleName), + Short: fmt.Sprintf("Query all %s module bonds and unbondings associated with an account", incentive.ModuleName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -78,7 +79,8 @@ func GetCmdQueryUnbondings() *cobra.Command { } queryClient := incentive.NewQueryClient(clientCtx) - resp, err := queryClient.Unbondings(cmd.Context(), &incentive.QueryUnbondings{Address: args[0]}) + + resp, err := queryClient.AccountBonds(cmd.Context(), &incentive.QueryAccountBonds{Address: args[0]}) return cli.PrintOrErr(resp, err, clientCtx) }, } @@ -109,24 +111,29 @@ func GetCmdQueryPendingRewards() *cobra.Command { return cmd } -// GetCmdQueryBonded creates a Cobra command to query bonded tokens associated with a single account. -func GetCmdQueryBonded() *cobra.Command { +// GetCmdQueryCurrentRates creates a Cobra command to query current annual rewards for a reference amount +// of a given bonded uToken. +func GetCmdQueryCurrentRates() *cobra.Command { cmd := &cobra.Command{ - Use: "bonded [address] [denom]", - Args: cobra.RangeArgs(1, 2), - Short: fmt.Sprintf("Query an address's uTokens bonded to the %s module", incentive.ModuleName), + Use: "current-rates[denom]", + Args: cobra.RangeArgs(0, 1), + Short: "Query the current annual rewards for a reference amount of a given bonded uToken.", RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } denom := "" - if len(args) > 1 { - denom = args[1] + if len(args) > 0 { + denom = args[0] } queryClient := incentive.NewQueryClient(clientCtx) - resp, err := queryClient.Bonded(cmd.Context(), &incentive.QueryBonded{Address: args[0], Denom: denom}) + resp, err := queryClient.CurrentRates(cmd.Context(), &incentive.QueryCurrentRates{UToken: denom}) + if err != nil { + return err + } + return cli.PrintOrErr(resp, err, clientCtx) }, } @@ -153,6 +160,40 @@ func GetCmdQueryTotalBonded() *cobra.Command { queryClient := incentive.NewQueryClient(clientCtx) resp, err := queryClient.TotalBonded(cmd.Context(), &incentive.QueryTotalBonded{Denom: denom}) + if err != nil { + return err + } + + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdQueryTotalUnbonding creates a Cobra command to query unbonding tokens across all users. +func GetCmdQueryTotalUnbonding() *cobra.Command { + cmd := &cobra.Command{ + Use: "total-unbonding [denom]", + Args: cobra.RangeArgs(0, 1), + Short: fmt.Sprintf("Query the total uTokens unbonding from the %s module", incentive.ModuleName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + denom := "" + if len(args) > 0 { + denom = args[0] + } + + queryClient := incentive.NewQueryClient(clientCtx) + resp, err := queryClient.TotalUnbonding(cmd.Context(), &incentive.QueryTotalUnbonding{Denom: denom}) + if err != nil { + return err + } + return cli.PrintOrErr(resp, err, clientCtx) }, } diff --git a/x/incentive/client/cli/tx.go b/x/incentive/client/cli/tx.go index 7edc05314d..c33140bb0e 100644 --- a/x/incentive/client/cli/tx.go +++ b/x/incentive/client/cli/tx.go @@ -27,6 +27,7 @@ func GetTxCmd() *cobra.Command { GetCmdClaim(), GetCmdBond(), GetCmdBeginUnbonding(), + GetCmdEmergencyUnbond(), GetCmdSponsor(), ) @@ -60,26 +61,21 @@ func GetCmdClaim() *cobra.Command { // transaction with a MsgBond message. func GetCmdBond() *cobra.Command { cmd := &cobra.Command{ - Use: "bond [tier] [utokens]", - Args: cobra.ExactArgs(2), - Short: "Bond some uToken collateral to a specific unbonding tier", + Use: "bond [utokens]", + Args: cobra.ExactArgs(1), + Short: "Bond some uToken collateral", RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - asset, err := sdk.ParseCoinNormalized(args[1]) + asset, err := sdk.ParseCoinNormalized(args[0]) if err != nil { return err } - tier, err := strconv.ParseUint(args[0], 10, 32) - if err != nil { - return err - } - - msg := incentive.NewMsgBond(clientCtx.GetFromAddress(), uint32(tier), asset) + msg := incentive.NewMsgBond(clientCtx.GetFromAddress(), asset) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -93,26 +89,49 @@ func GetCmdBond() *cobra.Command { // transaction with a MsgBeginUnbonding message. func GetCmdBeginUnbonding() *cobra.Command { cmd := &cobra.Command{ - Use: "begin-unbonding [tier] [utokens]", - Args: cobra.ExactArgs(2), - Short: "Begin unbonding some currently bonded utokens from a specifc unbonding tier", + Use: "begin-unbonding [utokens]", + Args: cobra.ExactArgs(1), + Short: "Begin unbonding some currently bonded utokens", RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - asset, err := sdk.ParseCoinNormalized(args[1]) + asset, err := sdk.ParseCoinNormalized(args[0]) if err != nil { return err } - tier, err := strconv.ParseUint(args[0], 10, 32) + msg := incentive.NewMsgBeginUnbonding(clientCtx.GetFromAddress(), asset) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// transaction with a MsgEmergencyUnbond message. +func GetCmdEmergencyUnbond() *cobra.Command { + cmd := &cobra.Command{ + Use: "emergency-unbond [utokens]", + Args: cobra.ExactArgs(1), + Short: "Instantly unbond some currently bonded or unbonding utokens, for a fee", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + asset, err := sdk.ParseCoinNormalized(args[0]) if err != nil { return err } - msg := incentive.NewMsgBeginUnbonding(clientCtx.GetFromAddress(), uint32(tier), asset) + msg := incentive.NewMsgEmergencyUnbond(clientCtx.GetFromAddress(), asset) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -126,8 +145,8 @@ func GetCmdBeginUnbonding() *cobra.Command { // transaction with a MsgSponsor message. func GetCmdSponsor() *cobra.Command { cmd := &cobra.Command{ - Use: "sponsor [program-id] [tokens]", - Args: cobra.ExactArgs(2), + Use: "sponsor [program-id]", + Args: cobra.ExactArgs(1), Short: "Fund a governance-approved, not yet funded incentive program with its exact total reward tokens", RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) @@ -135,17 +154,12 @@ func GetCmdSponsor() *cobra.Command { return err } - asset, err := sdk.ParseCoinNormalized(args[1]) - if err != nil { - return err - } - id, err := strconv.ParseUint(args[0], 10, 32) if err != nil { return err } - msg := incentive.NewMsgSponsor(clientCtx.GetFromAddress(), uint32(id), asset) + msg := incentive.NewMsgSponsor(clientCtx.GetFromAddress(), uint32(id)) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/incentive/codec.go b/x/incentive/codec.go index 230ed7cccc..ebe8b9beef 100644 --- a/x/incentive/codec.go +++ b/x/incentive/codec.go @@ -6,7 +6,6 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) var ( @@ -43,11 +42,5 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { &MsgGovCreatePrograms{}, ) - registry.RegisterImplementations( - (*govtypes.Content)(nil), - &MsgGovSetParams{}, - &MsgGovCreatePrograms{}, - ) - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/incentive/errors.go b/x/incentive/errors.go index fca0429e59..2da4db65bf 100644 --- a/x/incentive/errors.go +++ b/x/incentive/errors.go @@ -7,19 +7,17 @@ import ( ) var ( - // 0 = TODO - ErrNotImplemented = errors.Register(ModuleName, 0, "not implemented") - // 1XX = General - ErrInvalidProgramID = errors.Register(ModuleName, 100, "invalid program ID") - ErrNilAsset = errors.Register(ModuleName, 101, "nil asset") - ErrInvalidTier = errors.Register(ModuleName, 102, "invalid unbonding tier") - ErrEmptyAddress = errors.Register(ModuleName, 103, "empty address") - ErrInvalidProgramStatus = errors.Register(ModuleName, 104, "invalid program status") - - // 2XX = Params - ErrUnbondingTierOrder = errors.Register(ModuleName, 200, "unbonding tier lock durations out of order") - ErrUnbondingWeightOrder = errors.Register(ModuleName, 201, "unbonding tier weights out of order") + ErrInvalidProgramID = errors.Register(ModuleName, 100, "invalid program ID") + ErrNilAsset = errors.Register(ModuleName, 101, "nil asset") + ErrEmptyAddress = errors.Register(ModuleName, 102, "empty address") + ErrInvalidProgramStatus = errors.Register(ModuleName, 103, "invalid program status") + ErrInvalidProgramDuration = errors.Register(ModuleName, 104, "invalid program duration") + ErrInvalidProgramStart = errors.Register(ModuleName, 105, "invalid program start time") + ErrProgramRewardMismatch = errors.Register(ModuleName, 106, "program total and remaining reward denoms mismatched") + ErrNonfundedProgramRewards = errors.Register(ModuleName, 107, "nonzero remaining rewards on a non-funded program") + ErrProgramWithoutRewards = errors.Register(ModuleName, 108, "incentive program must have nonzero rewards") + ErrInvalidUnbonding = errors.Register(ModuleName, 109, "invalid unbonding") // 3XX = Gov Proposal ErrNonzeroRemainingRewards = errors.Register(ModuleName, 300, "remaining rewards must be zero in proposal") diff --git a/x/incentive/expected_keepers.go b/x/incentive/expected_keepers.go index a48bf6a9d8..1aa271ece2 100644 --- a/x/incentive/expected_keepers.go +++ b/x/incentive/expected_keepers.go @@ -2,23 +2,21 @@ package incentive import ( sdk "github.com/cosmos/cosmos-sdk/types" + + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" ) // BankKeeper defines the expected x/bank keeper interface. type BankKeeper interface { - SendCoinsFromModuleToAccount( - ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, - ) error - SendCoinsFromAccountToModule( - ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, - ) error + SendCoinsFromModuleToAccount(ctx sdk.Context, fromModule string, toAddr sdk.AccAddress, coins sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, toModule string, coins sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, fromModule string, toModule string, coins sdk.Coins) error SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } // LeverageKeeper defines the expected x/leverage keeper interface. type LeverageKeeper interface { - GetCollateralAmount(ctx sdk.Context, borrowerAddr sdk.AccAddress, denom string) sdk.Coin - IsAcceptedUToken(ctx sdk.Context, uTokenDenom string) bool - AssertNotBlacklisted(ctx sdk.Context, denom string) error - // TODO: hooks + GetCollateral(ctx sdk.Context, borrowerAddr sdk.AccAddress, denom string) sdk.Coin + DonateCollateral(ctx sdk.Context, fromAddr sdk.AccAddress, uToken sdk.Coin) error + GetTokenSettings(ctx sdk.Context, denom string) (leveragetypes.Token, error) } diff --git a/x/incentive/genesis.go b/x/incentive/genesis.go index d8e90ae7a0..3b8742cb0c 100644 --- a/x/incentive/genesis.go +++ b/x/incentive/genesis.go @@ -3,8 +3,11 @@ package incentive import ( "encoding/json" + "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" ) // NewGenesisState creates a new GenesisState object @@ -14,7 +17,7 @@ func NewGenesisState( ongoingPrograms []IncentiveProgram, upcomingPrograms []IncentiveProgram, nextProgramID uint32, - lastRewardTime uint64, + lastRewardTime int64, bonds []Bond, rewardTrackers []RewardTracker, rewardAccumulators []RewardAccumulator, @@ -34,8 +37,8 @@ func NewGenesisState( } } -// DefaultGenesisState returns the default genesis state -func DefaultGenesisState() *GenesisState { +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { return &GenesisState{ Params: DefaultParams(), NextProgramId: 1, @@ -43,9 +46,63 @@ func DefaultGenesisState() *GenesisState { } } -// ValidateGenesis checks a genesis state for basic issues -func ValidateGenesis(_ GenesisState) error { - // TODO #1749 +// Validate checks a genesis state for basic issues +func (gs GenesisState) Validate() error { + if err := gs.Params.Validate(); err != nil { + return err + } + if gs.NextProgramId == 0 { + return ErrInvalidProgramID.Wrap("next program ID must not be zero") + } + if gs.LastRewardsTime < 0 { + return ErrDecreaseLastRewardTime.Wrap("last reward time must not be negative") + } + + // TODO: enforce no duplicate (account,denom) + for _, rt := range gs.RewardTrackers { + if err := rt.Validate(); err != nil { + return err + } + } + + // TODO: enforce no duplicate denoms + for _, ra := range gs.RewardAccumulators { + if err := ra.Validate(); err != nil { + return err + } + } + + // TODO: enforce no duplicate program IDs + for _, up := range gs.UpcomingPrograms { + if err := up.ValidatePassed(); err != nil { + return err + } + } + for _, op := range gs.OngoingPrograms { + if err := op.ValidatePassed(); err != nil { + return err + } + } + for _, cp := range gs.CompletedPrograms { + if err := cp.ValidatePassed(); err != nil { + return err + } + } + + // TODO: enforce no duplicate (account,denom) + for _, b := range gs.Bonds { + if err := b.Validate(); err != nil { + return err + } + } + + // TODO: enforce no duplicate (account,denom) + for _, au := range gs.AccountUnbondings { + if err := au.Validate(); err != nil { + return err + } + } + return nil } @@ -64,8 +121,8 @@ func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.R // NewIncentiveProgram creates the IncentiveProgram struct used in GenesisState func NewIncentiveProgram( id uint32, - startTime uint64, - duration uint64, + startTime int64, + duration int64, uDenom string, totalRewards, remainingRewards sdk.Coin, funded bool, @@ -81,56 +138,184 @@ func NewIncentiveProgram( } } +// Validate performs validation on an IncentiveProgram type returning an error +// if the program is invalid. +func (ip IncentiveProgram) Validate() error { + if err := sdk.ValidateDenom(ip.UToken); err != nil { + return err + } + if !leveragetypes.HasUTokenPrefix(ip.UToken) { + // only allow uToken denoms as bonded denoms + return errors.Wrap(leveragetypes.ErrNotUToken, ip.UToken) + } + + if err := ip.TotalRewards.Validate(); err != nil { + return err + } + if leveragetypes.HasUTokenPrefix(ip.TotalRewards.Denom) { + // only allow base token denoms as rewards + return errors.Wrap(leveragetypes.ErrUToken, ip.TotalRewards.Denom) + } + if ip.TotalRewards.IsZero() { + return ErrProgramWithoutRewards + } + + if err := ip.RemainingRewards.Validate(); err != nil { + return err + } + if ip.RemainingRewards.Denom != ip.TotalRewards.Denom { + return ErrProgramRewardMismatch + } + if !ip.Funded && ip.RemainingRewards.IsPositive() { + return ErrNonfundedProgramRewards + } + + if ip.Duration <= 0 { + return errors.Wrapf(ErrInvalidProgramDuration, "%d", ip.Duration) + } + if ip.StartTime <= 0 { + return errors.Wrapf(ErrInvalidProgramStart, "%d", ip.Duration) + } + + return nil +} + +// ValidateProposed runs IncentiveProgram.Validate and also checks additional requirements applying +// to incentive programs which have not yet been funded or passed by governance +func (ip IncentiveProgram) ValidateProposed() error { + if ip.ID != 0 { + return ErrInvalidProgramID.Wrapf("%d", ip.ID) + } + if !ip.RemainingRewards.IsZero() { + return ErrNonzeroRemainingRewards.Wrap(ip.RemainingRewards.String()) + } + if ip.Funded { + return ErrProposedFundedProgram + } + return ip.Validate() +} + +// ValidatePassed runs IncentiveProgram.Validate and also checks additional requirements applying +// to incentive programs which have already been passed by governance +func (ip IncentiveProgram) ValidatePassed() error { + if ip.ID == 0 { + return ErrInvalidProgramID.Wrapf("%d", ip.ID) + } + return ip.Validate() +} + // NewBond creates the Bond struct used in GenesisState -func NewBond(addr string, tier uint32, coin sdk.Coin) Bond { +func NewBond(addr string, coin sdk.Coin) Bond { return Bond{ Account: addr, - Tier: tier, - Amount: coin, + UToken: coin, } } -// NewTotalBond creates the TotalBond struct used in GenesisState -func NewTotalBond(tier uint32, coin sdk.Coin) Bond { - return Bond{ - Tier: tier, - Amount: coin, +func (b Bond) Validate() error { + if _, err := sdk.AccAddressFromBech32(b.Account); err != nil { + return err + } + if err := b.UToken.Validate(); err != nil { + return err } + if !leveragetypes.HasUTokenPrefix(b.UToken.Denom) { + return leveragetypes.ErrNotUToken.Wrap(b.UToken.Denom) + } + return nil } // NewRewardTracker creates the RewardTracker struct used in GenesisState -func NewRewardTracker(addr, denom string, tier uint32, coins sdk.DecCoins) RewardTracker { +func NewRewardTracker(addr, uDenom string, coins sdk.DecCoins) RewardTracker { return RewardTracker{ - Account: addr, - Denom: denom, - Tier: tier, - RewardTracker: coins, + Account: addr, + UToken: uDenom, + Rewards: coins, + } +} + +func (rt RewardTracker) Validate() error { + if _, err := sdk.AccAddressFromBech32(rt.Account); err != nil { + return err + } + if !leveragetypes.HasUTokenPrefix(rt.UToken) { + return leveragetypes.ErrNotUToken.Wrap(rt.UToken) + } + if err := rt.Rewards.Validate(); err != nil { + return err } + for _, r := range rt.Rewards { + if leveragetypes.HasUTokenPrefix(r.Denom) { + return leveragetypes.ErrUToken.Wrap(r.Denom) + } + } + return nil } // NewRewardAccumulator creates the RewardAccumulator struct used in GenesisState -func NewRewardAccumulator(denom string, tier uint32, coins sdk.DecCoins) RewardAccumulator { +func NewRewardAccumulator(uDenom string, exponent uint32, coins sdk.DecCoins) RewardAccumulator { return RewardAccumulator{ - Denom: denom, - Tier: tier, - RewardTracker: coins, + UToken: uDenom, + Exponent: exponent, + Rewards: coins, } } +func (ra RewardAccumulator) Validate() error { + if !leveragetypes.HasUTokenPrefix(ra.UToken) { + return leveragetypes.ErrNotUToken.Wrap(ra.UToken) + } + if err := ra.Rewards.Validate(); err != nil { + return err + } + for _, r := range ra.Rewards { + if leveragetypes.HasUTokenPrefix(r.Denom) { + return leveragetypes.ErrUToken.Wrap(r.Denom) + } + } + return nil +} + // NewUnbonding creates the Unbonding struct used in GenesisState -func NewUnbonding(endTime uint64, coin sdk.Coin) Unbonding { +func NewUnbonding(startTime, endTime int64, coin sdk.Coin) Unbonding { return Unbonding{ + Start: startTime, End: endTime, - Amount: coin, + UToken: coin, } } +func (u Unbonding) Validate() error { + if u.End < u.Start { + return ErrInvalidUnbonding.Wrap("start time > end time") + } + return u.UToken.Validate() +} + // NewAccountUnbondings creates the AccountUnbondings struct used in GenesisState -func NewAccountUnbondings(addr, denom string, tier BondTier, unbondings []Unbonding) AccountUnbondings { +func NewAccountUnbondings(addr, uDenom string, unbondings []Unbonding) AccountUnbondings { return AccountUnbondings{ Account: addr, - Tier: uint32(tier), - Denom: denom, + UToken: uDenom, Unbondings: unbondings, } } + +func (au AccountUnbondings) Validate() error { + if _, err := sdk.AccAddressFromBech32(au.Account); err != nil { + return err + } + if !leveragetypes.HasUTokenPrefix(au.UToken) { + return leveragetypes.ErrNotUToken.Wrap(au.UToken) + } + for _, u := range au.Unbondings { + if u.UToken.Denom != au.UToken { + return ErrInvalidUnbonding.Wrapf("unbonding denom %s does not match accountUnbondings denom %s", + u.UToken.Denom, au.UToken) + } + if err := u.Validate(); err != nil { + return err + } + } + return nil +} diff --git a/x/incentive/genesis.pb.go b/x/incentive/genesis.pb.go index 9304598fbc..7bbaa7b8d1 100644 --- a/x/incentive/genesis.pb.go +++ b/x/incentive/genesis.pb.go @@ -29,7 +29,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type GenesisState struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` NextProgramId uint32 `protobuf:"varint,2,opt,name=next_program_id,json=nextProgramId,proto3" json:"next_program_id,omitempty"` - LastRewardsTime uint64 `protobuf:"varint,3,opt,name=last_rewards_time,json=lastRewardsTime,proto3" json:"last_rewards_time,omitempty"` + LastRewardsTime int64 `protobuf:"varint,3,opt,name=last_rewards_time,json=lastRewardsTime,proto3" json:"last_rewards_time,omitempty"` RewardTrackers []RewardTracker `protobuf:"bytes,4,rep,name=reward_trackers,json=rewardTrackers,proto3" json:"reward_trackers"` RewardAccumulators []RewardAccumulator `protobuf:"bytes,5,rep,name=reward_accumulators,json=rewardAccumulators,proto3" json:"reward_accumulators"` UpcomingPrograms []IncentiveProgram `protobuf:"bytes,6,rep,name=upcoming_programs,json=upcomingPrograms,proto3" json:"upcoming_programs"` @@ -86,7 +86,7 @@ func (m *GenesisState) GetNextProgramId() uint32 { return 0 } -func (m *GenesisState) GetLastRewardsTime() uint64 { +func (m *GenesisState) GetLastRewardsTime() int64 { if m != nil { return m.LastRewardsTime } @@ -142,73 +142,18 @@ func (m *GenesisState) GetAccountUnbondings() []AccountUnbondings { return nil } -// TotalBond tracks the amount of coins of one uToken denomination bonded to a -// given reward tier by all accounts. Used by queries TotalBonded and TotalUnbonding. -type TotalBond struct { - Tier uint32 `protobuf:"varint,1,opt,name=tier,proto3" json:"tier,omitempty"` - Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` -} - -func (m *TotalBond) Reset() { *m = TotalBond{} } -func (m *TotalBond) String() string { return proto.CompactTextString(m) } -func (*TotalBond) ProtoMessage() {} -func (*TotalBond) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{1} -} -func (m *TotalBond) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TotalBond) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TotalBond.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TotalBond) XXX_Merge(src proto.Message) { - xxx_messageInfo_TotalBond.Merge(m, src) -} -func (m *TotalBond) XXX_Size() int { - return m.Size() -} -func (m *TotalBond) XXX_DiscardUnknown() { - xxx_messageInfo_TotalBond.DiscardUnknown(m) -} - -var xxx_messageInfo_TotalBond proto.InternalMessageInfo - -func (m *TotalBond) GetTier() uint32 { - if m != nil { - return m.Tier - } - return 0 -} - -func (m *TotalBond) GetAmount() types.Coin { - if m != nil { - return m.Amount - } - return types.Coin{} -} - -// Bond tracks the amount of coins of one uToken denomination bonded to a -// given reward tier by a single account. +// Bond tracks the amount of coins of one uToken denomination bonded +// by a single account. type Bond struct { Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` - Tier uint32 `protobuf:"varint,2,opt,name=tier,proto3" json:"tier,omitempty"` - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` + UToken types.Coin `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken"` } func (m *Bond) Reset() { *m = Bond{} } func (m *Bond) String() string { return proto.CompactTextString(m) } func (*Bond) ProtoMessage() {} func (*Bond) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{2} + return fileDescriptor_3f117566517b8062, []int{1} } func (m *Bond) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -244,37 +189,29 @@ func (m *Bond) GetAccount() string { return "" } -func (m *Bond) GetTier() uint32 { - if m != nil { - return m.Tier - } - return 0 -} - -func (m *Bond) GetAmount() types.Coin { +func (m *Bond) GetUToken() types.Coin { if m != nil { - return m.Amount + return m.UToken } return types.Coin{} } -// RewardTracker tracks the value of a given tier and lock denom's RewardAccumulator -// at the last time a specific account calculated pending rewards for it. When calculating +// RewardTracker tracks the value of a given lock denom's RewardAccumulator at the +// last time a specific account calculated pending rewards for it. When calculating // available rewards, this value is used to determine the difference between the current -// RewardAccumulator for a tier and the last value at which the user updated bonds or claimed +// RewardAccumulator for a uToken and the last value at which the user updated bonds or claimed // tokens. Their pending rewards increase by only the rewards accrued in that time period. type RewardTracker struct { - Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` - Tier uint32 `protobuf:"varint,2,opt,name=tier,proto3" json:"tier,omitempty"` - Denom string `protobuf:"bytes,3,opt,name=denom,proto3" json:"denom,omitempty"` - RewardTracker github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,4,rep,name=reward_tracker,json=rewardTracker,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"reward_tracker"` + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` + UToken string `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken,omitempty"` + Rewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,3,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"rewards"` } func (m *RewardTracker) Reset() { *m = RewardTracker{} } func (m *RewardTracker) String() string { return proto.CompactTextString(m) } func (*RewardTracker) ProtoMessage() {} func (*RewardTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{3} + return fileDescriptor_3f117566517b8062, []int{2} } func (m *RewardTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -310,41 +247,36 @@ func (m *RewardTracker) GetAccount() string { return "" } -func (m *RewardTracker) GetTier() uint32 { - if m != nil { - return m.Tier - } - return 0 -} - -func (m *RewardTracker) GetDenom() string { +func (m *RewardTracker) GetUToken() string { if m != nil { - return m.Denom + return m.UToken } return "" } -func (m *RewardTracker) GetRewardTracker() github_com_cosmos_cosmos_sdk_types.DecCoins { +func (m *RewardTracker) GetRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { if m != nil { - return m.RewardTracker + return m.Rewards } return nil } // RewardAccumulator is a global reward tracking struct that indicates the amount -// of rewards that a single unit of denom would have accumulated if it was bonded -// at a given tier since genesis. +// of rewards that a reference amount of a bonded uToken denom would have accumulated +// if it was bonded since genesis. To prevent rounding issues, the reference amount is +// 10^exponent of the uToken's smallest possible amount, generally matching the exponent +// of the associated base token registered with the leverage module. type RewardAccumulator struct { - Tier uint32 `protobuf:"varint,1,opt,name=tier,proto3" json:"tier,omitempty"` - Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` - RewardTracker github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,3,rep,name=reward_tracker,json=rewardTracker,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"reward_tracker"` + UToken string `protobuf:"bytes,1,opt,name=uToken,proto3" json:"uToken,omitempty"` + Rewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,2,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"rewards"` + Exponent uint32 `protobuf:"varint,3,opt,name=exponent,proto3" json:"exponent,omitempty"` } func (m *RewardAccumulator) Reset() { *m = RewardAccumulator{} } func (m *RewardAccumulator) String() string { return proto.CompactTextString(m) } func (*RewardAccumulator) ProtoMessage() {} func (*RewardAccumulator) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{4} + return fileDescriptor_3f117566517b8062, []int{3} } func (m *RewardAccumulator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -373,38 +305,42 @@ func (m *RewardAccumulator) XXX_DiscardUnknown() { var xxx_messageInfo_RewardAccumulator proto.InternalMessageInfo -func (m *RewardAccumulator) GetTier() uint32 { +func (m *RewardAccumulator) GetUToken() string { if m != nil { - return m.Tier + return m.UToken } - return 0 + return "" } -func (m *RewardAccumulator) GetDenom() string { +func (m *RewardAccumulator) GetRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { if m != nil { - return m.Denom + return m.Rewards } - return "" + return nil } -func (m *RewardAccumulator) GetRewardTracker() github_com_cosmos_cosmos_sdk_types.DecCoins { +func (m *RewardAccumulator) GetExponent() uint32 { if m != nil { - return m.RewardTracker + return m.Exponent } - return nil + return 0 } // Unbonding is a structure that tracks an in-progress token unbonding. +// It tracks both its start time and end time, so that if the module's +// unbonding time changes, the unbonding can complete at the earlier of +// its original end time or its new one based on the new parameter. type Unbonding struct { - End uint64 `protobuf:"varint,1,opt,name=end,proto3" json:"end,omitempty"` - Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` + Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + UToken types.Coin `protobuf:"bytes,3,opt,name=uToken,proto3" json:"uToken"` } func (m *Unbonding) Reset() { *m = Unbonding{} } func (m *Unbonding) String() string { return proto.CompactTextString(m) } func (*Unbonding) ProtoMessage() {} func (*Unbonding) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{5} + return fileDescriptor_3f117566517b8062, []int{4} } func (m *Unbonding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -433,34 +369,40 @@ func (m *Unbonding) XXX_DiscardUnknown() { var xxx_messageInfo_Unbonding proto.InternalMessageInfo -func (m *Unbonding) GetEnd() uint64 { +func (m *Unbonding) GetStart() int64 { + if m != nil { + return m.Start + } + return 0 +} + +func (m *Unbonding) GetEnd() int64 { if m != nil { return m.End } return 0 } -func (m *Unbonding) GetAmount() types.Coin { +func (m *Unbonding) GetUToken() types.Coin { if m != nil { - return m.Amount + return m.UToken } return types.Coin{} } // AccountUnbondings is a structure that is used to store all of an account's unbondings -// for a single bonded uToken denom and and unbonding tier in both KVStore and genesis state. +// for a single bonded uToken denom in both KVStore and genesis state. type AccountUnbondings struct { Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` - Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` - Tier uint32 `protobuf:"varint,3,opt,name=tier,proto3" json:"tier,omitempty"` - Unbondings []Unbonding `protobuf:"bytes,4,rep,name=unbondings,proto3" json:"unbondings"` + UToken string `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken,omitempty"` + Unbondings []Unbonding `protobuf:"bytes,3,rep,name=unbondings,proto3" json:"unbondings"` } func (m *AccountUnbondings) Reset() { *m = AccountUnbondings{} } func (m *AccountUnbondings) String() string { return proto.CompactTextString(m) } func (*AccountUnbondings) ProtoMessage() {} func (*AccountUnbondings) Descriptor() ([]byte, []int) { - return fileDescriptor_3f117566517b8062, []int{6} + return fileDescriptor_3f117566517b8062, []int{5} } func (m *AccountUnbondings) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -496,20 +438,13 @@ func (m *AccountUnbondings) GetAccount() string { return "" } -func (m *AccountUnbondings) GetDenom() string { +func (m *AccountUnbondings) GetUToken() string { if m != nil { - return m.Denom + return m.UToken } return "" } -func (m *AccountUnbondings) GetTier() uint32 { - if m != nil { - return m.Tier - } - return 0 -} - func (m *AccountUnbondings) GetUnbondings() []Unbonding { if m != nil { return m.Unbondings @@ -518,63 +453,61 @@ func (m *AccountUnbondings) GetUnbondings() []Unbonding { } func init() { - proto.RegisterType((*GenesisState)(nil), "umeenetwork.umee.incentive.v1.GenesisState") - proto.RegisterType((*TotalBond)(nil), "umeenetwork.umee.incentive.v1.TotalBond") - proto.RegisterType((*Bond)(nil), "umeenetwork.umee.incentive.v1.Bond") - proto.RegisterType((*RewardTracker)(nil), "umeenetwork.umee.incentive.v1.RewardTracker") - proto.RegisterType((*RewardAccumulator)(nil), "umeenetwork.umee.incentive.v1.RewardAccumulator") - proto.RegisterType((*Unbonding)(nil), "umeenetwork.umee.incentive.v1.Unbonding") - proto.RegisterType((*AccountUnbondings)(nil), "umeenetwork.umee.incentive.v1.AccountUnbondings") + proto.RegisterType((*GenesisState)(nil), "umee.incentive.v1.GenesisState") + proto.RegisterType((*Bond)(nil), "umee.incentive.v1.Bond") + proto.RegisterType((*RewardTracker)(nil), "umee.incentive.v1.RewardTracker") + proto.RegisterType((*RewardAccumulator)(nil), "umee.incentive.v1.RewardAccumulator") + proto.RegisterType((*Unbonding)(nil), "umee.incentive.v1.Unbonding") + proto.RegisterType((*AccountUnbondings)(nil), "umee.incentive.v1.AccountUnbondings") } func init() { proto.RegisterFile("umee/incentive/v1/genesis.proto", fileDescriptor_3f117566517b8062) } var fileDescriptor_3f117566517b8062 = []byte{ - // 697 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x4f, 0x6f, 0xd3, 0x3c, - 0x18, 0x6f, 0xd6, 0xae, 0x7b, 0xfb, 0xec, 0xed, 0xba, 0x9a, 0x1d, 0xc2, 0x04, 0x59, 0x29, 0x02, - 0x55, 0xc0, 0x12, 0xb6, 0x21, 0x71, 0x44, 0xdb, 0x40, 0x68, 0x17, 0x34, 0x85, 0x81, 0x10, 0x1c, - 0x8a, 0x9b, 0x58, 0x21, 0x5a, 0x63, 0x57, 0xb1, 0xd3, 0x8d, 0x6f, 0xc1, 0xb7, 0x40, 0xe2, 0x0b, - 0x70, 0xe6, 0xb6, 0x0b, 0xd2, 0x8e, 0x9c, 0x00, 0x6d, 0x5f, 0x04, 0xc5, 0x76, 0xd2, 0x76, 0xab, - 0xda, 0x8d, 0x49, 0x9c, 0x6a, 0x3f, 0x7e, 0x7e, 0x7f, 0xf4, 0xd8, 0xbf, 0x06, 0x56, 0x92, 0x88, - 0x10, 0x27, 0xa4, 0x1e, 0xa1, 0x22, 0xec, 0x13, 0xa7, 0xbf, 0xe6, 0x04, 0x84, 0x12, 0x1e, 0x72, - 0xbb, 0x17, 0x33, 0xc1, 0xd0, 0xcd, 0xb4, 0x81, 0x12, 0x71, 0xc0, 0xe2, 0x7d, 0x3b, 0x5d, 0xdb, - 0x79, 0xb3, 0xdd, 0x5f, 0x5b, 0xb6, 0x3c, 0xc6, 0x23, 0xc6, 0x9d, 0x0e, 0xe6, 0x29, 0xb8, 0x43, - 0x04, 0x5e, 0x73, 0x3c, 0x16, 0x52, 0x05, 0x5f, 0x5e, 0x0a, 0x58, 0xc0, 0xe4, 0xd2, 0x49, 0x57, - 0xba, 0x7a, 0xeb, 0xbc, 0xea, 0x80, 0x55, 0xb6, 0x34, 0xbf, 0x95, 0xe1, 0xff, 0xe7, 0xca, 0xc9, - 0x4b, 0x81, 0x05, 0x41, 0xdb, 0x50, 0xee, 0xe1, 0x18, 0x47, 0xdc, 0x34, 0x1a, 0x46, 0x6b, 0x7e, - 0xfd, 0x8e, 0x3d, 0xd1, 0x99, 0xbd, 0x2b, 0x9b, 0xb7, 0x4a, 0x47, 0x3f, 0x57, 0x0a, 0xae, 0x86, - 0xa2, 0xbb, 0x50, 0xa3, 0xe4, 0x50, 0xb4, 0x7b, 0x31, 0x0b, 0x62, 0x1c, 0xb5, 0x43, 0xdf, 0x9c, - 0x69, 0x18, 0xad, 0xaa, 0x5b, 0x4d, 0xcb, 0xbb, 0xaa, 0xba, 0xe3, 0xa3, 0x7b, 0x50, 0xef, 0x62, - 0x2e, 0xda, 0x31, 0x39, 0xc0, 0xb1, 0xcf, 0xdb, 0x22, 0x8c, 0x88, 0x59, 0x6c, 0x18, 0xad, 0x92, - 0x5b, 0x4b, 0x0f, 0x5c, 0x55, 0xdf, 0x0b, 0x23, 0x82, 0xde, 0x41, 0x4d, 0xb5, 0xb5, 0x45, 0x8c, - 0xbd, 0x7d, 0x12, 0x73, 0xb3, 0xd4, 0x28, 0xb6, 0xe6, 0xd7, 0x1f, 0x4c, 0x71, 0xa8, 0x48, 0xf6, - 0x14, 0x48, 0x1b, 0x5d, 0x88, 0x87, 0x8b, 0x1c, 0x05, 0x70, 0x4d, 0x93, 0x63, 0xcf, 0x4b, 0xa2, - 0xa4, 0x8b, 0x05, 0x8b, 0xb9, 0x39, 0x2b, 0x05, 0x1e, 0x5e, 0x48, 0x60, 0x73, 0x00, 0xd4, 0x22, - 0x28, 0x3e, 0x7b, 0xc0, 0x51, 0x07, 0xea, 0x49, 0xcf, 0x63, 0x51, 0x48, 0x83, 0x6c, 0x3a, 0xdc, - 0x2c, 0x4b, 0x19, 0x67, 0x8a, 0xcc, 0x4e, 0xb6, 0xd1, 0xf3, 0xd3, 0x2a, 0x8b, 0x19, 0x9f, 0x2e, - 0x73, 0xf4, 0x1e, 0x16, 0x19, 0x0d, 0xd8, 0x88, 0xc4, 0xdc, 0x55, 0x24, 0x6a, 0x9a, 0x2e, 0x57, - 0xf0, 0x01, 0x79, 0x2c, 0xea, 0x75, 0x89, 0x20, 0xfe, 0x40, 0xe3, 0xbf, 0xab, 0x68, 0xd4, 0x73, - 0xc2, 0x5c, 0xe5, 0x09, 0xcc, 0x76, 0x18, 0xf5, 0xb9, 0x59, 0x91, 0xc4, 0xb7, 0xa7, 0x10, 0x6f, - 0x31, 0xea, 0x6b, 0x32, 0x85, 0x43, 0x04, 0x10, 0xf6, 0x3c, 0x96, 0x50, 0xd1, 0x4e, 0x68, 0x5a, - 0x0a, 0x69, 0xc0, 0x4d, 0xb8, 0xd0, 0xa5, 0x6e, 0x2a, 0xe0, 0xab, 0x1c, 0x97, 0xf9, 0xc4, 0x67, - 0x0f, 0x9a, 0x6f, 0xa0, 0xb2, 0xc7, 0x04, 0xee, 0xa6, 0x06, 0x10, 0x82, 0x92, 0x08, 0x49, 0x2c, - 0xd3, 0x53, 0x75, 0xe5, 0x1a, 0x3d, 0x86, 0x32, 0x8e, 0x52, 0x90, 0x4c, 0xc1, 0xfc, 0xfa, 0x75, - 0x5b, 0xc5, 0xd9, 0x4e, 0xe3, 0x6c, 0xeb, 0x38, 0xdb, 0xdb, 0x2c, 0xa4, 0x59, 0x8e, 0x54, 0x7b, - 0x33, 0x82, 0x92, 0x24, 0x35, 0x61, 0x4e, 0xcb, 0x4a, 0xde, 0x8a, 0x9b, 0x6d, 0x73, 0xb9, 0x99, - 0xb1, 0x72, 0xc5, 0xcb, 0xc9, 0x7d, 0x37, 0xa0, 0x3a, 0x92, 0x96, 0x4b, 0x0a, 0x2f, 0xc1, 0xac, - 0x4f, 0x28, 0x8b, 0xa4, 0x6e, 0xc5, 0x55, 0x1b, 0x74, 0x08, 0x0b, 0xa3, 0xc1, 0xd5, 0xb9, 0xbd, - 0x31, 0xd6, 0xd6, 0x53, 0xe2, 0x49, 0x67, 0x1b, 0xa9, 0xb3, 0x2f, 0xbf, 0x56, 0xee, 0x07, 0xa1, - 0xf8, 0x90, 0x74, 0x6c, 0x8f, 0x45, 0x8e, 0xfe, 0x13, 0x54, 0x3f, 0xab, 0xdc, 0xdf, 0x77, 0xc4, - 0xc7, 0x1e, 0xe1, 0x19, 0x86, 0xbb, 0xd5, 0x91, 0x58, 0x37, 0xbf, 0x1a, 0x50, 0x3f, 0x17, 0xce, - 0xb1, 0x37, 0x94, 0x3b, 0x9f, 0x99, 0xec, 0xbc, 0xf8, 0x8f, 0x9c, 0xbf, 0x86, 0x4a, 0xfe, 0xc0, - 0xd0, 0x22, 0x14, 0x09, 0xf5, 0xa5, 0xdf, 0x92, 0x9b, 0x2e, 0xff, 0xfe, 0x41, 0x7d, 0x36, 0xa0, - 0x7e, 0xee, 0x65, 0x4f, 0xb8, 0xe5, 0xf1, 0x73, 0xc9, 0x26, 0x58, 0x1c, 0x9a, 0xe0, 0x0b, 0x80, - 0xa1, 0x8c, 0xa9, 0x1b, 0x6e, 0x4d, 0xc9, 0x58, 0x6e, 0x41, 0xbb, 0x1c, 0x62, 0xd8, 0x7a, 0x76, - 0x74, 0x62, 0x19, 0xc7, 0x27, 0x96, 0xf1, 0xfb, 0xc4, 0x32, 0x3e, 0x9d, 0x5a, 0x85, 0xe3, 0x53, - 0xab, 0xf0, 0xe3, 0xd4, 0x2a, 0xbc, 0x1d, 0x9e, 0x6b, 0xca, 0xb9, 0xaa, 0x05, 0xe4, 0xc6, 0xe9, - 0x3f, 0x72, 0x0e, 0x07, 0x5f, 0xb9, 0x4e, 0x59, 0x7e, 0xe6, 0x36, 0xfe, 0x04, 0x00, 0x00, 0xff, - 0xff, 0x32, 0x0c, 0xbb, 0x1e, 0x81, 0x07, 0x00, 0x00, + // 677 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xcd, 0x6e, 0xd3, 0x4a, + 0x14, 0xc7, 0xe3, 0xba, 0x69, 0x9b, 0xe9, 0xcd, 0x4d, 0x33, 0xb7, 0xba, 0x98, 0x0a, 0xb9, 0x21, + 0x20, 0x14, 0x81, 0x6a, 0xab, 0x2d, 0x12, 0xeb, 0x06, 0x10, 0xea, 0x8a, 0xca, 0x04, 0x44, 0x61, + 0x11, 0x4d, 0xec, 0x91, 0xb1, 0x12, 0xcf, 0x58, 0x33, 0xe3, 0xb4, 0x3c, 0x02, 0x3b, 0x9e, 0x83, + 0x05, 0x2b, 0x1e, 0xa2, 0xcb, 0x2e, 0x59, 0xf1, 0xd1, 0xbe, 0x08, 0x9a, 0x0f, 0x3b, 0x69, 0x93, + 0x22, 0x15, 0x89, 0x55, 0x3c, 0x67, 0xfe, 0xf3, 0x3b, 0x27, 0x73, 0xfe, 0x73, 0xc0, 0x66, 0x9e, + 0x62, 0xec, 0x27, 0x24, 0xc4, 0x44, 0x24, 0x63, 0xec, 0x8f, 0xb7, 0xfd, 0x18, 0x13, 0xcc, 0x13, + 0xee, 0x65, 0x8c, 0x0a, 0x0a, 0x9b, 0x52, 0xe0, 0x95, 0x02, 0x6f, 0xbc, 0xbd, 0xe1, 0x86, 0x94, + 0xa7, 0x94, 0xfb, 0x03, 0xc4, 0xe5, 0x81, 0x01, 0x16, 0x68, 0xdb, 0x0f, 0x69, 0x42, 0xf4, 0x91, + 0x8d, 0xf5, 0x98, 0xc6, 0x54, 0x7d, 0xfa, 0xf2, 0xcb, 0x44, 0x6f, 0xcf, 0x66, 0x9a, 0x50, 0x95, + 0xa4, 0xfd, 0xb3, 0x0a, 0xfe, 0x79, 0xa6, 0xb3, 0xbf, 0x10, 0x48, 0x60, 0xf8, 0x08, 0x2c, 0x65, + 0x88, 0xa1, 0x94, 0x3b, 0x56, 0xcb, 0xea, 0xac, 0xee, 0xdc, 0xf4, 0x66, 0xaa, 0xf1, 0x0e, 0x94, + 0xa0, 0xbb, 0x78, 0xf2, 0x6d, 0xb3, 0x12, 0x18, 0x39, 0xbc, 0x07, 0x1a, 0x04, 0x1f, 0x8b, 0x7e, + 0xc6, 0x68, 0xcc, 0x50, 0xda, 0x4f, 0x22, 0x67, 0xa1, 0x65, 0x75, 0xea, 0x41, 0x5d, 0x86, 0x0f, + 0x74, 0x74, 0x3f, 0x82, 0xf7, 0x41, 0x73, 0x84, 0xb8, 0xe8, 0x33, 0x7c, 0x84, 0x58, 0xc4, 0xfb, + 0x22, 0x49, 0xb1, 0x63, 0xb7, 0xac, 0x8e, 0x1d, 0x34, 0xe4, 0x46, 0xa0, 0xe3, 0xbd, 0x24, 0xc5, + 0xf0, 0x39, 0x68, 0x68, 0x59, 0x5f, 0x30, 0x14, 0x0e, 0x31, 0xe3, 0xce, 0x62, 0xcb, 0xee, 0xac, + 0xee, 0xb4, 0xe6, 0x54, 0xa5, 0x0f, 0xf6, 0xb4, 0xd0, 0x14, 0xf7, 0x2f, 0x9b, 0x0e, 0x72, 0xf8, + 0x16, 0xfc, 0x67, 0x80, 0x28, 0x0c, 0xf3, 0x34, 0x1f, 0x21, 0x41, 0x19, 0x77, 0xaa, 0x0a, 0x7a, + 0xf7, 0x4a, 0xe8, 0xde, 0x44, 0x6c, 0xc0, 0x90, 0x5d, 0xde, 0xe0, 0xf0, 0x15, 0x68, 0xe6, 0x59, + 0x48, 0xd3, 0x84, 0xc4, 0xc5, 0x2d, 0x70, 0x67, 0x49, 0xa1, 0xef, 0xcc, 0x41, 0xef, 0x17, 0x0b, + 0x73, 0x37, 0x86, 0xbc, 0x56, 0x30, 0x4c, 0x98, 0xc3, 0x1e, 0x58, 0xa3, 0x24, 0xa6, 0x17, 0xb0, + 0xcb, 0xd7, 0xc5, 0x36, 0x0c, 0xa2, 0xa4, 0xbe, 0x06, 0x30, 0xa4, 0x69, 0x36, 0xc2, 0x02, 0x47, + 0x13, 0xee, 0xca, 0x75, 0xb9, 0xcd, 0x12, 0x52, 0x92, 0x77, 0x41, 0x75, 0x40, 0x49, 0xc4, 0x9d, + 0x9a, 0x82, 0xdd, 0x98, 0x03, 0xeb, 0x52, 0x12, 0x19, 0x80, 0xd6, 0xc2, 0x43, 0x00, 0x51, 0x18, + 0xd2, 0x9c, 0x88, 0x7e, 0x4e, 0x64, 0x28, 0x21, 0x31, 0x77, 0xc0, 0x95, 0x8d, 0xd9, 0xd3, 0xe2, + 0x97, 0xa5, 0xb6, 0xa8, 0x07, 0x5d, 0xde, 0x68, 0x1f, 0x82, 0x45, 0x99, 0x0f, 0x3a, 0x60, 0xd9, + 0x6c, 0x2a, 0x6f, 0xd7, 0x82, 0x62, 0x29, 0x4d, 0x9f, 0xf7, 0xe8, 0x10, 0x13, 0x65, 0x59, 0x69, + 0x7a, 0xfd, 0xde, 0x3c, 0xf9, 0xde, 0x3c, 0xf3, 0xde, 0xbc, 0xc7, 0x34, 0x21, 0x85, 0xe9, 0xb5, + 0xbc, 0xfd, 0xd9, 0x02, 0xf5, 0x0b, 0xbe, 0xfb, 0x4d, 0x92, 0xff, 0x2f, 0x24, 0xa9, 0x15, 0x0c, + 0x38, 0x04, 0xcb, 0xe6, 0x2d, 0x38, 0xb6, 0xfa, 0xbb, 0xb7, 0xe6, 0x66, 0x7f, 0x82, 0x43, 0x55, + 0xc0, 0xae, 0x2c, 0xe0, 0xd3, 0xf7, 0xcd, 0x07, 0x71, 0x22, 0xde, 0xe5, 0x03, 0x2f, 0xa4, 0xa9, + 0x6f, 0xa6, 0x83, 0xfe, 0xd9, 0xe2, 0xd1, 0xd0, 0x17, 0xef, 0x33, 0xcc, 0x8b, 0x33, 0x3c, 0x28, + 0x32, 0xb4, 0xbf, 0x58, 0xa0, 0x39, 0xe3, 0xe9, 0xa9, 0xd2, 0xac, 0xab, 0x4a, 0x5b, 0xf8, 0xdb, + 0xa5, 0xc1, 0x0d, 0xb0, 0x82, 0x8f, 0x33, 0x4a, 0x30, 0x11, 0x6a, 0x1e, 0xd4, 0x83, 0x72, 0xdd, + 0x1e, 0x81, 0x5a, 0xd9, 0x50, 0xb8, 0x0e, 0xaa, 0x5c, 0x20, 0xa6, 0x2f, 0xd8, 0x0e, 0xf4, 0x02, + 0xae, 0x01, 0x1b, 0x13, 0x3d, 0x73, 0xec, 0x40, 0x7e, 0x4e, 0x75, 0xd5, 0xbe, 0x5e, 0x57, 0x3f, + 0x58, 0xa0, 0x39, 0xe3, 0xaf, 0x3f, 0xe8, 0x6c, 0x17, 0x80, 0x29, 0x2f, 0x17, 0xcd, 0x9d, 0xf5, + 0x72, 0x99, 0xc4, 0xd4, 0x31, 0x75, 0xaa, 0xfb, 0xf4, 0xe4, 0xcc, 0xb5, 0x4e, 0xcf, 0x5c, 0xeb, + 0xc7, 0x99, 0x6b, 0x7d, 0x3c, 0x77, 0x2b, 0xa7, 0xe7, 0x6e, 0xe5, 0xeb, 0xb9, 0x5b, 0x79, 0x33, + 0x7d, 0xcb, 0x92, 0xb9, 0x45, 0xb0, 0x38, 0xa2, 0x6c, 0xa8, 0x16, 0xfe, 0xf8, 0xa1, 0x7f, 0x3c, + 0x99, 0xf6, 0x83, 0x25, 0x35, 0xee, 0x77, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x03, 0xc9, + 0x23, 0x7d, 0x06, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -718,44 +651,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *TotalBond) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TotalBond) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TotalBond) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.Tier != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - func (m *Bond) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -777,7 +672,7 @@ func (m *Bond) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UToken.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -785,12 +680,7 @@ func (m *Bond) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if m.Tier != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x10 - } + dAtA[i] = 0x12 if len(m.Account) > 0 { i -= len(m.Account) copy(dAtA[i:], m.Account) @@ -821,10 +711,10 @@ func (m *RewardTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.RewardTracker) > 0 { - for iNdEx := len(m.RewardTracker) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.RewardTracker[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -832,20 +722,15 @@ func (m *RewardTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x1a } } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0x1a - } - if m.Tier != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Tier)) + if len(m.UToken) > 0 { + i -= len(m.UToken) + copy(dAtA[i:], m.UToken) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UToken))) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } if len(m.Account) > 0 { i -= len(m.Account) @@ -877,10 +762,15 @@ func (m *RewardAccumulator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.RewardTracker) > 0 { - for iNdEx := len(m.RewardTracker) - 1; iNdEx >= 0; iNdEx-- { + if m.Exponent != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Exponent)) + i-- + dAtA[i] = 0x18 + } + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.RewardTracker[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -888,20 +778,15 @@ func (m *RewardAccumulator) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + if len(m.UToken) > 0 { + i -= len(m.UToken) + copy(dAtA[i:], m.UToken) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UToken))) i-- - dAtA[i] = 0x12 - } - if m.Tier != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -927,7 +812,7 @@ func (m *Unbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UToken.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -935,10 +820,15 @@ func (m *Unbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a if m.End != 0 { i = encodeVarintGenesis(dAtA, i, uint64(m.End)) i-- + dAtA[i] = 0x10 + } + if m.Start != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Start)) + i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil @@ -975,18 +865,13 @@ func (m *AccountUnbondings) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x1a } } - if m.Tier != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x18 - } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + if len(m.UToken) > 0 { + i -= len(m.UToken) + copy(dAtA[i:], m.UToken) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UToken))) i-- dAtA[i] = 0x12 } @@ -1070,20 +955,6 @@ func (m *GenesisState) Size() (n int) { return n } -func (m *TotalBond) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Tier != 0 { - n += 1 + sovGenesis(uint64(m.Tier)) - } - l = m.Amount.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n -} - func (m *Bond) Size() (n int) { if m == nil { return 0 @@ -1094,10 +965,7 @@ func (m *Bond) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - if m.Tier != 0 { - n += 1 + sovGenesis(uint64(m.Tier)) - } - l = m.Amount.Size() + l = m.UToken.Size() n += 1 + l + sovGenesis(uint64(l)) return n } @@ -1112,15 +980,12 @@ func (m *RewardTracker) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - if m.Tier != 0 { - n += 1 + sovGenesis(uint64(m.Tier)) - } - l = len(m.Denom) + l = len(m.UToken) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - if len(m.RewardTracker) > 0 { - for _, e := range m.RewardTracker { + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } @@ -1134,19 +999,19 @@ func (m *RewardAccumulator) Size() (n int) { } var l int _ = l - if m.Tier != 0 { - n += 1 + sovGenesis(uint64(m.Tier)) - } - l = len(m.Denom) + l = len(m.UToken) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - if len(m.RewardTracker) > 0 { - for _, e := range m.RewardTracker { + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } } + if m.Exponent != 0 { + n += 1 + sovGenesis(uint64(m.Exponent)) + } return n } @@ -1156,10 +1021,13 @@ func (m *Unbonding) Size() (n int) { } var l int _ = l + if m.Start != 0 { + n += 1 + sovGenesis(uint64(m.Start)) + } if m.End != 0 { n += 1 + sovGenesis(uint64(m.End)) } - l = m.Amount.Size() + l = m.UToken.Size() n += 1 + l + sovGenesis(uint64(l)) return n } @@ -1174,13 +1042,10 @@ func (m *AccountUnbondings) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - l = len(m.Denom) + l = len(m.UToken) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - if m.Tier != 0 { - n += 1 + sovGenesis(uint64(m.Tier)) - } if len(m.Unbondings) > 0 { for _, e := range m.Unbondings { l = e.Size() @@ -1291,7 +1156,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.LastRewardsTime |= uint64(b&0x7F) << shift + m.LastRewardsTime |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -1555,108 +1420,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *TotalBond) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TotalBond: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TotalBond: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *Bond) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1719,27 +1482,8 @@ func (m *Bond) Unmarshal(dAtA []byte) error { m.Account = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1766,7 +1510,7 @@ func (m *Bond) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1853,27 +1597,8 @@ func (m *RewardTracker) Unmarshal(dAtA []byte) error { m.Account = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1901,11 +1626,11 @@ func (m *RewardTracker) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + m.UToken = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RewardTracker", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1932,8 +1657,8 @@ func (m *RewardTracker) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RewardTracker = append(m.RewardTracker, types.DecCoin{}) - if err := m.RewardTracker[len(m.RewardTracker)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Rewards = append(m.Rewards, types.DecCoin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1988,27 +1713,8 @@ func (m *RewardAccumulator) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2036,11 +1742,11 @@ func (m *RewardAccumulator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + m.UToken = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RewardTracker", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2067,11 +1773,30 @@ func (m *RewardAccumulator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RewardTracker = append(m.RewardTracker, types.DecCoin{}) - if err := m.RewardTracker[len(m.RewardTracker)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Rewards = append(m.Rewards, types.DecCoin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exponent", wireType) + } + m.Exponent = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Exponent |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -2123,6 +1848,25 @@ func (m *Unbonding) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) } @@ -2136,14 +1880,14 @@ func (m *Unbonding) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.End |= uint64(b&0x7F) << shift + m.End |= int64(b&0x7F) << shift if b < 0x80 { break } } - case 2: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2170,7 +1914,7 @@ func (m *Unbonding) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2258,7 +2002,7 @@ func (m *AccountUnbondings) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2286,28 +2030,9 @@ func (m *AccountUnbondings) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + m.UToken = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Unbondings", wireType) } diff --git a/x/incentive/genesis_test.go b/x/incentive/genesis_test.go new file mode 100644 index 0000000000..6434e828f2 --- /dev/null +++ b/x/incentive/genesis_test.go @@ -0,0 +1,12 @@ +package incentive + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestValidateGenesis(t *testing.T) { + genesis := DefaultGenesis() + assert.NilError(t, genesis.Validate()) +} diff --git a/x/incentive/incentive.pb.go b/x/incentive/incentive.pb.go index 5315c36880..3e7d021140 100644 --- a/x/incentive/incentive.pb.go +++ b/x/incentive/incentive.pb.go @@ -27,31 +27,14 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the incentive module. type Params struct { - // max_unbondings defines the maximum amount of concurrent unbondings an address can have - // on each unbonding tier of each bonded uToken denom. + // max_unbondings is the maximum amount of concurrent unbondings an address can have + // of each bonded uToken denom. Zero is interpreted as no limit. MaxUnbondings uint32 `protobuf:"varint,1,opt,name=max_unbondings,json=maxUnbondings,proto3" json:"max_unbondings,omitempty"` - // unbonding_duration_long defines the unbonding duration (in seconds) of the long tier. - UnbondingDurationLong uint64 `protobuf:"varint,2,opt,name=unbonding_duration_long,json=unbondingDurationLong,proto3" json:"unbonding_duration_long,omitempty"` - // unbonding_duration_middle defines the unbonding duration (in seconds) of the middle tier. - UnbondingDurationMiddle uint64 `protobuf:"varint,3,opt,name=unbonding_duration_middle,json=unbondingDurationMiddle,proto3" json:"unbonding_duration_middle,omitempty"` - // unbonding_duration_short defines the unbonding duration (in seconds) of the short tier. - UnbondingDurationShort uint64 `protobuf:"varint,4,opt,name=unbonding_duration_short,json=unbondingDurationShort,proto3" json:"unbonding_duration_short,omitempty"` - // tier_weight_short defines the proportion of rewards which assets bonded - // in the short unbonding duration receive compared to what the same amount - // would receive bonded to the long tier. - // valid values: [0;1] - TierWeightShort github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=tier_weight_short,json=tierWeightShort,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tier_weight_short"` - // tier_weight_middle defines the proportion of rewards which assets bonded - // in the middle unbonding duration receive compared to what the same amount - // would receive bonded to the long tier. - // valid values: [0;1] - TierWeightMiddle github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=tier_weight_middle,json=tierWeightMiddle,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tier_weight_middle"` - // community_fund_address is the address from which all incentive programs - // proposed with "from_community_fund = true" will receive their funding. - // Since funds are withdrawn automatically when an incentive program passes - // governance, this account should always contain sufficient balance to - // cover incentive programs which are being voted upon. - CommunityFundAddress string `protobuf:"bytes,7,opt,name=community_fund_address,json=communityFundAddress,proto3" json:"community_fund_address,omitempty"` + // unbonding_duration is the unbonding duration (in seconds). + UnbondingDuration int64 `protobuf:"varint,2,opt,name=unbonding_duration,json=unbondingDuration,proto3" json:"unbonding_duration,omitempty"` + // emergency_unbond_fee is the portion of a bond that is paid when it is instantly + // released using MsgEmergencyUnbond. For example, 0.01 is a 1% fee. Ranges 0-1. + EmergencyUnbondFee github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=emergency_unbond_fee,json=emergencyUnbondFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"emergency_unbond_fee"` } func (m *Params) Reset() { *m = Params{} } @@ -94,34 +77,13 @@ func (m *Params) GetMaxUnbondings() uint32 { return 0 } -func (m *Params) GetUnbondingDurationLong() uint64 { +func (m *Params) GetUnbondingDuration() int64 { if m != nil { - return m.UnbondingDurationLong + return m.UnbondingDuration } return 0 } -func (m *Params) GetUnbondingDurationMiddle() uint64 { - if m != nil { - return m.UnbondingDurationMiddle - } - return 0 -} - -func (m *Params) GetUnbondingDurationShort() uint64 { - if m != nil { - return m.UnbondingDurationShort - } - return 0 -} - -func (m *Params) GetCommunityFundAddress() string { - if m != nil { - return m.CommunityFundAddress - } - return "" -} - // IncentiveProgram defines a liquidity mining incentive program on a single // locked uToken denom that will run for a set amount of time. type IncentiveProgram struct { @@ -132,11 +94,11 @@ type IncentiveProgram struct { // start_time is the unix time (in seconds) at which the incentives begin. // If a program is passed after its intended start time, its start time // will be increased to the current time, with program duration unchanged. - StartTime uint64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` // duration is the length of the incentive program from start time to // completion in seconds. - Duration uint64 `protobuf:"varint,3,opt,name=duration,proto3" json:"duration,omitempty"` - // uToken is the incentivized uToken collateral. Suppliers who collateralize + Duration int64 `protobuf:"varint,3,opt,name=duration,proto3" json:"duration,omitempty"` + // uToken is the incentivized uToken collateral denom. Suppliers who collateralize // this asset then bond it to the incentive module are eligible for this program's // rewards. UToken string `protobuf:"bytes,4,opt,name=uToken,proto3" json:"uToken,omitempty"` @@ -197,14 +159,14 @@ func (m *IncentiveProgram) GetID() uint32 { return 0 } -func (m *IncentiveProgram) GetStartTime() uint64 { +func (m *IncentiveProgram) GetStartTime() int64 { if m != nil { return m.StartTime } return 0 } -func (m *IncentiveProgram) GetDuration() uint64 { +func (m *IncentiveProgram) GetDuration() int64 { if m != nil { return m.Duration } @@ -240,49 +202,43 @@ func (m *IncentiveProgram) GetRemainingRewards() types.Coin { } func init() { - proto.RegisterType((*Params)(nil), "umeenetwork.umee.incentive.v1.Params") - proto.RegisterType((*IncentiveProgram)(nil), "umeenetwork.umee.incentive.v1.IncentiveProgram") + proto.RegisterType((*Params)(nil), "umee.incentive.v1.Params") + proto.RegisterType((*IncentiveProgram)(nil), "umee.incentive.v1.IncentiveProgram") } func init() { proto.RegisterFile("umee/incentive/v1/incentive.proto", fileDescriptor_8c99c623956e199b) } var fileDescriptor_8c99c623956e199b = []byte{ - // 550 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6b, 0x13, 0x41, - 0x14, 0xc7, 0xb3, 0x69, 0x4c, 0xdb, 0xd1, 0xd6, 0x76, 0xa8, 0xed, 0x36, 0xd0, 0x4d, 0x2c, 0x28, - 0x01, 0xe9, 0x2e, 0xd1, 0x22, 0xd2, 0x9b, 0x31, 0x0a, 0x81, 0x0a, 0x65, 0xad, 0x08, 0x45, 0x58, - 0x26, 0xbb, 0xe3, 0x66, 0x48, 0x66, 0xa6, 0xcc, 0xcc, 0x26, 0xe9, 0xb7, 0xf0, 0x23, 0x78, 0xf3, - 0xab, 0xf4, 0x58, 0xf0, 0x22, 0x1e, 0x8a, 0x24, 0x17, 0x3f, 0x86, 0xcc, 0xec, 0x64, 0x53, 0x68, - 0x0f, 0xe2, 0x29, 0xf3, 0xde, 0x9b, 0xdf, 0x3f, 0x3b, 0xff, 0xf7, 0x1e, 0x78, 0x9c, 0x51, 0x8c, - 0x03, 0xc2, 0x62, 0xcc, 0x14, 0x19, 0xe1, 0x60, 0xd4, 0x5a, 0x04, 0xfe, 0xb9, 0xe0, 0x8a, 0xc3, - 0x3d, 0x7d, 0x85, 0x61, 0x35, 0xe6, 0x62, 0xe0, 0xeb, 0xb3, 0xbf, 0xb8, 0x31, 0x6a, 0xd5, 0xbc, - 0x98, 0x4b, 0xca, 0x65, 0xd0, 0x43, 0x52, 0xe3, 0x3d, 0xac, 0x50, 0x2b, 0x88, 0x39, 0x61, 0x39, - 0x5e, 0xdb, 0x4a, 0x79, 0xca, 0xcd, 0x31, 0xd0, 0xa7, 0x3c, 0xbb, 0xff, 0x63, 0x09, 0x54, 0x4f, - 0x90, 0x40, 0x54, 0xc2, 0x27, 0x60, 0x9d, 0xa2, 0x49, 0x94, 0xb1, 0x1e, 0x67, 0x09, 0x61, 0xa9, - 0x74, 0x9d, 0x86, 0xd3, 0x5c, 0x0b, 0xd7, 0x28, 0x9a, 0x7c, 0x2c, 0x92, 0xf0, 0x25, 0xd8, 0x29, - 0xae, 0x44, 0x49, 0x26, 0x90, 0x22, 0x9c, 0x45, 0x43, 0xce, 0x52, 0xb7, 0xdc, 0x70, 0x9a, 0x95, - 0xf0, 0x51, 0x51, 0xee, 0xd8, 0xea, 0x31, 0x67, 0x29, 0x3c, 0x02, 0xbb, 0x77, 0x70, 0x94, 0x24, - 0xc9, 0x10, 0xbb, 0x4b, 0x86, 0xdc, 0xb9, 0x45, 0xbe, 0x37, 0x65, 0xf8, 0x0a, 0xb8, 0x77, 0xb0, - 0xb2, 0xcf, 0x85, 0x72, 0x2b, 0x06, 0xdd, 0xbe, 0x85, 0x7e, 0xd0, 0x55, 0x78, 0x06, 0x36, 0x15, - 0xc1, 0x22, 0x1a, 0x63, 0x92, 0xf6, 0x95, 0x45, 0xee, 0x35, 0x9c, 0xe6, 0x6a, 0xdb, 0xbf, 0xbc, - 0xae, 0x97, 0x7e, 0x5d, 0xd7, 0x9f, 0xa6, 0x44, 0xf5, 0xb3, 0x9e, 0x1f, 0x73, 0x1a, 0x58, 0x0f, - 0xf3, 0x9f, 0x03, 0x99, 0x0c, 0x02, 0x75, 0x71, 0x8e, 0xa5, 0xdf, 0xc1, 0x71, 0xf8, 0x50, 0x0b, - 0x7d, 0x32, 0x3a, 0xb9, 0xf6, 0x67, 0x00, 0x6f, 0x6a, 0xdb, 0xa7, 0x54, 0xff, 0x4b, 0x7c, 0x63, - 0x21, 0x6e, 0xdf, 0x7c, 0x08, 0xb6, 0x63, 0x4e, 0x69, 0xc6, 0x88, 0xba, 0x88, 0xbe, 0x64, 0x2c, - 0x89, 0x50, 0x92, 0x08, 0x2c, 0xa5, 0xbb, 0xac, 0xff, 0x21, 0xdc, 0x2a, 0xaa, 0xef, 0x32, 0x96, - 0xbc, 0xce, 0x6b, 0x47, 0x95, 0x3f, 0xdf, 0xea, 0xce, 0xfe, 0xf7, 0x32, 0xd8, 0xe8, 0xce, 0x87, - 0xe3, 0x44, 0xf0, 0x54, 0x20, 0x0a, 0xd7, 0x41, 0xb9, 0xdb, 0xb1, 0x3d, 0x2d, 0x77, 0x3b, 0x70, - 0x0f, 0x00, 0xa9, 0x90, 0x50, 0x91, 0x22, 0x14, 0xdb, 0xde, 0xad, 0x9a, 0xcc, 0x29, 0xa1, 0x18, - 0xd6, 0xc0, 0xca, 0xdc, 0x69, 0xdb, 0x9e, 0x22, 0x86, 0xdb, 0xa0, 0x9a, 0x9d, 0xf2, 0x01, 0x66, - 0xc6, 0xfd, 0xd5, 0xd0, 0x46, 0x3a, 0xaf, 0xbf, 0x14, 0x27, 0xc6, 0xe2, 0x95, 0xd0, 0x46, 0xb0, - 0x03, 0xd6, 0x14, 0x57, 0x68, 0x18, 0x09, 0x3c, 0x46, 0x22, 0x91, 0xc6, 0xa4, 0xfb, 0xcf, 0x77, - 0xfd, 0xdc, 0x0b, 0x5f, 0xcf, 0xac, 0x6f, 0x67, 0xd6, 0x7f, 0xc3, 0x09, 0x6b, 0x57, 0xb4, 0x7f, - 0xe1, 0x03, 0x43, 0x85, 0x39, 0x04, 0x8f, 0xc1, 0xa6, 0xc0, 0x14, 0x11, 0xa6, 0xa7, 0x60, 0xae, - 0xb4, 0xfc, 0x6f, 0x4a, 0x1b, 0x05, 0x69, 0xd5, 0x72, 0xa7, 0xda, 0x6f, 0x2f, 0xa7, 0x9e, 0x73, - 0x35, 0xf5, 0x9c, 0xdf, 0x53, 0xcf, 0xf9, 0x3a, 0xf3, 0x4a, 0x57, 0x33, 0xaf, 0xf4, 0x73, 0xe6, - 0x95, 0xce, 0x9e, 0xdd, 0xe8, 0x9c, 0xde, 0xb6, 0x03, 0xbb, 0x7a, 0x26, 0x08, 0x46, 0x87, 0xc1, - 0x64, 0xb1, 0xa1, 0xbd, 0xaa, 0xd9, 0xa6, 0x17, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xc1, - 0xf4, 0x33, 0xc7, 0x03, 0x00, 0x00, + // 453 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x6f, 0xd3, 0x30, + 0x18, 0xae, 0xdb, 0x52, 0x36, 0x43, 0xa7, 0xd5, 0x9a, 0x50, 0xa8, 0x44, 0x1a, 0x26, 0x81, 0x22, + 0xa1, 0x26, 0x2a, 0x70, 0xe2, 0x58, 0x02, 0x52, 0x25, 0x0e, 0x53, 0x34, 0x2e, 0x5c, 0x82, 0x93, + 0xbc, 0x0b, 0x56, 0xb1, 0x3d, 0x39, 0x4e, 0xd7, 0xfd, 0x0b, 0x7e, 0x02, 0x37, 0xfe, 0x09, 0xda, + 0x71, 0x47, 0xc4, 0x61, 0x42, 0xed, 0x85, 0x9f, 0x81, 0x9c, 0x78, 0x29, 0xc7, 0x9d, 0xec, 0xe7, + 0x79, 0xdf, 0xe7, 0xd1, 0xfb, 0x85, 0x9f, 0x56, 0x1c, 0x20, 0x64, 0x22, 0x03, 0xa1, 0xd9, 0x0a, + 0xc2, 0xd5, 0x6c, 0x07, 0x82, 0x73, 0x25, 0xb5, 0x24, 0x23, 0x93, 0x12, 0xec, 0xd8, 0xd5, 0x6c, + 0xec, 0x66, 0xb2, 0xe4, 0xb2, 0x0c, 0x53, 0x5a, 0x1a, 0x49, 0x0a, 0x9a, 0xce, 0xc2, 0x4c, 0x32, + 0xd1, 0x48, 0xc6, 0x47, 0x85, 0x2c, 0x64, 0xfd, 0x0d, 0xcd, 0xaf, 0x61, 0x8f, 0x7f, 0x22, 0x3c, + 0x38, 0xa1, 0x8a, 0xf2, 0x92, 0x3c, 0xc3, 0x07, 0x9c, 0xae, 0x93, 0x4a, 0xa4, 0x52, 0xe4, 0x4c, + 0x14, 0xa5, 0x83, 0x3c, 0xe4, 0x0f, 0xe3, 0x21, 0xa7, 0xeb, 0x8f, 0x2d, 0x49, 0xa6, 0x98, 0xb4, + 0x29, 0x49, 0x5e, 0x29, 0xaa, 0x99, 0x14, 0x4e, 0xd7, 0x43, 0x7e, 0x2f, 0x1e, 0xb5, 0x91, 0xc8, + 0x06, 0xc8, 0x67, 0x7c, 0x04, 0x1c, 0x54, 0x01, 0x22, 0xbb, 0xb4, 0xde, 0xc9, 0x19, 0x80, 0xd3, + 0xf3, 0x90, 0xbf, 0x3f, 0x0f, 0xae, 0x6e, 0x26, 0x9d, 0xdf, 0x37, 0x93, 0xe7, 0x05, 0xd3, 0x5f, + 0xaa, 0x34, 0xc8, 0x24, 0x0f, 0x6d, 0x1f, 0xcd, 0x33, 0x2d, 0xf3, 0x65, 0xa8, 0x2f, 0xcf, 0xa1, + 0x0c, 0x22, 0xc8, 0x62, 0xd2, 0x7a, 0x35, 0x15, 0xbd, 0x07, 0x78, 0xd3, 0xff, 0xfb, 0x7d, 0x82, + 0x8e, 0x7f, 0x74, 0xf1, 0xe1, 0xe2, 0x76, 0x1e, 0x27, 0x4a, 0x16, 0x8a, 0x72, 0x72, 0x80, 0xbb, + 0x8b, 0xc8, 0xb6, 0xd1, 0x5d, 0x44, 0xe4, 0x09, 0xc6, 0xa5, 0xa6, 0x4a, 0x27, 0x9a, 0x71, 0xb0, + 0x35, 0xef, 0xd7, 0xcc, 0x29, 0xe3, 0x40, 0xc6, 0x78, 0xaf, 0x6d, 0xa8, 0x57, 0x07, 0x5b, 0x4c, + 0x1e, 0xe1, 0x41, 0x75, 0x2a, 0x97, 0x20, 0x9c, 0xbe, 0xa9, 0x3c, 0xb6, 0xc8, 0xf0, 0x67, 0x95, + 0xc8, 0x21, 0x77, 0xee, 0x79, 0xc8, 0xdf, 0x8b, 0x2d, 0x22, 0x11, 0x1e, 0x6a, 0xa9, 0xe9, 0xd7, + 0x44, 0xc1, 0x05, 0x55, 0x79, 0xe9, 0x0c, 0x3c, 0xe4, 0x3f, 0x78, 0xf9, 0x38, 0x68, 0xfa, 0x0a, + 0xcc, 0x9a, 0x02, 0xbb, 0xa6, 0xe0, 0xad, 0x64, 0x62, 0xde, 0x37, 0xb3, 0x88, 0x1f, 0xd6, 0xaa, + 0xb8, 0x11, 0x91, 0x0f, 0x78, 0xa4, 0x80, 0x53, 0x26, 0xcc, 0xb0, 0x6f, 0x9d, 0xee, 0xdf, 0xcd, + 0xe9, 0xb0, 0x55, 0x5a, 0xb7, 0x66, 0x52, 0xf3, 0x77, 0x57, 0x1b, 0x17, 0x5d, 0x6f, 0x5c, 0xf4, + 0x67, 0xe3, 0xa2, 0x6f, 0x5b, 0xb7, 0x73, 0xbd, 0x75, 0x3b, 0xbf, 0xb6, 0x6e, 0xe7, 0xd3, 0x8b, + 0xff, 0xb6, 0x60, 0x0e, 0x6c, 0x2a, 0x40, 0x5f, 0x48, 0xb5, 0xac, 0x41, 0xb8, 0x7a, 0x1d, 0xae, + 0x77, 0x87, 0x98, 0x0e, 0xea, 0x03, 0x7a, 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xae, 0xa2, + 0xff, 0xae, 0x02, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -307,22 +263,10 @@ func (this *Params) Equal(that interface{}) bool { if this.MaxUnbondings != that1.MaxUnbondings { return false } - if this.UnbondingDurationLong != that1.UnbondingDurationLong { - return false - } - if this.UnbondingDurationMiddle != that1.UnbondingDurationMiddle { + if this.UnbondingDuration != that1.UnbondingDuration { return false } - if this.UnbondingDurationShort != that1.UnbondingDurationShort { - return false - } - if !this.TierWeightShort.Equal(that1.TierWeightShort) { - return false - } - if !this.TierWeightMiddle.Equal(that1.TierWeightMiddle) { - return false - } - if this.CommunityFundAddress != that1.CommunityFundAddress { + if !this.EmergencyUnbondFee.Equal(that1.EmergencyUnbondFee) { return false } return true @@ -389,45 +333,18 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.CommunityFundAddress) > 0 { - i -= len(m.CommunityFundAddress) - copy(dAtA[i:], m.CommunityFundAddress) - i = encodeVarintIncentive(dAtA, i, uint64(len(m.CommunityFundAddress))) - i-- - dAtA[i] = 0x3a - } { - size := m.TierWeightMiddle.Size() + size := m.EmergencyUnbondFee.Size() i -= size - if _, err := m.TierWeightMiddle.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.EmergencyUnbondFee.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintIncentive(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x32 - { - size := m.TierWeightShort.Size() - i -= size - if _, err := m.TierWeightShort.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintIncentive(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - if m.UnbondingDurationShort != 0 { - i = encodeVarintIncentive(dAtA, i, uint64(m.UnbondingDurationShort)) - i-- - dAtA[i] = 0x20 - } - if m.UnbondingDurationMiddle != 0 { - i = encodeVarintIncentive(dAtA, i, uint64(m.UnbondingDurationMiddle)) - i-- - dAtA[i] = 0x18 - } - if m.UnbondingDurationLong != 0 { - i = encodeVarintIncentive(dAtA, i, uint64(m.UnbondingDurationLong)) + dAtA[i] = 0x1a + if m.UnbondingDuration != 0 { + i = encodeVarintIncentive(dAtA, i, uint64(m.UnbondingDuration)) i-- dAtA[i] = 0x10 } @@ -534,23 +451,11 @@ func (m *Params) Size() (n int) { if m.MaxUnbondings != 0 { n += 1 + sovIncentive(uint64(m.MaxUnbondings)) } - if m.UnbondingDurationLong != 0 { - n += 1 + sovIncentive(uint64(m.UnbondingDurationLong)) - } - if m.UnbondingDurationMiddle != 0 { - n += 1 + sovIncentive(uint64(m.UnbondingDurationMiddle)) - } - if m.UnbondingDurationShort != 0 { - n += 1 + sovIncentive(uint64(m.UnbondingDurationShort)) + if m.UnbondingDuration != 0 { + n += 1 + sovIncentive(uint64(m.UnbondingDuration)) } - l = m.TierWeightShort.Size() + l = m.EmergencyUnbondFee.Size() n += 1 + l + sovIncentive(uint64(l)) - l = m.TierWeightMiddle.Size() - n += 1 + l + sovIncentive(uint64(l)) - l = len(m.CommunityFundAddress) - if l > 0 { - n += 1 + l + sovIncentive(uint64(l)) - } return n } @@ -639,9 +544,9 @@ func (m *Params) Unmarshal(dAtA []byte) error { } case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingDurationLong", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingDuration", wireType) } - m.UnbondingDurationLong = 0 + m.UnbondingDuration = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowIncentive @@ -651,52 +556,14 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.UnbondingDurationLong |= uint64(b&0x7F) << shift + m.UnbondingDuration |= int64(b&0x7F) << shift if b < 0x80 { break } } case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingDurationMiddle", wireType) - } - m.UnbondingDurationMiddle = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowIncentive - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.UnbondingDurationMiddle |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingDurationShort", wireType) - } - m.UnbondingDurationShort = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowIncentive - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.UnbondingDurationShort |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TierWeightShort", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EmergencyUnbondFee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -724,76 +591,10 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.TierWeightShort.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.EmergencyUnbondFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TierWeightMiddle", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowIncentive - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthIncentive - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthIncentive - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.TierWeightMiddle.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CommunityFundAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowIncentive - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthIncentive - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthIncentive - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.CommunityFundAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipIncentive(dAtA[iNdEx:]) @@ -877,7 +678,7 @@ func (m *IncentiveProgram) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.StartTime |= uint64(b&0x7F) << shift + m.StartTime |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -896,7 +697,7 @@ func (m *IncentiveProgram) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Duration |= uint64(b&0x7F) << shift + m.Duration |= int64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/incentive/keeper/bond.go b/x/incentive/keeper/bond.go index 8fdf3fc76e..b9fcdea11f 100644 --- a/x/incentive/keeper/bond.go +++ b/x/incentive/keeper/bond.go @@ -7,94 +7,73 @@ import ( "github.com/umee-network/umee/v4/x/incentive" ) -var bondTiers = []incentive.BondTier{incentive.BondTierLong, incentive.BondTierMiddle, incentive.BondTierShort} - -// bondTier converts from the uint32 used in message types to the enumeration, returning an error -// if it is not valid. Does not allow incentive.BondTierUnspecified -func bondTier(n uint32) (incentive.BondTier, error) { - if n == 0 || n > uint32(incentive.BondTierLong) { - return incentive.BondTierUnspecified, incentive.ErrInvalidTier.Wrapf("%d", n) - } - return incentive.BondTier(n), nil +// restrictedCollateral is used by leverage to see the amount of collateral an account has +// which cannot be voluntarily withdrawn. This is the sum of bonded and unbonding uTokens. +func (k Keeper) restrictedCollateral(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + return k.GetBonded(ctx, addr, denom).Add(k.getUnbondingAmount(ctx, addr, denom)) } -// getAllBonded gets the total amount of a uToken bonded to an account across all three unbonding tiers. -// This does not include tokens currently unbonding. -func (k Keeper) getAllBonded(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { - bonded := coin.Zero(denom) - for _, tier := range bondTiers { - bonded = bonded.Add(k.getBonded(ctx, addr, denom, tier)) - } - return bonded -} - -// accountBonds gets the total bonded and unbonding for a given account, as well as a list of ongoing unbondings, -// for a single bond tier and uToken denom. Using incentive.BondTierUnspecified returns all tiers instead. -// It ignores completed unbondings without actually clearing those unbondings in state, so it is safe for -// queries and any parts of Msg functions which are not intended to alter state. -func (k Keeper) accountBonds(ctx sdk.Context, addr sdk.AccAddress, denom string, tier incentive.BondTier) ( +// BondSummary gets the total bonded and unbonding for a given account, as well as a list of ongoing unbondings, +// for a single uToken denom. It ignores completed unbondings without actually clearing those unbondings in state, +// so it is safe for use by queries and any parts of Msg functions which are not intended to alter state. +func (k Keeper) BondSummary(ctx sdk.Context, addr sdk.AccAddress, denom string) ( bonded sdk.Coin, unbonding sdk.Coin, unbondings []incentive.Unbonding, ) { - bonded = coin.Zero(denom) unbonding = coin.Zero(denom) unbondings = []incentive.Unbonding{} - time := k.getLastRewardsTime(ctx) + time := k.GetLastRewardsTime(ctx) + duration := k.GetParams(ctx).UnbondingDuration - // sum all bonded and unbonding tokens for this denom, for the specified tier or across all tiers - for _, t := range bondTiers { - if tier == incentive.BondTierUnspecified || t == tier { - bonded = bonded.Add(k.getBonded(ctx, addr, denom, t)) + // sum all bonded and unbonding tokens for this denom + bonded = k.GetBonded(ctx, addr, denom) - tierUnbondings := k.getUnbondings(ctx, addr, denom, t) - for _, u := range tierUnbondings { - if u.End > time { - // this unbonding is still ongoing, and can be counted normally - unbondings = append(unbondings, u) - unbonding = unbonding.Add(u.Amount) - } - // Otherwise, this unbonding is completed, and will be quietly cleared by the next state-altering message - // which is permitted to affect this account. For now, it is omitted from the returned unbonding total. - } + storedUnbondings := k.getUnbondings(ctx, addr, denom) + for _, u := range storedUnbondings { + if u.End > time && u.Start+duration > time { + // If unbonding has passed neither its original end time nor its dynamic end time based on parameters + // the unbonding is still ongoing, and can be counted normally. + // This logic allows a reduction in unbonding duration param to speed up existing unbondings. + unbondings = append(unbondings, u) + unbonding = unbonding.Add(u.UToken) } + // Otherwise, this unbonding is completed, and will be quietly cleared by the next state-altering message + // which is permitted to affect this account. For now, it is omitted from the returned unbonding total. } // returned values reflect the real situation (after completed unbondings), not what is currently stored in state return bonded, unbonding, unbondings } -// increaseBond increases the bonded uToken amount for an account at a given tier, and updates the module's total. +// increaseBond increases the bonded uToken amount for an account, and updates the module's total. // it also initializes the account's reward tracker if the bonded amount was zero. This function should only be // called during MsgBond. -func (k Keeper) increaseBond(ctx sdk.Context, addr sdk.AccAddress, tier incentive.BondTier, bond sdk.Coin) error { +func (k Keeper) increaseBond(ctx sdk.Context, addr sdk.AccAddress, bond sdk.Coin) error { // get bonded amount before adding the currently bonding tokens - bonded := k.getBonded(ctx, addr, bond.Denom, tier) + bonded := k.GetBonded(ctx, addr, bond.Denom) // if bonded amount was zero, reward tracker must be initialized if bonded.IsZero() { - if err := k.UpdateRewardTracker(ctx, addr, tier, bond.Denom); err != nil { + if err := k.updateRewardTracker(ctx, addr, bond.Denom); err != nil { return err } } // update bonded amount (also increases TotalBonded) - return k.setBonded(ctx, addr, bonded.Add(bond), tier) + return k.setBonded(ctx, addr, bonded.Add(bond)) } -// decreaseBond decreases the bonded uToken amount for an account at a given tier, and updates the module's total. -// it also clears reward trackers for any bond tiers which have reached zero for the account, to save storage. +// decreaseBond decreases the bonded uToken amount for an account, and updates the module's total. +// it also clears reward trackers if bond amount reached zero for the account, to save storage. // This function must be called during MsgBeginUnbonding and when the leverage module forcefully liquidates bonded // (but not already unbonding) collateral. -func (k Keeper) decreaseBond(ctx sdk.Context, addr sdk.AccAddress, tier incentive.BondTier, unbond sdk.Coin) error { +func (k Keeper) decreaseBond(ctx sdk.Context, addr sdk.AccAddress, unbond sdk.Coin) error { // calculate new bonded amount after subtracting the currently unbonding tokens - bonded := k.getBonded(ctx, addr, unbond.Denom, tier).Sub(unbond) + bonded := k.GetBonded(ctx, addr, unbond.Denom).Sub(unbond) - // if the new bond for this account + tier + denom has reached zero, it is safe to stop tracking rewards + // if the new bond for this account + denom has reached zero, it is safe to stop tracking rewards if bonded.IsZero() { - err := k.clearRewardTracker(ctx, addr, tier, unbond.Denom) - if err != nil { - return err - } + k.clearRewardTracker(ctx, addr, unbond.Denom) } // update bonded amount (also decreases TotalBonded) - return k.setBonded(ctx, addr, bonded, tier) + return k.setBonded(ctx, addr, bonded) } diff --git a/x/incentive/keeper/genesis.go b/x/incentive/keeper/genesis.go new file mode 100644 index 0000000000..2843b3a272 --- /dev/null +++ b/x/incentive/keeper/genesis.go @@ -0,0 +1,104 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/umee-network/umee/v4/x/incentive" +) + +// InitGenesis initializes the x/incentive module state from a provided genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, gs incentive.GenesisState) { + if err := k.setParams(ctx, gs.Params); err != nil { + panic(err) + } + if err := k.setNextProgramID(ctx, gs.NextProgramId); err != nil { + panic(err) + } + if err := k.setLastRewardsTime(ctx, gs.LastRewardsTime); err != nil { + panic(err) + } + + for _, ip := range gs.UpcomingPrograms { + if err := k.setIncentiveProgram(ctx, ip, incentive.ProgramStatusUpcoming); err != nil { + panic(err) + } + } + for _, ip := range gs.OngoingPrograms { + if err := k.setIncentiveProgram(ctx, ip, incentive.ProgramStatusOngoing); err != nil { + panic(err) + } + } + for _, ip := range gs.CompletedPrograms { + if err := k.setIncentiveProgram(ctx, ip, incentive.ProgramStatusCompleted); err != nil { + panic(err) + } + } + + for _, b := range gs.Bonds { + if err := k.setBonded(ctx, sdk.MustAccAddressFromBech32(b.Account), b.UToken); err != nil { + panic(err) + } + } + + for _, au := range gs.AccountUnbondings { + if err := k.setUnbondings(ctx, au); err != nil { + panic(err) + } + } + + for _, ra := range gs.RewardAccumulators { + if err := k.setRewardAccumulator(ctx, ra); err != nil { + panic(err) + } + } + + for _, rt := range gs.RewardTrackers { + if err := k.setRewardTracker(ctx, rt); err != nil { + panic(err) + } + } +} + +// ExportGenesis returns the x/incentive module's exported genesis state. +func (k Keeper) ExportGenesis(ctx sdk.Context) *incentive.GenesisState { + completedPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusCompleted) + if err != nil { + panic(err) + } + ongoingPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusOngoing) + if err != nil { + panic(err) + } + upcomingPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusUpcoming) + if err != nil { + panic(err) + } + bonds, err := k.getAllBonds(ctx) + if err != nil { + panic(err) + } + trackers, err := k.getAllRewardTrackers(ctx) + if err != nil { + panic(err) + } + accumulators, err := k.getAllRewardAccumulators(ctx) + if err != nil { + panic(err) + } + unbondings, err := k.getAllAccountUnbondings(ctx) + if err != nil { + panic(err) + } + return incentive.NewGenesisState( + k.GetParams(ctx), + completedPrograms, + ongoingPrograms, + upcomingPrograms, + k.getNextProgramID(ctx), + k.GetLastRewardsTime(ctx), + bonds, + trackers, + accumulators, + unbondings, + ) +} diff --git a/x/incentive/keeper/grpc_query.go b/x/incentive/keeper/grpc_query.go index da8e40c636..704ed02d0c 100644 --- a/x/incentive/keeper/grpc_query.go +++ b/x/incentive/keeper/grpc_query.go @@ -31,7 +31,7 @@ func (q Querier) Params( k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) - params := k.getParams(ctx) + params := k.GetParams(ctx) return &incentive.QueryParamsResponse{Params: params}, nil } @@ -77,7 +77,7 @@ func (q Querier) UpcomingIncentivePrograms( Programs: programs, } - return resp, incentive.ErrNotImplemented + return resp, err } func (q Querier) OngoingIncentivePrograms( @@ -130,76 +130,150 @@ func (q Querier) CompletedIncentivePrograms( } func (q Querier) PendingRewards( - _ context.Context, + goCtx context.Context, req *incentive.QueryPendingRewards, ) (*incentive.QueryPendingRewardsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } + addr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } - // TODO: calculate, without modifying, rewards which would result from MsgClaim - - return &incentive.QueryPendingRewardsResponse{}, incentive.ErrNotImplemented + k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) + pending, err := k.calculateRewards(ctx, addr) + if err != nil { + return nil, err + } + return &incentive.QueryPendingRewardsResponse{Rewards: pending}, err } -func (q Querier) Bonded( - _ context.Context, - req *incentive.QueryBonded, -) (*incentive.QueryBondedResponse, error) { +func (q Querier) AccountBonds( + goCtx context.Context, + req *incentive.QueryAccountBonds, +) (*incentive.QueryAccountBondsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } + addr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } - // TODO: get one or all denoms, all tiers bonded to this address + totalBonded := sdk.NewCoins() + totalUnbonding := sdk.NewCoins() + accountUnbondings := []incentive.Unbonding{} + + k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) + denoms, err := k.getAllBondDenoms(ctx, addr) + if err != nil { + return nil, err + } + for _, denom := range denoms { + bonded, unbonding, unbondings := k.BondSummary(ctx, addr, denom) + totalBonded = totalBonded.Add(bonded) + totalUnbonding = totalUnbonding.Add(unbonding) + // Only nonzero unbondings will be stored, so this list is already filtered + accountUnbondings = append(accountUnbondings, unbondings...) + } - return &incentive.QueryBondedResponse{}, incentive.ErrNotImplemented + return &incentive.QueryAccountBondsResponse{ + Bonded: totalBonded, + Unbonding: totalUnbonding, + Unbondings: accountUnbondings, + }, nil } func (q Querier) TotalBonded( - _ context.Context, + goCtx context.Context, req *incentive.QueryTotalBonded, ) (*incentive.QueryTotalBondedResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } - // TODO: bonded uTokens across one or all denoms, all tiers + k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) + + var total sdk.Coins + if req.Denom != "" { + total = sdk.NewCoins(k.getTotalBonded(ctx, req.Denom)) + } else { + var err error + total, err = k.getAllTotalBonded(ctx) + if err != nil { + return nil, err + } + } - return &incentive.QueryTotalBondedResponse{}, incentive.ErrNotImplemented + return &incentive.QueryTotalBondedResponse{Bonded: total}, nil } func (q Querier) TotalUnbonding( - _ context.Context, + goCtx context.Context, req *incentive.QueryTotalUnbonding, ) (*incentive.QueryTotalUnbondingResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } - // TODO: unbonding uTokens across one or all denoms, all tiers + k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) + + var total sdk.Coins + if req.Denom != "" { + total = sdk.NewCoins(k.getTotalUnbonding(ctx, req.Denom)) + } else { + var err error + total, err = k.getAllTotalUnbonding(ctx) + if err != nil { + return nil, err + } + } - return &incentive.QueryTotalUnbondingResponse{}, incentive.ErrNotImplemented + return &incentive.QueryTotalUnbondingResponse{Unbonding: total}, nil } -func (q Querier) Unbondings( +func (q Querier) CurrentRates( goCtx context.Context, - req *incentive.QueryUnbondings, -) (*incentive.QueryUnbondingsResponse, error) { + req *incentive.QueryCurrentRates, +) (*incentive.QueryCurrentRatesResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx) - addr, err := sdk.AccAddressFromBech32(req.Address) + + programs, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusOngoing) if err != nil { return nil, err } - unbondings := []incentive.Unbonding{} - err = k.iterateAccountUnbondings(ctx, addr, func(ctx sdk.Context, au incentive.AccountUnbondings) error { - unbondings = append(unbondings, au.Unbondings...) - return nil - }) - - return &incentive.QueryUnbondingsResponse{Unbondings: unbondings}, err + // to compute the rewards a reference amount (10^exponent) of bonded uToken is currently earning, + // we need to divide the total rewards being distributed by all ongoing incentive programs targeting + // that uToken denom, by the ratio of the total bonded amount to the reference amount. + bonded := k.getTotalBonded(ctx, req.UToken) + rewards := sdk.NewCoins() + exponent := k.getRewardAccumulator(ctx, req.UToken).Exponent + for _, p := range programs { + if p.UToken == req.UToken { + // seconds per year / duration = programsPerYear (as this query assumes incentives will stay constant) + programsPerYear := sdk.MustNewDecFromStr("31557600").Quo(sdk.NewDec(p.Duration)) + // reference amount / total bonded = rewardPortion (as the more uTokens bond, the fewer rewards each earns) + rewardPortion := ten.Power(uint64(exponent)).QuoInt(bonded.Amount) + // annual rewards for reference amount for this specific program, assuming current rates continue + rewardCoin := sdk.NewCoin( + p.TotalRewards.Denom, + programsPerYear.Mul(rewardPortion).MulInt(p.TotalRewards.Amount).TruncateInt(), + ) + // add this program's annual rewards to the total for all programs incentivizing this uToken denom + rewards = rewards.Add(rewardCoin) + } + } + return &incentive.QueryCurrentRatesResponse{ + ReferenceBond: sdk.NewCoin( + req.UToken, + ten.Power(uint64(exponent)).TruncateInt(), + ), + Rewards: rewards, + }, nil } diff --git a/x/incentive/keeper/hooks.go b/x/incentive/keeper/hooks.go new file mode 100644 index 0000000000..17df749040 --- /dev/null +++ b/x/incentive/keeper/hooks.go @@ -0,0 +1,36 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" +) + +// BondHooks defines a structure around the x/incentive Keeper that implements various +// BondHooks interface defined by other modules such as x/leverage. +type BondHooks struct { + k Keeper +} + +var _ leveragetypes.BondHooks = BondHooks{} + +// BondHooks returns a new Hooks instance that wraps the x/incentive keeper. +func (k Keeper) BondHooks() BondHooks { + return BondHooks{k} +} + +// GetBonded gets sum of bonded and unbonding uTokens of a given denom for an account. +func (h BondHooks) GetBonded(ctx sdk.Context, addr sdk.AccAddress, uDenom string) sdkmath.Int { + return h.k.restrictedCollateral(ctx, addr, uDenom).Amount +} + +// ForceUnbondTo instantly unbonds uTokens until an account's bonded amount of a given uToken +// is no greater than a certain amount. +func (h BondHooks) ForceUnbondTo(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error { + // ensure rewards and unbondings are up to date when using liquidation hooks + if _, err := h.k.UpdateAccount(ctx, addr); err != nil { + return err + } + return h.k.reduceBondTo(ctx, addr, uToken) +} diff --git a/x/incentive/keeper/invariants.go b/x/incentive/keeper/invariants.go new file mode 100644 index 0000000000..32b7ccd695 --- /dev/null +++ b/x/incentive/keeper/invariants.go @@ -0,0 +1,8 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// RegisterInvariants registers empty incentive module invariants +func RegisterInvariants(_ sdk.InvariantRegistry, _ Keeper) {} diff --git a/x/incentive/keeper/iter.go b/x/incentive/keeper/iter.go index 805b7468fc..4f9a959e92 100644 --- a/x/incentive/keeper/iter.go +++ b/x/incentive/keeper/iter.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/umee-network/umee/v4/util" + "github.com/umee-network/umee/v4/util/keys" "github.com/umee-network/umee/v4/util/store" "github.com/umee-network/umee/v4/x/incentive" ) @@ -29,10 +29,7 @@ func (k Keeper) getAllIncentivePrograms(ctx sdk.Context, status incentive.Progra iterator := func(_, val []byte) error { var p incentive.IncentiveProgram - if err := p.Unmarshal(val); err != nil { - // improperly marshaled IncentiveProgram should never happen - return err - } + k.cdc.MustUnmarshal(val, &p) programs = append(programs, p) return nil @@ -42,98 +39,163 @@ func (k Keeper) getAllIncentivePrograms(ctx sdk.Context, status incentive.Progra return programs, err } -// iterateAccountUnbondings iterates over all unbonding uTokens for an address -func (k Keeper) iterateAccountUnbondings(ctx sdk.Context, addr sdk.AccAddress, - _ func(_ sdk.Context, _ incentive.AccountUnbondings) error, -) error { - prefix := keyUnbondingsNoDenom(addr) +// getPaginatedIncentivePrograms returns all incentive programs +// that have been passed by governance and have a particular status. +// The status of an incentive program is either Upcoming, Ongoing, or Completed. +// Accepts pagination parameters which specify the length of a page and which page to fetch. +func (k Keeper) getPaginatedIncentivePrograms( + ctx sdk.Context, status incentive.ProgramStatus, page, limit uint64, +) ([]incentive.IncentiveProgram, error) { + programs := []incentive.IncentiveProgram{} - iterator := func(key, val []byte) error { - // TODO: implement (used for account updating and also queries) - return incentive.ErrNotImplemented + var prefix []byte + switch status { + case incentive.ProgramStatusUpcoming: + prefix = keyPrefixUpcomingIncentiveProgram + case incentive.ProgramStatusOngoing: + prefix = keyPrefixOngoingIncentiveProgram + case incentive.ProgramStatusCompleted: + prefix = keyPrefixCompletedIncentiveProgram + default: + return []incentive.IncentiveProgram{}, incentive.ErrInvalidProgramStatus } - return store.Iterate(k.KVStore(ctx), prefix, iterator) + iterator := func(_, val []byte) error { + var p incentive.IncentiveProgram + k.cdc.MustUnmarshal(val, &p) + + programs = append(programs, p) + return nil + } + + err := store.IteratePaginated(k.KVStore(ctx), prefix, uint(page), uint(limit), iterator) + return programs, err } -// IterateAccountBonds iterates over all bonded uTokens for an address by each individual -// uToken denom and tier -func (k Keeper) IterateAccountBonds(ctx sdk.Context, addr sdk.AccAddress, - _ func(ctx sdk.Context, addr sdk.AccAddress, _ incentive.BondTier, _ sdk.Coin) error, -) error { +// getAllBondDenoms gets all uToken denoms for which an account has nonzero bonded amounts. +// useful for setting up queries which look at all of an account's bonds or unbondings. +func (k Keeper) getAllBondDenoms(ctx sdk.Context, addr sdk.AccAddress) ([]string, error) { prefix := keyBondAmountNoDenom(addr) + bonds := []string{} iterator := func(key, val []byte) error { - // TODO: implement (used for reward claiming and also queries) - return incentive.ErrNotImplemented + _, denom, _, err := keys.ExtractAddressAndString(len(keyPrefixBondAmount), key) + if err != nil { + return err + } + bonds = append(bonds, denom) + return nil } - return store.Iterate(k.KVStore(ctx), prefix, iterator) + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return bonds, err } -// getFullRewardTracker combines all single-reward-denom reward trackers for a bonded uToken and tier -func (k Keeper) getFullRewardTracker(ctx sdk.Context, addr sdk.AccAddress, denom string, tier incentive.BondTier, -) sdk.DecCoins { - prefix := keyRewardTrackerNoReward(addr, denom, tier) +// getAllBonds gets all bonds for all accounts (used during export genesis) +func (k Keeper) getAllBonds(ctx sdk.Context) ([]incentive.Bond, error) { + prefix := keyPrefixBondAmount + bonds := []incentive.Bond{} - tracker := sdk.NewDecCoins() iterator := func(key, val []byte) error { - // TODO: implement + addr, denom, _, err := keys.ExtractAddressAndString(len(keyPrefixBondAmount), key) + if err != nil { + return err + } + amount := store.Int(val, "bond amount") + bonds = append(bonds, incentive.NewBond( + addr.String(), + sdk.NewCoin(denom, amount), + )) - return incentive.ErrNotImplemented + return nil } - util.Panic(store.Iterate(k.KVStore(ctx), prefix, iterator)) - return tracker + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return bonds, err } -// getFullRewardAccumulator combines all single-reward-denom reward accumulators for a uToken denom and tier -func (k Keeper) getFullRewardAccumulator(ctx sdk.Context, denom string, tier incentive.BondTier) sdk.DecCoins { - prefix := keyRewardAccumulatorNoReward(denom, tier) +// getAllTotalBonded gets total bonded for all uTokens (used for a query) +func (k Keeper) getAllTotalBonded(ctx sdk.Context) (sdk.Coins, error) { + prefix := keyPrefixTotalBonded + total := sdk.NewCoins() - accumulator := sdk.NewDecCoins() iterator := func(key, val []byte) error { - // TODO: implement - - return incentive.ErrNotImplemented + denom, _, err := keys.ExtractString(len(keyPrefixTotalBonded), key) + if err != nil { + return err + } + amount := store.Int(val, "total bonded") + total = total.Add(sdk.NewCoin(denom, amount)) + return nil } - util.Panic(store.Iterate(k.KVStore(ctx), prefix, iterator)) - return accumulator + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return total, err } -// getPaginatedIncentivePrograms returns all incentive programs -// that have been passed by governance and have a particular status. -// The status of an incentive program is either Upcoming, Ongoing, or Completed. -// Accepts pagination parameters which specify the length of a page and which page to fetch. -func (k Keeper) getPaginatedIncentivePrograms( - ctx sdk.Context, status incentive.ProgramStatus, page, limit uint64, -) ([]incentive.IncentiveProgram, error) { - programs := []incentive.IncentiveProgram{} +// getAllRewardTrackers gets all reward trackers for all accounts (used during export genesis) +func (k Keeper) getAllRewardTrackers(ctx sdk.Context) ([]incentive.RewardTracker, error) { + prefix := keyPrefixRewardTracker + rewardTrackers := []incentive.RewardTracker{} - var prefix []byte - switch status { - case incentive.ProgramStatusUpcoming: - prefix = keyPrefixUpcomingIncentiveProgram - case incentive.ProgramStatusOngoing: - prefix = keyPrefixOngoingIncentiveProgram - case incentive.ProgramStatusCompleted: - prefix = keyPrefixCompletedIncentiveProgram - default: - return []incentive.IncentiveProgram{}, incentive.ErrInvalidProgramStatus + iterator := func(_, val []byte) error { + tracker := incentive.RewardTracker{} + k.cdc.MustUnmarshal(val, &tracker) + rewardTrackers = append(rewardTrackers, tracker) + return nil } + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return rewardTrackers, err +} + +// getAllRewardAccumulators gets all reward accumulators for all uTokens (used during export genesis) +func (k Keeper) getAllRewardAccumulators(ctx sdk.Context) ([]incentive.RewardAccumulator, error) { + prefix := keyPrefixRewardAccumulator + rewardAccumulators := []incentive.RewardAccumulator{} + iterator := func(_, val []byte) error { - var p incentive.IncentiveProgram - if err := p.Unmarshal(val); err != nil { - // improperly marshaled IncentiveProgram should never happen + accumulator := incentive.RewardAccumulator{} + k.cdc.MustUnmarshal(val, &accumulator) + rewardAccumulators = append(rewardAccumulators, accumulator) + return nil + } + + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return rewardAccumulators, err +} + +// getAllAccountUnbondings gets all account unbondings for all accounts (used during export genesis) +func (k Keeper) getAllAccountUnbondings(ctx sdk.Context) ([]incentive.AccountUnbondings, error) { + prefix := keyPrefixUnbondings + unbondings := []incentive.AccountUnbondings{} + + iterator := func(key, val []byte) error { + au := incentive.AccountUnbondings{} + k.cdc.MustUnmarshal(val, &au) + unbondings = append(unbondings, au) + return nil + } + + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return unbondings, err +} + +// getAllTotalUnbonding gets total unbonding for all uTokens (used for a query) +func (k Keeper) getAllTotalUnbonding(ctx sdk.Context) (sdk.Coins, error) { + prefix := keyPrefixTotalUnbonding + total := sdk.NewCoins() + + iterator := func(key, val []byte) error { + denom, _, err := keys.ExtractString(len(keyPrefixTotalUnbonding), key) + if err != nil { return err } - - programs = append(programs, p) + amount := store.Int(val, "total unbonding") + total = total.Add(sdk.NewCoin(denom, amount)) return nil } - err := store.IteratePaginated(k.KVStore(ctx), prefix, uint(page), uint(limit), iterator) - return programs, err + err := store.Iterate(k.KVStore(ctx), prefix, iterator) + return total, err } diff --git a/x/incentive/keeper/keys.go b/x/incentive/keeper/keys.go index cc59c70768..c940cf5a9a 100644 --- a/x/incentive/keeper/keys.go +++ b/x/incentive/keeper/keys.go @@ -12,16 +12,7 @@ import ( // KVStore key prefixes var ( - // Individually store params from MsgGovSetParams - keyPrefixParamMaxUnbondings = []byte{0x01, 0x01} - keyPrefixParamUnbondingDurationLong = []byte{0x01, 0x02} - keyPrefixParamUnbondingDurationMiddle = []byte{0x01, 0x03} - keyPrefixParamUnbondingDurationShort = []byte{0x01, 0x04} - keyPrefixParamTierWeightShort = []byte{0x01, 0x05} - keyPrefixParamTierWeightMiddle = []byte{0x01, 0x06} - keyPrefixParamCommunityFundAddress = []byte{0x01, 0x07} - - // Regular state + keyPrefixParams = []byte{0x01} keyPrefixUpcomingIncentiveProgram = []byte{0x02} keyPrefixOngoingIncentiveProgram = []byte{0x03} keyPrefixCompletedIncentiveProgram = []byte{0x04} @@ -55,38 +46,20 @@ func keyIncentiveProgram(id uint32, status incentive.ProgramStatus) []byte { return util.ConcatBytes(0, prefix, bz) } -// keyTotalBonded returns a KVStore key for total bonded uTokens for a single tier. -func keyTotalBonded(denom string, tier incentive.BondTier) []byte { - // totalBondedPrefix | denom | 0x00 | tier - return util.ConcatBytes(0, keyTotalBondedNoTier(denom), []byte{byte(tier)}) -} - -// keyTotalBondedNoTier returns the common prefix used by all TotalBonds for a uToken denom. -func keyTotalBondedNoTier(denom string) []byte { +// keyTotalBonded returns a KVStore key for total bonded uTokens of a given denom. +func keyTotalBonded(denom string) []byte { // totalBondedPrefix | denom | 0x00 return util.ConcatBytes(1, keyPrefixTotalBonded, []byte(denom)) } -// keyTotalUnbonding returns a KVStore key for total unbonding uTokens for a single tier. -func keyTotalUnbonding(denom string, tier incentive.BondTier) []byte { - // totalUnbondingPrefix | denom | 0x00 | tier - return util.ConcatBytes(0, keyTotalUnbondingNoTier(denom), []byte{byte(tier)}) -} - -// keyTotalUnbondingNoTier returns the common prefix used by all total unbondings for a uToken denom. -func keyTotalUnbondingNoTier(denom string) []byte { +// keyTotalUnbonding returns a KVStore key for total unbonding uTokens of a given denom. +func keyTotalUnbonding(denom string) []byte { // totalUnbondingPrefix | denom | 0x00 return util.ConcatBytes(1, keyPrefixTotalUnbonding, []byte(denom)) } -// keyBondAmount returns a KVStore key for bonded amounts for a uToken denom, account, and tier. -func keyBondAmount(addr sdk.AccAddress, denom string, tier incentive.BondTier) []byte { - // bondPrefix | lengthprefixed(addr) | denom | 0x00 | tier - return util.ConcatBytes(0, keyBondAmountNoTier(addr, denom), []byte{byte(tier)}) -} - -// keyBondAmountNoTier returns the common prefix used by all uTokens bonded to a given account and denom. -func keyBondAmountNoTier(addr sdk.AccAddress, denom string) []byte { +// keyBondAmount returns a KVStore key for bonded amounts for a uToken denom and account. +func keyBondAmount(addr sdk.AccAddress, denom string) []byte { // bondPrefix | lengthprefixed(addr) | denom | 0x00 return util.ConcatBytes(1, keyBondAmountNoDenom(addr), []byte(denom)) } @@ -97,14 +70,8 @@ func keyBondAmountNoDenom(addr sdk.AccAddress) []byte { return util.ConcatBytes(0, keyPrefixBondAmount, address.MustLengthPrefix(addr)) } -// keyUnbondAmount returns a KVStore key for unbonding amounts for a uToken denom, account, and tier. -func keyUnbondAmount(addr sdk.AccAddress, denom string, tier incentive.BondTier) []byte { - // unbondPrefix | lengthprefixed(addr) | denom | 0x00 | tier - return util.ConcatBytes(0, keyUnbondAmountNoTier(addr, denom), []byte{byte(tier)}) -} - -// keyUnbondAmountNoTier returns the common prefix used by all uTokens unbonding from a given account and denom. -func keyUnbondAmountNoTier(addr sdk.AccAddress, denom string) []byte { +// keyUnbondAmount returns a KVStore key for unbonding amounts for a uToken denom and account. +func keyUnbondAmount(addr sdk.AccAddress, denom string) []byte { // unbondPrefix | lengthprefixed(addr) | denom | 0x00 return util.ConcatBytes(1, keyUnbondAmountNoDenom(addr), []byte(denom)) } @@ -115,44 +82,14 @@ func keyUnbondAmountNoDenom(addr sdk.AccAddress) []byte { return util.ConcatBytes(0, keyPrefixUnbondAmount, address.MustLengthPrefix(addr)) } -// keyRewardAccumulator returns a KVStore key for a single RewardAccumulator denom for a bonded uToken -// denom and tier. -func keyRewardAccumulator(bondedDenom, rewardDenom string, tier incentive.BondTier) []byte { - // rewardAccumulatorPrefix | bondedDenom | 0x00 | tier | rewardDenom | 0x00 - return util.ConcatBytes(1, keyRewardAccumulatorNoReward(bondedDenom, tier), []byte(rewardDenom)) -} - -// keyRewardAccumulatorNoReward returns the common prefix used by all RewardAccumulators for a bonded uToken -// denom and tier. -func keyRewardAccumulatorNoReward(bondedDenom string, tier incentive.BondTier) []byte { - // rewardAccumulatorPrefix | bondedDenom | 0x00 | tier - return util.ConcatBytes(0, keyRewardAccumulatorNoTier(bondedDenom), []byte{byte(tier)}) -} - -// keyRewardAccumulatorNoTier returns the common prefix used by all RewardAccumulators for a bonded uToken -// denom. -func keyRewardAccumulatorNoTier(bondedDenom string) []byte { +// keyRewardAccumulator returns a KVStore key for a RewardAccumulator denom for a bonded uToken. +func keyRewardAccumulator(bondedDenom string) []byte { // rewardAccumulatorPrefix | bondedDenom | 0x00 return util.ConcatBytes(1, keyPrefixRewardAccumulator, []byte(bondedDenom)) } -// keyRewardTracker returns a KVStore key for a single reward tracker denom for an account and bonded uToken -// denom and tier. -func keyRewardTracker(addr sdk.AccAddress, bondedDenom, rewardDenom string, tier incentive.BondTier) []byte { - // rewardTrackerPrefix | lengthprefixed(addr) | bondedDenom | 0x00 | tier | rewardDenom | 0x00 - return util.ConcatBytes(1, keyRewardTrackerNoReward(addr, bondedDenom, tier), []byte(rewardDenom)) -} - -// keyRewardTrackerNoReward returns a KVStore key for a single reward tracker denom for an account and bonded uToken -// denom and tier. -func keyRewardTrackerNoReward(addr sdk.AccAddress, bondedDenom string, tier incentive.BondTier) []byte { - // rewardTrackerPrefix | lengthprefixed(addr) | bondedDenom | 0x00 | tier - return util.ConcatBytes(0, keyRewardTrackerNoTier(addr, bondedDenom), []byte{byte(tier)}) -} - -// keyRewardTrackerNoTier returns the common prefix used by all reward trackers for an account and bonded uToken -// denom across all unbonding tiers. -func keyRewardTrackerNoTier(addr sdk.AccAddress, bondedDenom string) []byte { +// keyRewardTracker returns a KVStore key for a single reward tracker denom for an account and bonded uToken. +func keyRewardTracker(addr sdk.AccAddress, bondedDenom string) []byte { // rewardTrackerPrefix | lengthprefixed(addr) | bondedDenom | 0x00 return util.ConcatBytes(1, keyRewardTrackerNoDenom(addr), []byte(bondedDenom)) } @@ -163,14 +100,8 @@ func keyRewardTrackerNoDenom(addr sdk.AccAddress) []byte { return util.ConcatBytes(0, keyPrefixRewardTracker, address.MustLengthPrefix(addr)) } -// keyUnbondings returns a key to store all active unbondings on an account for a given denom and tier -func keyUnbondings(addr sdk.AccAddress, denom string, tier incentive.BondTier) []byte { - // unbondingPrefix | lengthprefixed(addr) | denom | 0x00 | tier - return util.ConcatBytes(0, keyUnbondingsNoTier(addr, denom), []byte{byte(tier)}) -} - -// keyUnbondingsNoTier returns the common prefix used by all unbondings from a given account and denom. -func keyUnbondingsNoTier(addr sdk.AccAddress, denom string) []byte { +// keyUnbondings returns a key to store all active unbondings on an account for a given uToken. +func keyUnbondings(addr sdk.AccAddress, denom string) []byte { // unbondingPrefix | lengthprefixed(addr) | denom | 0x00 return util.ConcatBytes(1, keyUnbondingsNoDenom(addr), []byte(denom)) } diff --git a/x/incentive/keeper/mock_test.go b/x/incentive/keeper/mock_test.go new file mode 100644 index 0000000000..e6f50fda58 --- /dev/null +++ b/x/incentive/keeper/mock_test.go @@ -0,0 +1,193 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/umee-network/umee/v4/util/coin" + leveragefixtures "github.com/umee-network/umee/v4/x/leverage/fixtures" + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" +) + +// mockBankKeeper mocks the bank keeper +type mockBankKeeper struct { + spendableCoins map[string]sdk.Coins +} + +func newMockBankKeeper() mockBankKeeper { + m := mockBankKeeper{ + spendableCoins: map[string]sdk.Coins{}, + } + return m +} + +// SendCoinsFromModuleToAccount sends coins from a module balance to an account's spendable coins. +// Error on insufficient module balance. +func (m *mockBankKeeper) SendCoinsFromModuleToAccount( + _ sdk.Context, fromModule string, toAddr sdk.AccAddress, coins sdk.Coins, +) error { + moduleAddr := authtypes.NewModuleAddress(fromModule) + spendable, ok := m.spendableCoins[toAddr.String()] + if !ok { + spendable = sdk.NewCoins() + } + moduleBalance, ok := m.spendableCoins[moduleAddr.String()] + if !ok { + moduleBalance = sdk.NewCoins() + } + if coins.IsAnyGT(moduleBalance) { + return errors.New("mock bank: insufficient module balance") + } + m.spendableCoins[moduleAddr.String()] = moduleBalance.Sub(coins...) + m.spendableCoins[toAddr.String()] = spendable.Add(coins...) + return nil +} + +// SendCoinsFromAccountToModule sends coins from an account's spendable balance to a module balance. +// Error on insufficient spendable coins. +func (m *mockBankKeeper) SendCoinsFromAccountToModule( + _ sdk.Context, fromAddr sdk.AccAddress, toModule string, coins sdk.Coins, +) error { + moduleAddr := authtypes.NewModuleAddress(toModule) + spendable, ok := m.spendableCoins[fromAddr.String()] + if !ok { + spendable = sdk.NewCoins() + } + moduleBalance, ok := m.spendableCoins[moduleAddr.String()] + if !ok { + moduleBalance = sdk.NewCoins() + } + if coins.IsAnyGT(spendable) { + return errors.New("mock bank: insufficient account balance") + } + m.spendableCoins[fromAddr.String()] = spendable.Sub(coins...) + m.spendableCoins[moduleAddr.String()] = moduleBalance.Add(coins...) + return nil +} + +// SendCoinsFromModuleToModule sends coins from one module balance to another. +// Error on insufficient module balance. +func (m *mockBankKeeper) SendCoinsFromModuleToModule(_ sdk.Context, fromModule, toModule string, coins sdk.Coins) error { + fromAddr := authtypes.NewModuleAddress(fromModule) + fromBalance, ok := m.spendableCoins[fromAddr.String()] + if !ok { + fromBalance = sdk.NewCoins() + } + toAddr := authtypes.NewModuleAddress(toModule) + toBalance, ok := m.spendableCoins[toAddr.String()] + if !ok { + toBalance = sdk.NewCoins() + } + if coins.IsAnyGT(fromBalance) { + return errors.New("mock bank: insufficient module balance") + } + m.spendableCoins[fromAddr.String()] = fromBalance.Sub(coins...) + m.spendableCoins[toAddr.String()] = toBalance.Add(coins...) + return nil +} + +// SpendableCoins returns an account's spendable coins, without validating the address +func (m *mockBankKeeper) SpendableCoins(_ sdk.Context, addr sdk.AccAddress) sdk.Coins { + spendable, ok := m.spendableCoins[addr.String()] + if !ok { + return sdk.NewCoins() + } + return spendable +} + +// FundAccount mints new coins and sends them to an address. +func (m *mockBankKeeper) FundAccount(addr sdk.AccAddress, coins sdk.Coins) { + coins = sdk.NewCoins(coins...) // prevents panic: Wrong argument: coins must be sorted + spendable, ok := m.spendableCoins[addr.String()] + if !ok { + spendable = sdk.NewCoins() + } + m.spendableCoins[addr.String()] = spendable.Add(coins...) +} + +// FundModule mints new coins and adds them to a module balance. +func (m *mockBankKeeper) FundModule(module string, coins sdk.Coins) { + coins = sdk.NewCoins(coins...) // prevents panic: Wrong argument: coins must be sorted + moduleAddr := authtypes.NewModuleAddress(module) + balance, ok := m.spendableCoins[moduleAddr.String()] + if !ok { + balance = sdk.NewCoins() + } + m.spendableCoins[moduleAddr.String()] = balance.Add(coins...) +} + +// mockLeverageKeeper implements the methods called by the incentive module on the leverage module, +// but will not independently call any methods on the incentive module as the real leverage module does. +type mockLeverageKeeper struct { + // collateral[address] = coins + collateral map[string]sdk.Coins + // to test emergency unbondings + donatedCollateral sdk.Coins +} + +func newMockLeverageKeeper() mockLeverageKeeper { + m := mockLeverageKeeper{ + collateral: map[string]sdk.Coins{}, + donatedCollateral: sdk.NewCoins(), + } + return m +} + +// GetCollateral implements the expected leverage keeper +func (m *mockLeverageKeeper) GetCollateral(_ sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + collateral, ok := m.collateral[addr.String()] + if !ok { + return coin.Zero(denom) + } + return sdk.NewCoin(denom, collateral.AmountOf(denom)) +} + +// DonateCollateral implements the expected leverage keeper +func (m *mockLeverageKeeper) DonateCollateral(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error { + newCollateral := m.GetCollateral(ctx, addr, uToken.Denom).Sub(uToken).Amount.Int64() + m.setCollateral(addr, uToken.Denom, newCollateral) + m.donatedCollateral = m.donatedCollateral.Add(uToken) + return nil +} + +// getDonatedCollateral is used to test the effects of emergency unbondings +func (m *mockLeverageKeeper) getDonatedCollateral(_ sdk.Context, denom string) sdk.Coin { + return sdk.NewCoin(denom, m.donatedCollateral.AmountOf(denom)) +} + +// setCollateral sets an account's collateral in the mock leverage keeper without requiring any supplying action +func (m *mockLeverageKeeper) setCollateral(addr sdk.AccAddress, denom string, amount int64) { + collateral, ok := m.collateral[addr.String()] + if !ok { + // initialize + collateral = sdk.NewCoins() + } + if collateral.AmountOf(denom).IsZero() { + // no existing collateral of this denom + collateral = collateral.Add(sdk.NewInt64Coin(denom, amount)) + } else { + // overwrite existing collateral of this denom + for i := range collateral { + if collateral[i].Denom == denom { + collateral[i].Amount = sdk.NewInt(amount) + } + } + } + // set collateral + m.collateral[addr.String()] = collateral +} + +// GetTokenSettings implements the expected leverage keeper, with UMEE, ATOM, and DAI registered. +func (m *mockLeverageKeeper) GetTokenSettings(_ sdk.Context, denom string) (leveragetypes.Token, error) { + switch denom { + case leveragefixtures.UmeeDenom: + return leveragefixtures.Token(denom, "UMEE", 6), nil + case leveragefixtures.AtomDenom: + return leveragefixtures.Token(denom, "ATOM", 6), nil + case leveragefixtures.DaiDenom: + return leveragefixtures.Token(denom, "DAI", 18), nil + } + return leveragetypes.Token{}, leveragetypes.ErrNotRegisteredToken +} diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index 92a8b22e4f..3c3352fc1a 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -32,7 +32,7 @@ func (s msgServer) Claim( } // clear completed unbondings and claim all rewards - rewards, err := k.updateAccount(ctx, addr) + rewards, err := k.UpdateAccount(ctx, addr) if err != nil { return nil, err } @@ -45,31 +45,31 @@ func (s msgServer) Bond( msg *incentive.MsgBond, ) (*incentive.MsgBondResponse, error) { k, ctx := s.keeper, sdk.UnwrapSDKContext(goCtx) - addr, denom, tier, err := addressUTokenTier(msg.Account, msg.Asset, msg.Tier) + addr, denom, err := addressUToken(msg.Account, msg.UToken) if err != nil { return nil, err } // clear completed unbondings and claim all rewards // this must happen before bonded amount is increased, as rewards are for the previously bonded amount only - _, err = k.updateAccount(ctx, addr) + _, err = k.UpdateAccount(ctx, addr) if err != nil { return nil, err } // get current account state for the requested uToken denom only - bonded := k.getAllBonded(ctx, addr, denom) + bonded := k.GetBonded(ctx, addr, denom) // ensure account has enough collateral to bond the new amount on top of its current amount - collateral := k.leverageKeeper.GetCollateralAmount(ctx, addr, denom) - if collateral.IsLT(bonded.Add(msg.Asset)) { + collateral := k.leverageKeeper.GetCollateral(ctx, addr, denom) + if collateral.IsLT(bonded.Add(msg.UToken)) { return nil, incentive.ErrInsufficientCollateral.Wrapf( "collateral: %s bonded: %s requested: %s", - collateral, bonded, msg.Asset, + collateral, bonded, msg.UToken, ) } - err = k.increaseBond(ctx, addr, tier, msg.Asset) + err = k.increaseBond(ctx, addr, msg.UToken) return &incentive.MsgBondResponse{}, err } @@ -78,84 +78,96 @@ func (s msgServer) BeginUnbonding( msg *incentive.MsgBeginUnbonding, ) (*incentive.MsgBeginUnbondingResponse, error) { k, ctx := s.keeper, sdk.UnwrapSDKContext(goCtx) - addr, denom, tier, err := addressUTokenTier(msg.Account, msg.Asset, msg.Tier) + addr, denom, err := addressUToken(msg.Account, msg.UToken) if err != nil { return nil, err } // clear completed unbondings and claim all rewards // this must happen before unbonding is created, as rewards are for the previously bonded amount - _, err = k.updateAccount(ctx, addr) + _, err = k.UpdateAccount(ctx, addr) if err != nil { return nil, err } - // get current account state for the requested uToken denom and unbonding tier only - bonded, currentUnbonding, unbondings := k.accountBonds(ctx, addr, denom, tier) + // get current account state for the requested uToken denom only + bonded, currentUnbonding, unbondings := k.BondSummary(ctx, addr, denom) - // prevent unbonding spam - if len(unbondings) >= int(k.getMaxUnbondings(ctx)) { + maxUnbondings := int(k.GetParams(ctx).MaxUnbondings) + if maxUnbondings > 0 && len(unbondings) >= maxUnbondings { + // reject concurrent unbondings that would exceed max unbondings - zero is unlimited return nil, incentive.ErrMaxUnbondings.Wrapf("%d", len(unbondings)) } // reject unbondings greater than maximum available amount - if currentUnbonding.Add(msg.Asset).Amount.GT(bonded.Amount) { + if currentUnbonding.Add(msg.UToken).Amount.GT(bonded.Amount) { return nil, incentive.ErrInsufficientBonded.Wrapf( "bonded: %s, unbonding: %s, requested: %s", bonded, currentUnbonding, - msg.Asset, + msg.UToken, ) } // start the unbonding - err = k.addUnbonding(ctx, addr, msg.Asset, tier) + err = k.addUnbonding(ctx, addr, msg.UToken) return &incentive.MsgBeginUnbondingResponse{}, err } -func (s msgServer) Sponsor( +func (s msgServer) EmergencyUnbond( goCtx context.Context, - msg *incentive.MsgSponsor, -) (*incentive.MsgSponsorResponse, error) { + msg *incentive.MsgEmergencyUnbond, +) (*incentive.MsgEmergencyUnbondResponse, error) { k, ctx := s.keeper, sdk.UnwrapSDKContext(goCtx) - - sponsor, err := sdk.AccAddressFromBech32(msg.Sponsor) + addr, denom, err := addressUToken(msg.Account, msg.UToken) if err != nil { return nil, err } - // Error messages that follow are designed to promote third party usability, so they are more - // verbose and situational than usual. - program, status, err := k.getIncentiveProgram(ctx, msg.Program) + // clear completed unbondings and claim all rewards + // this must happen before emergency unbonding, as rewards are for the previously bonded amount + _, err = k.UpdateAccount(ctx, addr) if err != nil { return nil, err } - if status != incentive.ProgramStatusUpcoming { - return nil, incentive.ErrSponsorIneligible.Wrap("program exists but is not upcoming") - } - if program.Funded { - return nil, incentive.ErrSponsorIneligible.Wrap("program is already funded") - } - if program.TotalRewards.Denom != msg.Asset.Denom { - return nil, incentive.ErrSponsorInvalid.Wrap("reward denom mismatch") + + maxEmergencyUnbond := k.restrictedCollateral(ctx, addr, msg.UToken.Denom) + + // reject emergency unbondings greater than maximum available amount + if msg.UToken.Amount.GT(maxEmergencyUnbond.Amount) { + return nil, incentive.ErrInsufficientBonded.Wrapf( + "requested: %s, maximum: %s", + msg.UToken, + maxEmergencyUnbond, + ) } - if !program.TotalRewards.Amount.Equal(msg.Asset.Amount) { - return nil, incentive.ErrSponsorInvalid.Wrap("sponsor amount must match exact total rewards required") + + // instant unbonding penalty is donated to the leverage module as uTokens which are immediately + // burned. leverage reserved amount increases by token equivalent. + penaltyAmount := k.GetParams(ctx).EmergencyUnbondFee.MulInt(msg.UToken.Amount).TruncateInt() + if err := k.leverageKeeper.DonateCollateral(ctx, addr, sdk.NewCoin(denom, penaltyAmount)); err != nil { + return nil, err } - // transfer rewards from sponsor to incentive module - err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, - sponsor, - incentive.ModuleName, - sdk.NewCoins(program.TotalRewards), - ) + // reduce account's bonded and unbonding amounts, thus releasing the appropriate collateral. + newBondPlusUnbond := maxEmergencyUnbond.Sub(msg.UToken) + // besides the penalty fee, this is the same mechanism used to free collateral before liquidation. + err = k.reduceBondTo(ctx, addr, newBondPlusUnbond) + return &incentive.MsgEmergencyUnbondResponse{}, err +} + +func (s msgServer) Sponsor( + goCtx context.Context, + msg *incentive.MsgSponsor, +) (*incentive.MsgSponsorResponse, error) { + k, ctx := s.keeper, sdk.UnwrapSDKContext(goCtx) + + sponsor, err := sdk.AccAddressFromBech32(msg.Sponsor) if err != nil { return nil, err } - // update the program's funded amount in store - program.Funded = true - err = k.setIncentiveProgram(ctx, program, incentive.ProgramStatusUpcoming) + err = k.sponsorIncentiveProgram(ctx, sponsor, msg.Program) return &incentive.MsgSponsorResponse{}, err } @@ -165,8 +177,6 @@ func (s msgServer) GovSetParams( ) (*incentive.MsgGovSetParamsResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // todo: check GetSigners security, other things - if err := msg.Params.Validate(); err != nil { return &incentive.MsgGovSetParamsResponse{}, err } @@ -184,8 +194,6 @@ func (s msgServer) GovCreatePrograms( ) (*incentive.MsgGovCreateProgramsResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // todo: check GetSigners security, other things - // For each program being created, create it with the next available ID for _, program := range msg.Programs { if err := s.keeper.createIncentiveProgram(ctx, program, msg.FromCommunityFund); err != nil { @@ -196,21 +204,16 @@ func (s msgServer) GovCreatePrograms( return &incentive.MsgGovCreateProgramsResponse{}, nil } -// addressUTokenTier parses common input fields from MsgBond and MsgBeginUnbonding, and ensures the asset is a uToken. +// addressUToken parses common input fields from MsgBond and MsgBeginUnbonding, and ensures the asset is a uToken. // Returns account as AccAddress, uToken denom and error. -func addressUTokenTier(account string, asset sdk.Coin, tierUint uint32, -) (sdk.AccAddress, string, incentive.BondTier, error) { +func addressUToken(account string, asset sdk.Coin) (sdk.AccAddress, string, error) { addr, err := sdk.AccAddressFromBech32(account) if err != nil { - return sdk.AccAddress{}, "", incentive.BondTierUnspecified, err - } - tier, err := bondTier(tierUint) - if err != nil { - return sdk.AccAddress{}, "", incentive.BondTierUnspecified, err + return sdk.AccAddress{}, "", err } if !leveragetypes.HasUTokenPrefix(asset.Denom) { - return sdk.AccAddress{}, "", incentive.BondTierUnspecified, leveragetypes.ErrNotUToken.Wrap(asset.Denom) + return sdk.AccAddress{}, "", leveragetypes.ErrNotUToken.Wrap(asset.Denom) } - return addr, asset.Denom, tier, err + return addr, asset.Denom, err } diff --git a/x/incentive/keeper/msg_server_test.go b/x/incentive/keeper/msg_server_test.go new file mode 100644 index 0000000000..b475991705 --- /dev/null +++ b/x/incentive/keeper/msg_server_test.go @@ -0,0 +1,436 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/umee-network/umee/v4/util/coin" + "github.com/umee-network/umee/v4/x/incentive" + "github.com/umee-network/umee/v4/x/leverage/fixtures" + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" +) + +func (k *testKeeper) TestMsgBond() { + const ( + umee = fixtures.UmeeDenom + atom = fixtures.AtomDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + uatom = leveragetypes.UTokenPrefix + fixtures.AtomDenom + ) + + // create an account which the mock leverage keeper will report as + // having 50u/uumee collateral. No tokens ot uTokens are actually minted. + umeeSupplier := k.newAccount() + k.lk.setCollateral(umeeSupplier, uumee, 50) + + // create an additional account which has supplied an unregistered denom + // which nonetheless has a uToken prefix. The incentive module will allow + // this to be bonded (though u/atom wounldn't be eligible for rewards unless + // a program was passed to incentivize it) + atomSupplier := k.newAccount() + k.lk.setCollateral(atomSupplier, uatom, 50) + + // create an account which has somehow managed to collateralize tokens (not uTokens). + // bonding these should not be possible + errorSupplier := k.newAccount() + k.lk.setCollateral(errorSupplier, umee, 50) + + // empty address + msg := &incentive.MsgBond{ + Account: "", + UToken: coin.New(uumee, 10), + } + _, err := k.msrv.Bond(k.ctx, msg) + require.ErrorContains(k.t, err, "empty address", "empty address") + + // attempt to bond 10 u/uumee out of 50 available + msg = &incentive.MsgBond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 10), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.Nil(k.t, err, "bond 10") + + // attempt to bond 40 u/uumee out of the remaining 40 available + msg = &incentive.MsgBond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 40), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.Nil(k.t, err, "bond 40") + + // attempt to bond 10 u/uumee, but all 50 is already bonded + msg = &incentive.MsgBond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 40), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientCollateral, "bond 10 #2") + + // attempt to bond 10 u/atom, which should work + msg = &incentive.MsgBond{ + Account: atomSupplier.String(), + UToken: coin.New(uatom, 10), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.Nil(k.t, err, "bond 10 unregistered uToken") + + // attempt to bond 10 u/uumee, from an account which has zero + msg = &incentive.MsgBond{ + Account: atomSupplier.String(), + UToken: coin.New(uumee, 10), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientCollateral, "bond 10 #3") + + // attempt to bond 10 uumee, which should fail + msg = &incentive.MsgBond{ + Account: errorSupplier.String(), + UToken: coin.New(umee, 10), + } + _, err = k.msrv.Bond(k.ctx, msg) + require.ErrorIs(k.t, err, leveragetypes.ErrNotUToken, "bond non-uToken") +} + +func (k *testKeeper) TestMsgBeginUnbonding() { + const ( + umee = fixtures.UmeeDenom + atom = fixtures.AtomDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + uatom = leveragetypes.UTokenPrefix + fixtures.AtomDenom + ) + + // create an account which the mock leverage keeper will report as + // having 50u/uumee collateral. No tokens ot uTokens are actually minted. + // bond those uTokens. + umeeSupplier := k.newAccount() + k.lk.setCollateral(umeeSupplier, uumee, 50) + k.mustBond(umeeSupplier, coin.New(uumee, 50)) + + // create an additional account which has supplied an unregistered denom + // which nonetheless has a uToken prefix. Bond those utokens. + atomSupplier := k.newAccount() + k.lk.setCollateral(atomSupplier, uatom, 50) + k.mustBond(atomSupplier, coin.New(uatom, 50)) + + // empty address + msg := &incentive.MsgBeginUnbonding{ + Account: "", + UToken: coin.New(uumee, 10), + } + _, err := k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorContains(k.t, err, "empty address", "empty address") + + // base token + msg = &incentive.MsgBeginUnbonding{ + Account: umeeSupplier.String(), + UToken: coin.New(umee, 10), + } + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorIs(k.t, err, leveragetypes.ErrNotUToken) + + // attempt to begin unbonding 10 u/uumee out of 50 available + msg = &incentive.MsgBeginUnbonding{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 10), + } + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.Nil(k.t, err, "begin unbonding 10") + + // attempt to begin unbonding 50 u/uumee more (only 40 available) + msg = &incentive.MsgBeginUnbonding{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 50), + } + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientBonded, "begin unbonding 50") + + // attempt to begin unbonding 50 u/atom but from the wrong account + msg = &incentive.MsgBeginUnbonding{ + Account: umeeSupplier.String(), + UToken: coin.New(uatom, 50), + } + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientBonded, "begin unbonding 50 unknown (wrong account)") + + // attempt to begin unbonding 50 u/atom but from the correct account + msg = &incentive.MsgBeginUnbonding{ + Account: atomSupplier.String(), + UToken: coin.New(uatom, 50), + } + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.Nil(k.t, err, "begin unbonding 50 unknown") + + // attempt a large number of unbondings to hit MaxUnbondings + msg = &incentive.MsgBeginUnbonding{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 1), + } + // create 9 more unbondings of u/uumee on this account, to hit the default maximum of 10 + for i := 1; i < 10; i++ { + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.Nil(k.t, err, "repeat begin unbonding 1") + } + // exceed max unbondings + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrMaxUnbondings, "max unbondings") + + // forcefully advance time, but not enough to finish any unbondings + k.advanceTime(1) + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrMaxUnbondings, "max unbondings") + + // forcefully advance time, enough to finish all unbondings + k.advanceTime(k.GetParams(k.ctx).UnbondingDuration) + _, err = k.msrv.BeginUnbonding(k.ctx, msg) + require.Nil(k.t, err, "unbonding available after max unbondings finish") +} + +func (k *testKeeper) TestMsgEmergencyUnbond() { + const ( + umee = fixtures.UmeeDenom + atom = fixtures.AtomDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + uatom = leveragetypes.UTokenPrefix + fixtures.AtomDenom + ) + + // create an account which the mock leverage keeper will report as + // having 50u/uumee collateral. No tokens ot uTokens are actually minted. + // bond those uTokens. + umeeSupplier := k.newAccount() + k.lk.setCollateral(umeeSupplier, uumee, 50) + k.mustBond(umeeSupplier, coin.New(uumee, 50)) + + // create an additional account which has supplied an unregistered denom + // which nonetheless has a uToken prefix. Bond those utokens. + atomSupplier := k.newAccount() + k.lk.setCollateral(atomSupplier, uatom, 50) + k.mustBond(atomSupplier, coin.New(uatom, 50)) + + // empty address + msg := &incentive.MsgEmergencyUnbond{ + Account: "", + UToken: coin.New(uumee, 10), + } + _, err := k.msrv.EmergencyUnbond(k.ctx, msg) + require.ErrorContains(k.t, err, "empty address", "empty address") + + // base token + msg = &incentive.MsgEmergencyUnbond{ + Account: umeeSupplier.String(), + UToken: coin.New(umee, 10), + } + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.ErrorIs(k.t, err, leveragetypes.ErrNotUToken) + + // attempt to emergency unbond 10 u/uumee out of 50 available + msg = &incentive.MsgEmergencyUnbond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 10), + } + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.Nil(k.t, err, "emergency unbond 10") + + // attempt to emergency unbond 50 u/uumee more (only 40 available) + msg = &incentive.MsgEmergencyUnbond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 50), + } + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientBonded, "emergency unbond 50") + + // attempt to emergency unbond 50 u/atom but from the wrong account + msg = &incentive.MsgEmergencyUnbond{ + Account: umeeSupplier.String(), + UToken: coin.New(uatom, 50), + } + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.ErrorIs(k.t, err, incentive.ErrInsufficientBonded, "emergency unbond 50 unknown (wrong account)") + + // attempt to emergency unbond 50 u/atom but from the correct account + msg = &incentive.MsgEmergencyUnbond{ + Account: atomSupplier.String(), + UToken: coin.New(uatom, 50), + } + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.Nil(k.t, err, "emergency unbond 50 unknown") + + // attempt a large number of emergency unbondings which would hit MaxUnbondings if they were not instant + msg = &incentive.MsgEmergencyUnbond{ + Account: umeeSupplier.String(), + UToken: coin.New(uumee, 1), + } + // 9 more emergency unbondings of u/uumee on this account, which would reach the default maximum of 10 if not instant + for i := 1; i < 10; i++ { + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.Nil(k.t, err, "repeat emergency unbond 1") + } + // this would exceed max unbondings, but because the unbondings are instant, it does not + _, err = k.msrv.EmergencyUnbond(k.ctx, msg) + require.Nil(k.t, err, "emergency unbond does is not restricted by max unbondings") + + // TODO: confirm donated collateral amounts using mock leverage keeper +} + +func (k *testKeeper) TestMsgSponsor() { + const ( + umee = fixtures.UmeeDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + ) + + sponsor := k.newAccount(sdk.NewInt64Coin(umee, 15_000000)) + + govAccAddr := "govAcct" + + validProgram := incentive.IncentiveProgram{ + ID: 0, + StartTime: 100, + Duration: 100, + UToken: uumee, + Funded: false, + TotalRewards: sdk.NewInt64Coin(umee, 10_000000), + RemainingRewards: coin.Zero(umee), + } + + // require that NextProgramID starts at the correct value + require.Equal(k.t, uint32(1), k.getNextProgramID(k.ctx), "initial next ID") + + // add program and expect no error + validMsg := &incentive.MsgGovCreatePrograms{ + Authority: govAccAddr, + Title: "Add two valid program", + Description: "Both will require manual funding", + Programs: []incentive.IncentiveProgram{validProgram, validProgram}, + FromCommunityFund: true, + } + // pass but do not fund the programs + _, err := k.msrv.GovCreatePrograms(k.ctx, validMsg) + require.Nil(k.t, err, "set valid programs") + require.Equal(k.t, uint32(3), k.getNextProgramID(k.ctx), "next Id after 2 programs passed") + + wrongProgramSponsorMsg := &incentive.MsgSponsor{ + Sponsor: sponsor.String(), + Program: 3, + } + validSponsorMsg := &incentive.MsgSponsor{ + Sponsor: sponsor.String(), + Program: 1, + } + failSponsorMsg := &incentive.MsgSponsor{ + Sponsor: sponsor.String(), + Program: 2, + } + + // test cases + _, err = k.msrv.Sponsor(k.ctx, wrongProgramSponsorMsg) + require.ErrorContains(k.t, err, "not found", "sponsor non-existing program") + _, err = k.msrv.Sponsor(k.ctx, validSponsorMsg) + require.Nil(k.t, err, "valid sponsor") + _, err = k.msrv.Sponsor(k.ctx, validSponsorMsg) + require.ErrorIs(k.t, err, incentive.ErrSponsorIneligible, "already funded program") + _, err = k.msrv.Sponsor(k.ctx, failSponsorMsg) + require.ErrorContains(k.t, err, "insufficient sponsor tokens", "sponsor with insufficient funds") +} + +func (k *testKeeper) TestMsgGovSetParams() { + govAccAddr := "govAcct" + + // ensure that module is starting with default params + defaultParams := incentive.DefaultParams() + require.Equal(k.t, defaultParams, k.GetParams(k.ctx)) + + // create new set of params which is different (in every field) from default + newParams := incentive.Params{ + MaxUnbondings: defaultParams.MaxUnbondings + 1, + UnbondingDuration: defaultParams.UnbondingDuration + 1, + EmergencyUnbondFee: sdk.MustNewDecFromStr("0.99"), + } + + // set params and expect no error + validMsg := &incentive.MsgGovSetParams{ + Authority: govAccAddr, + Title: "Update Params", + Description: "New valid values", + Params: newParams, + } + _, err := k.msrv.GovSetParams(k.ctx, validMsg) + require.Nil(k.t, err, "set valid params") + + // ensure params have changed + require.Equal(k.t, newParams, k.GetParams(k.ctx)) + + // create an invalid message + invalidMsg := &incentive.MsgGovSetParams{ + Authority: "", + Title: "", + Description: "", + Params: incentive.Params{}, + } + _, err = k.msrv.GovSetParams(k.ctx, invalidMsg) + // error comes from params validate + require.ErrorContains(k.t, err, "max unbondings cannot be zero") + // ensure params have not changed + require.Equal(k.t, newParams, k.GetParams(k.ctx)) +} + +func (k *testKeeper) TestMsgGovCreatePrograms() { + const ( + umee = fixtures.UmeeDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + ) + + // fund community fund with 15 UMEE + k.initCommunityFund( + sdk.NewInt64Coin(umee, 15_000000), + ) + + govAccAddr := "govAcct" + + validProgram := incentive.IncentiveProgram{ + ID: 0, + StartTime: 100, + Duration: 100, + UToken: uumee, + Funded: false, + TotalRewards: sdk.NewInt64Coin(umee, 10_000000), + RemainingRewards: coin.Zero(umee), + } + + // require that NextProgramID starts at the correct value + require.Equal(k.t, uint32(1), k.getNextProgramID(k.ctx), "initial next ID") + + // add program and expect no error + validMsg := &incentive.MsgGovCreatePrograms{ + Authority: govAccAddr, + Title: "Add valid program", + Description: "Awards 10 UMEE to u/UMEE suppliers over 100 blocks", + Programs: []incentive.IncentiveProgram{validProgram}, + FromCommunityFund: true, + } + // pass and fund the program using 10 UMEE from community fund + _, err := k.msrv.GovCreatePrograms(k.ctx, validMsg) + require.Nil(k.t, err, "set valid program") + require.Equal(k.t, uint32(2), k.getNextProgramID(k.ctx), "next Id after 1 program passed") + + // pass and then attempt to fund the program again using 10 UMEE from community fund, but only 5 remains + _, err = k.msrv.GovCreatePrograms(k.ctx, validMsg) + require.Nil(k.t, err, "insufficient funds, but still passes and reverts to manual funding") + require.Equal(k.t, uint32(3), k.getNextProgramID(k.ctx), "next Id after 2 programs passed") + + invalidProgram := validProgram + invalidProgram.ID = 1 + invalidMsg := &incentive.MsgGovCreatePrograms{ + Authority: govAccAddr, + Title: "Add invalid program", + Description: "", + Programs: []incentive.IncentiveProgram{invalidProgram}, + FromCommunityFund: true, + } + // program should fail to be added, and nextID is unchanged + _, err = k.msrv.GovCreatePrograms(k.ctx, invalidMsg) + require.ErrorIs(k.t, err, incentive.ErrInvalidProgramID, "set invalid program") + require.Equal(k.t, uint32(3), k.getNextProgramID(k.ctx), "next ID after 2 programs passed an 1 failed") + + // TODO: messages with multiple programs, including partially invalid + // and checking exact equality with upcoming programs set +} diff --git a/x/incentive/keeper/params.go b/x/incentive/keeper/params.go deleted file mode 100644 index 346083ec02..0000000000 --- a/x/incentive/keeper/params.go +++ /dev/null @@ -1,19 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/umee-network/umee/v4/x/incentive" -) - -func (k Keeper) getParams(ctx sdk.Context) incentive.Params { - return incentive.Params{ - MaxUnbondings: k.getMaxUnbondings(ctx), - TierWeightShort: k.getTierWeightShort(ctx), - TierWeightMiddle: k.getTierWeightMiddle(ctx), - UnbondingDurationLong: k.getUnbondingDurationLong(ctx), - UnbondingDurationMiddle: k.getUnbondingDurationMiddle(ctx), - UnbondingDurationShort: k.getUnbondingDurationShort(ctx), - CommunityFundAddress: k.getCommunityFundAddress(ctx).String(), - } -} diff --git a/x/incentive/keeper/program.go b/x/incentive/keeper/program.go index bfdcd1db22..5fef08aa59 100644 --- a/x/incentive/keeper/program.go +++ b/x/incentive/keeper/program.go @@ -3,7 +3,11 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/umee-network/umee/v4/x/incentive" + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" ) // createIncentiveProgram saves an incentive program to upcoming programs after it @@ -16,41 +20,136 @@ func (k Keeper) createIncentiveProgram( program incentive.IncentiveProgram, fromCommunityFund bool, ) error { - if err := program.Validate(); err != nil { + if err := program.ValidateProposed(); err != nil { return err } - addr := k.getCommunityFundAddress(ctx) + // communityFund returns the amount of a given token held in the dist module account + distAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + communityFund := k.bankKeeper.SpendableCoins(ctx, distAddr) + if fromCommunityFund { - if !addr.Empty() { - // If the module has set a community fund address and the proposal - // requested it, we can attempt to instantly fund the module when - // the proposal passes. - funds := k.bankKeeper.SpendableCoins(ctx, addr) - rewards := sdk.NewCoins(program.TotalRewards) - if funds.IsAllGT(rewards) { - // Community fund has the required tokens to fund the program - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, incentive.ModuleName, rewards); err != nil { - return err - } - // Set program's funded and remaining rewards to the amount just funded - program.Funded = true - program.RemainingRewards = program.TotalRewards - } else { - ctx.Logger().Error("incentive community fund insufficient. proposal will revert to manual funding.") + // If the proposal requested it, we can attempt to instantly fund the program when + // the proposal passes. + rewards := sdk.NewCoins(program.TotalRewards) + if communityFund.IsAllGT(rewards) { + // Community fund has the required tokens to fund the program + err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, disttypes.ModuleName, incentive.ModuleName, rewards) + if err != nil { + return err } + // Set program's funded and remaining rewards to the amount just funded + program.Funded = true + program.RemainingRewards = program.TotalRewards } else { - ctx.Logger().Error("incentive community fund not set. proposal will revert to manual funding.") + ctx.Logger().Error("community fund insufficient. proposal will revert to manual funding.") + } + } + + // If this is the first time this uToken has been incentivized, initialize its rewardAccumulator exponent. + // Note that this interprets Exponent == 0 as needing initialization, but if an asset actually had exponent zero, + // and had already been initialized, this would be a harmless no-op. + if ra := k.getRewardAccumulator(ctx, program.UToken); ra.Exponent == 0 { + token, err := k.leverageKeeper.GetTokenSettings(ctx, leveragetypes.ToTokenDenom(program.UToken)) + if err != nil { + // unregistered tokens do not have uTokens, so they cannot be incentivized + return err + } + // Set exponent, preserving all other fields in the reward accumulator in case they are not zero + ra.Exponent = token.Exponent + if err = k.setRewardAccumulator(ctx, ra); err != nil { + return err } } // Set program's ID to the next available value and store it in upcoming incentive programs id := k.getNextProgramID(ctx) + if id == 0 { + return incentive.ErrInvalidProgramID.Wrap("next id was zero") + } program.ID = id - if err := k.setIncentiveProgram(ctx, program, incentive.ProgramStatusUpcoming); err != nil { + + // Increment module's NextProgramID + if err := k.setNextProgramID(ctx, id+1); err != nil { return err } + return k.setIncentiveProgram(ctx, program, incentive.ProgramStatusUpcoming) +} - // Increment module's NextProgramID - return k.setNextProgramID(ctx, id+1) +// moveIncentiveProgram moves an incentive program from one status to another. +// Valid status changes are upcoming -> [ongoing, completed] and ongoing -> upcoming +func (k Keeper) moveIncentiveProgram(ctx sdk.Context, id uint32, toStatus incentive.ProgramStatus) error { + if id == 0 { + return incentive.ErrInvalidProgramID.Wrap("zero") + } + program, fromStatus, err := k.getIncentiveProgram(ctx, id) + if err != nil { + return err + } + + // enforces strict status change rules + switch fromStatus { + case incentive.ProgramStatusCompleted: + return incentive.ErrInvalidProgramStatus.Wrap("cannot move program from completed status") + case incentive.ProgramStatusOngoing: + if toStatus != incentive.ProgramStatusCompleted { + return incentive.ErrInvalidProgramStatus.Wrap("ongoing programs can only be moved to completed") + } + case incentive.ProgramStatusUpcoming: + if toStatus != incentive.ProgramStatusOngoing && toStatus != incentive.ProgramStatusCompleted { + return incentive.ErrInvalidProgramStatus.Wrap("upcoming programs can be moved to ongoing or completed") + } + default: + return incentive.ErrInvalidProgramStatus + } + + if err := k.deleteIncentiveProgram(ctx, id); err != nil { + return err + } + + // add program to new status + return k.setIncentiveProgram(ctx, program, toStatus) +} + +// sponsorIncentiveProgram sponsors an incentive program from an account and updates +// it in the store. +func (k Keeper) sponsorIncentiveProgram(ctx sdk.Context, sponsor sdk.AccAddress, id uint32) error { + if id == 0 { + return incentive.ErrInvalidProgramID.Wrap("zero") + } + + // Error messages that follow are designed to promote third party usability, so they are more + // verbose and situational than usual. + program, status, err := k.getIncentiveProgram(ctx, id) + if err != nil { + return err + } + if status != incentive.ProgramStatusUpcoming { + return incentive.ErrSponsorIneligible.Wrap("program exists but does not have status upcoming") + } + if program.Funded { + return incentive.ErrSponsorIneligible.Wrap("program is already funded") + } + spendable := k.bankKeeper.SpendableCoins(ctx, sponsor).AmountOf(program.TotalRewards.Denom) + if spendable.LT(program.TotalRewards.Amount) { + return incentive.ErrSponsorInvalid.Wrapf("insufficient sponsor tokens: want %s, have %s", + program.TotalRewards, spendable) + } + + // transfer rewards from sponsor to incentive module + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, + sponsor, + incentive.ModuleName, + sdk.NewCoins(program.TotalRewards), + ) + if err != nil { + return err + } + + // set update program state + program.Funded = true + program.RemainingRewards = program.TotalRewards + + // add program to new status + return k.setIncentiveProgram(ctx, program, status) } diff --git a/x/incentive/keeper/reward.go b/x/incentive/keeper/reward.go index 72af79d0c9..c34f72106d 100644 --- a/x/incentive/keeper/reward.go +++ b/x/incentive/keeper/reward.go @@ -2,78 +2,99 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/umee-network/umee/v4/x/incentive" ) -// UpdateRewards increases the module's LastInterestTime and any rewardAccumulators associated with -// ongoing incentive programs. -func (k Keeper) UpdateRewards(ctx sdk.Context) error { - currentTime := uint64(ctx.BlockTime().Unix()) - prevRewardTime := k.getLastRewardsTime(ctx) - if prevRewardTime <= 0 { - // if stored LastRewardTime is zero (or negative), either the chain has just started - // or the genesis file has been modified intentionally. In either case, proceed as if - // 0 seconds have passed since the last block, thus accruing no rewards and setting - // the current BlockTime as the new starting point. - prevRewardTime = currentTime - } +// updateRewardTracker updates the reward tracker matching a specific account + bonded uToken denom +// by setting it to the current value of that uToken denom's reward accumulator. Used after claiming +// rewards or when setting bonded amount from zero to a nonzero amount (i.e. initializing reward tracker). +func (k Keeper) updateRewardTracker(ctx sdk.Context, addr sdk.AccAddress, bondDenom string, +) error { + tracker := k.getRewardTracker(ctx, addr, bondDenom) + accumulator := k.getRewardAccumulator(ctx, bondDenom) - if currentTime < prevRewardTime { - // TODO fix this when tendermint solves https://github.com/tendermint/tendermint/issues/8773 - k.Logger(ctx).With("EndBlocker will wait for block time > prevRewardTime").Error( - incentive.ErrDecreaseLastRewardTime.Error(), - "current", currentTime, - "prev", prevRewardTime, - ) + tracker.Rewards = accumulator.Rewards - // if LastRewardTime appears to be in the future, do nothing (besides logging) and leave - // LastRewardTime at its stored value. This will repeat every block until BlockTime exceeds - // LastRewardTime. - return nil - } + // reward tracker contains address and bond denom, plus updated reward coins + return k.setRewardTracker(ctx, tracker) +} - // TODO: reward accumulator math +// claimRewards claims a single account's uToken's rewards for all bonded uToken denoms. Returns rewards claimed. +func (k Keeper) claimRewards(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) { + rewards := sdk.NewCoins() + bondedDenoms, err := k.getAllBondDenoms(ctx, addr) + if err != nil { + return sdk.NewCoins(), err + } + for _, bondDenom := range bondedDenoms { + tokens := k.calculateSingleReward(ctx, addr, bondDenom) - // set LastRewardTime to current block time - return k.setLastRewardsTime(ctx, currentTime) -} + // If all rewards were too small to disburse for this specific bonded denom, + // skips updating its reward tracker to prevent wasting of fractional rewards. + // If nonzero, proceed to claim. + if !tokens.IsZero() { + // send claimed rewards from incentive module to user account + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, incentive.ModuleName, addr, tokens); err != nil { + return sdk.NewCoins(), err + } + // update the user's reward tracker to indicate that they last claimed rewards at the current + // value of rewardAccumulator + if err := k.updateRewardTracker(ctx, addr, bondDenom); err != nil { + return sdk.NewCoins(), err + } -// clearRewardTracker clears all reward trackers matching a specific account + tier + bonded uToken denom -// from the store by setting them to zero -func (k Keeper) clearRewardTracker(ctx sdk.Context, addr sdk.AccAddress, tier incentive.BondTier, bondDenom string, -) error { - trackers := k.getFullRewardTracker(ctx, addr, bondDenom, tier) - for _, rewardCoin := range trackers { - zeroCoin := sdk.NewDecCoinFromDec(rewardCoin.Denom, sdk.ZeroDec()) - if err := k.setRewardTracker(ctx, addr, bondDenom, zeroCoin, tier); err != nil { - return err + // adds rewards claimed from this single bonded denom to the total + rewards = rewards.Add(tokens...) } } - return nil + return rewards, nil } -// UpdateRewardTracker updates all reward trackers matching a specific account + tier + bonded uToken denom -// by setting them to the current values of that tier + uToken denom's reward accumulators -func (k Keeper) UpdateRewardTracker(ctx sdk.Context, addr sdk.AccAddress, tier incentive.BondTier, bondDenom string, -) error { - trackers := k.getFullRewardTracker(ctx, addr, bondDenom, tier) - accumulators := k.getFullRewardAccumulator(ctx, bondDenom, tier) - for _, rewardCoin := range trackers { - accumulator := sdk.NewDecCoinFromDec(rewardCoin.Denom, accumulators.AmountOf(rewardCoin.Denom)) - if err := k.setRewardTracker(ctx, addr, bondDenom, accumulator, tier); err != nil { - return err +// calculateRewards calculates a single account's uToken's pending rewards for all bonded uToken denoms, +// without claiming them or updating its reward trackers. Returns rewards pending. +func (k Keeper) calculateRewards(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) { + rewards := sdk.NewCoins() + bondedDenoms, err := k.getAllBondDenoms(ctx, addr) + if err != nil { + return sdk.NewCoins(), err + } + for _, bondDenom := range bondedDenoms { + tokens := k.calculateSingleReward(ctx, addr, bondDenom) + if !tokens.IsZero() { + // adds rewards pending for this single bonded denom to the total + rewards = rewards.Add(tokens...) } } - return nil + return rewards, nil } -// ClaimReward claims a single account's bonded uToken tier's reward, then updates its reward tracker. -// Returns rewards claimed. -func (k Keeper) ClaimReward(_ sdk.Context, _ sdk.AccAddress, _ incentive.BondTier, _ sdk.Coin, -) (sdk.Coins, error) { - // TODO - implement claim logic (especially needs high exponent asset compatibility) +// calculateSingleReward calculates a single account's uToken's rewards for a single bonded uToken denom, +// without claiming them or updating its reward tracker. Returns rewards pending. +func (k Keeper) calculateSingleReward(ctx sdk.Context, addr sdk.AccAddress, bondDenom string) sdk.Coins { rewards := sdk.NewCoins() - return rewards, incentive.ErrNotImplemented - // k.updateRewardTracker(ctx, addr, tier, bonded.Denom) + + accumulator := k.getRewardAccumulator(ctx, bondDenom) + tracker := k.getRewardTracker(ctx, addr, bondDenom) + + // Rewards are based on the amount accumulator has increased since tracker was last updated + delta := accumulator.Rewards.Sub(tracker.Rewards) + if delta.IsZero() { + return sdk.NewCoins() + } + + // Actual token amounts must be reduced according to accumulator's exponent + for _, coin := range delta { + bonded := k.GetBonded(ctx, addr, bondDenom) + + // reward = bonded * delta / 10^exponent + rewardDec := sdk.NewDecFromInt(bonded.Amount).Quo( + ten.Power(uint64(accumulator.Exponent)), + ).Mul(coin.Amount) + + // rewards round down + reward := sdk.NewCoin(coin.Denom, rewardDec.TruncateInt()) + rewards = rewards.Add(reward) + } + + return rewards } diff --git a/x/incentive/keeper/scenario_test.go b/x/incentive/keeper/scenario_test.go new file mode 100644 index 0000000000..71cfa1dc13 --- /dev/null +++ b/x/incentive/keeper/scenario_test.go @@ -0,0 +1,184 @@ +package keeper + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/umee-network/umee/v4/x/incentive" + + "github.com/umee-network/umee/v4/util/coin" + //"github.com/umee-network/umee/v4/x/incentive" + "github.com/umee-network/umee/v4/x/leverage/fixtures" + leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" +) + +func TestBasicIncentivePrograms(t *testing.T) { + const ( + umee = fixtures.UmeeDenom + atom = fixtures.AtomDenom + uumee = leveragetypes.UTokenPrefix + fixtures.UmeeDenom + uatom = leveragetypes.UTokenPrefix + fixtures.AtomDenom + ) + + k := newTestKeeper(t) + + // init a community fund with 1000 UMEE and 10 ATOM available for funding + k.initCommunityFund( + coin.New(umee, 1000_000000), + coin.New(atom, 10_000000), + ) + + // init a third party sponsor account with 1000 UMEE and 10 ATOM available for funding + sponsor := k.newAccount( + coin.New(umee, 1000_000000), + coin.New(atom, 10_000000), + ) + + // init a supplier with bonded uTokens + alice := k.newBondedAccount( + coin.New("u/"+fixtures.UmeeDenom, 100_000000), + ) + + // create three separate programs for 10UMEE, which will run for 100 seconds + // one is funded by the community fund, and two are not. The non-community ones are start later than the first. + // The first non-community-funded program will not be sponsored, and should thus be cancelled and create no rewards. + k.addIncentiveProgram(uumee, 100, 100, sdk.NewInt64Coin(umee, 10_000000), true) + k.addIncentiveProgram(uumee, 120, 120, sdk.NewInt64Coin(umee, 10_000000), false) + k.addIncentiveProgram(uumee, 120, 120, sdk.NewInt64Coin(umee, 10_000000), false) + + // verify all 3 programs added + programs, err := k.getAllIncentivePrograms(k.ctx, incentive.ProgramStatusUpcoming) + require.NoError(k.t, err) + require.Equal(k.t, 3, len(programs)) + + // fund the third program manually + k.sponsor(sponsor, 3) + + // Verify funding states + require.True(k.t, k.programFunded(1)) + require.False(k.t, k.programFunded(2)) + require.True(k.t, k.programFunded(3)) + + // Verify program status + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(1), "program 1 status (time 1)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(2), "program 2 status (time 1)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(3), "program 3 status (time 1)") + + // Advance last rewards time to 100, thus starting the first program + k.advanceTimeTo(100) + require.Equal(k.t, incentive.ProgramStatusOngoing, k.programStatus(1), "program 1 status (time 100)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(2), "program 2 status (time 100)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(3), "program 3 status (time 100)") + // Because rewards are distributed before programs status is updated, no rewards + // should have been distributed this block + program1 := k.getProgram(1) + require.Equal(k.t, program1.TotalRewards, program1.RemainingRewards, "no rewards on program's start block") + + // Advance last rewards time to 101, thus distributing 1 block (1%) of the first program's rewards. + // No additional programs have started yet. + k.advanceTimeTo(101) + require.Equal(k.t, incentive.ProgramStatusOngoing, k.programStatus(1), "program 1 status (time 101)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(2), "program 2 status (time 101)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(3), "program 3 status (time 101)") + // 9.9UMEE of the original 10 UMEE remain + program1 = k.getProgram(1) + require.Equal(k.t, sdk.NewInt(9_900000), program1.RemainingRewards.Amount, "99 percent of program 1 rewards remain") + + // init a second supplier with bonded uTokens - but he was not present during updateRewards + bob := k.newBondedAccount( + coin.New("u/"+fixtures.UmeeDenom, 25_000000), + coin.New("u/"+fixtures.AtomDenom, 8_000000), + ) + + // From 100000 rewards distributed, 100% went to alice and 0% went to bob. + // Pending rewards round down. + rewards, err := k.calculateRewards(k.ctx, alice) + require.NoError(k.t, err) + require.Equal( + k.t, + sdk.NewCoins(sdk.NewInt64Coin(umee, 100000)), + rewards, + "alice pending rewards at time 101", + ) + rewards, err = k.calculateRewards(k.ctx, bob) + require.NoError(k.t, err) + require.Equal( + k.t, + sdk.NewCoins(), + rewards, + "bob pending rewards at time 101", + ) + + // Advance last rewards time to 102, thus distributing 1 block (1%) of the first program's rewards. + // No additional programs have started yet. + k.advanceTimeTo(102) + require.Equal(k.t, incentive.ProgramStatusOngoing, k.programStatus(1), "program 1 status (time 102)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(2), "program 2 status (time 102)") + require.Equal(k.t, incentive.ProgramStatusUpcoming, k.programStatus(3), "program 3 status (time 102)") + // 9.8UMEE of the original 10 UMEE remain. + // rewards actually distributed rounded down a bit, so remaining rewards have a little more left over. + program1 = k.getProgram(1) + require.Equal(k.t, sdk.NewInt(9_800001), program1.RemainingRewards.Amount, "98 percent of program 1 rewards remain") + + // From 100000 rewards distributed this new block, 80% went to alice and 20% went to bob. + // since alice hasn't claimed rewards yet, these add to the previous block's rewards. + // rewards actually distributed rounded down a bit, and due to decimal remainders, their sum falls short + // of the amount that was removed from remainingRewards. + rewards, err = k.calculateRewards(k.ctx, alice) + require.NoError(k.t, err) + require.Equal( + k.t, + sdk.NewCoins(sdk.NewInt64Coin(umee, 179999)), + rewards, + "alice pending rewards at time 102", + ) + rewards, err = k.calculateRewards(k.ctx, bob) + require.NoError(k.t, err) + require.Equal( + k.t, + sdk.NewCoins(sdk.NewInt64Coin(umee, 19999)), + rewards, + "bob pending rewards at time 102", + ) + + // Advance last rewards time to 120, starting two additional programs. + // The one that was not funded is considered completed (a no-op for rewards) instead. + k.advanceTimeTo(120) + require.Equal(k.t, incentive.ProgramStatusOngoing, k.programStatus(1), "program 1 status (time 120)") + require.Equal(k.t, incentive.ProgramStatusCompleted, k.programStatus(2), "program 2 status (time 120)") + require.Equal(k.t, incentive.ProgramStatusOngoing, k.programStatus(3), "program 3 status (time 120)") + + // Advance last rewards time to 300, ending all programs. + k.advanceTimeTo(300) + require.Equal(k.t, incentive.ProgramStatusCompleted, k.programStatus(1), "program 1 status (time 300)") + require.Equal(k.t, incentive.ProgramStatusCompleted, k.programStatus(2), "program 2 status (time 300)") + require.Equal(k.t, incentive.ProgramStatusCompleted, k.programStatus(3), "program 3 status (time 300)") + // Remaining rewards should be exactly zero. + program1 = k.getProgram(1) + program2 := k.getProgram(2) + program3 := k.getProgram(3) + require.Equal(k.t, sdk.ZeroInt(), program1.RemainingRewards.Amount, "0 percent of program 1 rewards remain") + require.Equal(k.t, sdk.ZeroInt(), program2.RemainingRewards.Amount, "0 percent of program 2 rewards remain") + require.Equal(k.t, sdk.ZeroInt(), program3.RemainingRewards.Amount, "0 percent of program 3 rewards remain") + + // These are the final pending rewards observed. + rewards, err = k.calculateRewards(k.ctx, alice) + require.NoError(k.t, err) + require.Equal( + k.t, + // a small amount from before bob joined, then 80% of the rest of program 1, and 80% of program 3 + sdk.NewCoins(sdk.NewInt64Coin(umee, 100000+7_920000+8_000000)), + rewards, + "alice pending rewards at time 300", + ) + rewards, err = k.calculateRewards(k.ctx, bob) + require.NoError(k.t, err) + require.Equal( + k.t, + // 20% of the rest of program 1 (missing the first block), and 20% of program 3 + sdk.NewCoins(sdk.NewInt64Coin(umee, 1_980000+2_000000)), + rewards, + "bob pending rewards at time 300", + ) +} diff --git a/x/incentive/keeper/store.go b/x/incentive/keeper/store.go index 36c2369196..07f42fd18e 100644 --- a/x/incentive/keeper/store.go +++ b/x/incentive/keeper/store.go @@ -8,47 +8,14 @@ import ( "github.com/umee-network/umee/v4/x/incentive" ) -// getMaxUnbondings gets the maximum number of unbondings an account is allowed to have at one time. -func (k Keeper) getMaxUnbondings(ctx sdk.Context) uint32 { - return store.GetUint32(k.KVStore(ctx), - keyPrefixParamMaxUnbondings, "max unbondings") -} - -// getUnbondingDurationLong gets the duration in seconds of the long bonding tier. -func (k Keeper) getUnbondingDurationLong(ctx sdk.Context) uint64 { - return store.GetUint64(k.KVStore(ctx), - keyPrefixParamUnbondingDurationLong, "long unbonding duration") -} - -// getUnbondingDurationMiddle gets the duration in seconds of the middle bonding tier. -func (k Keeper) getUnbondingDurationMiddle(ctx sdk.Context) uint64 { - return store.GetUint64(k.KVStore(ctx), - keyPrefixParamUnbondingDurationMiddle, "middle unbonding duration") -} - -// getUnbondingDurationShort gets the duration in seconds of the short bonding tier. -func (k Keeper) getUnbondingDurationShort(ctx sdk.Context) uint64 { - return store.GetUint64(k.KVStore(ctx), - keyPrefixParamUnbondingDurationShort, "short unbonding duration") -} - -// GetTierWeightShort gets the ratio of rewards received by the short tier of bonded assets. Ranges 0 - 1. -func (k Keeper) getTierWeightMiddle(ctx sdk.Context) sdk.Dec { - return store.GetDec(k.KVStore(ctx), - keyPrefixParamTierWeightMiddle, "middle tier weight") -} - -// getTierWeightShort gets the ratio of rewards received by the middle tier of bonded assets. Ranges 0 - 1. -func (k Keeper) getTierWeightShort(ctx sdk.Context) sdk.Dec { - return store.GetDec(k.KVStore(ctx), - keyPrefixParamTierWeightShort, "short tier weight") -} - -// getCommunityFundAddress retrieves the community fund address parameter. It is guaranteed to be -// either valid (by sdk.ValidateAddressFormat) or empty. -func (k Keeper) getCommunityFundAddress(ctx sdk.Context) sdk.AccAddress { - return store.GetAddress(k.KVStore(ctx), - keyPrefixParamCommunityFundAddress, "community fund address") +func (k Keeper) GetParams(ctx sdk.Context) incentive.Params { + params := incentive.Params{} + ok := store.GetObject(k.KVStore(ctx), k.cdc, keyPrefixParams, ¶ms, "params") + if !ok { + // on missing module parameters, return defaults rather than panicking or returning zero values + return incentive.DefaultParams() + } + return params } // setParams validates and sets the incentive module parameters @@ -57,42 +24,48 @@ func (k Keeper) setParams(ctx sdk.Context, params incentive.Params) error { if err := params.Validate(); err != nil { return err } - err := store.SetUint32(kvs, keyPrefixParamMaxUnbondings, - params.MaxUnbondings, "max unbondings") - if err != nil { - return err - } - err = store.SetUint64(kvs, keyPrefixParamUnbondingDurationLong, - params.UnbondingDurationLong, "long unbonding duration") - if err != nil { - return err - } - err = store.SetUint64(kvs, keyPrefixParamUnbondingDurationMiddle, - params.UnbondingDurationMiddle, "middle unbonding duration") - if err != nil { - return err - } - err = store.SetUint64(kvs, keyPrefixParamUnbondingDurationShort, - params.UnbondingDurationShort, "short unbonding duration") - if err != nil { - return err + return store.SetObject(kvs, k.cdc, keyPrefixParams, ¶ms, "params") +} + +// incentiveProgramStatus gets an incentive program status by ID. If the program is not found, +// the status is NotExist. Error only if the program is found under multiple statuses. +func (k Keeper) incentiveProgramStatus(ctx sdk.Context, id uint32) (incentive.ProgramStatus, error) { + if id == 0 { + return incentive.ProgramStatusNotExist, incentive.ErrInvalidProgramID.Wrap("zero") } - err = store.SetDec(kvs, keyPrefixParamTierWeightMiddle, - params.TierWeightMiddle, "middle tier weight") - if err != nil { - return err + + statuses := []incentive.ProgramStatus{ + incentive.ProgramStatusUpcoming, + incentive.ProgramStatusOngoing, + incentive.ProgramStatusCompleted, } - err = store.SetDec(kvs, keyPrefixParamTierWeightShort, - params.TierWeightShort, "short tier weight") - if err != nil { - return err + + kvStore := k.KVStore(ctx) + + var found int + var status incentive.ProgramStatus + + // Looks for an incentive program in upcoming, ongoing, then completed program lists. + for _, s := range statuses { + if kvStore.Has(keyIncentiveProgram(id, s)) { + found++ + status = s + } } - err = store.SetAddress(kvs, keyPrefixParamCommunityFundAddress, - sdk.MustAccAddressFromBech32(params.CommunityFundAddress), "community fund address") - if err != nil { - return err + + switch found { + case 0: + // If the program was not found in any of the three lists + return incentive.ProgramStatusNotExist, nil + case 1: + // If the program existed + return status, nil + default: + // If the program somehow existed in multiple statuses at once (should never happen) + return incentive.ProgramStatusNotExist, incentive.ErrInvalidProgramStatus.Wrapf( + "multiple statuses found for incentive program %d", id, + ) } - return nil } // getIncentiveProgram gets an incentive program by ID, regardless of the program's status. @@ -100,50 +73,68 @@ func (k Keeper) setParams(ctx sdk.Context, params incentive.Params) error { func (k Keeper) getIncentiveProgram(ctx sdk.Context, id uint32) ( incentive.IncentiveProgram, incentive.ProgramStatus, error, ) { - statuses := []incentive.ProgramStatus{ - incentive.ProgramStatusUpcoming, - incentive.ProgramStatusOngoing, - incentive.ProgramStatusCompleted, + program := incentive.IncentiveProgram{} + if id == 0 { + return program, incentive.ProgramStatusNotExist, incentive.ErrInvalidProgramID.Wrap("zero") + } + + status, err := k.incentiveProgramStatus(ctx, id) + if err != nil { + return program, incentive.ProgramStatusNotExist, err + } + if status == incentive.ProgramStatusNotExist { + return program, incentive.ProgramStatusNotExist, sdkerrors.ErrNotFound.Wrapf("program id %d", id) } kvStore := k.KVStore(ctx) - // Looks for an incentive program with the specified ID in upcoming, ongoing, then completed program lists. - for _, status := range statuses { - program := incentive.IncentiveProgram{} - bz := kvStore.Get(keyIncentiveProgram(id, status)) - if len(bz) != 0 { - err := k.cdc.Unmarshal(bz, &program) - return program, status, err - } + // Looks for an incentive program with the specified ID and status + if !store.GetObject(kvStore, k.cdc, keyIncentiveProgram(id, status), &program, "incentive program") { + return program, incentive.ProgramStatusNotExist, sdkerrors.ErrNotFound.Wrapf("program id %d", id) } - - return incentive.IncentiveProgram{}, 0, sdkerrors.ErrNotFound + // Enforces that program ID matches where it was stored + if program.ID != id { + return program, incentive.ProgramStatusNotExist, incentive.ErrInvalidProgramID.Wrap("mismatch") + } + return program, status, nil } -// setIncentiveProgram stores an incentive program in either the upcoming, ongoing, or completed program lists. -// does not validate the incentive program struct or the validity of its status change (e.g. upcoming -> complete) -func (k Keeper) setIncentiveProgram(ctx sdk.Context, - program incentive.IncentiveProgram, status incentive.ProgramStatus, +// setIncentiveProgram stores an incentive program with a given status. +// this can overwrite existing programs, but will not move them to a new status. +func (k Keeper) setIncentiveProgram( + ctx sdk.Context, program incentive.IncentiveProgram, status incentive.ProgramStatus, ) error { - keys := [][]byte{ - keyIncentiveProgram(program.ID, incentive.ProgramStatusUpcoming), - keyIncentiveProgram(program.ID, incentive.ProgramStatusOngoing), - keyIncentiveProgram(program.ID, incentive.ProgramStatusCompleted), + if program.ID == 0 { + return incentive.ErrInvalidProgramID.Wrap("zero") } - - kvStore := k.KVStore(ctx) - for _, key := range keys { - // always clear the program from the status it was prevously stored under - kvStore.Delete(key) + s, err := k.incentiveProgramStatus(ctx, program.ID) + if err != nil { + return err + } + // error if program exists but not with intended status + if s != incentive.ProgramStatusNotExist && s != status { + return sdkerrors.ErrInvalidRequest.Wrapf("program %d already exists with status %d", program.ID, s) } + kvStore := k.KVStore(ctx) key := keyIncentiveProgram(program.ID, status) - bz, err := k.cdc.Marshal(&program) + return store.SetObject(kvStore, k.cdc, key, &program, "incentive program") +} + +// deleteIncentiveProgram deletes an incentive program. Returns an error if the program +// did not exist or was found with two different statuses. +func (k Keeper) deleteIncentiveProgram(ctx sdk.Context, id uint32) error { + status, err := k.incentiveProgramStatus(ctx, id) if err != nil { return err } - kvStore.Set(key, bz) + if status == incentive.ProgramStatusNotExist { + return sdkerrors.ErrNotFound.Wrapf("program %d", id) + } + + kvStore := k.KVStore(ctx) + key := keyIncentiveProgram(id, status) + kvStore.Delete(key) return nil } @@ -162,125 +153,90 @@ func (k Keeper) setNextProgramID(ctx sdk.Context, id uint32) error { } // getLastRewardsTime gets the last unix time incentive rewards were computed globally by EndBlocker. -func (k Keeper) getLastRewardsTime(ctx sdk.Context) uint64 { - return store.GetUint64(k.KVStore(ctx), keyPrefixLastRewardsTime, "last reward time") +// panics if it would return a negative value. +func (k Keeper) GetLastRewardsTime(ctx sdk.Context) int64 { + t := store.GetInt64(k.KVStore(ctx), keyPrefixLastRewardsTime, "last reward time") + if t < 0 { + panic("negative last reward time") + } + return t } // setLastRewardsTime sets the last unix time incentive rewards were computed globally by EndBlocker. -func (k Keeper) setLastRewardsTime(ctx sdk.Context, time uint64) error { - prev := k.getLastRewardsTime(ctx) - if time < prev { +// does not accept negative unix time. +func (k Keeper) setLastRewardsTime(ctx sdk.Context, time int64) error { + prev := k.GetLastRewardsTime(ctx) + if time < 0 || time < prev { return incentive.ErrDecreaseLastRewardTime.Wrapf("%d to %d", time, prev) } - return store.SetUint64(k.KVStore(ctx), keyPrefixLastRewardsTime, time, "last reward time") + return store.SetInt64(k.KVStore(ctx), keyPrefixLastRewardsTime, time, "last reward time") } // getTotalBonded retrieves the total amount of uTokens of a given denom which are bonded to the incentive module -func (k Keeper) getTotalBonded(ctx sdk.Context, denom string, tier incentive.BondTier) sdk.Coin { - key := keyTotalBonded(denom, tier) +func (k Keeper) getTotalBonded(ctx sdk.Context, denom string) sdk.Coin { + key := keyTotalBonded(denom) amount := store.GetInt(k.KVStore(ctx), key, "total bonded") return sdk.NewCoin(denom, amount) } -// getTotalUnbonding retrieves the total amount of uTokens of a given denom which are unbonding from -// the incentive module -func (k Keeper) getTotalUnbonding(ctx sdk.Context, denom string, tier incentive.BondTier) sdk.Coin { - key := keyTotalUnbonding(denom, tier) - amount := store.GetInt(k.KVStore(ctx), key, "total unbonding") - return sdk.NewCoin(denom, amount) -} - -// getBonded retrieves the amount of uTokens of a given denom which are bonded to a single tier by an account -func (k Keeper) getBonded(ctx sdk.Context, addr sdk.AccAddress, denom string, tier incentive.BondTier) sdk.Coin { - key := keyBondAmount(addr, denom, tier) +// GetBonded retrieves the amount of uTokens of a given denom which are bonded by an account +func (k Keeper) GetBonded(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + key := keyBondAmount(addr, denom) amount := store.GetInt(k.KVStore(ctx), key, "bonded amount") return sdk.NewCoin(denom, amount) } -// setBonded sets the amount of uTokens of a given denom which are bonded to a single tier by an account. +// setBonded sets the amount of uTokens of a given denom which are bonded by an account. // Automatically updates TotalBonded as well. // // REQUIREMENT: This is the only function which is allowed to set TotalBonded. -func (k Keeper) setBonded(ctx sdk.Context, - addr sdk.AccAddress, uToken sdk.Coin, tier incentive.BondTier, -) error { +func (k Keeper) setBonded(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error { // compute the change in bonded amount (can be negative when bond decreases) - delta := uToken.Amount.Sub(k.getBonded(ctx, addr, uToken.Denom, tier).Amount) + delta := uToken.Amount.Sub(k.GetBonded(ctx, addr, uToken.Denom).Amount) // Set bond amount - key := keyBondAmount(addr, uToken.Denom, tier) + key := keyBondAmount(addr, uToken.Denom) if err := store.SetInt(k.KVStore(ctx), key, uToken.Amount, "bonded amount"); err != nil { return err } // Update total bonded for this utoken denom using the computed change - total := k.getTotalBonded(ctx, uToken.Denom, tier) - totalkey := keyTotalBonded(uToken.Denom, tier) + total := k.getTotalBonded(ctx, uToken.Denom) + totalkey := keyTotalBonded(uToken.Denom) return store.SetInt(k.KVStore(ctx), totalkey, total.Amount.Add(delta), "total bonded") } -// getUnbonding retrieves the amount of uTokens of a given denom which are unbonding from a single tier by an account -func (k Keeper) getUnbondingAmount(ctx sdk.Context, addr sdk.AccAddress, denom string, tier incentive.BondTier, -) sdk.Coin { - key := keyUnbondAmount(addr, denom, tier) +// getUnbonding retrieves the amount of uTokens of a given denom which are unbonding by an account +func (k Keeper) getUnbondingAmount(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + key := keyUnbondAmount(addr, denom) amount := store.GetInt(k.KVStore(ctx), key, "unbonding amount") return sdk.NewCoin(denom, amount) } -// GetRewardAccumulator retrieves the reward accumulator of a reward token for a single bonded uToken and tier - -// for example, how much UMEE (reward) would have been earned by 1 ATOM bonded to the middle tier since genesis. -func (k Keeper) GetRewardAccumulator(ctx sdk.Context, bondDenom, rewardDenom string, tier incentive.BondTier, -) sdk.DecCoin { - key := keyRewardAccumulator(bondDenom, rewardDenom, tier) - amount := store.GetDec(k.KVStore(ctx), key, "reward accumulator") - return sdk.NewDecCoinFromDec(rewardDenom, amount) -} - -// SetRewardAccumulator sets the reward accumulator of a reward token for a single bonded uToken and tier. -func (k Keeper) SetRewardAccumulator(ctx sdk.Context, - bondDenom string, reward sdk.DecCoin, tier incentive.BondTier, -) error { - key := keyRewardAccumulator(bondDenom, reward.Denom, tier) - return store.SetDec(k.KVStore(ctx), key, reward.Amount, "reward accumulator") -} - -// GetRewardTracker retrieves the reward tracker of a reward token for a single bonded uToken and tier on one account - -// this is the value of the reward accumulator for those specific denoms and tier the last time this account performed -// and action that requires a reward tracker update (i.e. Bond, Claim, BeginUnbonding, or being Liquidated). -func (k Keeper) GetRewardTracker(ctx sdk.Context, - addr sdk.AccAddress, bondDenom, rewardDenom string, tier incentive.BondTier, -) sdk.DecCoin { - key := keyRewardTracker(addr, bondDenom, rewardDenom, tier) - amount := store.GetDec(k.KVStore(ctx), key, "reward tracker") - return sdk.NewDecCoinFromDec(rewardDenom, amount) -} - -// setRewardTracker sets the reward tracker of a reward token for a single bonded uToken and tier for an address. -func (k Keeper) setRewardTracker(ctx sdk.Context, - addr sdk.AccAddress, bondDenom string, reward sdk.DecCoin, tier incentive.BondTier, -) error { - key := keyRewardTracker(addr, bondDenom, reward.Denom, tier) - return store.SetDec(k.KVStore(ctx), key, reward.Amount, "reward tracker") +// getTotalUnbonding retrieves the total amount of uTokens of a given denom which are unbonding from +// the incentive module +func (k Keeper) getTotalUnbonding(ctx sdk.Context, denom string) sdk.Coin { + key := keyTotalUnbonding(denom) + amount := store.GetInt(k.KVStore(ctx), key, "total unbonding") + return sdk.NewCoin(denom, amount) } -// getUnbondings gets all unbondings currently associated with an account, bonded denom, and tier. -func (k Keeper) getUnbondings(ctx sdk.Context, addr sdk.AccAddress, denom string, tier incentive.BondTier, -) []incentive.Unbonding { - key := keyUnbondings(addr, denom, tier) +// getUnbondings gets all unbondings currently associated with an account and bonded denom. +func (k Keeper) getUnbondings(ctx sdk.Context, addr sdk.AccAddress, denom string) []incentive.Unbonding { + key := keyUnbondings(addr, denom) kvStore := k.KVStore(ctx) accUnbondings := incentive.AccountUnbondings{} - bz := kvStore.Get(key) - if len(bz) == 0 { + ok := store.GetObject(kvStore, k.cdc, key, &accUnbondings, "account unbondings") + if !ok { return []incentive.Unbonding{} } - - k.cdc.MustUnmarshal(bz, &accUnbondings) return accUnbondings.Unbondings } -// setUnbondings stores the list of unbondings currently associated with an account, denom, and tier. +// setUnbondings stores the list of unbondings currently associated with an account and denom. // It also updates the account's stored unbonding amounts, and thus the module's total unbonding as well. +// Any zero-amount unbondings are automatically filtered out before storage. // // REQUIREMENT: This is the only function which is allowed to set unbonding amounts and total unbonding. func (k Keeper) setUnbondings(ctx sdk.Context, unbondings incentive.AccountUnbondings) error { @@ -290,44 +246,91 @@ func (k Keeper) setUnbondings(ctx sdk.Context, unbondings incentive.AccountUnbon // catches invalid and empty addresses return err } - tier, err := bondTier(unbondings.Tier) - if err != nil { - // catches invalid or unspecified tier - return err + denom := unbondings.UToken + + // remove any zero-amount unbondings before setting + nonzeroUnbondings := []incentive.Unbonding{} + for _, u := range unbondings.Unbondings { + if u.UToken.Amount.IsPositive() { + nonzeroUnbondings = append(nonzeroUnbondings, u) + } } - denom := unbondings.Denom + unbondings.Unbondings = nonzeroUnbondings - // compute the new total unbonding specific to this account, denom, and tier + // compute the new total unbonding specific to this account and denom. newUnbonding := sdk.ZeroInt() for _, u := range unbondings.Unbondings { - newUnbonding = newUnbonding.Add(u.Amount.Amount) + newUnbonding = newUnbonding.Add(u.UToken.Amount) } // compute the change in unbonding amount (can be negative when unbonding decreases) - delta := newUnbonding.Sub(k.getUnbondingAmount(ctx, addr, denom, tier).Amount) + delta := newUnbonding.Sub(k.getUnbondingAmount(ctx, addr, denom).Amount) // Update unbonding amount - amountKey := keyUnbondAmount(addr, denom, tier) + amountKey := keyUnbondAmount(addr, denom) if err := store.SetInt(k.KVStore(ctx), amountKey, newUnbonding, "unbonding amount"); err != nil { return err } // Update total unbonding for this utoken denom using the computed change - total := k.getTotalUnbonding(ctx, denom, tier) - totalkey := keyTotalUnbonding(denom, tier) + total := k.getTotalUnbonding(ctx, denom) + totalkey := keyTotalUnbonding(denom) if err := store.SetInt(k.KVStore(ctx), totalkey, total.Amount.Add(delta), "total unbonding"); err != nil { return err } // set list of unbondings - key := keyUnbondings(addr, unbondings.Denom, tier) + key := keyUnbondings(addr, unbondings.UToken) if len(unbondings.Unbondings) == 0 { // clear store on no unbondings remaining kvStore.Delete(key) } - bz, err := k.cdc.Marshal(&unbondings) - if err != nil { - return err + return store.SetObject(kvStore, k.cdc, key, &unbondings, "account unbondings") +} + +// getRewardAccumulator retrieves the reward accumulator of all reward tokens for a single bonded uToken - +// for example, how much UMEE, ATOM, etc (reward) would have been earned by 1 ATOM (bonded) since genesis. +func (k Keeper) getRewardAccumulator(ctx sdk.Context, bondDenom string) incentive.RewardAccumulator { + key := keyRewardAccumulator(bondDenom) + accumulator := incentive.RewardAccumulator{} + ok := store.GetObject(k.KVStore(ctx), k.cdc, key, &accumulator, "reward accumulator") + if ok { + return accumulator } - kvStore.Set(key, bz) - return nil + return incentive.NewRewardAccumulator(bondDenom, 0, sdk.NewDecCoins()) +} + +// setRewardAccumulator sets the full reward accumulator for a single bonded uToken. +func (k Keeper) setRewardAccumulator(ctx sdk.Context, accumulator incentive.RewardAccumulator) error { + key := keyRewardAccumulator(accumulator.UToken) + return store.SetObject(k.KVStore(ctx), k.cdc, key, &accumulator, "reward accumulator") +} + +// GetRewardTracker retrieves the reward tracker for a single bonded uToken on one account - this is the value of +// the reward accumulator for that specific denom the last time this account performed any action that required +// a reward tracker update (i.e. Bond, Claim, BeginUnbonding, or being Liquidated). +func (k Keeper) getRewardTracker(ctx sdk.Context, addr sdk.AccAddress, bondDenom string) incentive.RewardTracker { + key := keyRewardTracker(addr, bondDenom) + tracker := incentive.RewardTracker{} + ok := store.GetObject(k.KVStore(ctx), k.cdc, key, &tracker, "reward tracker") + if ok { + return tracker + } + return incentive.NewRewardTracker(addr.String(), bondDenom, sdk.NewDecCoins()) +} + +// setRewardTracker sets the reward tracker for a single bonded uToken for an address. +// automatically clear the entry if rewards are all zero. +func (k Keeper) setRewardTracker(ctx sdk.Context, tracker incentive.RewardTracker) error { + key := keyRewardTracker(sdk.MustAccAddressFromBech32(tracker.Account), tracker.UToken) + if tracker.Rewards.IsZero() { + k.clearRewardTracker(ctx, sdk.MustAccAddressFromBech32(tracker.Account), tracker.UToken) + return nil + } + return store.SetObject(k.KVStore(ctx), k.cdc, key, &tracker, "reward tracker") +} + +// clearRewardTracker clears a reward tracker matching a specific account + bonded uToken from the store +func (k Keeper) clearRewardTracker(ctx sdk.Context, addr sdk.AccAddress, bondDenom string) { + key := keyRewardTracker(addr, bondDenom) + k.KVStore(ctx).Delete(key) } diff --git a/x/incentive/keeper/unbonding.go b/x/incentive/keeper/unbonding.go index 92ded6cfca..611a758c0c 100644 --- a/x/incentive/keeper/unbonding.go +++ b/x/incentive/keeper/unbonding.go @@ -8,34 +8,112 @@ import ( // addUnbonding creates an unbonding and adds it to the account's current unbondings in the store. // Assumes the validity of the unbonding has already been checked. Also updates unbonding amounts // indirectly by calling setUnbondings. -func (k Keeper) addUnbonding(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin, tier incentive.BondTier) error { - if err := k.decreaseBond(ctx, addr, tier, uToken); err != nil { +func (k Keeper) addUnbonding(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error { + if err := k.decreaseBond(ctx, addr, uToken); err != nil { return err } + unbondingDuration := k.GetParams(ctx).UnbondingDuration + if unbondingDuration == 0 { + // For unbonding duration zero, return after decreasing bonded amount + // without creating an unbonding struct + return nil + } + currentTime := k.GetLastRewardsTime(ctx) unbonding := incentive.Unbonding{ - Amount: uToken, - End: k.getLastRewardsTime(ctx) + k.unbondTime(ctx, tier), + UToken: uToken, + // Start and end time are stored based on current parameters, and + // the stored end time does not change even if the module's unbonding + // duration parameter is changed. The unbonding will still end early + // if that parameter is reduced though. + Start: currentTime, + End: currentTime + unbondingDuration, } unbondings := incentive.AccountUnbondings{ Account: addr.String(), - Tier: uint32(tier), - Denom: uToken.Denom, - Unbondings: append(k.getUnbondings(ctx, addr, uToken.Denom, tier), unbonding), + UToken: uToken.Denom, + Unbondings: append(k.getUnbondings(ctx, addr, uToken.Denom), unbonding), } return k.setUnbondings(ctx, unbondings) } -// unbondTime returns how long a given tier must wait to unbond, in seconds. -// returns zero on invalid unbond tier, though this will not happen in practice. -func (k Keeper) unbondTime(ctx sdk.Context, tier incentive.BondTier) uint64 { - switch tier { - case incentive.BondTierLong: - return k.getUnbondingDurationLong(ctx) - case incentive.BondTierMiddle: - return k.getUnbondingDurationMiddle(ctx) - case incentive.BondTierShort: - return k.getUnbondingDurationShort(ctx) - default: - return 0 +// cleanupUnbondings finishes any unbondings on an account which have reached their end time +func (k Keeper) cleanupUnbondings(ctx sdk.Context, addr sdk.AccAddress) error { + time := k.GetLastRewardsTime(ctx) + duration := k.GetParams(ctx).UnbondingDuration + bondedDenoms, err := k.getAllBondDenoms(ctx, addr) + if err != nil { + return err + } + + for _, denom := range bondedDenoms { + storedUnbondings := k.getUnbondings(ctx, addr, denom) + newUnbondings := incentive.NewAccountUnbondings( + addr.String(), + denom, + []incentive.Unbonding{}, + ) + for _, u := range storedUnbondings { + if u.End > time && u.Start+duration > time { + // If unbonding has passed neither its original end time nor its dynamic end time based on parameters + // the unbonding is still ongoing, and can be counted normally. + // This logic allows a reduction in unbonding duration param to speed up existing unbondings. + newUnbondings.Unbondings = append(newUnbondings.Unbondings, u) + } + // Otherwise, this unbonding is completed, and will be cleared. + } + // Set new unbondings list, which contains only unbondings which are still ongoing + if err := k.setUnbondings(ctx, newUnbondings); err != nil { + return err + } + } + return nil +} + +// reduceBondTo is used by MsgEmergencyUnbond and by liquidation hooks to immediately unbond collateral +// which is bonded to or unbonding from an account. The uToken it accepts as input is the amount of +// collateral which the borrower is left with: bonds and unbondings must be removed until they do not +// total to more than this amount. +func (k Keeper) reduceBondTo(ctx sdk.Context, addr sdk.AccAddress, newCollateral sdk.Coin) error { + // detect if bonded or unbonding collateral needs to be forcefully reduced + bonded, unbonding, unbondings := k.BondSummary(ctx, addr, newCollateral.Denom) + if bonded.Amount.Add(unbonding.Amount).LTE(newCollateral.Amount) { + // nothing needs to happen + return nil + } + if bonded.Amount.GTE(newCollateral.Amount) { + // if remaining collateral is less than or equal to bonded amount, + // all in-progress unbondings and potentially some bonded tokens + // must be instantly unbonded. + if err := k.setBonded(ctx, addr, newCollateral); err != nil { + return err + } + // set new (empty) list of unbondings, which clears it from store + au := incentive.AccountUnbondings{ + Account: addr.String(), + UToken: newCollateral.Denom, + Unbondings: []incentive.Unbonding{}, + } + return k.setUnbondings(ctx, au) + } + // if we have not returned yet, the only some in-progress unbondings will be + // instantly unbonded. + amountToUnbond := bonded.Amount.Add(unbonding.Amount).Sub(newCollateral.Amount) + for _, u := range unbondings { + // for ongoing unbondings, starting with the oldest + specificReduction := sdk.MinInt(amountToUnbond, u.UToken.Amount) + // reduce the in-progress unbonding amount, and the remaining instant unbond + u.UToken.Amount = u.UToken.Amount.Sub(specificReduction) + amountToUnbond = amountToUnbond.Sub(specificReduction) + // if no more unbondings need to be reduced, break out of the loop early + if amountToUnbond.IsZero() { + break + } + } + // set new (reduced but not empty) list of unbondings + au := incentive.AccountUnbondings{ + Account: addr.String(), + UToken: newCollateral.Denom, + Unbondings: unbondings, } + return k.setUnbondings(ctx, au) } diff --git a/x/incentive/keeper/unit_test.go b/x/incentive/keeper/unit_test.go new file mode 100644 index 0000000000..7b873d5165 --- /dev/null +++ b/x/incentive/keeper/unit_test.go @@ -0,0 +1,179 @@ +package keeper + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + "github.com/umee-network/umee/v4/tests/tsdk" + "github.com/umee-network/umee/v4/util/coin" + "github.com/umee-network/umee/v4/x/incentive" +) + +// creates keeper with mock leverage keeper +func newTestKeeper(t *testing.T) testKeeper { + // codec and store + cdc := codec.NewProtoCodec(nil) + storeKey := storetypes.NewMemoryStoreKey(incentive.StoreKey) + ctx, _ := tsdk.NewCtxOneStore(t, storeKey) + // keepers + lk := newMockLeverageKeeper() + bk := newMockBankKeeper() + k := NewKeeper(cdc, storeKey, &bk, &lk) + msrv := NewMsgServerImpl(k) + // modify genesis if necessary + gen := incentive.DefaultGenesis() + gen.LastRewardsTime = 1 // initializes last reward time + k.InitGenesis(ctx, *gen) + return testKeeper{k, bk, lk, t, ctx, sdk.ZeroInt(), msrv} +} + +type testKeeper struct { + Keeper + bk mockBankKeeper + lk mockLeverageKeeper + t *testing.T + ctx sdk.Context + setupAccountCounter sdkmath.Int + msrv incentive.MsgServer +} + +// newAccount creates a new account for testing, and funds it with any input tokens. +func (k *testKeeper) newAccount(funds ...sdk.Coin) sdk.AccAddress { + // create a unique address + k.setupAccountCounter = k.setupAccountCounter.Add(sdk.OneInt()) + addrStr := fmt.Sprintf("%-20s", "addr"+k.setupAccountCounter.String()+"_______________") + addr := sdk.AccAddress([]byte(addrStr)) + // we skip accountKeeper SetAccount, because we are using mock bank keeper + k.bk.FundAccount(addr, funds) + return addr +} + +// newBondedAccount creates a new account for testing, and bonds a uToken amount to it. +// For accuracy, it first sets the account's mock leverage collateral to that value. +// A MsgBond is used for the bonding step. +func (k *testKeeper) newBondedAccount(funds ...sdk.Coin) sdk.AccAddress { + // create a unique address + k.setupAccountCounter = k.setupAccountCounter.Add(sdk.OneInt()) + addrStr := fmt.Sprintf("%-20s", "addr"+k.setupAccountCounter.String()+"_______________") + addr := sdk.AccAddress([]byte(addrStr)) + // we skip accountKeeper SetAccount, because we are using mock bank keeper + // first set account's collateral + for _, uToken := range funds { + k.lk.setCollateral(addr, uToken.Denom, uToken.Amount.Int64()) + } + // then bond uTokens, requring no error + k.mustBond(addr, funds...) + return addr +} + +// mustBond bonds utokens to an account and requires no errors. Use when setting up incentive scenarios. +func (k *testKeeper) mustBond(addr sdk.AccAddress, coins ...sdk.Coin) { + for _, coin := range coins { + msg := &incentive.MsgBond{ + Account: addr.String(), + UToken: coin, + } + _, err := k.msrv.Bond(k.ctx, msg) + require.NoError(k.t, err, "bond") + } +} + +// initCommunityFund funds the mock bank keeper's distribution module account with some tokens +func (k *testKeeper) initCommunityFund(funds ...sdk.Coin) { + k.bk.FundModule(disttypes.ModuleName, funds) +} + +// addIncentiveProgram used MsgGovCreateProgram to create and fund (if community funded) an incentive program. +// and requires no errors. Use when setting up incentive scenarios. +func (k *testKeeper) addIncentiveProgram(uDenom string, start, duration int64, reward sdk.Coin, fromCommunity bool, +) { + // govAccAddr := s.app.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String() + govAccAddr := "govAcct" + + program := incentive.IncentiveProgram{ + ID: 0, + StartTime: start, + Duration: duration, + UToken: uDenom, + Funded: false, + TotalRewards: reward, + RemainingRewards: coin.Zero(reward.Denom), + } + + // add program and expect no error + validMsg := &incentive.MsgGovCreatePrograms{ + Authority: govAccAddr, + Title: "Add valid program", + Description: "using addIncentiveProgram helper function", + Programs: []incentive.IncentiveProgram{program}, + FromCommunityFund: fromCommunity, + } + // pass and optionally fund the program from community fund + _, err := k.msrv.GovCreatePrograms(k.ctx, validMsg) + require.Nil(k.t, err, "addIncentiveProgram") +} + +// sponsor a program with tokens and require no errors. Use when setting up incentive scenarios. +func (k *testKeeper) sponsor(addr sdk.AccAddress, programID uint32) { + msg := &incentive.MsgSponsor{ + Sponsor: addr.String(), + Program: programID, + } + _, err := k.msrv.Sponsor(k.ctx, msg) + require.NoError(k.t, err, "sponsor program", programID) +} + +// advanceTime runs the functions normally contained in EndBlocker from the current rewards time +// to a target time a fixed duration later. Requires non-negative duration and an initialized lastRewardsTime. +func (k *testKeeper) advanceTime(duration int64) { + prevTime := k.GetLastRewardsTime(k.ctx) + k.advanceTimeTo(prevTime + duration) +} + +// advanceTimeTo runs the functions normally contained in EndBlocker from the current rewards time +// to a target time. Requires non-negative duration and an initialized lastRewardsTime. +func (k *testKeeper) advanceTimeTo(blockTime int64) { + prevTime := k.GetLastRewardsTime(k.ctx) + if prevTime <= 0 { + panic("last rewards time not initialized") + } + + require.Nil(k.t, k.updateRewards(k.ctx, blockTime), "update rewards") + require.Nil(k.t, k.updatePrograms(k.ctx), "update programs") + require.Equal(k.t, blockTime, k.GetLastRewardsTime(k.ctx)) +} + +// getProgram gets an incentive program by ID and requires no error +func (k *testKeeper) getProgram(programID uint32) incentive.IncentiveProgram { + program, _, err := k.getIncentiveProgram(k.ctx, programID) + require.NoError(k.t, err, "get program", programID) + return program +} + +// programStatus checks whether an incentive program's status. Also asserts that +// the program exists. +func (k *testKeeper) programStatus(programID uint32) incentive.ProgramStatus { + _, status, err := k.getIncentiveProgram(k.ctx, programID) + require.NoError(k.t, err, "get program (programStatus)", programID) + return status +} + +// programFunded checks whether an incentive program is funded. Also asserts that +// the program exists and that its funded status is not contradictory with its rewards. +func (k *testKeeper) programFunded(programID uint32) bool { + program, _, err := k.getIncentiveProgram(k.ctx, programID) + require.NoError(k.t, err, "get program (programFunded)", programID) + if !program.Funded { + require.Equal(k.t, program.RemainingRewards.Amount, sdk.ZeroInt(), + "non-funded must have zero remaining rewards. program id", programID) + } + return program.Funded +} diff --git a/x/incentive/keeper/update.go b/x/incentive/keeper/update.go index 412e951651..f9ddd16fa5 100644 --- a/x/incentive/keeper/update.go +++ b/x/incentive/keeper/update.go @@ -6,14 +6,191 @@ import ( "github.com/umee-network/umee/v4/x/incentive" ) -// updateAccount finishes any unbondings associated with an account which have ended and claims any pending rewards. +var ten = sdk.MustNewDecFromStr("10") + +// UpdateAccount finishes any unbondings associated with an account which have ended and claims any pending rewards. // It returns the amount of rewards claimed. // +// Unlike updateRewards and updatePrograms, this function is not called during EndBlock. +// // REQUIREMENT: This function must be called during any message or hook which creates an unbonding or updates // bonded amounts. Leverage hooks which decrease borrower collateral must also call this before acting. // This ensures that between any two consecutive claims by a single account, bonded amounts were constant -// on that account for each bond tier and collateral uToken denom. -func (k Keeper) updateAccount(_ sdk.Context, _ sdk.AccAddress) (sdk.Coins, error) { - // TODO - return sdk.Coins{}, incentive.ErrNotImplemented +// on that account for each collateral uToken denom. +func (k Keeper) UpdateAccount(ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, error) { + // unbondings have already been subtracted from bonded amounts when they are started, + // so it is fine to finish completed unbondings before claiming rewards. + if err := k.cleanupUnbondings(ctx, addr); err != nil { + return sdk.NewCoins(), err + } + + return k.claimRewards(ctx, addr) +} + +// updateRewards updates any rewardAccumulators associated with ongoing incentive programs +// based on the time elapsed between LastRewardTime and block time. It decreases active +// incentive programs' RemainingRewards by the amount of coins distributed. +// Also sets module's LastRewardsTime to block time. +func (k Keeper) updateRewards(ctx sdk.Context, blockTime int64) error { + prevTime := k.GetLastRewardsTime(ctx) + if prevTime > blockTime { + return incentive.ErrDecreaseLastRewardTime + } + if prevTime == blockTime { + return nil + } + timeElapsed := blockTime - prevTime + ongoingPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusOngoing) + if err != nil { + return err + } + for _, p := range ongoingPrograms { + bondedDenom := p.UToken + bonded := k.getTotalBonded(ctx, bondedDenom) + + // calculate the amount of time (in seconds) that remained on the incentive + // program after the previous calculation. + prevRemainingTime := (p.StartTime + p.Duration) - prevTime + // if remaining time was zero or negative, but program had not been removed + // from ongoing programs, using a value of 1 second ensures all its remaining + // rewards are distributed + if prevRemainingTime < 1 { + prevRemainingTime = 1 + } + + // The portion of a program's remaining rewards, + // ranging from 0 to 1, which will be distributed this + // block. The max value of 1 means 100% of remaining rewards + // will be used, as occurs when a program is ending. + programRewardsFraction := sdk.MinDec( + sdk.OneDec(), + sdk.NewDecFromInt(sdk.NewInt(timeElapsed)). + Quo(sdk.NewDec(prevRemainingTime))) + + // each incentive program has only one reward denom + rewardDenom := p.RemainingRewards.Denom + + // get this block's rewards (as a token amount) for this incentive program only + thisBlockRewards := sdk.NewCoin( + rewardDenom, + sdk.NewDecFromInt(p.RemainingRewards.Amount).Mul(programRewardsFraction).TruncateInt()) + + // get expected increase of bondDenom's rewardAccumulator of reward denom, + // by dividing this block's rewards proportionally among bonded uTokens, + // and adjusting for the reward accumulator's exponent + accumulator := k.getRewardAccumulator(ctx, bondedDenom) + accumulatorIncrease := sdk.NewDecFromInt(thisBlockRewards.Amount). + Mul(ten.Power(uint64(accumulator.Exponent))). + Quo(sdk.NewDecFromInt(bonded.Amount)) + + // if accumulator increase is so small it rounds to zero even after power adjustment, + // no rewards were distributed + if accumulatorIncrease.IsZero() { + continue + } + + // if nonzero, increase reward accumulator using rewards from this incentive program + // and subtract them from that program's remaining rewards + accumulator.Rewards = accumulator.Rewards.Add(sdk.NewDecCoinFromDec(rewardDenom, accumulatorIncrease)) + p.RemainingRewards = p.RemainingRewards.Sub(thisBlockRewards) + + // update program state and reward accumulator + if err := k.setIncentiveProgram(ctx, p, incentive.ProgramStatusOngoing); err != nil { + return err + } + if err := k.setRewardAccumulator(ctx, accumulator); err != nil { + return err + } + } + + // After updates, module's LastRewardTime increases to current block time + return k.setLastRewardsTime(ctx, blockTime) +} + +// updatePrograms moves any incentive programs which have reached their end time from Ongoing to Completed, +// and moves any funded programs which should start from Upcoming to Ongoing. Non-funded programs which +// would start are moved to completed status instead. Uses the current LastRewardsTime but does not update it. +func (k Keeper) updatePrograms(ctx sdk.Context) error { + blockTime := k.GetLastRewardsTime(ctx) + ongoingPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusOngoing) + if err != nil { + return err + } + for _, op := range ongoingPrograms { + // if an ongoing program is ending, move it to completed programs without modifying any fields + if blockTime >= op.Duration+op.StartTime { + if err := k.moveIncentiveProgram(ctx, op.ID, incentive.ProgramStatusCompleted); err != nil { + return err + } + } + } + upcomingPrograms, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusUpcoming) + if err != nil { + return err + } + for _, up := range upcomingPrograms { + // if an upcoming program has reached its start time + if blockTime >= up.StartTime { + // prepare to start the program + newStatus := incentive.ProgramStatusOngoing + // or immediately cancel it if it was not funded + if !up.Funded { + newStatus = incentive.ProgramStatusCompleted + } + if err := k.moveIncentiveProgram(ctx, up.ID, newStatus); err != nil { + return err + } + } + } + + // Note that even if a program had a duration shorter than the time between blocks, this function's + // order of ending eligible ongoing programs before starting eligible upcoming ones ensures that each + // program will be active for updateRewards for at least one full block. (The same program will not be + // both started and ended in the same block._ + return nil +} + +// EndBlock updates incentive programs and reward accumulators, then sets LastRewardTime +// to the current block time. Also protects against negative time elapsed (without causing chain halt). +func (k Keeper) EndBlock(ctx sdk.Context) error { + blockTime := ctx.BlockTime().Unix() + if blockTime < 0 { + k.Logger(ctx).With("Negative").Error( + incentive.ErrDecreaseLastRewardTime.Error(), + "block time", blockTime, + ) + return nil + } + + prevTime := k.GetLastRewardsTime(ctx) + if prevTime <= 0 { + // if stored LastRewardTime is zero (or negative), either the chain has just started or the genesis file has been + // modified intentionally. In either case, proceed as if 0 seconds have passed since the last block, + // thus accruing no rewards and setting the current BlockTime as the new starting point. + prevTime = blockTime + } + + if blockTime <= prevTime { + // Avoids this and related issues: https://github.com/tendermint/tendermint/issues/8773 + k.Logger(ctx).With("EndBlocker will wait for block time > prevRewardTime").Error( + incentive.ErrDecreaseLastRewardTime.Error(), + "current", blockTime, + "prev", prevTime, + ) + + // if LastRewardTime appears to be in the future, do nothing (besides logging) and leave + // LastRewardTime at its stored value. This will repeat every block until BlockTime exceeds + // LastRewardTime. + return nil + } + + // Implications of updating reward accumulators and PrevRewardTime before starting/completing incentive programs: + // - if an incentive program starts this block, it does not disburse any rewards this block + // - if an incentive program completes this block, it distributes its remaining rewards before being completed + // - in the case of a chain halt which misses a program's start time, rewards before its late start are skipped + // - in the case of a chain halt which misses a program's end time, remaining rewards are correctly distributed + if err := k.updateRewards(ctx, prevTime); err != nil { + return err + } + return k.updatePrograms(ctx) } diff --git a/x/incentive/keys.go b/x/incentive/keys.go index ac5f23505d..368380db69 100644 --- a/x/incentive/keys.go +++ b/x/incentive/keys.go @@ -15,34 +15,19 @@ const ( ) type ( - BondTier uint8 ProgramStatus uint8 ) const ( - // BondTierUnspecified is used in functions which query unbondings, to indicate that all tiers should be counted - BondTierUnspecified BondTier = iota - BondTierShort - BondTierMiddle - BondTierLong -) - -const ( - ProgramStatusUpcoming ProgramStatus = iota + ProgramStatusNotExist ProgramStatus = iota + ProgramStatusUpcoming ProgramStatusOngoing ProgramStatusCompleted ) func (p ProgramStatus) Validate() error { - if p > ProgramStatusCompleted { + if p == ProgramStatusNotExist || p > ProgramStatusCompleted { return ErrInvalidProgramStatus.Wrapf("%d", p) } return nil } - -func (t BondTier) Validate(canBeUnspecified bool) error { - if t > BondTierLong || (!canBeUnspecified && t == BondTierUnspecified) { - return ErrInvalidTier.Wrapf("%d", t) - } - return nil -} diff --git a/x/incentive/keys_test.go b/x/incentive/keys_test.go index d10c2efe85..c90af14245 100644 --- a/x/incentive/keys_test.go +++ b/x/incentive/keys_test.go @@ -6,31 +6,6 @@ import ( "gotest.tools/v3/assert" ) -func TestValidateTier(t *testing.T) { - cases := []struct { - desc string - tier BondTier - canBeUnspecified bool - expectError error - }{ - {"valid unspecified tier", 0, true, nil}, - {"invalid unspecified tier", 0, false, ErrInvalidTier}, - {"short tier", BondTierShort, false, nil}, - {"middle tier", BondTierMiddle, false, nil}, - {"long tier", BondTierLong, false, nil}, - {"invalid tier", BondTierLong + 1, false, ErrInvalidTier}, - } - - for _, c := range cases { - err := c.tier.Validate(c.canBeUnspecified) - if c.expectError == nil { - assert.NilError(t, err, c.desc) - } else { - assert.ErrorContains(t, err, c.expectError.Error(), c.desc) - } - } -} - func TestValidateProgramStatus(t *testing.T) { cases := []struct { desc string diff --git a/x/incentive/module/abci.go b/x/incentive/module/abci.go index 280465d3e0..b882fc1dae 100644 --- a/x/incentive/module/abci.go +++ b/x/incentive/module/abci.go @@ -10,8 +10,6 @@ import ( // EndBlocker implements EndBlock for the x/incentive module. func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate { - util.Panic(k.UpdateRewards(ctx)) - - // TODO #1749: Programs change in status, and reward distribution amounts are updated + util.Panic(k.EndBlock(ctx)) return []abci.ValidatorUpdate{} } diff --git a/x/incentive/module/genesis.go b/x/incentive/module/genesis.go new file mode 100644 index 0000000000..8c4dfe4ae6 --- /dev/null +++ b/x/incentive/module/genesis.go @@ -0,0 +1,19 @@ +package module + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/umee-network/umee/v4/x/incentive" + "github.com/umee-network/umee/v4/x/incentive/keeper" +) + +// InitGenesis initializes the x/incentive module's state from a provided genesis +// state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState incentive.GenesisState) { + k.InitGenesis(ctx, genState) +} + +// ExportGenesis returns the x/incentive module's exported genesis state. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *incentive.GenesisState { + return k.ExportGenesis(ctx) +} diff --git a/x/incentive/module/module.go b/x/incentive/module/module.go new file mode 100644 index 0000000000..0f3376eac6 --- /dev/null +++ b/x/incentive/module/module.go @@ -0,0 +1,175 @@ +package module + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/umee-network/umee/v4/x/incentive" + "github.com/umee-network/umee/v4/x/incentive/client/cli" + "github.com/umee-network/umee/v4/x/incentive/keeper" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic implements the AppModuleBasic interface for the x/leverage +// module. +type AppModuleBasic struct { + cdc codec.Codec +} + +func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the x/incentive module's name. +func (AppModuleBasic) Name() string { + return incentive.ModuleName +} + +// RegisterLegacyAminoCodec registers the x/incentive module's types with a legacy +// Amino codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + incentive.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types. +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + incentive.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the x/incentive module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(incentive.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the x/incentive module. +func (AppModuleBasic) ValidateGenesis( + cdc codec.JSONCodec, + _ client.TxEncodingConfig, + bz json.RawMessage, +) error { + var genState incentive.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", incentive.ModuleName, err) + } + + return genState.Validate() +} + +// Deprecated: RegisterRESTRoutes performs a no-op. Querying is delegated to the +// gRPC service. +func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the x/leverage +// module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := incentive.RegisterQueryHandlerClient(context.Background(), mux, incentive.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} + +// GetTxCmd returns the x/incentive module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the x/incentive module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// AppModule implements the AppModule interface for the x/incentive module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + bankKeeper incentive.BankKeeper + leverageKeeper incentive.LeverageKeeper +} + +func NewAppModule( + cdc codec.Codec, keeper keeper.Keeper, bk incentive.BankKeeper, lk incentive.LeverageKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + bankKeeper: bk, + leverageKeeper: lk, + } +} + +// Name returns the x/incentive module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +func (AppModule) ConsensusVersion() uint64 { + return 1 +} + +// Deprecated: Route returns the message routing key for the x/incentive module. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute returns the x/incentive module's query routing key. +func (AppModule) QuerierRoute() string { return incentive.QuerierRoute } + +// LegacyQuerierHandler returns a no-op legacy querier. +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return func(sdk.Context, []string, abci.RequestQuery) ([]byte, error) { + return nil, fmt.Errorf("legacy querier not supported for the x/%s module", incentive.ModuleName) + } +} + +// RegisterServices registers gRPC services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + incentive.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + incentive.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) +} + +// RegisterInvariants registers the x/incentive module's invariants. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + keeper.RegisterInvariants(ir, am.keeper) +} + +// InitGenesis performs the x/incentive module's genesis initialization. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genState incentive.GenesisState + cdc.MustUnmarshalJSON(data, &genState) + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the x/incentive module's exported genesis state as raw +// JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the x/incentive module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the x/incentive module. +// It returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return EndBlocker(ctx, am.keeper) +} diff --git a/x/incentive/msgs.go b/x/incentive/msgs.go index c0f1df8bd9..68f0b7892c 100644 --- a/x/incentive/msgs.go +++ b/x/incentive/msgs.go @@ -8,8 +8,9 @@ import ( var ( _ sdk.Msg = &MsgClaim{} - _ sdk.Msg = &MsgBeginUnbonding{} _ sdk.Msg = &MsgBond{} + _ sdk.Msg = &MsgBeginUnbonding{} + _ sdk.Msg = &MsgEmergencyUnbond{} _ sdk.Msg = &MsgSponsor{} _ sdk.Msg = &MsgGovSetParams{} _ sdk.Msg = &MsgGovCreatePrograms{} @@ -42,16 +43,15 @@ func (msg MsgClaim) Route() string { return RouterKey } // Type implements the sdk.Msg interface. func (msg MsgClaim) Type() string { return sdk.MsgTypeURL(&msg) } -func NewMsgBond(account sdk.AccAddress, tier uint32, asset sdk.Coin) *MsgBond { +func NewMsgBond(account sdk.AccAddress, asset sdk.Coin) *MsgBond { return &MsgBond{ Account: account.String(), - Tier: tier, - Asset: asset, + UToken: asset, } } func (msg MsgBond) ValidateBasic() error { - return validateSenderAssetTier(msg.Account, msg.Tier, &msg.Asset) + return validateSenderAsset(msg.Account, &msg.UToken) } func (msg MsgBond) GetSigners() []sdk.AccAddress { @@ -70,16 +70,15 @@ func (msg MsgBond) Route() string { return RouterKey } // Type implements the sdk.Msg interface. func (msg MsgBond) Type() string { return sdk.MsgTypeURL(&msg) } -func NewMsgBeginUnbonding(account sdk.AccAddress, tier uint32, asset sdk.Coin) *MsgBeginUnbonding { +func NewMsgBeginUnbonding(account sdk.AccAddress, asset sdk.Coin) *MsgBeginUnbonding { return &MsgBeginUnbonding{ Account: account.String(), - Tier: tier, - Asset: asset, + UToken: asset, } } func (msg MsgBeginUnbonding) ValidateBasic() error { - return validateSenderAssetTier(msg.Account, msg.Tier, &msg.Asset) + return validateSenderAsset(msg.Account, &msg.UToken) } func (msg MsgBeginUnbonding) GetSigners() []sdk.AccAddress { @@ -98,11 +97,37 @@ func (msg MsgBeginUnbonding) Route() string { return RouterKey } // Type implements the sdk.Msg interface. func (msg MsgBeginUnbonding) Type() string { return sdk.MsgTypeURL(&msg) } -func NewMsgSponsor(sponsor sdk.AccAddress, programID uint32, asset sdk.Coin) *MsgSponsor { +func NewMsgEmergencyUnbond(account sdk.AccAddress, asset sdk.Coin) *MsgEmergencyUnbond { + return &MsgEmergencyUnbond{ + Account: account.String(), + UToken: asset, + } +} + +func (msg MsgEmergencyUnbond) ValidateBasic() error { + return validateSenderAsset(msg.Account, &msg.UToken) +} + +func (msg MsgEmergencyUnbond) GetSigners() []sdk.AccAddress { + return checkers.Signers(msg.Account) +} + +// GetSignBytes get the bytes for the message signer to sign on +func (msg MsgEmergencyUnbond) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// Route implements the sdk.Msg interface. +func (msg MsgEmergencyUnbond) Route() string { return RouterKey } + +// Type implements the sdk.Msg interface. +func (msg MsgEmergencyUnbond) Type() string { return sdk.MsgTypeURL(&msg) } + +func NewMsgSponsor(sponsor sdk.AccAddress, programID uint32) *MsgSponsor { return &MsgSponsor{ Sponsor: sponsor.String(), Program: programID, - Asset: asset, } } @@ -110,7 +135,8 @@ func (msg MsgSponsor) ValidateBasic() error { if msg.Program == 0 { return ErrInvalidProgramID.Wrapf("%d", msg.Program) } - return validateSenderAsset(msg.Sponsor, &msg.Asset) + _, err := sdk.AccAddressFromBech32(msg.Sponsor) + return err } func (msg MsgSponsor) GetSigners() []sdk.AccAddress { @@ -179,7 +205,7 @@ func (msg MsgGovCreatePrograms) ValidateBasic() error { return ErrEmptyProposal } for _, p := range msg.Programs { - if err := validateProposedIncentiveProgram(p); err != nil { + if err := p.ValidateProposed(); err != nil { return err } } @@ -213,13 +239,3 @@ func validateSenderAsset(sender string, asset *sdk.Coin) error { } return asset.Validate() } - -func validateSenderAssetTier(sender string, tier uint32, asset *sdk.Coin) error { - if err := validateSenderAsset(sender, asset); err != nil { - return err - } - if tier < 1 || tier > 3 { - return ErrInvalidTier.Wrapf("%d", tier) - } - return nil -} diff --git a/x/incentive/msgs_test.go b/x/incentive/msgs_test.go index 55f5526f5a..c5886179db 100644 --- a/x/incentive/msgs_test.go +++ b/x/incentive/msgs_test.go @@ -13,8 +13,7 @@ import ( ) const ( - govAddr = "umee10d07y265gmmuvt4z0w9aw880jnsr700jg5w6jp" - longTier = uint32(incentive.BondTierLong) + govAddr = "umee10d07y265gmmuvt4z0w9aw880jnsr700jg5w6jp" ) var ( @@ -26,10 +25,11 @@ var ( func TestMsgs(t *testing.T) { userMsgs := []sdk.Msg{ - incentive.NewMsgBond(testAddr, longTier, uToken), - incentive.NewMsgBeginUnbonding(testAddr, longTier, uToken), + incentive.NewMsgBond(testAddr, uToken), + incentive.NewMsgBeginUnbonding(testAddr, uToken), + incentive.NewMsgEmergencyUnbond(testAddr, uToken), incentive.NewMsgClaim(testAddr), - incentive.NewMsgSponsor(testAddr, 3, token), + incentive.NewMsgSponsor(testAddr, 3), } govMsgs := []sdk.Msg{ @@ -63,10 +63,11 @@ type sdkmsg interface { func TestRoutes(t *testing.T) { msgs := []sdkmsg{ - *incentive.NewMsgBond(testAddr, longTier, uToken), - *incentive.NewMsgBeginUnbonding(testAddr, longTier, uToken), + *incentive.NewMsgBond(testAddr, uToken), + *incentive.NewMsgBeginUnbonding(testAddr, uToken), + *incentive.NewMsgEmergencyUnbond(testAddr, uToken), *incentive.NewMsgClaim(testAddr), - *incentive.NewMsgSponsor(testAddr, 3, token), + *incentive.NewMsgSponsor(testAddr, 3), *incentive.NewMsgGovCreatePrograms(govAddr, "title", "desc", []incentive.IncentiveProgram{program}), *incentive.NewMsgGovSetParams(govAddr, "title", "desc", incentive.DefaultParams()), } @@ -77,9 +78,9 @@ func TestRoutes(t *testing.T) { assert.Assert(t, len(msg.GetSignBytes()) != 0) // exact match required assert.Equal(t, - // example: "/umeenetwork.umee.incentive.v1.MsgBond" + // example: "/umee.incentive.v1.MsgBond" // with %T returning "incentive.MsgBond" - addV1ToType(fmt.Sprintf("/umeenetwork.umee.%T", msg)), + addV1ToType(fmt.Sprintf("/umee.%T", msg)), msg.Type(), ) } diff --git a/x/incentive/params.go b/x/incentive/params.go index 27c34165c2..4ae62a81c6 100644 --- a/x/incentive/params.go +++ b/x/incentive/params.go @@ -11,13 +11,9 @@ const secondsPerDay = 86400 // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - MaxUnbondings: 5, - UnbondingDurationLong: secondsPerDay * 14, - UnbondingDurationMiddle: secondsPerDay * 7, - UnbondingDurationShort: secondsPerDay, - TierWeightMiddle: sdk.MustNewDecFromStr("0.8"), - TierWeightShort: sdk.MustNewDecFromStr("0.5"), - CommunityFundAddress: "", + MaxUnbondings: 10, + UnbondingDuration: secondsPerDay * 1, + EmergencyUnbondFee: sdk.MustNewDecFromStr("0.01"), } } @@ -26,68 +22,29 @@ func (p Params) Validate() error { if err := validateMaxUnbondings(p.MaxUnbondings); err != nil { return err } - if err := validateUnbondingDuration(p.UnbondingDurationLong); err != nil { + if err := validateUnbondingDuration(p.UnbondingDuration); err != nil { return err } - if err := validateUnbondingDuration(p.UnbondingDurationMiddle); err != nil { - return err - } - if err := validateUnbondingDuration(p.UnbondingDurationShort); err != nil { - return err - } - if err := validateTierWeight(p.TierWeightMiddle); err != nil { - return err - } - if err := validateTierWeight(p.TierWeightShort); err != nil { - return err - } - if err := validateCommunityFundAddress(p.CommunityFundAddress); err != nil { - return err - } - if p.UnbondingDurationLong < p.UnbondingDurationMiddle || p.UnbondingDurationMiddle < p.UnbondingDurationShort { - return ErrUnbondingTierOrder - } - if p.TierWeightMiddle.LT(p.TierWeightShort) { - return ErrUnbondingWeightOrder - } - return nil + return validateEmergencyUnbondFee(p.EmergencyUnbondFee) } -func validateTierWeight(v sdk.Dec) error { - if v.IsNegative() { - return fmt.Errorf("tier weight cannot be negative: %d", v) - } - if v.GT(sdk.OneDec()) { - return fmt.Errorf("tier weight cannot exceed 1: %d", v) +func validateUnbondingDuration(v int64) error { + // non-negative durations, including zero (instant unbond), are allowed + if v < 0 { + return fmt.Errorf("invalid unbonding duration: %d", v) } - return nil } -func validateUnbondingDuration(v uint64) error { - if v == 0 { - return fmt.Errorf("unbonding duration cannot be zero") +func validateEmergencyUnbondFee(v sdk.Dec) error { + if v.IsNil() || v.IsNegative() || v.GTE(sdk.OneDec()) { + return fmt.Errorf("invalid emergency unbonding fee: %s, valid values: [0, 1)", v) } return nil } -func validateMaxUnbondings(v uint32) error { - if v == 0 { - return fmt.Errorf("max unbondings cannot be zero") - } - - return nil -} - -func validateCommunityFundAddress(addr string) error { - // Address must be either empty or fully valid - if addr != "" { - _, err := sdk.AccAddressFromBech32(addr) - if err != nil { - return err - } - } - +func validateMaxUnbondings(_ uint32) error { + // max unbondings can be any positive number, or zero for unlimited return nil } diff --git a/x/incentive/params_test.go b/x/incentive/params_test.go index 807ad6b9ec..f9fe4e1280 100644 --- a/x/incentive/params_test.go +++ b/x/incentive/params_test.go @@ -12,47 +12,11 @@ func TestDefaultParams(t *testing.T) { params := DefaultParams() assert.NilError(t, params.Validate()) - invalidMaxUnbondings := DefaultParams() - invalidMaxUnbondings.MaxUnbondings = 0 - assert.ErrorContains(t, invalidMaxUnbondings.Validate(), "max unbondings cannot be zero") + invalidUnbondingDuration := DefaultParams() + invalidUnbondingDuration.UnbondingDuration = -1 + assert.ErrorContains(t, invalidUnbondingDuration.Validate(), "invalid unbonding duration") - invalidLongUnbond := DefaultParams() - invalidLongUnbond.UnbondingDurationLong = 0 - assert.ErrorContains(t, invalidLongUnbond.Validate(), "unbonding duration cannot be zero") - - invalidMidUnbond := DefaultParams() - invalidMidUnbond.UnbondingDurationMiddle = 0 - assert.ErrorContains(t, invalidMidUnbond.Validate(), "unbonding duration cannot be zero") - - invalidShortUnbond := DefaultParams() - invalidShortUnbond.UnbondingDurationShort = 0 - assert.ErrorContains(t, invalidShortUnbond.Validate(), "unbonding duration cannot be zero") - - invalidMidTier := DefaultParams() - invalidMidTier.TierWeightMiddle = sdk.MustNewDecFromStr("1.5") - assert.ErrorContains(t, invalidMidTier.Validate(), "tier weight cannot exceed 1") - - negativeMidTier := DefaultParams() - negativeMidTier.TierWeightMiddle = sdk.MustNewDecFromStr("-0.5") - assert.ErrorContains(t, negativeMidTier.Validate(), "tier weight cannot be negative") - - invalidShortTier := DefaultParams() - invalidShortTier.TierWeightShort = sdk.MustNewDecFromStr("1.5") - assert.ErrorContains(t, invalidShortTier.Validate(), "tier weight cannot exceed 1") - - negativeShortTier := DefaultParams() - negativeShortTier.TierWeightShort = sdk.MustNewDecFromStr("-0.5") - assert.ErrorContains(t, negativeShortTier.Validate(), "tier weight cannot be negative") - - invalidCommunityFund := DefaultParams() - invalidCommunityFund.CommunityFundAddress = "abcdefgh" - assert.ErrorContains(t, invalidCommunityFund.Validate(), "decoding bech32 failed") - - invalidTierOrder := DefaultParams() - invalidTierOrder.UnbondingDurationLong = 1 - assert.ErrorIs(t, invalidTierOrder.Validate(), ErrUnbondingTierOrder) - - invalidWeightOrder := DefaultParams() - invalidWeightOrder.TierWeightShort = sdk.MustNewDecFromStr("0.9") - assert.ErrorIs(t, invalidWeightOrder.Validate(), ErrUnbondingWeightOrder) + invalidEmergencyUnbondFee := DefaultParams() + invalidEmergencyUnbondFee.EmergencyUnbondFee = sdk.OneDec() + assert.ErrorContains(t, invalidEmergencyUnbondFee.Validate(), "invalid emergency unbonding fee") } diff --git a/x/incentive/program.go b/x/incentive/program.go deleted file mode 100644 index 6e18995fdb..0000000000 --- a/x/incentive/program.go +++ /dev/null @@ -1,51 +0,0 @@ -package incentive - -import ( - "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - - leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" -) - -// validateProposedIncentiveProgram runs IncentiveProgram.Validate and also checks additional requirements applying -// to incentive programs which have not yet been funded or passed by governance -func validateProposedIncentiveProgram(program IncentiveProgram) error { - if program.ID != 0 { - return ErrInvalidProgramID.Wrapf("%d", program.ID) - } - if !program.RemainingRewards.IsZero() { - return ErrNonzeroRemainingRewards.Wrap(program.RemainingRewards.String()) - } - if program.Funded { - return ErrProposedFundedProgram - } - return program.Validate() -} - -// Validate performs validation on an IncentiveProgram type returning an error -// if the program is invalid. -func (ip IncentiveProgram) Validate() error { - if err := sdk.ValidateDenom(ip.UToken); err != nil { - return err - } - if !leveragetypes.HasUTokenPrefix(ip.UToken) { - // only allow uToken denoms as bonded denoms - return errors.Wrap(leveragetypes.ErrNotUToken, ip.UToken) - } - - if err := ip.TotalRewards.Validate(); err != nil { - return err - } - if leveragetypes.HasUTokenPrefix(ip.TotalRewards.Denom) { - // only allow base token denoms as rewards - return errors.Wrap(leveragetypes.ErrUToken, ip.TotalRewards.Denom) - } - - if err := ip.RemainingRewards.Validate(); err != nil { - return err - } - - // TODO #1749: Finish validate logic - - return nil -} diff --git a/x/incentive/query.pb.go b/x/incentive/query.pb.go index 75df9f7d09..5740385d8f 100644 --- a/x/incentive/query.pb.go +++ b/x/incentive/query.pb.go @@ -206,25 +206,23 @@ func (m *QueryPendingRewardsResponse) GetRewards() github_com_cosmos_cosmos_sdk_ return nil } -// QueryBonded defines the request structure for the Bonded gRPC service handler. -type QueryBonded struct { +// QueryAccountBonds defines the request structure for the AccountBonds gRPC service handler. +type QueryAccountBonds struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // denom is an optional field which causes the query to return the totals of only one uToken - Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` } -func (m *QueryBonded) Reset() { *m = QueryBonded{} } -func (m *QueryBonded) String() string { return proto.CompactTextString(m) } -func (*QueryBonded) ProtoMessage() {} -func (*QueryBonded) Descriptor() ([]byte, []int) { +func (m *QueryAccountBonds) Reset() { *m = QueryAccountBonds{} } +func (m *QueryAccountBonds) String() string { return proto.CompactTextString(m) } +func (*QueryAccountBonds) ProtoMessage() {} +func (*QueryAccountBonds) Descriptor() ([]byte, []int) { return fileDescriptor_98af6650734ce845, []int{4} } -func (m *QueryBonded) XXX_Unmarshal(b []byte) error { +func (m *QueryAccountBonds) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryBonded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryAccountBonds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryBonded.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryAccountBonds.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -234,49 +232,44 @@ func (m *QueryBonded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) return b[:n], nil } } -func (m *QueryBonded) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryBonded.Merge(m, src) +func (m *QueryAccountBonds) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAccountBonds.Merge(m, src) } -func (m *QueryBonded) XXX_Size() int { +func (m *QueryAccountBonds) XXX_Size() int { return m.Size() } -func (m *QueryBonded) XXX_DiscardUnknown() { - xxx_messageInfo_QueryBonded.DiscardUnknown(m) +func (m *QueryAccountBonds) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAccountBonds.DiscardUnknown(m) } -var xxx_messageInfo_QueryBonded proto.InternalMessageInfo +var xxx_messageInfo_QueryAccountBonds proto.InternalMessageInfo -func (m *QueryBonded) GetAddress() string { +func (m *QueryAccountBonds) GetAddress() string { if m != nil { return m.Address } return "" } -func (m *QueryBonded) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -// QueryBondedResponse defines the response structure for the Bonded gRPC service handler. -type QueryBondedResponse struct { - Bonded []TotalBond `protobuf:"bytes,1,rep,name=bonded,proto3" json:"bonded"` +// QueryAccountBondsResponse defines the response structure for the AccountBonds gRPC service handler. +type QueryAccountBondsResponse struct { + Bonded github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=bonded,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"bonded"` + Unbonding github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=unbonding,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"unbonding"` + Unbondings []Unbonding `protobuf:"bytes,3,rep,name=unbondings,proto3" json:"unbondings"` } -func (m *QueryBondedResponse) Reset() { *m = QueryBondedResponse{} } -func (m *QueryBondedResponse) String() string { return proto.CompactTextString(m) } -func (*QueryBondedResponse) ProtoMessage() {} -func (*QueryBondedResponse) Descriptor() ([]byte, []int) { +func (m *QueryAccountBondsResponse) Reset() { *m = QueryAccountBondsResponse{} } +func (m *QueryAccountBondsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAccountBondsResponse) ProtoMessage() {} +func (*QueryAccountBondsResponse) Descriptor() ([]byte, []int) { return fileDescriptor_98af6650734ce845, []int{5} } -func (m *QueryBondedResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryAccountBondsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryBondedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryAccountBondsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryBondedResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryAccountBondsResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -286,109 +279,33 @@ func (m *QueryBondedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, return b[:n], nil } } -func (m *QueryBondedResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryBondedResponse.Merge(m, src) +func (m *QueryAccountBondsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAccountBondsResponse.Merge(m, src) } -func (m *QueryBondedResponse) XXX_Size() int { +func (m *QueryAccountBondsResponse) XXX_Size() int { return m.Size() } -func (m *QueryBondedResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryBondedResponse.DiscardUnknown(m) +func (m *QueryAccountBondsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAccountBondsResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryBondedResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryAccountBondsResponse proto.InternalMessageInfo -func (m *QueryBondedResponse) GetBonded() []TotalBond { +func (m *QueryAccountBondsResponse) GetBonded() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.Bonded } return nil } -// QueryUnbondings defines the request structure for the Unbondings gRPC service handler. -type QueryUnbondings struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *QueryUnbondings) Reset() { *m = QueryUnbondings{} } -func (m *QueryUnbondings) String() string { return proto.CompactTextString(m) } -func (*QueryUnbondings) ProtoMessage() {} -func (*QueryUnbondings) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{6} -} -func (m *QueryUnbondings) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryUnbondings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryUnbondings.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryUnbondings) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryUnbondings.Merge(m, src) -} -func (m *QueryUnbondings) XXX_Size() int { - return m.Size() -} -func (m *QueryUnbondings) XXX_DiscardUnknown() { - xxx_messageInfo_QueryUnbondings.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryUnbondings proto.InternalMessageInfo - -func (m *QueryUnbondings) GetAddress() string { +func (m *QueryAccountBondsResponse) GetUnbonding() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { - return m.Address - } - return "" -} - -// QueryUnbondingsResponse defines the response structure for the Unbondings gRPC service handler. -type QueryUnbondingsResponse struct { - Unbondings []Unbonding `protobuf:"bytes,1,rep,name=unbondings,proto3" json:"unbondings"` -} - -func (m *QueryUnbondingsResponse) Reset() { *m = QueryUnbondingsResponse{} } -func (m *QueryUnbondingsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryUnbondingsResponse) ProtoMessage() {} -func (*QueryUnbondingsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{7} -} -func (m *QueryUnbondingsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryUnbondingsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryUnbondingsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil + return m.Unbonding } + return nil } -func (m *QueryUnbondingsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryUnbondingsResponse.Merge(m, src) -} -func (m *QueryUnbondingsResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryUnbondingsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryUnbondingsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryUnbondingsResponse proto.InternalMessageInfo -func (m *QueryUnbondingsResponse) GetUnbondings() []Unbonding { +func (m *QueryAccountBondsResponse) GetUnbondings() []Unbonding { if m != nil { return m.Unbondings } @@ -405,7 +322,7 @@ func (m *QueryTotalBonded) Reset() { *m = QueryTotalBonded{} } func (m *QueryTotalBonded) String() string { return proto.CompactTextString(m) } func (*QueryTotalBonded) ProtoMessage() {} func (*QueryTotalBonded) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{8} + return fileDescriptor_98af6650734ce845, []int{6} } func (m *QueryTotalBonded) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -443,14 +360,14 @@ func (m *QueryTotalBonded) GetDenom() string { // QueryTotalBondedResponse defines the response structure for the TotalBonded gRPC service handler. type QueryTotalBondedResponse struct { - Bonded []TotalBond `protobuf:"bytes,1,rep,name=bonded,proto3" json:"bonded"` + Bonded github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=bonded,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"bonded"` } func (m *QueryTotalBondedResponse) Reset() { *m = QueryTotalBondedResponse{} } func (m *QueryTotalBondedResponse) String() string { return proto.CompactTextString(m) } func (*QueryTotalBondedResponse) ProtoMessage() {} func (*QueryTotalBondedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{9} + return fileDescriptor_98af6650734ce845, []int{7} } func (m *QueryTotalBondedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -479,7 +396,7 @@ func (m *QueryTotalBondedResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryTotalBondedResponse proto.InternalMessageInfo -func (m *QueryTotalBondedResponse) GetBonded() []TotalBond { +func (m *QueryTotalBondedResponse) GetBonded() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.Bonded } @@ -496,7 +413,7 @@ func (m *QueryTotalUnbonding) Reset() { *m = QueryTotalUnbonding{} } func (m *QueryTotalUnbonding) String() string { return proto.CompactTextString(m) } func (*QueryTotalUnbonding) ProtoMessage() {} func (*QueryTotalUnbonding) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{10} + return fileDescriptor_98af6650734ce845, []int{8} } func (m *QueryTotalUnbonding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -534,14 +451,14 @@ func (m *QueryTotalUnbonding) GetDenom() string { // QueryTotalUnbondingResponse defines the response structure for the TotalUnbonding gRPC service handler. type QueryTotalUnbondingResponse struct { - Unbonding []TotalBond `protobuf:"bytes,1,rep,name=unbonding,proto3" json:"unbonding"` + Unbonding github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=unbonding,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"unbonding"` } func (m *QueryTotalUnbondingResponse) Reset() { *m = QueryTotalUnbondingResponse{} } func (m *QueryTotalUnbondingResponse) String() string { return proto.CompactTextString(m) } func (*QueryTotalUnbondingResponse) ProtoMessage() {} func (*QueryTotalUnbondingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{11} + return fileDescriptor_98af6650734ce845, []int{9} } func (m *QueryTotalUnbondingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -570,7 +487,7 @@ func (m *QueryTotalUnbondingResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryTotalUnbondingResponse proto.InternalMessageInfo -func (m *QueryTotalUnbondingResponse) GetUnbonding() []TotalBond { +func (m *QueryTotalUnbondingResponse) GetUnbonding() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.Unbonding } @@ -586,7 +503,7 @@ func (m *QueryUpcomingIncentivePrograms) Reset() { *m = QueryUpcomingInc func (m *QueryUpcomingIncentivePrograms) String() string { return proto.CompactTextString(m) } func (*QueryUpcomingIncentivePrograms) ProtoMessage() {} func (*QueryUpcomingIncentivePrograms) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{12} + return fileDescriptor_98af6650734ce845, []int{10} } func (m *QueryUpcomingIncentivePrograms) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -627,7 +544,7 @@ func (m *QueryUpcomingIncentiveProgramsResponse) Reset() { func (m *QueryUpcomingIncentiveProgramsResponse) String() string { return proto.CompactTextString(m) } func (*QueryUpcomingIncentiveProgramsResponse) ProtoMessage() {} func (*QueryUpcomingIncentiveProgramsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{13} + return fileDescriptor_98af6650734ce845, []int{11} } func (m *QueryUpcomingIncentiveProgramsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -672,7 +589,7 @@ func (m *QueryOngoingIncentivePrograms) Reset() { *m = QueryOngoingIncen func (m *QueryOngoingIncentivePrograms) String() string { return proto.CompactTextString(m) } func (*QueryOngoingIncentivePrograms) ProtoMessage() {} func (*QueryOngoingIncentivePrograms) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{14} + return fileDescriptor_98af6650734ce845, []int{12} } func (m *QueryOngoingIncentivePrograms) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -711,7 +628,7 @@ func (m *QueryOngoingIncentiveProgramsResponse) Reset() { *m = QueryOngo func (m *QueryOngoingIncentiveProgramsResponse) String() string { return proto.CompactTextString(m) } func (*QueryOngoingIncentiveProgramsResponse) ProtoMessage() {} func (*QueryOngoingIncentiveProgramsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{15} + return fileDescriptor_98af6650734ce845, []int{13} } func (m *QueryOngoingIncentiveProgramsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -758,7 +675,7 @@ func (m *QueryCompletedIncentivePrograms) Reset() { *m = QueryCompletedI func (m *QueryCompletedIncentivePrograms) String() string { return proto.CompactTextString(m) } func (*QueryCompletedIncentivePrograms) ProtoMessage() {} func (*QueryCompletedIncentivePrograms) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{16} + return fileDescriptor_98af6650734ce845, []int{14} } func (m *QueryCompletedIncentivePrograms) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -808,7 +725,7 @@ func (m *QueryCompletedIncentiveProgramsResponse) Reset() { func (m *QueryCompletedIncentiveProgramsResponse) String() string { return proto.CompactTextString(m) } func (*QueryCompletedIncentiveProgramsResponse) ProtoMessage() {} func (*QueryCompletedIncentiveProgramsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{17} + return fileDescriptor_98af6650734ce845, []int{15} } func (m *QueryCompletedIncentiveProgramsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -862,7 +779,7 @@ func (m *QueryIncentiveProgram) Reset() { *m = QueryIncentiveProgram{} } func (m *QueryIncentiveProgram) String() string { return proto.CompactTextString(m) } func (*QueryIncentiveProgram) ProtoMessage() {} func (*QueryIncentiveProgram) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{18} + return fileDescriptor_98af6650734ce845, []int{16} } func (m *QueryIncentiveProgram) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -908,7 +825,7 @@ func (m *QueryIncentiveProgramResponse) Reset() { *m = QueryIncentivePro func (m *QueryIncentiveProgramResponse) String() string { return proto.CompactTextString(m) } func (*QueryIncentiveProgramResponse) ProtoMessage() {} func (*QueryIncentiveProgramResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_98af6650734ce845, []int{19} + return fileDescriptor_98af6650734ce845, []int{17} } func (m *QueryIncentiveProgramResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -944,96 +861,205 @@ func (m *QueryIncentiveProgramResponse) GetProgram() IncentiveProgram { return IncentiveProgram{} } +// QueryCurrentRates defines the request structure for the CurrentRates gRPC service handler. +type QueryCurrentRates struct { + // uToken is the uToken denomination whose current annual rate of rewards is being queried + UToken string `protobuf:"bytes,1,opt,name=uToken,proto3" json:"uToken,omitempty"` +} + +func (m *QueryCurrentRates) Reset() { *m = QueryCurrentRates{} } +func (m *QueryCurrentRates) String() string { return proto.CompactTextString(m) } +func (*QueryCurrentRates) ProtoMessage() {} +func (*QueryCurrentRates) Descriptor() ([]byte, []int) { + return fileDescriptor_98af6650734ce845, []int{18} +} +func (m *QueryCurrentRates) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCurrentRates) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCurrentRates.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryCurrentRates) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCurrentRates.Merge(m, src) +} +func (m *QueryCurrentRates) XXX_Size() int { + return m.Size() +} +func (m *QueryCurrentRates) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCurrentRates.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCurrentRates proto.InternalMessageInfo + +func (m *QueryCurrentRates) GetUToken() string { + if m != nil { + return m.UToken + } + return "" +} + +// QueryCurrentRatesResponse defines the response structure for the CurrentRates gRPC service handler. +type QueryCurrentRatesResponse struct { + // Reference Bond is an amount of bonded uTokens (usually 10^exponent) whose current rewards are being + // calculated. This amount can be used to compute an individual user's rewards: for example, if a user has + // 2.5x the reference amount currently bonded, then they would receive 2.5x the rewards below annually + // at current rates. + ReferenceBond types.Coin `protobuf:"bytes,1,opt,name=reference_bond,json=referenceBond,proto3" json:"reference_bond"` + // Rewards are the amount of base token rewards that the reference amount of bonded uTokens would earn + // if current rates continued for a full year. + Rewards github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"rewards"` +} + +func (m *QueryCurrentRatesResponse) Reset() { *m = QueryCurrentRatesResponse{} } +func (m *QueryCurrentRatesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryCurrentRatesResponse) ProtoMessage() {} +func (*QueryCurrentRatesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_98af6650734ce845, []int{19} +} +func (m *QueryCurrentRatesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCurrentRatesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCurrentRatesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryCurrentRatesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCurrentRatesResponse.Merge(m, src) +} +func (m *QueryCurrentRatesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryCurrentRatesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCurrentRatesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCurrentRatesResponse proto.InternalMessageInfo + +func (m *QueryCurrentRatesResponse) GetReferenceBond() types.Coin { + if m != nil { + return m.ReferenceBond + } + return types.Coin{} +} + +func (m *QueryCurrentRatesResponse) GetRewards() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Rewards + } + return nil +} + func init() { - proto.RegisterType((*QueryParams)(nil), "umeenetwork.umee.incentive.v1.QueryParams") - proto.RegisterType((*QueryParamsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryParamsResponse") - proto.RegisterType((*QueryPendingRewards)(nil), "umeenetwork.umee.incentive.v1.QueryPendingRewards") - proto.RegisterType((*QueryPendingRewardsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryPendingRewardsResponse") - proto.RegisterType((*QueryBonded)(nil), "umeenetwork.umee.incentive.v1.QueryBonded") - proto.RegisterType((*QueryBondedResponse)(nil), "umeenetwork.umee.incentive.v1.QueryBondedResponse") - proto.RegisterType((*QueryUnbondings)(nil), "umeenetwork.umee.incentive.v1.QueryUnbondings") - proto.RegisterType((*QueryUnbondingsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryUnbondingsResponse") - proto.RegisterType((*QueryTotalBonded)(nil), "umeenetwork.umee.incentive.v1.QueryTotalBonded") - proto.RegisterType((*QueryTotalBondedResponse)(nil), "umeenetwork.umee.incentive.v1.QueryTotalBondedResponse") - proto.RegisterType((*QueryTotalUnbonding)(nil), "umeenetwork.umee.incentive.v1.QueryTotalUnbonding") - proto.RegisterType((*QueryTotalUnbondingResponse)(nil), "umeenetwork.umee.incentive.v1.QueryTotalUnbondingResponse") - proto.RegisterType((*QueryUpcomingIncentivePrograms)(nil), "umeenetwork.umee.incentive.v1.QueryUpcomingIncentivePrograms") - proto.RegisterType((*QueryUpcomingIncentiveProgramsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryUpcomingIncentiveProgramsResponse") - proto.RegisterType((*QueryOngoingIncentivePrograms)(nil), "umeenetwork.umee.incentive.v1.QueryOngoingIncentivePrograms") - proto.RegisterType((*QueryOngoingIncentiveProgramsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryOngoingIncentiveProgramsResponse") - proto.RegisterType((*QueryCompletedIncentivePrograms)(nil), "umeenetwork.umee.incentive.v1.QueryCompletedIncentivePrograms") - proto.RegisterType((*QueryCompletedIncentiveProgramsResponse)(nil), "umeenetwork.umee.incentive.v1.QueryCompletedIncentiveProgramsResponse") - proto.RegisterType((*QueryIncentiveProgram)(nil), "umeenetwork.umee.incentive.v1.QueryIncentiveProgram") - proto.RegisterType((*QueryIncentiveProgramResponse)(nil), "umeenetwork.umee.incentive.v1.QueryIncentiveProgramResponse") + proto.RegisterType((*QueryParams)(nil), "umee.incentive.v1.QueryParams") + proto.RegisterType((*QueryParamsResponse)(nil), "umee.incentive.v1.QueryParamsResponse") + proto.RegisterType((*QueryPendingRewards)(nil), "umee.incentive.v1.QueryPendingRewards") + proto.RegisterType((*QueryPendingRewardsResponse)(nil), "umee.incentive.v1.QueryPendingRewardsResponse") + proto.RegisterType((*QueryAccountBonds)(nil), "umee.incentive.v1.QueryAccountBonds") + proto.RegisterType((*QueryAccountBondsResponse)(nil), "umee.incentive.v1.QueryAccountBondsResponse") + proto.RegisterType((*QueryTotalBonded)(nil), "umee.incentive.v1.QueryTotalBonded") + proto.RegisterType((*QueryTotalBondedResponse)(nil), "umee.incentive.v1.QueryTotalBondedResponse") + proto.RegisterType((*QueryTotalUnbonding)(nil), "umee.incentive.v1.QueryTotalUnbonding") + proto.RegisterType((*QueryTotalUnbondingResponse)(nil), "umee.incentive.v1.QueryTotalUnbondingResponse") + proto.RegisterType((*QueryUpcomingIncentivePrograms)(nil), "umee.incentive.v1.QueryUpcomingIncentivePrograms") + proto.RegisterType((*QueryUpcomingIncentiveProgramsResponse)(nil), "umee.incentive.v1.QueryUpcomingIncentiveProgramsResponse") + proto.RegisterType((*QueryOngoingIncentivePrograms)(nil), "umee.incentive.v1.QueryOngoingIncentivePrograms") + proto.RegisterType((*QueryOngoingIncentiveProgramsResponse)(nil), "umee.incentive.v1.QueryOngoingIncentiveProgramsResponse") + proto.RegisterType((*QueryCompletedIncentivePrograms)(nil), "umee.incentive.v1.QueryCompletedIncentivePrograms") + proto.RegisterType((*QueryCompletedIncentiveProgramsResponse)(nil), "umee.incentive.v1.QueryCompletedIncentiveProgramsResponse") + proto.RegisterType((*QueryIncentiveProgram)(nil), "umee.incentive.v1.QueryIncentiveProgram") + proto.RegisterType((*QueryIncentiveProgramResponse)(nil), "umee.incentive.v1.QueryIncentiveProgramResponse") + proto.RegisterType((*QueryCurrentRates)(nil), "umee.incentive.v1.QueryCurrentRates") + proto.RegisterType((*QueryCurrentRatesResponse)(nil), "umee.incentive.v1.QueryCurrentRatesResponse") } func init() { proto.RegisterFile("umee/incentive/v1/query.proto", fileDescriptor_98af6650734ce845) } var fileDescriptor_98af6650734ce845 = []byte{ - // 1006 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x97, 0xcf, 0x6f, 0xdc, 0x44, - 0x14, 0xc7, 0x33, 0x0b, 0xdd, 0xd0, 0x17, 0x35, 0x54, 0xd3, 0x22, 0x36, 0x2e, 0xdd, 0x4d, 0x2d, - 0xb5, 0xd9, 0x26, 0x8d, 0xa7, 0xbb, 0x0d, 0xad, 0x84, 0x5a, 0x0e, 0x09, 0x8d, 0x84, 0x84, 0x68, - 0xba, 0x82, 0x4b, 0x25, 0x14, 0x79, 0xd7, 0x23, 0x63, 0x25, 0x3b, 0xe3, 0xae, 0xbd, 0x5b, 0x4a, - 0x94, 0x0b, 0xe2, 0xc6, 0x05, 0x89, 0x33, 0x47, 0x24, 0xc4, 0x19, 0x21, 0x71, 0xe7, 0x90, 0x63, - 0x24, 0x84, 0x04, 0x07, 0x7e, 0x28, 0xe1, 0x0f, 0xa9, 0x3c, 0x33, 0x1e, 0x3b, 0xde, 0x1f, 0x99, - 0x24, 0xca, 0x29, 0xf6, 0xf8, 0x7d, 0xdf, 0xfb, 0x7c, 0x9f, 0xe3, 0x37, 0xb3, 0x70, 0xbd, 0xdf, - 0xa5, 0x94, 0x04, 0xac, 0x43, 0x59, 0x1c, 0x0c, 0x28, 0x19, 0x34, 0xc8, 0xf3, 0x3e, 0xed, 0xbd, - 0x74, 0xc2, 0x1e, 0x8f, 0x39, 0x16, 0x8f, 0x19, 0x8d, 0x5f, 0xf0, 0xde, 0x96, 0x93, 0x5c, 0x3b, - 0x3a, 0xd4, 0x19, 0x34, 0xac, 0xc5, 0x0e, 0x8f, 0xba, 0x3c, 0x22, 0x6d, 0x37, 0xa2, 0x52, 0x47, - 0x06, 0x8d, 0x36, 0x8d, 0xdd, 0x06, 0x09, 0x5d, 0x3f, 0x60, 0x6e, 0x1c, 0x70, 0x26, 0x53, 0x59, - 0xef, 0xf8, 0x9c, 0xfb, 0xdb, 0x94, 0xb8, 0x61, 0x40, 0x5c, 0xc6, 0x78, 0x2c, 0x1e, 0x46, 0xea, - 0xe9, 0x55, 0x9f, 0xfb, 0x5c, 0x5c, 0x92, 0xe4, 0x4a, 0xad, 0xde, 0x18, 0xa6, 0xcb, 0xea, 0xcb, - 0x90, 0xda, 0x70, 0x88, 0x4f, 0x19, 0x8d, 0x82, 0x34, 0x73, 0x35, 0xcf, 0x98, 0xd2, 0x75, 0x78, - 0xa0, 0xb8, 0xec, 0x4b, 0x30, 0xf3, 0x34, 0x21, 0xdf, 0x70, 0x7b, 0x6e, 0x37, 0xb2, 0x9f, 0xc1, - 0x95, 0xdc, 0x6d, 0x8b, 0x46, 0x21, 0x67, 0x11, 0xc5, 0x6b, 0x50, 0x0e, 0xc5, 0x4a, 0x05, 0xcd, - 0xa3, 0xfa, 0x4c, 0xf3, 0xa6, 0x33, 0xb1, 0x33, 0x8e, 0x94, 0xaf, 0xbe, 0xbe, 0xf7, 0x4f, 0x6d, - 0xaa, 0xa5, 0xa4, 0x36, 0x49, 0x73, 0x53, 0xe6, 0x05, 0xcc, 0x6f, 0xd1, 0x17, 0x6e, 0xcf, 0x8b, - 0x70, 0x05, 0xa6, 0x5d, 0xcf, 0xeb, 0xd1, 0x48, 0x26, 0xbf, 0xd8, 0x4a, 0x6f, 0xed, 0xaf, 0x11, - 0x5c, 0x1b, 0xa1, 0xd0, 0x54, 0x14, 0xa6, 0x7b, 0x72, 0xa9, 0x82, 0xe6, 0x5f, 0xab, 0xcf, 0x34, - 0xe7, 0x1c, 0xe9, 0xd6, 0x49, 0xdc, 0x3a, 0xca, 0xad, 0xb3, 0xc6, 0x03, 0xb6, 0x7a, 0x37, 0x41, - 0xf9, 0xe9, 0xdf, 0x5a, 0xdd, 0x0f, 0xe2, 0xcf, 0xfb, 0x6d, 0xa7, 0xc3, 0xbb, 0x44, 0xb5, 0x46, - 0xfe, 0x59, 0x8e, 0xbc, 0x2d, 0x12, 0xbf, 0x0c, 0x69, 0x24, 0x04, 0x51, 0x2b, 0xcd, 0x6d, 0x3f, - 0x52, 0x2d, 0x5a, 0xe5, 0xcc, 0xa3, 0xde, 0x78, 0x5e, 0x7c, 0x15, 0x2e, 0x78, 0x94, 0xf1, 0x6e, - 0xa5, 0x24, 0xd6, 0xe5, 0x8d, 0xfd, 0x99, 0xb2, 0x2d, 0xe5, 0x1a, 0x7e, 0x1d, 0xca, 0x6d, 0xb1, - 0xa2, 0xd8, 0xeb, 0xc7, 0xb4, 0xf4, 0x13, 0x1e, 0xbb, 0xdb, 0x49, 0x8e, 0xb4, 0xab, 0x52, 0x6d, - 0x2f, 0xc1, 0x9b, 0x22, 0xfd, 0xa7, 0x2c, 0x59, 0x08, 0x98, 0x3f, 0xa9, 0xa3, 0x01, 0xbc, 0x5d, - 0x08, 0xd6, 0x3c, 0x1f, 0x03, 0xf4, 0xf5, 0xaa, 0x21, 0x93, 0x4e, 0xa3, 0x98, 0x72, 0x19, 0xec, - 0x3a, 0x5c, 0x16, 0xa5, 0x34, 0x37, 0xf5, 0xb2, 0x06, 0xa1, 0x7c, 0x83, 0xda, 0x50, 0x29, 0x46, - 0x9e, 0x43, 0x97, 0xae, 0x64, 0x35, 0x34, 0xf6, 0x18, 0xa0, 0x2d, 0xf5, 0x6f, 0x77, 0x34, 0x58, - 0x33, 0x7d, 0x04, 0x17, 0xb5, 0xcf, 0x53, 0x62, 0x65, 0x09, 0xec, 0x79, 0xa8, 0xca, 0x57, 0x12, - 0x76, 0x78, 0x37, 0x60, 0xfe, 0x87, 0xa9, 0x6e, 0xa3, 0xc7, 0x7d, 0xf1, 0xdd, 0xec, 0xc0, 0xad, - 0xc9, 0x11, 0x9a, 0xec, 0x29, 0xbc, 0x11, 0xaa, 0x35, 0x05, 0x46, 0x8e, 0x01, 0x2b, 0xe6, 0x52, - 0x7c, 0x3a, 0x8d, 0x5d, 0x83, 0xeb, 0xa2, 0xf8, 0x13, 0xe6, 0xf3, 0x91, 0x74, 0x5f, 0xc2, 0xcd, - 0x89, 0x01, 0xe7, 0x09, 0x17, 0x40, 0x4d, 0xd4, 0x5e, 0xe3, 0xdd, 0x70, 0x9b, 0xc6, 0xd4, 0x1b, - 0xaa, 0x8e, 0xd7, 0x01, 0xb2, 0x59, 0xac, 0xa6, 0xd7, 0xad, 0x23, 0x63, 0x42, 0x0e, 0xfc, 0x74, - 0x58, 0x6c, 0xb8, 0x3e, 0x6d, 0xd1, 0xe7, 0x7d, 0x1a, 0xc5, 0xad, 0x9c, 0xd2, 0xfe, 0x0d, 0xc1, - 0xc2, 0x31, 0xb5, 0xce, 0xd1, 0x69, 0xc1, 0x46, 0xe9, 0xd4, 0x36, 0x16, 0xe0, 0x2d, 0xe1, 0xa2, - 0x58, 0x10, 0xcf, 0x42, 0x29, 0xf0, 0x44, 0x7f, 0x2e, 0xb5, 0x4a, 0x81, 0x67, 0x87, 0xea, 0xbd, - 0x17, 0x03, 0xb5, 0xc9, 0x27, 0x30, 0xad, 0xe8, 0x54, 0x57, 0x4f, 0xe9, 0x31, 0xcd, 0xd2, 0xdc, - 0x9b, 0x85, 0x0b, 0xa2, 0x24, 0xfe, 0x06, 0x41, 0x59, 0xee, 0x20, 0x78, 0xf1, 0x98, 0xa4, 0xb9, - 0xcd, 0xca, 0x6a, 0x9a, 0xc7, 0xa6, 0x2e, 0xec, 0x1b, 0x5f, 0xfd, 0xfe, 0xff, 0x77, 0xa5, 0x6b, - 0x78, 0x8e, 0x0c, 0x6f, 0xa4, 0x72, 0xdb, 0xc2, 0x3f, 0x22, 0x98, 0xc9, 0x0f, 0x31, 0x62, 0x52, - 0x26, 0x27, 0xb0, 0x1e, 0x9c, 0x50, 0xa0, 0xe1, 0x88, 0x80, 0xbb, 0x8d, 0x17, 0x46, 0xc0, 0xc5, - 0x49, 0xfc, 0xa6, 0x9c, 0x6e, 0x64, 0x47, 0xcc, 0xad, 0x5d, 0xfc, 0x33, 0x82, 0xd9, 0xc2, 0x84, - 0x6b, 0x1a, 0x17, 0xd7, 0x1a, 0xeb, 0xbd, 0x93, 0x6b, 0x34, 0x73, 0x53, 0x30, 0xdf, 0xc1, 0x8b, - 0x63, 0x99, 0xf5, 0xe8, 0xd3, 0xd8, 0xdf, 0x23, 0x28, 0xab, 0xe6, 0x1a, 0xbd, 0x6f, 0xd5, 0xd7, - 0xa6, 0x79, 0xac, 0xc6, 0xbb, 0x27, 0xf0, 0x96, 0xf1, 0xd2, 0x08, 0xbc, 0xb4, 0x99, 0x6a, 0xb3, - 0xdc, 0xd5, 0x7c, 0x3f, 0x20, 0x80, 0xdc, 0xf6, 0xea, 0x98, 0xd4, 0xcd, 0xe2, 0xad, 0xfb, 0x27, - 0x8b, 0x37, 0x7a, 0xfd, 0xd9, 0x46, 0x9b, 0xf1, 0xe2, 0x5f, 0x10, 0xcc, 0x16, 0x0e, 0x57, 0x66, - 0xdf, 0xc4, 0x11, 0x8d, 0xd9, 0xeb, 0x1f, 0x7d, 0x24, 0xb3, 0x57, 0x04, 0xb3, 0x83, 0xef, 0x8c, - 0xfa, 0x9e, 0xa4, 0x64, 0x53, 0x9d, 0xab, 0x72, 0xe0, 0x7f, 0x23, 0xb0, 0x26, 0xcc, 0xf0, 0xf7, - 0x4d, 0x80, 0xc6, 0xeb, 0xad, 0xf5, 0xb3, 0xe9, 0xb5, 0xb9, 0x07, 0xc2, 0x5c, 0x03, 0x13, 0x32, - 0xe1, 0x60, 0xbe, 0x99, 0xce, 0x6c, 0xd2, 0x49, 0x33, 0xe2, 0x3f, 0x10, 0x54, 0xc6, 0xed, 0x8f, - 0xf8, 0xa1, 0x09, 0xdd, 0x38, 0xb5, 0xf5, 0xc1, 0x59, 0xd4, 0xda, 0xd9, 0xbb, 0xc2, 0x19, 0xc1, - 0xcb, 0x66, 0xce, 0xb8, 0xcc, 0x87, 0xff, 0x42, 0x30, 0x37, 0xf6, 0x54, 0x82, 0x1f, 0x19, 0xfd, - 0xdf, 0x8f, 0x93, 0x5b, 0x8f, 0xcf, 0x24, 0xd7, 0xd6, 0xee, 0x0b, 0x6b, 0x77, 0xb1, 0x63, 0x66, - 0xad, 0xaf, 0x12, 0xe2, 0x5f, 0x11, 0x5c, 0x1e, 0xda, 0x25, 0x57, 0x4c, 0x98, 0x8a, 0x2a, 0xeb, - 0xe1, 0x69, 0x54, 0xda, 0x40, 0x43, 0x18, 0x58, 0xc2, 0xb7, 0x4d, 0x0c, 0x90, 0x9d, 0xc0, 0xdb, - 0x5d, 0x7d, 0xbc, 0x77, 0x50, 0x45, 0xfb, 0x07, 0x55, 0xf4, 0xdf, 0x41, 0x15, 0x7d, 0x7b, 0x58, - 0x9d, 0xda, 0x3f, 0xac, 0x4e, 0xfd, 0x79, 0x58, 0x9d, 0x7a, 0xb6, 0x94, 0xfb, 0xf9, 0x93, 0xa4, - 0x5b, 0x56, 0x54, 0x32, 0xf7, 0x60, 0x85, 0x7c, 0x91, 0xe5, 0x6c, 0x97, 0xc5, 0x4f, 0xc4, 0x7b, - 0xaf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0xae, 0x4f, 0xff, 0x26, 0x0f, 0x00, 0x00, + // 1066 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x97, 0xcf, 0x6f, 0x1b, 0x45, + 0x14, 0xc7, 0x33, 0x2e, 0x4d, 0xe8, 0xcb, 0x0f, 0xb5, 0x43, 0x41, 0xce, 0xb6, 0xb5, 0x93, 0x69, + 0x49, 0x42, 0x9c, 0xec, 0xc4, 0xa1, 0x50, 0xe0, 0x86, 0xa3, 0x56, 0xe2, 0x02, 0xc1, 0x6a, 0x2f, + 0x5c, 0xac, 0xf5, 0xee, 0xb0, 0xac, 0x12, 0xcf, 0xb8, 0xbb, 0x6b, 0x97, 0xaa, 0xaa, 0x90, 0x10, + 0x87, 0x1e, 0x38, 0x20, 0x81, 0x38, 0x22, 0x71, 0xe5, 0xc2, 0x95, 0x0b, 0x07, 0x0e, 0x48, 0x15, + 0xa7, 0x4a, 0x1c, 0xe0, 0x04, 0x28, 0xe1, 0x0f, 0x41, 0x3b, 0x33, 0x3b, 0x5e, 0xdb, 0xbb, 0xc6, + 0x41, 0x09, 0xa7, 0x78, 0x77, 0xbe, 0xef, 0xbd, 0xcf, 0x7b, 0x33, 0xfb, 0xde, 0x04, 0xae, 0xf5, + 0x3a, 0x8c, 0xd1, 0x80, 0xbb, 0x8c, 0xc7, 0x41, 0x9f, 0xd1, 0x7e, 0x9d, 0xde, 0xef, 0xb1, 0xf0, + 0xa1, 0xdd, 0x0d, 0x45, 0x2c, 0xf0, 0xa5, 0x64, 0xd9, 0x36, 0xcb, 0x76, 0xbf, 0x6e, 0x6d, 0xba, + 0x22, 0xea, 0x88, 0x88, 0xb6, 0x9d, 0x88, 0x29, 0x2d, 0xed, 0xd7, 0xdb, 0x2c, 0x76, 0xea, 0xb4, + 0xeb, 0xf8, 0x01, 0x77, 0xe2, 0x40, 0x70, 0x65, 0x6e, 0x5d, 0xf5, 0x85, 0xf0, 0x0f, 0x19, 0x75, + 0xba, 0x01, 0x75, 0x38, 0x17, 0xb1, 0x5c, 0x8c, 0xf4, 0xea, 0x65, 0x5f, 0xf8, 0x42, 0xfe, 0xa4, + 0xc9, 0x2f, 0xfd, 0x76, 0x75, 0x9c, 0x68, 0x10, 0x5f, 0x49, 0xaa, 0xe3, 0x12, 0x9f, 0x71, 0x16, + 0x05, 0xa9, 0xe7, 0x4a, 0x96, 0x31, 0xa5, 0x73, 0x45, 0xa0, 0xb9, 0xc8, 0x22, 0xcc, 0xbf, 0x9f, + 0x90, 0xef, 0x3b, 0xa1, 0xd3, 0x89, 0xc8, 0xbb, 0xf0, 0x42, 0xe6, 0xb1, 0xc9, 0xa2, 0xae, 0xe0, + 0x11, 0xc3, 0xb7, 0x60, 0xb6, 0x2b, 0xdf, 0x94, 0xd1, 0x0a, 0xda, 0x98, 0xdf, 0x5d, 0xb6, 0xc7, + 0xaa, 0x61, 0x2b, 0x93, 0xc6, 0x73, 0x4f, 0xff, 0xa8, 0xce, 0x34, 0xb5, 0x9c, 0xd0, 0xd4, 0x1f, + 0xe3, 0x5e, 0xc0, 0xfd, 0x26, 0x7b, 0xe0, 0x84, 0x5e, 0x84, 0xcb, 0x30, 0xe7, 0x78, 0x5e, 0xc8, + 0x22, 0xe5, 0xf0, 0x42, 0x33, 0x7d, 0x24, 0x9f, 0x21, 0xb8, 0x92, 0x63, 0x61, 0x48, 0x18, 0xcc, + 0x85, 0xea, 0x55, 0x19, 0xad, 0x9c, 0x93, 0x28, 0x2a, 0x43, 0x3b, 0xc9, 0xd0, 0xd6, 0x19, 0xda, + 0x7b, 0x22, 0xe0, 0x8d, 0x9d, 0x04, 0xe5, 0xbb, 0x3f, 0xab, 0x1b, 0x7e, 0x10, 0x7f, 0xd4, 0x6b, + 0xdb, 0xae, 0xe8, 0x50, 0x5d, 0x0e, 0xf5, 0x67, 0x3b, 0xf2, 0x0e, 0x68, 0xfc, 0xb0, 0xcb, 0x22, + 0x69, 0x10, 0x35, 0x53, 0xdf, 0x64, 0x1b, 0x2e, 0x49, 0x8a, 0xb7, 0x5d, 0x57, 0xf4, 0x78, 0xdc, + 0x10, 0x7c, 0x22, 0xf5, 0xf7, 0x25, 0x58, 0x1e, 0xd3, 0x1b, 0x66, 0x17, 0x66, 0xdb, 0x82, 0x7b, + 0xcc, 0x3b, 0x0b, 0x64, 0xed, 0x1a, 0x07, 0x70, 0xa1, 0xc7, 0x93, 0xdf, 0x01, 0xf7, 0xcb, 0xa5, + 0xd3, 0x8f, 0x33, 0xf0, 0x8e, 0x1b, 0x00, 0xe6, 0x21, 0x2a, 0x9f, 0x93, 0xb1, 0xae, 0xe6, 0x9c, + 0x88, 0x7b, 0xa9, 0x48, 0x1f, 0x8a, 0x8c, 0x15, 0xd9, 0x80, 0x8b, 0xb2, 0x60, 0x77, 0x45, 0xec, + 0x1c, 0x36, 0x54, 0x0a, 0x97, 0xe1, 0xbc, 0xc7, 0xb8, 0xe8, 0xe8, 0xea, 0xaa, 0x07, 0xf2, 0x09, + 0x94, 0x47, 0x95, 0xff, 0x6b, 0x65, 0x49, 0x4d, 0x9f, 0x61, 0x09, 0x60, 0x72, 0x2a, 0xa0, 0x7d, + 0x92, 0x9e, 0xdf, 0x61, 0xb5, 0x21, 0x1e, 0xda, 0x26, 0x74, 0x96, 0xdb, 0x44, 0x56, 0xa0, 0x22, + 0x49, 0xee, 0x75, 0x5d, 0xd1, 0x09, 0xb8, 0xff, 0x4e, 0xba, 0x37, 0xfb, 0xa1, 0xf0, 0xe5, 0xd7, + 0x29, 0x60, 0x6d, 0xb2, 0xc2, 0x60, 0xdf, 0x86, 0xe7, 0xbb, 0xfa, 0x9d, 0xa6, 0xbe, 0x9e, 0xb3, + 0xe1, 0xa3, 0xf6, 0x7a, 0xdf, 0x8d, 0x29, 0xa9, 0xc2, 0x35, 0x19, 0xf0, 0x3d, 0xee, 0x8b, 0x5c, + 0x22, 0x0e, 0x2f, 0x4f, 0x14, 0x9c, 0x36, 0x50, 0x00, 0x55, 0x19, 0x6f, 0x4f, 0x74, 0xba, 0x87, + 0x2c, 0x66, 0xde, 0x58, 0x44, 0x7c, 0x07, 0x60, 0xd0, 0xcd, 0x75, 0xff, 0x5b, 0x1b, 0xda, 0x32, + 0x35, 0x26, 0xd2, 0x8d, 0xdb, 0x77, 0x7c, 0xd6, 0x64, 0xf7, 0x7b, 0x2c, 0x8a, 0x9b, 0x19, 0x4b, + 0xf2, 0x03, 0x82, 0xf5, 0x7f, 0x89, 0x75, 0xca, 0xd9, 0x8d, 0xa0, 0x97, 0xfe, 0x33, 0xfa, 0x3a, + 0xbc, 0x28, 0xc9, 0x47, 0x03, 0xe2, 0x25, 0x28, 0x05, 0x9e, 0xac, 0xc9, 0x62, 0xb3, 0x14, 0x78, + 0xc4, 0xd3, 0xfb, 0x3b, 0x2a, 0x34, 0x89, 0xed, 0xc1, 0x9c, 0xa6, 0xd3, 0x95, 0x3c, 0x41, 0x5e, + 0xa9, 0x25, 0xa9, 0xe9, 0xe6, 0xbc, 0xd7, 0x0b, 0x43, 0xc6, 0xe3, 0xa6, 0x13, 0xb3, 0x08, 0xbf, + 0x04, 0xb3, 0xbd, 0xbb, 0xe2, 0x80, 0x71, 0xfd, 0x3d, 0xea, 0x27, 0xf2, 0x0b, 0xd2, 0xad, 0x39, + 0xab, 0x36, 0x3c, 0x77, 0x60, 0x29, 0x64, 0x1f, 0xb2, 0x90, 0x71, 0x97, 0xb5, 0x92, 0x0f, 0xc7, + 0x0c, 0xb8, 0xc2, 0x6f, 0x52, 0xc1, 0x2c, 0x1a, 0xb3, 0xa4, 0x25, 0x65, 0xc7, 0x52, 0xe9, 0xec, + 0xc6, 0xd2, 0xee, 0x6f, 0x0b, 0x70, 0x5e, 0x26, 0x83, 0x23, 0x98, 0x55, 0x03, 0x17, 0x57, 0x72, + 0x2a, 0x98, 0x99, 0xe1, 0xd6, 0xda, 0xe4, 0xf5, 0xb4, 0x14, 0x64, 0xf5, 0xd3, 0x5f, 0xff, 0xfe, + 0xb2, 0x74, 0x05, 0x2f, 0xd3, 0xf1, 0x3b, 0x85, 0x9a, 0xe6, 0xf8, 0x09, 0x82, 0xf9, 0x6c, 0xc3, + 0xbe, 0x5e, 0xe4, 0x3a, 0x23, 0xb2, 0x6a, 0x53, 0x88, 0x0c, 0xc4, 0xba, 0x84, 0x58, 0xc5, 0xd5, + 0x1c, 0x88, 0x38, 0xd1, 0xb7, 0xf4, 0xb8, 0xfb, 0x0a, 0xc1, 0xd2, 0x48, 0x43, 0x5e, 0x9b, 0x18, + 0xc8, 0xe8, 0x2c, 0x7b, 0x3a, 0x9d, 0x61, 0xda, 0x94, 0x4c, 0x37, 0x30, 0x29, 0x64, 0x1a, 0x8c, + 0xc6, 0xaf, 0x11, 0x2c, 0x0c, 0xdd, 0x19, 0x6e, 0x14, 0x05, 0xcb, 0xaa, 0xac, 0xad, 0x69, 0x54, + 0x06, 0x68, 0x57, 0x02, 0x6d, 0xe1, 0xcd, 0x1c, 0x20, 0x47, 0x19, 0xc8, 0x32, 0x45, 0xf4, 0x91, + 0xbe, 0xa0, 0x3c, 0xc6, 0xdf, 0x20, 0x58, 0x1a, 0xb9, 0x84, 0x15, 0x1f, 0x8c, 0x21, 0x5d, 0x71, + 0xbd, 0xf2, 0xaf, 0x68, 0xe4, 0xa6, 0xc4, 0xb3, 0xf1, 0x56, 0xde, 0x41, 0x52, 0x26, 0x2d, 0x7d, + 0xa0, 0x33, 0x80, 0x3f, 0x23, 0xb0, 0x26, 0x74, 0xe1, 0xdd, 0x22, 0x88, 0x62, 0x1b, 0xeb, 0xad, + 0x93, 0xdb, 0x98, 0x24, 0x6e, 0xc9, 0x24, 0xea, 0x98, 0xd2, 0x09, 0x97, 0xf0, 0x56, 0xda, 0x69, + 0xa9, 0x9b, 0x7a, 0xc4, 0x3f, 0x22, 0x28, 0x17, 0x4d, 0x2f, 0xbc, 0x53, 0x44, 0x54, 0x64, 0x61, + 0xbd, 0x71, 0x52, 0x0b, 0x93, 0xc1, 0x6b, 0x32, 0x03, 0x8a, 0xb7, 0xa7, 0xcb, 0x40, 0x28, 0x7f, + 0xf8, 0x27, 0x04, 0xcb, 0x85, 0xf7, 0x01, 0x5c, 0x2f, 0xc2, 0x29, 0x34, 0xb1, 0xde, 0x3c, 0xb1, + 0x89, 0x49, 0xe1, 0x75, 0x99, 0xc2, 0x0e, 0xb6, 0xa7, 0x4b, 0xa1, 0xa7, 0x1d, 0xe2, 0x6f, 0x11, + 0x5c, 0x1c, 0x9b, 0x55, 0x1b, 0x45, 0x1c, 0xa3, 0x4a, 0x6b, 0x67, 0x5a, 0xa5, 0x01, 0xad, 0x4b, + 0xd0, 0x1a, 0x7e, 0x65, 0x1a, 0x50, 0xfa, 0x28, 0xf0, 0x1e, 0xe3, 0xcf, 0x11, 0x2c, 0x0c, 0x0d, + 0xb0, 0xc2, 0x4e, 0x91, 0x55, 0x15, 0x77, 0x8a, 0xbc, 0xf1, 0x46, 0x36, 0x24, 0x17, 0xc1, 0x2b, + 0x39, 0x5c, 0xae, 0x32, 0x68, 0x85, 0x89, 0x45, 0xe3, 0xf6, 0xd3, 0xa3, 0x0a, 0x7a, 0x76, 0x54, + 0x41, 0x7f, 0x1d, 0x55, 0xd0, 0x17, 0xc7, 0x95, 0x99, 0x67, 0xc7, 0x95, 0x99, 0xdf, 0x8f, 0x2b, + 0x33, 0x1f, 0xd4, 0x32, 0x63, 0x2a, 0xf1, 0xb2, 0xcd, 0x59, 0xfc, 0x40, 0x84, 0x07, 0xca, 0x65, + 0xff, 0x26, 0xfd, 0x78, 0xe0, 0xb7, 0x3d, 0x2b, 0xff, 0xab, 0x7c, 0xf5, 0x9f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x7d, 0xcc, 0x9e, 0x00, 0x4d, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1050,14 +1076,12 @@ const _ = grpc.SupportPackageIsVersion4 type QueryClient interface { // Params queries the parameters of the x/incentive module. Params(ctx context.Context, in *QueryParams, opts ...grpc.CallOption) (*QueryParamsResponse, error) - // TotalBonded queries the sum of all bonded collateral uTokens, separated by tier. + // TotalBonded queries the sum of all bonded collateral uTokens. TotalBonded(ctx context.Context, in *QueryTotalBonded, opts ...grpc.CallOption) (*QueryTotalBondedResponse, error) - // TotalUnbonding queries the sum of all unbonding collateral uTokens, separated by tier. + // TotalUnbonding queries the sum of all unbonding collateral uTokens. TotalUnbonding(ctx context.Context, in *QueryTotalUnbonding, opts ...grpc.CallOption) (*QueryTotalUnbondingResponse, error) - // Bonded queries all bonded collateral uTokens associated with an account. - Bonded(ctx context.Context, in *QueryBonded, opts ...grpc.CallOption) (*QueryBondedResponse, error) - // Unbondings queries all current uToken unbondings associated with an account. - Unbondings(ctx context.Context, in *QueryUnbondings, opts ...grpc.CallOption) (*QueryUnbondingsResponse, error) + // AccountBonds queries all bonded collateral and unbondings associated with an account. + AccountBonds(ctx context.Context, in *QueryAccountBonds, opts ...grpc.CallOption) (*QueryAccountBondsResponse, error) // PendingRewards queries unclaimed incentive rewards associated with an account. PendingRewards(ctx context.Context, in *QueryPendingRewards, opts ...grpc.CallOption) (*QueryPendingRewardsResponse, error) // CompletedIncentivePrograms queries for all incentives programs that have been passed @@ -1071,6 +1095,10 @@ type QueryClient interface { UpcomingIncentivePrograms(ctx context.Context, in *QueryUpcomingIncentivePrograms, opts ...grpc.CallOption) (*QueryUpcomingIncentiveProgramsResponse, error) // IncentiveProgram queries a single incentive program by ID. IncentiveProgram(ctx context.Context, in *QueryIncentiveProgram, opts ...grpc.CallOption) (*QueryIncentiveProgramResponse, error) + // CurrentRates queries the hypothetical return of a bonded uToken denomination + // if current incentive rewards continued for one year. The response is an sdk.Coins + // of base token rewards, per reference amount (usually 10^exponent of the uToken.) + CurrentRates(ctx context.Context, in *QueryCurrentRates, opts ...grpc.CallOption) (*QueryCurrentRatesResponse, error) } type queryClient struct { @@ -1083,7 +1111,7 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { func (c *queryClient) Params(ctx context.Context, in *QueryParams, opts ...grpc.CallOption) (*QueryParamsResponse, error) { out := new(QueryParamsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/Params", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/Params", in, out, opts...) if err != nil { return nil, err } @@ -1092,7 +1120,7 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParams, opts ...grpc. func (c *queryClient) TotalBonded(ctx context.Context, in *QueryTotalBonded, opts ...grpc.CallOption) (*QueryTotalBondedResponse, error) { out := new(QueryTotalBondedResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/TotalBonded", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/TotalBonded", in, out, opts...) if err != nil { return nil, err } @@ -1101,25 +1129,16 @@ func (c *queryClient) TotalBonded(ctx context.Context, in *QueryTotalBonded, opt func (c *queryClient) TotalUnbonding(ctx context.Context, in *QueryTotalUnbonding, opts ...grpc.CallOption) (*QueryTotalUnbondingResponse, error) { out := new(QueryTotalUnbondingResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/TotalUnbonding", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) Bonded(ctx context.Context, in *QueryBonded, opts ...grpc.CallOption) (*QueryBondedResponse, error) { - out := new(QueryBondedResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/Bonded", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/TotalUnbonding", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *queryClient) Unbondings(ctx context.Context, in *QueryUnbondings, opts ...grpc.CallOption) (*QueryUnbondingsResponse, error) { - out := new(QueryUnbondingsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/Unbondings", in, out, opts...) +func (c *queryClient) AccountBonds(ctx context.Context, in *QueryAccountBonds, opts ...grpc.CallOption) (*QueryAccountBondsResponse, error) { + out := new(QueryAccountBondsResponse) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/AccountBonds", in, out, opts...) if err != nil { return nil, err } @@ -1128,7 +1147,7 @@ func (c *queryClient) Unbondings(ctx context.Context, in *QueryUnbondings, opts func (c *queryClient) PendingRewards(ctx context.Context, in *QueryPendingRewards, opts ...grpc.CallOption) (*QueryPendingRewardsResponse, error) { out := new(QueryPendingRewardsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/PendingRewards", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/PendingRewards", in, out, opts...) if err != nil { return nil, err } @@ -1137,7 +1156,7 @@ func (c *queryClient) PendingRewards(ctx context.Context, in *QueryPendingReward func (c *queryClient) CompletedIncentivePrograms(ctx context.Context, in *QueryCompletedIncentivePrograms, opts ...grpc.CallOption) (*QueryCompletedIncentiveProgramsResponse, error) { out := new(QueryCompletedIncentiveProgramsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/CompletedIncentivePrograms", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/CompletedIncentivePrograms", in, out, opts...) if err != nil { return nil, err } @@ -1146,7 +1165,7 @@ func (c *queryClient) CompletedIncentivePrograms(ctx context.Context, in *QueryC func (c *queryClient) OngoingIncentivePrograms(ctx context.Context, in *QueryOngoingIncentivePrograms, opts ...grpc.CallOption) (*QueryOngoingIncentiveProgramsResponse, error) { out := new(QueryOngoingIncentiveProgramsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/OngoingIncentivePrograms", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/OngoingIncentivePrograms", in, out, opts...) if err != nil { return nil, err } @@ -1155,7 +1174,7 @@ func (c *queryClient) OngoingIncentivePrograms(ctx context.Context, in *QueryOng func (c *queryClient) UpcomingIncentivePrograms(ctx context.Context, in *QueryUpcomingIncentivePrograms, opts ...grpc.CallOption) (*QueryUpcomingIncentiveProgramsResponse, error) { out := new(QueryUpcomingIncentiveProgramsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/UpcomingIncentivePrograms", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/UpcomingIncentivePrograms", in, out, opts...) if err != nil { return nil, err } @@ -1164,7 +1183,16 @@ func (c *queryClient) UpcomingIncentivePrograms(ctx context.Context, in *QueryUp func (c *queryClient) IncentiveProgram(ctx context.Context, in *QueryIncentiveProgram, opts ...grpc.CallOption) (*QueryIncentiveProgramResponse, error) { out := new(QueryIncentiveProgramResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Query/IncentiveProgram", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/IncentiveProgram", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) CurrentRates(ctx context.Context, in *QueryCurrentRates, opts ...grpc.CallOption) (*QueryCurrentRatesResponse, error) { + out := new(QueryCurrentRatesResponse) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Query/CurrentRates", in, out, opts...) if err != nil { return nil, err } @@ -1175,14 +1203,12 @@ func (c *queryClient) IncentiveProgram(ctx context.Context, in *QueryIncentivePr type QueryServer interface { // Params queries the parameters of the x/incentive module. Params(context.Context, *QueryParams) (*QueryParamsResponse, error) - // TotalBonded queries the sum of all bonded collateral uTokens, separated by tier. + // TotalBonded queries the sum of all bonded collateral uTokens. TotalBonded(context.Context, *QueryTotalBonded) (*QueryTotalBondedResponse, error) - // TotalUnbonding queries the sum of all unbonding collateral uTokens, separated by tier. + // TotalUnbonding queries the sum of all unbonding collateral uTokens. TotalUnbonding(context.Context, *QueryTotalUnbonding) (*QueryTotalUnbondingResponse, error) - // Bonded queries all bonded collateral uTokens associated with an account. - Bonded(context.Context, *QueryBonded) (*QueryBondedResponse, error) - // Unbondings queries all current uToken unbondings associated with an account. - Unbondings(context.Context, *QueryUnbondings) (*QueryUnbondingsResponse, error) + // AccountBonds queries all bonded collateral and unbondings associated with an account. + AccountBonds(context.Context, *QueryAccountBonds) (*QueryAccountBondsResponse, error) // PendingRewards queries unclaimed incentive rewards associated with an account. PendingRewards(context.Context, *QueryPendingRewards) (*QueryPendingRewardsResponse, error) // CompletedIncentivePrograms queries for all incentives programs that have been passed @@ -1196,6 +1222,10 @@ type QueryServer interface { UpcomingIncentivePrograms(context.Context, *QueryUpcomingIncentivePrograms) (*QueryUpcomingIncentiveProgramsResponse, error) // IncentiveProgram queries a single incentive program by ID. IncentiveProgram(context.Context, *QueryIncentiveProgram) (*QueryIncentiveProgramResponse, error) + // CurrentRates queries the hypothetical return of a bonded uToken denomination + // if current incentive rewards continued for one year. The response is an sdk.Coins + // of base token rewards, per reference amount (usually 10^exponent of the uToken.) + CurrentRates(context.Context, *QueryCurrentRates) (*QueryCurrentRatesResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1211,11 +1241,8 @@ func (*UnimplementedQueryServer) TotalBonded(ctx context.Context, req *QueryTota func (*UnimplementedQueryServer) TotalUnbonding(ctx context.Context, req *QueryTotalUnbonding) (*QueryTotalUnbondingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TotalUnbonding not implemented") } -func (*UnimplementedQueryServer) Bonded(ctx context.Context, req *QueryBonded) (*QueryBondedResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Bonded not implemented") -} -func (*UnimplementedQueryServer) Unbondings(ctx context.Context, req *QueryUnbondings) (*QueryUnbondingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Unbondings not implemented") +func (*UnimplementedQueryServer) AccountBonds(ctx context.Context, req *QueryAccountBonds) (*QueryAccountBondsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AccountBonds not implemented") } func (*UnimplementedQueryServer) PendingRewards(ctx context.Context, req *QueryPendingRewards) (*QueryPendingRewardsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PendingRewards not implemented") @@ -1232,6 +1259,9 @@ func (*UnimplementedQueryServer) UpcomingIncentivePrograms(ctx context.Context, func (*UnimplementedQueryServer) IncentiveProgram(ctx context.Context, req *QueryIncentiveProgram) (*QueryIncentiveProgramResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method IncentiveProgram not implemented") } +func (*UnimplementedQueryServer) CurrentRates(ctx context.Context, req *QueryCurrentRates) (*QueryCurrentRatesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CurrentRates not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1247,7 +1277,7 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/Params", + FullMethod: "/umee.incentive.v1.Query/Params", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).Params(ctx, req.(*QueryParams)) @@ -1265,7 +1295,7 @@ func _Query_TotalBonded_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/TotalBonded", + FullMethod: "/umee.incentive.v1.Query/TotalBonded", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).TotalBonded(ctx, req.(*QueryTotalBonded)) @@ -1283,7 +1313,7 @@ func _Query_TotalUnbonding_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/TotalUnbonding", + FullMethod: "/umee.incentive.v1.Query/TotalUnbonding", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).TotalUnbonding(ctx, req.(*QueryTotalUnbonding)) @@ -1291,38 +1321,20 @@ func _Query_TotalUnbonding_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } -func _Query_Bonded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryBonded) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).Bonded(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/Bonded", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Bonded(ctx, req.(*QueryBonded)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_Unbondings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryUnbondings) +func _Query_AccountBonds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAccountBonds) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).Unbondings(ctx, in) + return srv.(QueryServer).AccountBonds(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/Unbondings", + FullMethod: "/umee.incentive.v1.Query/AccountBonds", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Unbondings(ctx, req.(*QueryUnbondings)) + return srv.(QueryServer).AccountBonds(ctx, req.(*QueryAccountBonds)) } return interceptor(ctx, in, info, handler) } @@ -1337,7 +1349,7 @@ func _Query_PendingRewards_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/PendingRewards", + FullMethod: "/umee.incentive.v1.Query/PendingRewards", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).PendingRewards(ctx, req.(*QueryPendingRewards)) @@ -1355,7 +1367,7 @@ func _Query_CompletedIncentivePrograms_Handler(srv interface{}, ctx context.Cont } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/CompletedIncentivePrograms", + FullMethod: "/umee.incentive.v1.Query/CompletedIncentivePrograms", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).CompletedIncentivePrograms(ctx, req.(*QueryCompletedIncentivePrograms)) @@ -1373,7 +1385,7 @@ func _Query_OngoingIncentivePrograms_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/OngoingIncentivePrograms", + FullMethod: "/umee.incentive.v1.Query/OngoingIncentivePrograms", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).OngoingIncentivePrograms(ctx, req.(*QueryOngoingIncentivePrograms)) @@ -1391,7 +1403,7 @@ func _Query_UpcomingIncentivePrograms_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/UpcomingIncentivePrograms", + FullMethod: "/umee.incentive.v1.Query/UpcomingIncentivePrograms", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).UpcomingIncentivePrograms(ctx, req.(*QueryUpcomingIncentivePrograms)) @@ -1409,7 +1421,7 @@ func _Query_IncentiveProgram_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Query/IncentiveProgram", + FullMethod: "/umee.incentive.v1.Query/IncentiveProgram", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).IncentiveProgram(ctx, req.(*QueryIncentiveProgram)) @@ -1417,8 +1429,26 @@ func _Query_IncentiveProgram_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Query_CurrentRates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCurrentRates) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).CurrentRates(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umee.incentive.v1.Query/CurrentRates", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).CurrentRates(ctx, req.(*QueryCurrentRates)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "umeenetwork.umee.incentive.v1.Query", + ServiceName: "umee.incentive.v1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ { @@ -1434,12 +1464,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_TotalUnbonding_Handler, }, { - MethodName: "Bonded", - Handler: _Query_Bonded_Handler, - }, - { - MethodName: "Unbondings", - Handler: _Query_Unbondings_Handler, + MethodName: "AccountBonds", + Handler: _Query_AccountBonds_Handler, }, { MethodName: "PendingRewards", @@ -1461,6 +1487,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "IncentiveProgram", Handler: _Query_IncentiveProgram_Handler, }, + { + MethodName: "CurrentRates", + Handler: _Query_CurrentRates_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "umee/incentive/v1/query.proto", @@ -1589,7 +1619,7 @@ func (m *QueryPendingRewardsResponse) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } -func (m *QueryBonded) Marshal() (dAtA []byte, err error) { +func (m *QueryAccountBonds) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1599,23 +1629,16 @@ func (m *QueryBonded) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryBonded) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryAccountBonds) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryBonded) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryAccountBonds) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0x12 - } if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) @@ -1626,7 +1649,7 @@ func (m *QueryBonded) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryBondedResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryAccountBondsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1636,16 +1659,44 @@ func (m *QueryBondedResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryBondedResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryAccountBondsResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryBondedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryAccountBondsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if len(m.Unbondings) > 0 { + for iNdEx := len(m.Unbondings) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Unbondings[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Unbonding) > 0 { + for iNdEx := len(m.Unbonding) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Unbonding[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } if len(m.Bonded) > 0 { for iNdEx := len(m.Bonded) - 1; iNdEx >= 0; iNdEx-- { { @@ -1663,7 +1714,7 @@ func (m *QueryBondedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryUnbondings) Marshal() (dAtA []byte, err error) { +func (m *QueryTotalBonded) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1673,27 +1724,27 @@ func (m *QueryUnbondings) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryUnbondings) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTotalBonded) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryUnbondings) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTotalBonded) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *QueryUnbondingsResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryTotalBondedResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1703,20 +1754,20 @@ func (m *QueryUnbondingsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryUnbondingsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTotalBondedResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryUnbondingsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTotalBondedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Unbondings) > 0 { - for iNdEx := len(m.Unbondings) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Bonded) > 0 { + for iNdEx := len(m.Bonded) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Unbondings[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Bonded[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1730,7 +1781,7 @@ func (m *QueryUnbondingsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *QueryTotalBonded) Marshal() (dAtA []byte, err error) { +func (m *QueryTotalUnbonding) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1740,12 +1791,12 @@ func (m *QueryTotalBonded) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryTotalBonded) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTotalUnbonding) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryTotalBonded) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTotalUnbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1760,7 +1811,7 @@ func (m *QueryTotalBonded) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryTotalBondedResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryTotalUnbondingResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1770,20 +1821,20 @@ func (m *QueryTotalBondedResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryTotalBondedResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTotalUnbondingResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryTotalBondedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTotalUnbondingResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Bonded) > 0 { - for iNdEx := len(m.Bonded) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Unbonding) > 0 { + for iNdEx := len(m.Unbonding) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Bonded[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Unbonding[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1797,74 +1848,7 @@ func (m *QueryTotalBondedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } -func (m *QueryTotalUnbonding) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryTotalUnbonding) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryTotalUnbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryTotalUnbondingResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryTotalUnbondingResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryTotalUnbondingResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Unbonding) > 0 { - for iNdEx := len(m.Unbonding) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Unbonding[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryUpcomingIncentivePrograms) Marshal() (dAtA []byte, err error) { +func (m *QueryUpcomingIncentivePrograms) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2129,6 +2113,83 @@ func (m *QueryIncentiveProgramResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryCurrentRates) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryCurrentRates) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCurrentRates) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.UToken) > 0 { + i -= len(m.UToken) + copy(dAtA[i:], m.UToken) + i = encodeVarintQuery(dAtA, i, uint64(len(m.UToken))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryCurrentRatesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryCurrentRatesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCurrentRatesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.ReferenceBond.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -2188,7 +2249,7 @@ func (m *QueryPendingRewardsResponse) Size() (n int) { return n } -func (m *QueryBonded) Size() (n int) { +func (m *QueryAccountBonds) Size() (n int) { if m == nil { return 0 } @@ -2198,14 +2259,10 @@ func (m *QueryBonded) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } return n } -func (m *QueryBondedResponse) Size() (n int) { +func (m *QueryAccountBondsResponse) Size() (n int) { if m == nil { return 0 } @@ -2217,28 +2274,12 @@ func (m *QueryBondedResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } - return n -} - -func (m *QueryUnbondings) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryUnbondingsResponse) Size() (n int) { - if m == nil { - return 0 + if len(m.Unbonding) > 0 { + for _, e := range m.Unbonding { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } } - var l int - _ = l if len(m.Unbondings) > 0 { for _, e := range m.Unbondings { l = e.Size() @@ -2407,6 +2448,36 @@ func (m *QueryIncentiveProgramResponse) Size() (n int) { return n } +func (m *QueryCurrentRates) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UToken) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryCurrentRatesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ReferenceBond.Size() + n += 1 + l + sovQuery(uint64(l)) + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2687,205 +2758,7 @@ func (m *QueryPendingRewardsResponse) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } m.Rewards = append(m.Rewards, types.Coin{}) - if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryBonded) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryBonded: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryBonded: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryBondedResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryBondedResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryBondedResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Bonded", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Bonded = append(m.Bonded, TotalBond{}) - if err := m.Bonded[len(m.Bonded)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2910,7 +2783,7 @@ func (m *QueryBondedResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryUnbondings) Unmarshal(dAtA []byte) error { +func (m *QueryAccountBonds) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2933,10 +2806,10 @@ func (m *QueryUnbondings) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryUnbondings: wiretype end group for non-group") + return fmt.Errorf("proto: QueryAccountBonds: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryUnbondings: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryAccountBonds: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -2992,7 +2865,7 @@ func (m *QueryUnbondings) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryUnbondingsResponse) Unmarshal(dAtA []byte) error { +func (m *QueryAccountBondsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3015,13 +2888,81 @@ func (m *QueryUnbondingsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryUnbondingsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryAccountBondsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryUnbondingsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryAccountBondsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bonded", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Bonded = append(m.Bonded, types.Coin{}) + if err := m.Bonded[len(m.Bonded)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Unbonding", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Unbonding = append(m.Unbonding, types.Coin{}) + if err := m.Unbonding[len(m.Unbonding)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Unbondings", wireType) } @@ -3216,7 +3157,7 @@ func (m *QueryTotalBondedResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Bonded = append(m.Bonded, TotalBond{}) + m.Bonded = append(m.Bonded, types.Coin{}) if err := m.Bonded[len(m.Bonded)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -3382,7 +3323,7 @@ func (m *QueryTotalUnbondingResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Unbonding = append(m.Unbonding, TotalBond{}) + m.Unbonding = append(m.Unbonding, types.Coin{}) if err := m.Unbonding[len(m.Unbonding)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4034,6 +3975,205 @@ func (m *QueryIncentiveProgramResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryCurrentRates) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryCurrentRates: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCurrentRates: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UToken = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryCurrentRatesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryCurrentRatesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCurrentRatesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReferenceBond", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ReferenceBond.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewards = append(m.Rewards, types.Coin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/incentive/query.pb.gw.go b/x/incentive/query.pb.gw.go index ce98942233..6d1008b709 100644 --- a/x/incentive/query.pb.gw.go +++ b/x/incentive/query.pb.gw.go @@ -51,26 +51,19 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal } +var ( + filter_Query_TotalBonded_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Query_TotalBonded_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryTotalBonded var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalBonded_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.TotalBonded(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -82,22 +75,11 @@ func local_request_Query_TotalBonded_0(ctx context.Context, marshaler runtime.Ma var protoReq QueryTotalBonded var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalBonded_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.TotalBonded(ctx, &protoReq) @@ -105,26 +87,19 @@ func local_request_Query_TotalBonded_0(ctx context.Context, marshaler runtime.Ma } +var ( + filter_Query_TotalUnbonding_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Query_TotalUnbonding_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryTotalUnbonding var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalUnbonding_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.TotalUnbonding(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -136,22 +111,11 @@ func local_request_Query_TotalUnbonding_0(ctx context.Context, marshaler runtime var protoReq QueryTotalUnbonding var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalUnbonding_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.TotalUnbonding(ctx, &protoReq) @@ -159,46 +123,8 @@ func local_request_Query_TotalUnbonding_0(ctx context.Context, marshaler runtime } -func request_Query_Bonded_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryBonded - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") - } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) - } - - msg, err := client.Bonded(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_Bonded_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryBonded +func request_Query_AccountBonds_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAccountBonds var metadata runtime.ServerMetadata var ( @@ -219,24 +145,13 @@ func local_request_Query_Bonded_0(ctx context.Context, marshaler runtime.Marshal return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) } - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") - } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) - } - - msg, err := server.Bonded(ctx, &protoReq) + msg, err := client.AccountBonds(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func request_Query_Unbondings_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryUnbondings +func local_request_Query_AccountBonds_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAccountBonds var metadata runtime.ServerMetadata var ( @@ -257,34 +172,7 @@ func request_Query_Unbondings_0(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) } - msg, err := client.Unbondings(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_Unbondings_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryUnbondings - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - msg, err := server.Unbondings(ctx, &protoReq) + msg, err := server.AccountBonds(ctx, &protoReq) return msg, metadata, err } @@ -469,6 +357,42 @@ func local_request_Query_IncentiveProgram_0(ctx context.Context, marshaler runti } +var ( + filter_Query_CurrentRates_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_CurrentRates_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCurrentRates + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CurrentRates_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CurrentRates(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_CurrentRates_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCurrentRates + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CurrentRates_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CurrentRates(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -544,7 +468,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_Bonded_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_AccountBonds_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -555,7 +479,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_Bonded_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_AccountBonds_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -563,11 +487,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_Bonded_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_AccountBonds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_Unbondings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_PendingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -578,7 +502,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_Unbondings_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_PendingRewards_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -586,11 +510,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_Unbondings_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_PendingRewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_PendingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CompletedIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -601,7 +525,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_PendingRewards_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_CompletedIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -609,11 +533,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_PendingRewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CompletedIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_CompletedIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_OngoingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -624,7 +548,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_CompletedIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_OngoingIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -632,11 +556,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_CompletedIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_OngoingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_OngoingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_UpcomingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -647,7 +571,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_OngoingIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_UpcomingIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -655,11 +579,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_OngoingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_UpcomingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_UpcomingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_IncentiveProgram_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -670,7 +594,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_UpcomingIncentivePrograms_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_IncentiveProgram_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -678,11 +602,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_UpcomingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_IncentiveProgram_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_IncentiveProgram_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CurrentRates_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -693,7 +617,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_IncentiveProgram_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_CurrentRates_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -701,7 +625,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_IncentiveProgram_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CurrentRates_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -806,7 +730,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_Bonded_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_AccountBonds_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -815,18 +739,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_Bonded_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_AccountBonds_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_Bonded_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_AccountBonds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_Unbondings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_PendingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -835,18 +759,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_Unbondings_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_PendingRewards_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_Unbondings_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_PendingRewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_PendingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CompletedIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -855,18 +779,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_PendingRewards_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_CompletedIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_PendingRewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CompletedIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_CompletedIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_OngoingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -875,18 +799,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_CompletedIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_OngoingIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_CompletedIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_OngoingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_OngoingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_UpcomingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -895,18 +819,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_OngoingIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_UpcomingIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_OngoingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_UpcomingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_UpcomingIncentivePrograms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_IncentiveProgram_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -915,18 +839,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_UpcomingIncentivePrograms_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_IncentiveProgram_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_UpcomingIncentivePrograms_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_IncentiveProgram_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_IncentiveProgram_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CurrentRates_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -935,14 +859,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_IncentiveProgram_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_CurrentRates_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_IncentiveProgram_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CurrentRates_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -952,13 +876,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "incentive", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_TotalBonded_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "total_bonded", "denom"}, "", runtime.AssumeColonVerbOpt(false))) - - pattern_Query_TotalUnbonding_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "total_unbonding", "denom"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_TotalBonded_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "incentive", "v1", "total_bonded"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Bonded_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"umee", "incentive", "v1", "bonded", "address", "denom"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_TotalUnbonding_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "incentive", "v1", "total_unbonding"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Unbondings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "unbondings", "address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_AccountBonds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "account_bonds", "address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_PendingRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "pending_rewards", "address"}, "", runtime.AssumeColonVerbOpt(false))) @@ -969,6 +891,8 @@ var ( pattern_Query_UpcomingIncentivePrograms_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"umee", "incentive", "v1", "incentive_programs", "upcoming"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_IncentiveProgram_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"umee", "incentive", "v1", "incentive_program", "id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_CurrentRates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "incentive", "v1", "current_rates"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -978,9 +902,7 @@ var ( forward_Query_TotalUnbonding_0 = runtime.ForwardResponseMessage - forward_Query_Bonded_0 = runtime.ForwardResponseMessage - - forward_Query_Unbondings_0 = runtime.ForwardResponseMessage + forward_Query_AccountBonds_0 = runtime.ForwardResponseMessage forward_Query_PendingRewards_0 = runtime.ForwardResponseMessage @@ -991,4 +913,6 @@ var ( forward_Query_UpcomingIncentivePrograms_0 = runtime.ForwardResponseMessage forward_Query_IncentiveProgram_0 = runtime.ForwardResponseMessage + + forward_Query_CurrentRates_0 = runtime.ForwardResponseMessage ) diff --git a/x/incentive/tx.pb.go b/x/incentive/tx.pb.go index 535c9f30fb..7c7b7a01d0 100644 --- a/x/incentive/tx.pb.go +++ b/x/incentive/tx.pb.go @@ -125,8 +125,7 @@ func (m *MsgClaimResponse) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins // MsgBond represents a account's request to bond uToken collateral. type MsgBond struct { Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` - Tier uint32 `protobuf:"varint,2,opt,name=tier,proto3" json:"tier,omitempty"` - Asset types.Coin `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset"` + UToken types.Coin `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken"` } func (m *MsgBond) Reset() { *m = MsgBond{} } @@ -169,16 +168,9 @@ func (m *MsgBond) GetAccount() string { return "" } -func (m *MsgBond) GetTier() uint32 { +func (m *MsgBond) GetUToken() types.Coin { if m != nil { - return m.Tier - } - return 0 -} - -func (m *MsgBond) GetAsset() types.Coin { - if m != nil { - return m.Asset + return m.UToken } return types.Coin{} } @@ -223,8 +215,7 @@ var xxx_messageInfo_MsgBondResponse proto.InternalMessageInfo // MsgBeginUnbonding represents a account's request to begin unbonding uToken collateral. type MsgBeginUnbonding struct { Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` - Tier uint32 `protobuf:"varint,2,opt,name=tier,proto3" json:"tier,omitempty"` - Asset types.Coin `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset"` + UToken types.Coin `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken"` } func (m *MsgBeginUnbonding) Reset() { *m = MsgBeginUnbonding{} } @@ -267,16 +258,9 @@ func (m *MsgBeginUnbonding) GetAccount() string { return "" } -func (m *MsgBeginUnbonding) GetTier() uint32 { - if m != nil { - return m.Tier - } - return 0 -} - -func (m *MsgBeginUnbonding) GetAsset() types.Coin { +func (m *MsgBeginUnbonding) GetUToken() types.Coin { if m != nil { - return m.Asset + return m.UToken } return types.Coin{} } @@ -318,21 +302,110 @@ func (m *MsgBeginUnbondingResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgBeginUnbondingResponse proto.InternalMessageInfo +// MsgEmergencyUnbond represents a account's request to instantly unbond uToken collateral for a fee. +type MsgEmergencyUnbond struct { + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` + UToken types.Coin `protobuf:"bytes,2,opt,name=uToken,proto3" json:"uToken"` +} + +func (m *MsgEmergencyUnbond) Reset() { *m = MsgEmergencyUnbond{} } +func (m *MsgEmergencyUnbond) String() string { return proto.CompactTextString(m) } +func (*MsgEmergencyUnbond) ProtoMessage() {} +func (*MsgEmergencyUnbond) Descriptor() ([]byte, []int) { + return fileDescriptor_d04c68bb9e1f6306, []int{6} +} +func (m *MsgEmergencyUnbond) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEmergencyUnbond) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEmergencyUnbond.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgEmergencyUnbond) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEmergencyUnbond.Merge(m, src) +} +func (m *MsgEmergencyUnbond) XXX_Size() int { + return m.Size() +} +func (m *MsgEmergencyUnbond) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEmergencyUnbond.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEmergencyUnbond proto.InternalMessageInfo + +func (m *MsgEmergencyUnbond) GetAccount() string { + if m != nil { + return m.Account + } + return "" +} + +func (m *MsgEmergencyUnbond) GetUToken() types.Coin { + if m != nil { + return m.UToken + } + return types.Coin{} +} + +// MsgEmergencyUnbondResponse defines the Msg/EmergencyUnbond response type. +type MsgEmergencyUnbondResponse struct { +} + +func (m *MsgEmergencyUnbondResponse) Reset() { *m = MsgEmergencyUnbondResponse{} } +func (m *MsgEmergencyUnbondResponse) String() string { return proto.CompactTextString(m) } +func (*MsgEmergencyUnbondResponse) ProtoMessage() {} +func (*MsgEmergencyUnbondResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d04c68bb9e1f6306, []int{7} +} +func (m *MsgEmergencyUnbondResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEmergencyUnbondResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEmergencyUnbondResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgEmergencyUnbondResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEmergencyUnbondResponse.Merge(m, src) +} +func (m *MsgEmergencyUnbondResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgEmergencyUnbondResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEmergencyUnbondResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEmergencyUnbondResponse proto.InternalMessageInfo + // MsgSponsor represents a sponsor's request to fund rewards for an incentive program. // The program must have been passed by governance, not yet started, and not yet funded. // Funded assets must be the full amount required by the program. type MsgSponsor struct { // Sponsor bech32 account address - Sponsor string `protobuf:"bytes,1,opt,name=sponsor,proto3" json:"sponsor,omitempty"` - Program uint32 `protobuf:"varint,2,opt,name=program,proto3" json:"program,omitempty"` - Asset types.Coin `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset"` + Sponsor string `protobuf:"bytes,1,opt,name=sponsor,proto3" json:"sponsor,omitempty"` + Program uint32 `protobuf:"varint,2,opt,name=program,proto3" json:"program,omitempty"` } func (m *MsgSponsor) Reset() { *m = MsgSponsor{} } func (m *MsgSponsor) String() string { return proto.CompactTextString(m) } func (*MsgSponsor) ProtoMessage() {} func (*MsgSponsor) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{6} + return fileDescriptor_d04c68bb9e1f6306, []int{8} } func (m *MsgSponsor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -375,13 +448,6 @@ func (m *MsgSponsor) GetProgram() uint32 { return 0 } -func (m *MsgSponsor) GetAsset() types.Coin { - if m != nil { - return m.Asset - } - return types.Coin{} -} - // MsgSponsorResponse defines the Msg/Sponsor response type. type MsgSponsorResponse struct { } @@ -390,7 +456,7 @@ func (m *MsgSponsorResponse) Reset() { *m = MsgSponsorResponse{} } func (m *MsgSponsorResponse) String() string { return proto.CompactTextString(m) } func (*MsgSponsorResponse) ProtoMessage() {} func (*MsgSponsorResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{7} + return fileDescriptor_d04c68bb9e1f6306, []int{9} } func (m *MsgSponsorResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -432,7 +498,7 @@ func (m *MsgGovSetParams) Reset() { *m = MsgGovSetParams{} } func (m *MsgGovSetParams) String() string { return proto.CompactTextString(m) } func (*MsgGovSetParams) ProtoMessage() {} func (*MsgGovSetParams) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{8} + return fileDescriptor_d04c68bb9e1f6306, []int{10} } func (m *MsgGovSetParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -469,7 +535,7 @@ func (m *MsgGovSetParamsResponse) Reset() { *m = MsgGovSetParamsResponse func (m *MsgGovSetParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgGovSetParamsResponse) ProtoMessage() {} func (*MsgGovSetParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{9} + return fileDescriptor_d04c68bb9e1f6306, []int{11} } func (m *MsgGovSetParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -520,7 +586,7 @@ func (m *MsgGovCreatePrograms) Reset() { *m = MsgGovCreatePrograms{} } func (m *MsgGovCreatePrograms) String() string { return proto.CompactTextString(m) } func (*MsgGovCreatePrograms) ProtoMessage() {} func (*MsgGovCreatePrograms) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{10} + return fileDescriptor_d04c68bb9e1f6306, []int{12} } func (m *MsgGovCreatePrograms) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -557,7 +623,7 @@ func (m *MsgGovCreateProgramsResponse) Reset() { *m = MsgGovCreateProgra func (m *MsgGovCreateProgramsResponse) String() string { return proto.CompactTextString(m) } func (*MsgGovCreateProgramsResponse) ProtoMessage() {} func (*MsgGovCreateProgramsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d04c68bb9e1f6306, []int{11} + return fileDescriptor_d04c68bb9e1f6306, []int{13} } func (m *MsgGovCreateProgramsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -587,71 +653,74 @@ func (m *MsgGovCreateProgramsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgGovCreateProgramsResponse proto.InternalMessageInfo func init() { - proto.RegisterType((*MsgClaim)(nil), "umeenetwork.umee.incentive.v1.MsgClaim") - proto.RegisterType((*MsgClaimResponse)(nil), "umeenetwork.umee.incentive.v1.MsgClaimResponse") - proto.RegisterType((*MsgBond)(nil), "umeenetwork.umee.incentive.v1.MsgBond") - proto.RegisterType((*MsgBondResponse)(nil), "umeenetwork.umee.incentive.v1.MsgBondResponse") - proto.RegisterType((*MsgBeginUnbonding)(nil), "umeenetwork.umee.incentive.v1.MsgBeginUnbonding") - proto.RegisterType((*MsgBeginUnbondingResponse)(nil), "umeenetwork.umee.incentive.v1.MsgBeginUnbondingResponse") - proto.RegisterType((*MsgSponsor)(nil), "umeenetwork.umee.incentive.v1.MsgSponsor") - proto.RegisterType((*MsgSponsorResponse)(nil), "umeenetwork.umee.incentive.v1.MsgSponsorResponse") - proto.RegisterType((*MsgGovSetParams)(nil), "umeenetwork.umee.incentive.v1.MsgGovSetParams") - proto.RegisterType((*MsgGovSetParamsResponse)(nil), "umeenetwork.umee.incentive.v1.MsgGovSetParamsResponse") - proto.RegisterType((*MsgGovCreatePrograms)(nil), "umeenetwork.umee.incentive.v1.MsgGovCreatePrograms") - proto.RegisterType((*MsgGovCreateProgramsResponse)(nil), "umeenetwork.umee.incentive.v1.MsgGovCreateProgramsResponse") + proto.RegisterType((*MsgClaim)(nil), "umee.incentive.v1.MsgClaim") + proto.RegisterType((*MsgClaimResponse)(nil), "umee.incentive.v1.MsgClaimResponse") + proto.RegisterType((*MsgBond)(nil), "umee.incentive.v1.MsgBond") + proto.RegisterType((*MsgBondResponse)(nil), "umee.incentive.v1.MsgBondResponse") + proto.RegisterType((*MsgBeginUnbonding)(nil), "umee.incentive.v1.MsgBeginUnbonding") + proto.RegisterType((*MsgBeginUnbondingResponse)(nil), "umee.incentive.v1.MsgBeginUnbondingResponse") + proto.RegisterType((*MsgEmergencyUnbond)(nil), "umee.incentive.v1.MsgEmergencyUnbond") + proto.RegisterType((*MsgEmergencyUnbondResponse)(nil), "umee.incentive.v1.MsgEmergencyUnbondResponse") + proto.RegisterType((*MsgSponsor)(nil), "umee.incentive.v1.MsgSponsor") + proto.RegisterType((*MsgSponsorResponse)(nil), "umee.incentive.v1.MsgSponsorResponse") + proto.RegisterType((*MsgGovSetParams)(nil), "umee.incentive.v1.MsgGovSetParams") + proto.RegisterType((*MsgGovSetParamsResponse)(nil), "umee.incentive.v1.MsgGovSetParamsResponse") + proto.RegisterType((*MsgGovCreatePrograms)(nil), "umee.incentive.v1.MsgGovCreatePrograms") + proto.RegisterType((*MsgGovCreateProgramsResponse)(nil), "umee.incentive.v1.MsgGovCreateProgramsResponse") } func init() { proto.RegisterFile("umee/incentive/v1/tx.proto", fileDescriptor_d04c68bb9e1f6306) } var fileDescriptor_d04c68bb9e1f6306 = []byte{ - // 742 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x95, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xc7, 0xe3, 0x36, 0x69, 0x9b, 0x29, 0x5f, 0x31, 0x11, 0x4d, 0x0c, 0x38, 0x21, 0xe2, 0x23, - 0x80, 0x6a, 0x37, 0x2d, 0x54, 0x08, 0x4e, 0x24, 0x02, 0xc4, 0x21, 0x52, 0x71, 0xc5, 0x85, 0x03, - 0x95, 0x63, 0x6f, 0xdd, 0x55, 0xeb, 0xdd, 0xc8, 0xbb, 0x49, 0x5b, 0x89, 0x13, 0x12, 0x12, 0x47, - 0x1e, 0xa1, 0x5c, 0xb9, 0xc0, 0x81, 0x87, 0xe8, 0xb1, 0xe2, 0xc4, 0xa9, 0xa0, 0xf6, 0x00, 0x8f, - 0x81, 0xd6, 0x5e, 0x3b, 0xfd, 0xa0, 0x4d, 0xda, 0x43, 0x4f, 0xd9, 0xf1, 0xfc, 0x67, 0xe6, 0x37, - 0x13, 0xed, 0x2c, 0x68, 0x1d, 0x1f, 0x21, 0x13, 0x13, 0x07, 0x11, 0x8e, 0xbb, 0xc8, 0xec, 0xd6, - 0x4c, 0xbe, 0x66, 0xb4, 0x03, 0xca, 0xa9, 0x7a, 0x5d, 0xf8, 0x08, 0xe2, 0xab, 0x34, 0x58, 0x36, - 0xc4, 0xd9, 0x48, 0x74, 0x46, 0xb7, 0xa6, 0xe9, 0x0e, 0x65, 0x3e, 0x65, 0x66, 0xcb, 0x66, 0x22, - 0xae, 0x85, 0xb8, 0x5d, 0x33, 0x1d, 0x8a, 0x49, 0x14, 0xae, 0x15, 0x23, 0xff, 0x42, 0x68, 0x99, - 0x91, 0x21, 0x5d, 0x13, 0x32, 0xd4, 0x67, 0x9e, 0xa8, 0xe8, 0x33, 0x4f, 0x3a, 0xf2, 0x1e, 0xf5, - 0x68, 0x14, 0x20, 0x4e, 0xf2, 0xeb, 0x8d, 0xc3, 0x90, 0x3d, 0x92, 0x50, 0x52, 0xb9, 0x09, 0x63, - 0x4d, 0xe6, 0x35, 0x56, 0x6c, 0xec, 0xab, 0x05, 0x18, 0xb5, 0x1d, 0x87, 0x76, 0x08, 0x2f, 0x28, - 0x65, 0xa5, 0x9a, 0xb5, 0x62, 0xb3, 0xb2, 0x0a, 0x97, 0x62, 0x95, 0x85, 0x58, 0x9b, 0x12, 0x86, - 0x54, 0x07, 0x46, 0x6c, 0x5f, 0x8a, 0x87, 0xab, 0xe3, 0xd3, 0x45, 0x43, 0xa2, 0x8a, 0xbe, 0x0c, - 0xd9, 0x97, 0xd1, 0xa0, 0x98, 0xd4, 0xa7, 0x36, 0xb7, 0x4b, 0xa9, 0x2f, 0xbf, 0x4a, 0x55, 0x0f, - 0xf3, 0xa5, 0x4e, 0xcb, 0x70, 0xa8, 0x2f, 0xfb, 0x92, 0x3f, 0x93, 0xcc, 0x5d, 0x36, 0xf9, 0x7a, - 0x1b, 0xb1, 0x30, 0x80, 0x59, 0x32, 0x75, 0x85, 0xc0, 0x68, 0x93, 0x79, 0x75, 0x4a, 0xdc, 0xa3, - 0xe9, 0x54, 0x15, 0xd2, 0x1c, 0xa3, 0xa0, 0x30, 0x54, 0x56, 0xaa, 0xe7, 0xad, 0xf0, 0xac, 0x3e, - 0x84, 0x8c, 0xcd, 0x18, 0xe2, 0x85, 0xe1, 0xb2, 0x72, 0x3c, 0x5c, 0x5a, 0xc0, 0x59, 0x91, 0xba, - 0x92, 0x83, 0x8b, 0xb2, 0x5e, 0xdc, 0x67, 0x65, 0x0d, 0x72, 0xe2, 0x13, 0xf2, 0x30, 0x79, 0x4d, - 0x5a, 0x94, 0xb8, 0x98, 0x78, 0x67, 0x03, 0x73, 0x15, 0x8a, 0x87, 0x2a, 0x27, 0x58, 0xab, 0x00, - 0x4d, 0xe6, 0xcd, 0x0b, 0x83, 0x06, 0x82, 0x87, 0x45, 0xc7, 0x98, 0x87, 0xf5, 0x3c, 0xed, 0x80, - 0x7a, 0x81, 0xed, 0x4b, 0xa4, 0xd8, 0x3c, 0x2d, 0x55, 0x1e, 0xd4, 0x5e, 0xe1, 0x04, 0x67, 0x5b, - 0x09, 0x27, 0xf7, 0x82, 0x76, 0xe7, 0x11, 0x9f, 0xb3, 0x03, 0xdb, 0x67, 0xea, 0x2c, 0x64, 0xed, - 0x0e, 0x5f, 0xa2, 0x01, 0xe6, 0xeb, 0x11, 0x56, 0xbd, 0xf0, 0xe3, 0xfb, 0x64, 0x5e, 0xd6, 0x79, - 0xea, 0xba, 0x01, 0x62, 0x6c, 0x9e, 0x07, 0xa2, 0xaf, 0x9e, 0x54, 0xcd, 0x43, 0x86, 0x63, 0xbe, - 0x82, 0x42, 0xe0, 0xac, 0x15, 0x19, 0x6a, 0x19, 0xc6, 0x5d, 0xc4, 0x9c, 0x00, 0xb7, 0x39, 0xa6, - 0x24, 0x84, 0xce, 0x5a, 0x7b, 0x3f, 0xa9, 0x0d, 0x18, 0x69, 0x87, 0x95, 0x0b, 0xe9, 0xb0, 0xa3, - 0x5b, 0xc6, 0xb1, 0x17, 0xd1, 0x88, 0x30, 0x65, 0x77, 0x32, 0xf4, 0xf1, 0x95, 0x8f, 0x1b, 0xa5, - 0xd4, 0xdf, 0x8d, 0x92, 0xf2, 0xfe, 0xcf, 0xb7, 0x7b, 0x3d, 0xa8, 0x4a, 0x11, 0x26, 0x0e, 0xf4, - 0x97, 0xf4, 0xfe, 0x79, 0x08, 0xf2, 0x91, 0xaf, 0x11, 0x20, 0x9b, 0xa3, 0xb9, 0x68, 0xc0, 0x67, - 0x3f, 0x80, 0x57, 0x30, 0x26, 0xff, 0x5c, 0x31, 0x02, 0x71, 0x29, 0xcd, 0x3e, 0x23, 0x78, 0x19, - 0x1b, 0x92, 0x59, 0x0e, 0x23, 0x49, 0xa3, 0x1a, 0x70, 0x79, 0x31, 0xa0, 0xfe, 0x82, 0x43, 0x7d, - 0xbf, 0x43, 0x30, 0x5f, 0x5f, 0x58, 0xec, 0x10, 0xb7, 0x90, 0x29, 0x2b, 0xd5, 0x31, 0x2b, 0x27, - 0x5c, 0x8d, 0xd8, 0xf3, 0xbc, 0x43, 0xdc, 0x23, 0xc7, 0xa7, 0xc3, 0xb5, 0xff, 0x8d, 0x28, 0x9e, - 0xe1, 0xf4, 0xd7, 0x0c, 0x0c, 0x37, 0x99, 0xa7, 0xda, 0x90, 0x89, 0x96, 0xd1, 0x9d, 0x3e, 0xe4, - 0xf1, 0x3e, 0xd2, 0xcc, 0x01, 0x85, 0xc9, 0xe2, 0x7a, 0x0b, 0xe9, 0x70, 0xa1, 0xdc, 0xee, 0x1f, - 0x28, 0x74, 0x9a, 0x31, 0x98, 0x2e, 0xc9, 0xff, 0x0e, 0x2e, 0x1c, 0xd8, 0x16, 0x53, 0x03, 0x64, - 0xd8, 0x17, 0xa1, 0x3d, 0x3a, 0x69, 0x44, 0x52, 0xdd, 0x83, 0xd1, 0x78, 0x29, 0xdc, 0xed, 0x9f, - 0x44, 0x4a, 0xb5, 0xda, 0xc0, 0xd2, 0xa4, 0x50, 0x17, 0xce, 0xed, 0xbb, 0xed, 0x03, 0x8c, 0x69, - 0xaf, 0x5e, 0x9b, 0x3d, 0x99, 0x3e, 0xa9, 0xfb, 0x41, 0x81, 0xdc, 0xe1, 0xab, 0x36, 0x33, 0x50, - 0xb6, 0xfd, 0x41, 0xda, 0x93, 0x53, 0x04, 0xc5, 0x1c, 0xf5, 0x67, 0x9b, 0x3b, 0xba, 0xb2, 0xb5, - 0xa3, 0x2b, 0xbf, 0x77, 0x74, 0xe5, 0xd3, 0xae, 0x9e, 0xda, 0xda, 0xd5, 0x53, 0x3f, 0x77, 0xf5, - 0xd4, 0x9b, 0xfb, 0x7b, 0x9e, 0x39, 0x91, 0x74, 0x52, 0x56, 0x08, 0x0d, 0xb3, 0xfb, 0xc0, 0x5c, - 0xeb, 0x3d, 0xc3, 0xad, 0x91, 0xf0, 0x1d, 0x9e, 0xf9, 0x17, 0x00, 0x00, 0xff, 0xff, 0x86, 0xa6, - 0x35, 0xbf, 0x51, 0x08, 0x00, 0x00, + // 761 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcf, 0x4f, 0xdb, 0x48, + 0x14, 0x8e, 0x81, 0xf0, 0xe3, 0xb1, 0xbb, 0x6c, 0xbc, 0xd1, 0x92, 0x18, 0xd6, 0xc9, 0x1a, 0xd0, + 0x46, 0xec, 0xc6, 0x5e, 0xd8, 0xd5, 0xae, 0xb4, 0xa7, 0x6d, 0x22, 0xa8, 0x38, 0x44, 0x45, 0xa1, + 0xbd, 0x54, 0x55, 0x91, 0x63, 0x0f, 0x83, 0x05, 0x9e, 0x89, 0x3c, 0xe3, 0x40, 0xae, 0xbd, 0xb4, + 0xc7, 0x5e, 0x7a, 0xe7, 0xdc, 0x53, 0x0f, 0xfd, 0x23, 0x38, 0x22, 0x4e, 0x3d, 0xb5, 0x15, 0x1c, + 0xda, 0x3f, 0xa3, 0x1a, 0x7b, 0xec, 0x40, 0x7e, 0x50, 0x2e, 0xf4, 0x14, 0xbf, 0xf9, 0xbe, 0xf7, + 0xbe, 0xef, 0xbd, 0x68, 0xde, 0x80, 0x16, 0xfa, 0x08, 0x59, 0x1e, 0x71, 0x10, 0xe1, 0x5e, 0x07, + 0x59, 0x9d, 0x35, 0x8b, 0x1f, 0x9b, 0xed, 0x80, 0x72, 0xaa, 0xe6, 0x04, 0x66, 0xa6, 0x98, 0xd9, + 0x59, 0xd3, 0x74, 0x87, 0x32, 0x9f, 0x32, 0xab, 0x65, 0x33, 0xc1, 0x6d, 0x21, 0x6e, 0xaf, 0x59, + 0x0e, 0xf5, 0x48, 0x9c, 0xa2, 0x15, 0x63, 0x7c, 0x37, 0x8a, 0xac, 0x38, 0x90, 0xd0, 0xbc, 0x4c, + 0xf5, 0x19, 0x16, 0x2a, 0x3e, 0xc3, 0x12, 0xc8, 0x63, 0x8a, 0x69, 0x9c, 0x20, 0xbe, 0xe4, 0xe9, + 0xaf, 0x83, 0xc6, 0x7a, 0x4e, 0x22, 0x8a, 0xb1, 0x0c, 0xd3, 0x0d, 0x86, 0xeb, 0x87, 0xb6, 0xe7, + 0xab, 0x05, 0x98, 0xb2, 0x1d, 0x87, 0x86, 0x84, 0x17, 0x94, 0xb2, 0x52, 0x99, 0x69, 0x26, 0xa1, + 0x71, 0x04, 0x3f, 0x26, 0xac, 0x26, 0x62, 0x6d, 0x4a, 0x18, 0x52, 0x1d, 0x98, 0xb4, 0x7d, 0x49, + 0x1e, 0xaf, 0xcc, 0xae, 0x17, 0x4d, 0x69, 0x55, 0xf4, 0x65, 0xca, 0xbe, 0xcc, 0x3a, 0xf5, 0x48, + 0xed, 0xcf, 0xd3, 0xf7, 0xa5, 0xcc, 0xeb, 0x0f, 0xa5, 0x0a, 0xf6, 0xf8, 0x7e, 0xd8, 0x32, 0x1d, + 0xea, 0xcb, 0xbe, 0xe4, 0x4f, 0x95, 0xb9, 0x07, 0x16, 0xef, 0xb6, 0x11, 0x8b, 0x12, 0x58, 0x53, + 0x96, 0x36, 0x9e, 0xc0, 0x54, 0x83, 0xe1, 0x1a, 0x25, 0xee, 0x68, 0x77, 0xea, 0xbf, 0x30, 0x19, + 0x3e, 0xa4, 0x07, 0x88, 0x14, 0xc6, 0xca, 0xca, 0xcd, 0x4e, 0x26, 0x84, 0x93, 0xa6, 0xa4, 0x1b, + 0x39, 0x98, 0x93, 0xd5, 0x93, 0xae, 0x8c, 0x3d, 0xc8, 0x89, 0x23, 0x84, 0x3d, 0xf2, 0x88, 0xb4, + 0x28, 0x71, 0x3d, 0x82, 0xef, 0x42, 0x7a, 0x01, 0x8a, 0x03, 0x3a, 0xa9, 0x09, 0x0c, 0x6a, 0x83, + 0xe1, 0x0d, 0x1f, 0x05, 0x18, 0x11, 0xa7, 0x1b, 0x13, 0xee, 0xc2, 0xc5, 0x22, 0x68, 0x83, 0x42, + 0xa9, 0x8d, 0xff, 0x01, 0x1a, 0x0c, 0xef, 0x88, 0x80, 0x06, 0x42, 0x9e, 0xc5, 0x9f, 0x89, 0x3c, + 0xeb, 0x21, 0xed, 0x80, 0xe2, 0xc0, 0xf6, 0x23, 0xfd, 0xef, 0x9b, 0x49, 0x68, 0xe4, 0xa3, 0x46, + 0x64, 0x85, 0xb4, 0xee, 0xb9, 0x12, 0xcd, 0xfd, 0x3e, 0xed, 0xec, 0x20, 0xbe, 0x6d, 0x07, 0xb6, + 0xcf, 0xd4, 0x7f, 0x60, 0xc6, 0x0e, 0xf9, 0x3e, 0x0d, 0x3c, 0xde, 0x8d, 0xeb, 0xd7, 0x0a, 0xe7, + 0x6f, 0xab, 0x79, 0xd9, 0xc8, 0x3d, 0xd7, 0x0d, 0x10, 0x63, 0x3b, 0x3c, 0x10, 0x73, 0xea, 0x51, + 0xd5, 0x3c, 0x64, 0xb9, 0xc7, 0x0f, 0x51, 0xa4, 0x3c, 0xd3, 0x8c, 0x03, 0xb5, 0x0c, 0xb3, 0x2e, + 0x62, 0x4e, 0xe0, 0xb5, 0xb9, 0x47, 0x49, 0x61, 0x3c, 0xc2, 0xae, 0x1e, 0x89, 0x91, 0xb5, 0x23, + 0xe5, 0xc2, 0x84, 0x1c, 0xd9, 0xc0, 0x45, 0x35, 0x63, 0x6b, 0xc9, 0xc8, 0x62, 0xfa, 0x7f, 0x3f, + 0xbf, 0x38, 0x29, 0x65, 0x3e, 0x9f, 0x94, 0x94, 0x67, 0x9f, 0xde, 0xac, 0xf6, 0x8c, 0x18, 0x45, + 0x98, 0xef, 0xeb, 0x29, 0xed, 0xf7, 0xd5, 0x18, 0xe4, 0x63, 0xac, 0x1e, 0x20, 0x9b, 0xa3, 0xed, + 0x78, 0x3a, 0xdf, 0xbe, 0xe9, 0x0d, 0x98, 0x96, 0xff, 0x8c, 0x68, 0x5b, 0x5c, 0xda, 0xa5, 0x21, + 0x6d, 0x6f, 0x25, 0x81, 0xf4, 0x29, 0x07, 0x90, 0xa6, 0xaa, 0x26, 0xfc, 0xb4, 0x17, 0x50, 0x7f, + 0xd7, 0xa1, 0xbe, 0x1f, 0x12, 0x8f, 0x77, 0x77, 0xf7, 0x42, 0xe2, 0x16, 0xb2, 0x65, 0xa5, 0x32, + 0xdd, 0xcc, 0x09, 0xa8, 0x9e, 0x20, 0x9b, 0x21, 0x71, 0x47, 0x8e, 0x4c, 0x87, 0xc5, 0x61, 0x63, + 0x49, 0xe6, 0xb6, 0xfe, 0x3c, 0x0b, 0xe3, 0x0d, 0x86, 0xd5, 0x2d, 0xc8, 0xc6, 0x0b, 0x6a, 0x61, + 0x88, 0xdb, 0x64, 0x2f, 0x69, 0x4b, 0x37, 0x80, 0xe9, 0xd2, 0xda, 0x84, 0x89, 0x68, 0x99, 0x68, + 0xc3, 0xc9, 0x02, 0xd3, 0x8c, 0xd1, 0x58, 0x5a, 0xc7, 0x85, 0x1f, 0xfa, 0x76, 0xc4, 0xf2, 0x88, + 0xac, 0x6b, 0x2c, 0xed, 0x8f, 0xdb, 0xb0, 0x52, 0x15, 0x0c, 0x73, 0xfd, 0x4b, 0x60, 0x65, 0x78, + 0x81, 0x3e, 0x9a, 0x56, 0xbd, 0x15, 0x2d, 0x15, 0x7a, 0x00, 0x53, 0xc9, 0x35, 0xff, 0x65, 0x78, + 0xa6, 0x84, 0xb5, 0x95, 0x1b, 0xe1, 0xb4, 0xe0, 0x53, 0xf8, 0xee, 0xda, 0xf5, 0x1e, 0x31, 0xd3, + 0xab, 0x1c, 0x6d, 0xf5, 0xeb, 0x9c, 0xb4, 0xbe, 0x0f, 0xb9, 0xc1, 0xeb, 0xf4, 0xdb, 0xc8, 0x02, + 0xd7, 0x89, 0x9a, 0x75, 0x4b, 0x62, 0x22, 0x57, 0xdb, 0x38, 0xbd, 0xd0, 0x95, 0xb3, 0x0b, 0x5d, + 0xf9, 0x78, 0xa1, 0x2b, 0x2f, 0x2f, 0xf5, 0xcc, 0xd9, 0xa5, 0x9e, 0x79, 0x77, 0xa9, 0x67, 0x1e, + 0xff, 0x7e, 0xe5, 0x49, 0x13, 0x45, 0xab, 0x04, 0xf1, 0x23, 0x1a, 0x1c, 0x44, 0x81, 0xd5, 0xf9, + 0xdb, 0x3a, 0xee, 0x3d, 0xb9, 0xad, 0xc9, 0xe8, 0xcd, 0xfd, 0xeb, 0x4b, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xf3, 0x44, 0x62, 0x9a, 0x31, 0x08, 0x00, 0x00, } func (this *MsgGovSetParams) Equal(that interface{}) bool { @@ -743,10 +812,14 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // Claim defines a method for claiming any pending incentive rewards. Claim(ctx context.Context, in *MsgClaim, opts ...grpc.CallOption) (*MsgClaimResponse, error) - // Bond defines a method for bonding uToken collateral into reward tier. + // Bond defines a method for bonding uToken collateral. Bond(ctx context.Context, in *MsgBond, opts ...grpc.CallOption) (*MsgBondResponse, error) // BeginUnbonding defines a method for starting to unbond uToken collateral. + // Only max_unbondings unbondings can be active at per user, per denom, at once. BeginUnbonding(ctx context.Context, in *MsgBeginUnbonding, opts ...grpc.CallOption) (*MsgBeginUnbondingResponse, error) + // EmergencyUnbond defines a method for instantly unbonding uToken collateral in exchange for a fee. + // This can finish existing unbondings or unbond bonded tokens, and is not restricted by max_unbondings. + EmergencyUnbond(ctx context.Context, in *MsgEmergencyUnbond, opts ...grpc.CallOption) (*MsgEmergencyUnbondResponse, error) // Sponsor defines a permissionless method for sponsoring an upcoming, not yet funded incentive program. // The sponsor must be a single account and the MsgSponsor must fully cover the expected program rewards. Sponsor(ctx context.Context, in *MsgSponsor, opts ...grpc.CallOption) (*MsgSponsorResponse, error) @@ -766,7 +839,7 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { func (c *msgClient) Claim(ctx context.Context, in *MsgClaim, opts ...grpc.CallOption) (*MsgClaimResponse, error) { out := new(MsgClaimResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/Claim", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/Claim", in, out, opts...) if err != nil { return nil, err } @@ -775,7 +848,7 @@ func (c *msgClient) Claim(ctx context.Context, in *MsgClaim, opts ...grpc.CallOp func (c *msgClient) Bond(ctx context.Context, in *MsgBond, opts ...grpc.CallOption) (*MsgBondResponse, error) { out := new(MsgBondResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/Bond", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/Bond", in, out, opts...) if err != nil { return nil, err } @@ -784,7 +857,16 @@ func (c *msgClient) Bond(ctx context.Context, in *MsgBond, opts ...grpc.CallOpti func (c *msgClient) BeginUnbonding(ctx context.Context, in *MsgBeginUnbonding, opts ...grpc.CallOption) (*MsgBeginUnbondingResponse, error) { out := new(MsgBeginUnbondingResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/BeginUnbonding", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/BeginUnbonding", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) EmergencyUnbond(ctx context.Context, in *MsgEmergencyUnbond, opts ...grpc.CallOption) (*MsgEmergencyUnbondResponse, error) { + out := new(MsgEmergencyUnbondResponse) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/EmergencyUnbond", in, out, opts...) if err != nil { return nil, err } @@ -793,7 +875,7 @@ func (c *msgClient) BeginUnbonding(ctx context.Context, in *MsgBeginUnbonding, o func (c *msgClient) Sponsor(ctx context.Context, in *MsgSponsor, opts ...grpc.CallOption) (*MsgSponsorResponse, error) { out := new(MsgSponsorResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/Sponsor", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/Sponsor", in, out, opts...) if err != nil { return nil, err } @@ -802,7 +884,7 @@ func (c *msgClient) Sponsor(ctx context.Context, in *MsgSponsor, opts ...grpc.Ca func (c *msgClient) GovSetParams(ctx context.Context, in *MsgGovSetParams, opts ...grpc.CallOption) (*MsgGovSetParamsResponse, error) { out := new(MsgGovSetParamsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/GovSetParams", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/GovSetParams", in, out, opts...) if err != nil { return nil, err } @@ -811,7 +893,7 @@ func (c *msgClient) GovSetParams(ctx context.Context, in *MsgGovSetParams, opts func (c *msgClient) GovCreatePrograms(ctx context.Context, in *MsgGovCreatePrograms, opts ...grpc.CallOption) (*MsgGovCreateProgramsResponse, error) { out := new(MsgGovCreateProgramsResponse) - err := c.cc.Invoke(ctx, "/umeenetwork.umee.incentive.v1.Msg/GovCreatePrograms", in, out, opts...) + err := c.cc.Invoke(ctx, "/umee.incentive.v1.Msg/GovCreatePrograms", in, out, opts...) if err != nil { return nil, err } @@ -822,10 +904,14 @@ func (c *msgClient) GovCreatePrograms(ctx context.Context, in *MsgGovCreateProgr type MsgServer interface { // Claim defines a method for claiming any pending incentive rewards. Claim(context.Context, *MsgClaim) (*MsgClaimResponse, error) - // Bond defines a method for bonding uToken collateral into reward tier. + // Bond defines a method for bonding uToken collateral. Bond(context.Context, *MsgBond) (*MsgBondResponse, error) // BeginUnbonding defines a method for starting to unbond uToken collateral. + // Only max_unbondings unbondings can be active at per user, per denom, at once. BeginUnbonding(context.Context, *MsgBeginUnbonding) (*MsgBeginUnbondingResponse, error) + // EmergencyUnbond defines a method for instantly unbonding uToken collateral in exchange for a fee. + // This can finish existing unbondings or unbond bonded tokens, and is not restricted by max_unbondings. + EmergencyUnbond(context.Context, *MsgEmergencyUnbond) (*MsgEmergencyUnbondResponse, error) // Sponsor defines a permissionless method for sponsoring an upcoming, not yet funded incentive program. // The sponsor must be a single account and the MsgSponsor must fully cover the expected program rewards. Sponsor(context.Context, *MsgSponsor) (*MsgSponsorResponse, error) @@ -848,6 +934,9 @@ func (*UnimplementedMsgServer) Bond(ctx context.Context, req *MsgBond) (*MsgBond func (*UnimplementedMsgServer) BeginUnbonding(ctx context.Context, req *MsgBeginUnbonding) (*MsgBeginUnbondingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BeginUnbonding not implemented") } +func (*UnimplementedMsgServer) EmergencyUnbond(ctx context.Context, req *MsgEmergencyUnbond) (*MsgEmergencyUnbondResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EmergencyUnbond not implemented") +} func (*UnimplementedMsgServer) Sponsor(ctx context.Context, req *MsgSponsor) (*MsgSponsorResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Sponsor not implemented") } @@ -872,7 +961,7 @@ func _Msg_Claim_Handler(srv interface{}, ctx context.Context, dec func(interface } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/Claim", + FullMethod: "/umee.incentive.v1.Msg/Claim", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).Claim(ctx, req.(*MsgClaim)) @@ -890,7 +979,7 @@ func _Msg_Bond_Handler(srv interface{}, ctx context.Context, dec func(interface{ } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/Bond", + FullMethod: "/umee.incentive.v1.Msg/Bond", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).Bond(ctx, req.(*MsgBond)) @@ -908,7 +997,7 @@ func _Msg_BeginUnbonding_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/BeginUnbonding", + FullMethod: "/umee.incentive.v1.Msg/BeginUnbonding", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).BeginUnbonding(ctx, req.(*MsgBeginUnbonding)) @@ -916,6 +1005,24 @@ func _Msg_BeginUnbonding_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Msg_EmergencyUnbond_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgEmergencyUnbond) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).EmergencyUnbond(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umee.incentive.v1.Msg/EmergencyUnbond", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).EmergencyUnbond(ctx, req.(*MsgEmergencyUnbond)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_Sponsor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgSponsor) if err := dec(in); err != nil { @@ -926,7 +1033,7 @@ func _Msg_Sponsor_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/Sponsor", + FullMethod: "/umee.incentive.v1.Msg/Sponsor", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).Sponsor(ctx, req.(*MsgSponsor)) @@ -944,7 +1051,7 @@ func _Msg_GovSetParams_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/GovSetParams", + FullMethod: "/umee.incentive.v1.Msg/GovSetParams", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).GovSetParams(ctx, req.(*MsgGovSetParams)) @@ -962,7 +1069,7 @@ func _Msg_GovCreatePrograms_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umeenetwork.umee.incentive.v1.Msg/GovCreatePrograms", + FullMethod: "/umee.incentive.v1.Msg/GovCreatePrograms", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).GovCreatePrograms(ctx, req.(*MsgGovCreatePrograms)) @@ -971,7 +1078,7 @@ func _Msg_GovCreatePrograms_Handler(srv interface{}, ctx context.Context, dec fu } var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "umeenetwork.umee.incentive.v1.Msg", + ServiceName: "umee.incentive.v1.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { @@ -986,6 +1093,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "BeginUnbonding", Handler: _Msg_BeginUnbonding_Handler, }, + { + MethodName: "EmergencyUnbond", + Handler: _Msg_EmergencyUnbond_Handler, + }, { MethodName: "Sponsor", Handler: _Msg_Sponsor_Handler, @@ -1091,7 +1202,7 @@ func (m *MsgBond) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UToken.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1099,12 +1210,7 @@ func (m *MsgBond) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if m.Tier != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x10 - } + dAtA[i] = 0x12 if len(m.Account) > 0 { i -= len(m.Account) copy(dAtA[i:], m.Account) @@ -1159,7 +1265,7 @@ func (m *MsgBeginUnbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UToken.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1167,12 +1273,7 @@ func (m *MsgBeginUnbonding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if m.Tier != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Tier)) - i-- - dAtA[i] = 0x10 - } + dAtA[i] = 0x12 if len(m.Account) > 0 { i -= len(m.Account) copy(dAtA[i:], m.Account) @@ -1206,7 +1307,7 @@ func (m *MsgBeginUnbondingResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func (m *MsgSponsor) Marshal() (dAtA []byte, err error) { +func (m *MsgEmergencyUnbond) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1216,18 +1317,18 @@ func (m *MsgSponsor) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgSponsor) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgEmergencyUnbond) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgSponsor) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgEmergencyUnbond) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l { - size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UToken.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1235,7 +1336,60 @@ func (m *MsgSponsor) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 + if len(m.Account) > 0 { + i -= len(m.Account) + copy(dAtA[i:], m.Account) + i = encodeVarintTx(dAtA, i, uint64(len(m.Account))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgEmergencyUnbondResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgEmergencyUnbondResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEmergencyUnbondResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSponsor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSponsor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSponsor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l if m.Program != 0 { i = encodeVarintTx(dAtA, i, uint64(m.Program)) i-- @@ -1491,10 +1645,7 @@ func (m *MsgBond) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.Tier != 0 { - n += 1 + sovTx(uint64(m.Tier)) - } - l = m.Asset.Size() + l = m.UToken.Size() n += 1 + l + sovTx(uint64(l)) return n } @@ -1518,10 +1669,7 @@ func (m *MsgBeginUnbonding) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.Tier != 0 { - n += 1 + sovTx(uint64(m.Tier)) - } - l = m.Asset.Size() + l = m.UToken.Size() n += 1 + l + sovTx(uint64(l)) return n } @@ -1535,6 +1683,30 @@ func (m *MsgBeginUnbondingResponse) Size() (n int) { return n } +func (m *MsgEmergencyUnbond) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Account) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.UToken.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgEmergencyUnbondResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgSponsor) Size() (n int) { if m == nil { return 0 @@ -1548,8 +1720,6 @@ func (m *MsgSponsor) Size() (n int) { if m.Program != 0 { n += 1 + sovTx(uint64(m.Program)) } - l = m.Asset.Size() - n += 1 + l + sovTx(uint64(l)) return n } @@ -1867,27 +2037,8 @@ func (m *MsgBond) Unmarshal(dAtA []byte) error { m.Account = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1914,7 +2065,7 @@ func (m *MsgBond) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2051,27 +2202,8 @@ func (m *MsgBeginUnbonding) Unmarshal(dAtA []byte) error { m.Account = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Tier", wireType) - } - m.Tier = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Tier |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2098,7 +2230,7 @@ func (m *MsgBeginUnbonding) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2173,7 +2305,7 @@ func (m *MsgBeginUnbondingResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgSponsor) Unmarshal(dAtA []byte) error { +func (m *MsgEmergencyUnbond) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2196,15 +2328,15 @@ func (m *MsgSponsor) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgSponsor: wiretype end group for non-group") + return fmt.Errorf("proto: MsgEmergencyUnbond: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgSponsor: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgEmergencyUnbond: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sponsor", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2232,13 +2364,13 @@ func (m *MsgSponsor) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sponsor = string(dAtA[iNdEx:postIndex]) + m.Account = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Program", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UToken", wireType) } - m.Program = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2248,16 +2380,130 @@ func (m *MsgSponsor) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Program |= uint32(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 3: + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.UToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgEmergencyUnbondResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgEmergencyUnbondResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEmergencyUnbondResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSponsor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSponsor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSponsor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Sponsor", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -2267,25 +2513,43 @@ func (m *MsgSponsor) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Sponsor = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Program", wireType) + } + m.Program = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Program |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/leverage/fixtures/token.go b/x/leverage/fixtures/token.go index c89e7f1691..6cf2073065 100644 --- a/x/leverage/fixtures/token.go +++ b/x/leverage/fixtures/token.go @@ -7,6 +7,7 @@ import ( ) const ( + UmeeDenom = "uumee" // AtomDenom is an ibc denom to be used as ATOM's BaseDenom during testing. Matches mainnet. AtomDenom = "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9" // DaiDenom is an ibc denom to be used as DAI's BaseDenom during testing. Matches mainnet. diff --git a/x/leverage/keeper/collateral.go b/x/leverage/keeper/collateral.go index b38b45d7b2..009b6d9b71 100644 --- a/x/leverage/keeper/collateral.go +++ b/x/leverage/keeper/collateral.go @@ -7,6 +7,15 @@ import ( "github.com/umee-network/umee/v4/x/leverage/types" ) +// unbondedCollateral returns the collateral an account has which is neither bonded nor currently unbonding. +// This collateral is available for immediate decollateralizing or withdrawal. +func (k Keeper) unbondedCollateral(ctx sdk.Context, addr sdk.AccAddress, uDenom string) sdk.Coin { + collateralAmount := k.GetBorrowerCollateral(ctx, addr).AmountOf(uDenom) + unavailable := k.bondedCollateral(ctx, addr, uDenom) + available := sdk.MaxInt(collateralAmount.Sub(unavailable.Amount), sdk.ZeroInt()) + return sdk.NewCoin(uDenom, available) +} + // liquidateCollateral burns uToken collateral and sends the base token reward to the liquidator. // This occurs during direct liquidation. func (k Keeper) liquidateCollateral(ctx sdk.Context, borrower, liquidator sdk.AccAddress, uToken, token sdk.Coin, @@ -18,7 +27,7 @@ func (k Keeper) liquidateCollateral(ctx sdk.Context, borrower, liquidator sdk.Ac } // burnCollateral removes some uTokens from an account's collateral and burns them. This occurs -// during liquidations. +// during direct liquidations and during donateCollateral. func (k Keeper) burnCollateral(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error { err := k.setCollateral(ctx, addr, k.GetCollateral(ctx, addr, uToken.Denom).Sub(uToken)) if err != nil { @@ -262,12 +271,11 @@ func (k Keeper) moduleMaxWithdraw(ctx sdk.Context, spendableUTokens sdk.Coin) (s // // module_available_collateral = (module_liquidity - user_spendable_utokens - min_collateral_liquidity // * module_collateral) / (1 - min_collateral_liquidity) - moduleAvailableCollateral := - (sdk.NewDec(liquidity.Sub(spendableUTokens.Amount).Int64()).Sub( - minCollateralLiquidity.MulInt( - totalTokenCollateral.AmountOf(denom), - ), - )).Quo(sdk.NewDec(1).Sub(minCollateralLiquidity)) + moduleAvailableCollateral := (sdk.NewDec(liquidity.Sub(spendableUTokens.Amount).Int64()).Sub( + minCollateralLiquidity.MulInt( + totalTokenCollateral.AmountOf(denom), + ), + )).Quo(sdk.NewDec(1).Sub(minCollateralLiquidity)) // Adding (user_spendable_utokens + module_available_collateral) we obtain the max uTokens the account can // withdraw from the module. diff --git a/x/leverage/keeper/hooks.go b/x/leverage/keeper/hooks.go new file mode 100644 index 0000000000..b90cd196df --- /dev/null +++ b/x/leverage/keeper/hooks.go @@ -0,0 +1,56 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/umee-network/umee/v4/x/leverage/types" +) + +// afterTokenRegistered notifies any modules which have registered TokenHooks of +// a new token in the leverage module registry +func (k *Keeper) afterTokenRegistered(ctx sdk.Context, t types.Token) { + for _, h := range k.tokenHooks { + h.AfterTokenRegistered(ctx, t) + } +} + +// afterRegisteredTokenRemoved notifies any modules which have registered TokenHooks of +// a deleted token in the leverage module registry +func (k *Keeper) afterRegisteredTokenRemoved(ctx sdk.Context, t types.Token) { + for _, h := range k.tokenHooks { + h.AfterRegisteredTokenRemoved(ctx, t) + } +} + +// bondedCollateral returns how much of an account's collateral is bonded to external modules. +// this amount of collateral is not allowed to be decollateralized or withdrawn. Note that if multiple +// modules register bond hooks, the amount returned is the maximum (not the sum) of a user's bond +// amounts with each module. +// +// Tokens which are in an unbonding period should be considered as bonded for the purposes of this function, +// as they cannot be withdrawn until unbonding is completed. +// +// e.g. If addr has 45 u/uumee bonded to incentive module and 23 u/uumee bonded to a mystery module, +// bondedCollateral(addr,"u/uumee") returns 45. +func (k *Keeper) bondedCollateral(ctx sdk.Context, addr sdk.AccAddress, uDenom string) sdk.Coin { + bondedAmount := sdk.ZeroInt() + for _, h := range k.bondHooks { + bondedAmount = sdk.MaxInt(bondedAmount, h.GetBonded(ctx, addr, uDenom)) + } + return sdk.NewCoin(uDenom, bondedAmount) +} + +// reduceBondTo instantly unbonds an account's collateral from any modules which has registered bond hooks, +// until bonded (plus unbonding) amount is equal to or less than a given uToken amount. This is used during +// liquidations. +// +// If multiple modules have registered bondHooks, applies this effect to each module independently of the others. +func (k Keeper) reduceBondTo(ctx sdk.Context, addr sdk.AccAddress, collateral sdk.Coin) error { + for _, h := range k.bondHooks { + err := h.ForceUnbondTo(ctx, addr, collateral) + if err != nil { + return err + } + } + return nil +} diff --git a/x/leverage/keeper/incentive.go b/x/leverage/keeper/incentive.go new file mode 100644 index 0000000000..2266477193 --- /dev/null +++ b/x/leverage/keeper/incentive.go @@ -0,0 +1,21 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// DonateCollateral burns some collateral uTokens already present in the module, then adds their equivalent amount +// in tokens reserves. Currently, this is only used as the penalty for incentive module's MsgEmergencyUnbond. +func (k Keeper) DonateCollateral(ctx sdk.Context, fromAddr sdk.AccAddress, uToken sdk.Coin) error { + token, err := k.ExchangeUToken(ctx, uToken) + if err != nil { + return err + } + if err = k.burnCollateral(ctx, fromAddr, uToken); err != nil { + return err + } + + // increase module reserves + reserves := k.GetReserves(ctx, token.Denom) + return k.setReserves(ctx, reserves.Add(token)) +} diff --git a/x/leverage/keeper/keeper.go b/x/leverage/keeper/keeper.go index ef6090e795..d94628479c 100644 --- a/x/leverage/keeper/keeper.go +++ b/x/leverage/keeper/keeper.go @@ -18,10 +18,12 @@ type Keeper struct { cdc codec.Codec storeKey storetypes.StoreKey paramSpace paramtypes.Subspace - hooks types.Hooks bankKeeper types.BankKeeper oracleKeeper types.OracleKeeper liquidatorQueryEnabled bool + + tokenHooks []types.TokenHooks + bondHooks []types.BondHooks } func NewKeeper( @@ -51,15 +53,23 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// SetHooks sets the module's hooks. Note, hooks can only be set once. -func (k *Keeper) SetHooks(h types.Hooks) *Keeper { - if k.hooks != nil { - panic("leverage hooks already set") +// SetTokenHooks sets the module's token registry hooks. Token hooks can only be set once. +func (k *Keeper) SetTokenHooks(h ...types.TokenHooks) { + if k.tokenHooks != nil { + panic("leverage token hooks already set") } - k.hooks = h + k.tokenHooks = h +} + +// SetBondHooks sets the module's bonded amount and force unbonding hooks. +// Panics if Bond hooks have been already set. +func (k *Keeper) SetBondHooks(h ...types.BondHooks) { + if k.bondHooks != nil { + panic("leverage bond hooks already set") + } - return k + k.bondHooks = h } // ModuleBalance returns the amount of a given token held in the x/leverage module account @@ -143,12 +153,19 @@ func (k Keeper) Withdraw(ctx sdk.Context, supplierAddr sdk.AccAddress, uToken sd // Check for sufficient collateral collateral := k.GetBorrowerCollateral(ctx, supplierAddr) collateralAmount := collateral.AmountOf(uToken.Denom) - if collateral.AmountOf(uToken.Denom).LT(amountFromCollateral) { + if collateralAmount.LT(amountFromCollateral) { return sdk.Coin{}, isFromCollateral, types.ErrInsufficientBalance.Wrapf( "%s uToken balance + %s from collateral is less than %s to withdraw", amountFromWallet, collateralAmount, uToken) } + unbondedCollateral := k.unbondedCollateral(ctx, supplierAddr, uToken.Denom) + if unbondedCollateral.Amount.LT(amountFromCollateral) { + return sdk.Coin{}, isFromCollateral, types.ErrBondedCollateral.Wrapf( + "%s unbonded collateral is less than %s to withdraw from collateral", + unbondedCollateral, amountFromCollateral) + } + // reduce the supplier's collateral by amountFromCollateral newCollateral := sdk.NewCoin(uToken.Denom, collateralAmount.Sub(amountFromCollateral)) if err = k.setCollateral(ctx, supplierAddr, newCollateral); err != nil { @@ -261,12 +278,19 @@ func (k Keeper) Decollateralize(ctx sdk.Context, borrowerAddr sdk.AccAddress, uT // Detect where sufficient collateral exists to disable collateral := k.GetBorrowerCollateral(ctx, borrowerAddr) - if collateral.AmountOf(uToken.Denom).LT(uToken.Amount) { + collateralAmount := collateral.AmountOf(uToken.Denom) + if collateralAmount.LT(uToken.Amount) { return types.ErrInsufficientCollateral } - // Disabling uTokens as collateral withdraws any stored collateral of the denom in question - // from the module account and returns it to the user + unbondedCollateral := k.unbondedCollateral(ctx, borrowerAddr, uToken.Denom) + if unbondedCollateral.Amount.LT(uToken.Amount) { + return types.ErrBondedCollateral.Wrapf( + "%s unbonded collateral uTokens are less than %s to decollateralize", + unbondedCollateral, uToken) + } + + // Decollateralizing uTokens withdraws them from the module account and returns them to the user newCollateralAmount := collateral.AmountOf(uToken.Denom).Sub(uToken.Amount) if err := k.setCollateral(ctx, borrowerAddr, sdk.NewCoin(uToken.Denom, newCollateralAmount)); err != nil { return err @@ -336,6 +360,14 @@ func (k Keeper) Liquidate( return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } + // finally, force incentive module to update bond and unbonding amounts if required, + // by ending existing unbondings early or instantly unbonding some bonded tokens + // until bonded + unbonding for the account is not greater than its collateral amount + err = k.reduceBondTo(ctx, borrowerAddr, k.GetCollateral(ctx, borrowerAddr, uTokenLiquidate.Denom)) + if err != nil { + return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err + } + // the last return value is the liquidator's selected reward if directLiquidation { return tokenRepay, uTokenLiquidate, tokenReward, nil diff --git a/x/leverage/keeper/limits.go b/x/leverage/keeper/limits.go index f7bfe6b1fe..da87846cf6 100644 --- a/x/leverage/keeper/limits.go +++ b/x/leverage/keeper/limits.go @@ -22,6 +22,7 @@ func (k *Keeper) userMaxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom str totalCollateral := k.GetBorrowerCollateral(ctx, addr) thisCollateral := sdk.NewCoin(uDenom, totalCollateral.AmountOf(uDenom)) otherCollateral := totalCollateral.Sub(thisCollateral) + unbondedCollateral := k.unbondedCollateral(ctx, addr, uDenom) // calculate borrowed value for the account, using the higher of spot or historic prices for each token borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, types.PriceModeHigh) @@ -38,7 +39,7 @@ func (k *Keeper) userMaxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom str // if no non-blacklisted tokens are borrowed, withdraw the maximum available amount if borrowedValue.IsZero() { - withdrawAmount := walletUtokens.Add(totalCollateral.AmountOf(uDenom)) + withdrawAmount := walletUtokens.Add(unbondedCollateral.Amount) withdrawAmount = sdk.MinInt(withdrawAmount, availableUTokens.Amount) return sdk.NewCoin(uDenom, withdrawAmount), sdk.NewCoin(uDenom, walletUtokens), nil } @@ -51,7 +52,7 @@ func (k *Keeper) userMaxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom str } // if their other collateral fully covers all borrows, withdraw the maximum available amount if borrowedValue.LT(otherBorrowLimit) { - withdrawAmount := walletUtokens.Add(totalCollateral.AmountOf(uDenom)) + withdrawAmount := walletUtokens.Add(unbondedCollateral.Amount) withdrawAmount = sdk.MinInt(withdrawAmount, availableUTokens.Amount) return sdk.NewCoin(uDenom, withdrawAmount), sdk.NewCoin(uDenom, walletUtokens), nil } @@ -84,6 +85,11 @@ func (k *Keeper) userMaxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom str unusedCollateralFraction := unusedBorrowLimit.Quo(specificBorrowLimit) unusedCollateral := unusedCollateralFraction.MulInt(thisCollateral.Amount).TruncateInt() + // find the minimum of unused collateral (due to borrows) or unbonded collateral (incentive module) + if unbondedCollateral.Amount.LT(unusedCollateral) { + unusedCollateral = unbondedCollateral.Amount + } + // add wallet uTokens to the unused amount from collateral withdrawAmount := unusedCollateral.Add(walletUtokens) @@ -215,8 +221,9 @@ func (k Keeper) moduleAvailableLiquidity(ctx sdk.Context, denom string) (sdkmath // // min_collateral_liquidity = (module_liquidity - module_available_liquidity) / module_collateral // module_available_liquidity = module_liquidity - min_collateral_liquidity * module_collateral - moduleAvailableLiquidity := - sdk.NewDec(liquidity.Int64()).Sub(minCollateralLiquidity.MulInt(totalTokenCollateral.AmountOf(denom))) + moduleAvailableLiquidity := sdk.NewDec(liquidity.Int64()).Sub( + minCollateralLiquidity.MulInt(totalTokenCollateral.AmountOf(denom)), + ) return sdk.MaxInt(moduleAvailableLiquidity.TruncateInt(), sdk.ZeroInt()), nil } diff --git a/x/leverage/keeper/suite_test.go b/x/leverage/keeper/suite_test.go index d1188a23fe..c4303e0fc3 100644 --- a/x/leverage/keeper/suite_test.go +++ b/x/leverage/keeper/suite_test.go @@ -70,7 +70,9 @@ func (s *IntegrationTestSuite) SetupTest() { s.tk = tk app.LeverageKeeper = k - app.LeverageKeeper = *app.LeverageKeeper.SetHooks(types.NewMultiHooks()) + // since keeper was overridden, we need to set these hooks again + app.LeverageKeeper.SetTokenHooks() + app.LeverageKeeper.SetBondHooks() // TODO: add a mock (or real) incentive module here // override DefaultGenesis token registry with fixtures.Token leverage.InitGenesis(ctx, app.LeverageKeeper, *types.DefaultGenesis()) diff --git a/x/leverage/keeper/token.go b/x/leverage/keeper/token.go index 4a51a726fe..29c28a189b 100644 --- a/x/leverage/keeper/token.go +++ b/x/leverage/keeper/token.go @@ -32,8 +32,8 @@ func (k Keeper) deleteTokenSettings(ctx sdk.Context, token types.Token) error { store := ctx.KVStore(k.storeKey) tokenKey := types.KeyRegisteredToken(token.BaseDenom) store.Delete(tokenKey) - // call oracle hooks on deleted (not just blacklisted) token - k.hooks.AfterRegisteredTokenRemoved(ctx, token) + // call token hooks on deleted (not just blacklisted) token + k.afterRegisteredTokenRemoved(ctx, token) return nil } @@ -51,7 +51,7 @@ func (k Keeper) SetTokenSettings(ctx sdk.Context, token types.Token) error { return err } - k.hooks.AfterTokenRegistered(ctx, token) + k.afterTokenRegistered(ctx, token) store.Set(tokenKey, bz) return nil } diff --git a/x/leverage/types/errors.go b/x/leverage/types/errors.go index dde7399dbf..231c317670 100644 --- a/x/leverage/types/errors.go +++ b/x/leverage/types/errors.go @@ -32,6 +32,7 @@ var ( ErrInsufficientBalance = errors.Register(ModuleName, 300, "insufficient balance") ErrInsufficientCollateral = errors.Register(ModuleName, 301, "insufficient collateral") ErrLiquidationRepayZero = errors.Register(ModuleName, 303, "liquidation would repay zero tokens") + ErrBondedCollateral = errors.Register(ModuleName, 304, "collateral is bonded to incentive module") // 4XX = Price Sensitive ErrBadValue = errors.Register(ModuleName, 400, "bad USD value") @@ -55,8 +56,8 @@ var ( ErrInvalidExchangeRate = errors.Register(ModuleName, 604, "exchange rate less than one") ErrInconsistentTotalBorrow = errors.Register(ModuleName, 605, "total adjusted borrow inconsistency") ErrExcessiveTimeElapsed = errors.Register(ModuleName, 606, "excessive time elapsed since last interest time") + ErrIncentiveKeeperNotSet = errors.Register(ModuleName, 607, "incentive keeper not set") // 7XX = Disabled Functionality ErrNotLiquidatorNode = errors.Register(ModuleName, 700, "node has disabled liquidator queries") - ErrNotImplemented = errors.Register(ModuleName, 701, "not implemented") ) diff --git a/x/leverage/types/hooks.go b/x/leverage/types/hooks.go index 839700810f..2ad90fa096 100644 --- a/x/leverage/types/hooks.go +++ b/x/leverage/types/hooks.go @@ -1,39 +1,30 @@ package types import ( + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ) -// Hooks defines pre or post processing hooks for various actions the x/leverage -// module takes. -type Hooks interface { - // AfterTokenRegistered defines a hook another keeper can execute after the +// TokenHooks defines hooks other modules can execute when the leverage module +// adds or removes a token. +type TokenHooks interface { + // AfterTokenRegistered defines a hook any keeper can execute after the // x/leverage registers a token. AfterTokenRegistered(ctx sdk.Context, token Token) - // AfterRegisteredTokenRemoved defines a hook another keeper can execute after - // the x/leverage module removes a registered token. + // AfterRegisteredTokenRemoved defines a hook any keeper can execute after + // the x/leverage module deletes a registered token. AfterRegisteredTokenRemoved(ctx sdk.Context, token Token) } -var _ Hooks = MultiHooks{} +// BondHooks defines hooks leverage module can call on other modules to determine how much +// of a user's uToken collateral is bonded (i.e. not allowed to be withrdawn) or to force +// this amount to be reduced in the event of a liquidation. +type BondHooks interface { + // Used to ensure bonded or unbonding collateral cannot be decollateralized or withdrawn. + GetBonded(ctx sdk.Context, addr sdk.AccAddress, uDenom string) sdkmath.Int -// MultiHooks defines a type alias for multiple hooks, i.e. for multiple keepers -// to execute x/leverage hooks. -type MultiHooks []Hooks - -func NewMultiHooks(hooks ...Hooks) MultiHooks { - return hooks -} - -func (mh MultiHooks) AfterTokenRegistered(ctx sdk.Context, token Token) { - for _, h := range mh { - h.AfterTokenRegistered(ctx, token) - } -} - -func (mh MultiHooks) AfterRegisteredTokenRemoved(ctx sdk.Context, token Token) { - for _, h := range mh { - h.AfterRegisteredTokenRemoved(ctx, token) - } + // Used when liquidating an account, and collateral must be unbonded instantly until bonded amount + // is no greater than the account's remaining collateral uTokens. + ForceUnbondTo(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin) error } diff --git a/x/oracle/keeper/hooks.go b/x/oracle/keeper/hooks.go index 74cc1c8053..60b9948cfb 100644 --- a/x/oracle/keeper/hooks.go +++ b/x/oracle/keeper/hooks.go @@ -13,7 +13,7 @@ type Hooks struct { k Keeper } -var _ leveragetypes.Hooks = Hooks{} +var _ leveragetypes.TokenHooks = Hooks{} // Hooks returns a new Hooks instance that wraps the x/oracle keeper. func (k Keeper) Hooks() Hooks { diff --git a/x/oracle/types/errors.go b/x/oracle/types/errors.go index 9a26ad6e93..0817567098 100644 --- a/x/oracle/types/errors.go +++ b/x/oracle/types/errors.go @@ -25,7 +25,6 @@ var ( ErrNegativeOrZeroRate = errors.Register(ModuleName, 14, "invalid exchange rate; should be positive") ErrExistingPrevote = errors.Register(ModuleName, 15, "prevote already submitted for this voting period") ErrBallotNotSorted = errors.Register(ModuleName, 16, "ballot must be sorted before this operation") - ErrNotImplemented = errors.Register(ModuleName, 17, "function not implemented") ErrNoHistoricPrice = errors.Register(ModuleName, 18, "no historic price for this denom at this block") ErrNoMedian = errors.Register(ModuleName, 19, "no median for this denom at this block") ErrNoMedianDeviation = errors.Register(ModuleName, 20, "no median deviation for this denom at this block")