Skip to content

Commit 06b4a55

Browse files
committed
add current rates query for frontend
1 parent 28feba5 commit 06b4a55

File tree

5 files changed

+713
-61
lines changed

5 files changed

+713
-61
lines changed

proto/umee/incentive/v1/query.proto

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ service Query {
6767
returns (QueryIncentiveProgramResponse) {
6868
option (google.api.http).get = "/umee/incentive/v1/incentive_program/{id}";
6969
}
70+
71+
// CurrentRates queries the hypothetical return of a bonded uToken denomination
72+
// if current incentive rewards continued for one year. The response is an sdk.Coins
73+
// of base token rewards, per reference amount (usually 10^exponent of the uToken.)
74+
rpc CurrentRates(QueryCurrentRates)
75+
returns (QueryCurrentRatesResponse) {
76+
option (google.api.http).get = "/umee/incentive/v1/current_rates";
77+
}
7078
}
7179

7280
// QueryParams defines the request structure for the Params gRPC service
@@ -187,3 +195,26 @@ message QueryIncentiveProgram {
187195
message QueryIncentiveProgramResponse {
188196
IncentiveProgram program = 1 [(gogoproto.nullable) = false];
189197
}
198+
199+
// QueryCurrentRates defines the request structure for the CurrentRates gRPC service handler.
200+
message QueryCurrentRates {
201+
// uToken is the uToken denomination whose current annual rate of rewards is being queried
202+
string uToken = 1;
203+
}
204+
205+
// QueryCurrentRatesResponse defines the response structure for the CurrentRates gRPC service handler.
206+
message QueryCurrentRatesResponse {
207+
// Reference Bond is an amount of bonded uTokens (usually 10^exponent) whose current rewards are being
208+
// calculated. This amount can be used to compute an individual user's rewards: for example, if a user has
209+
// 2.5x the reference amount currently bonded, then they would receive 2.5x the rewards below annually
210+
// at current rates.
211+
cosmos.base.v1beta1.Coin reference_bond = 1 [
212+
(gogoproto.nullable) = false
213+
];
214+
// Rewards are the amount of base token rewards that the reference amount of bonded uTokens would earn
215+
// if current rates continued for a full year.
216+
repeated cosmos.base.v1beta1.Coin rewards = 2 [
217+
(gogoproto.nullable) = false,
218+
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
219+
];
220+
}

x/incentive/client/cli/query.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func GetQueryCmd() *cobra.Command {
3030
cmd.AddCommand(
3131
GetCmdQueryParams(),
3232
GetCmdQueryAccountBonds(),
33+
GetCmdQueryCurrentRates(),
3334
GetCmdQueryTotalBonded(),
3435
GetCmdQueryTotalUnbonding(),
3536
GetCmdQueryPendingRewards(),
@@ -110,6 +111,37 @@ func GetCmdQueryPendingRewards() *cobra.Command {
110111
return cmd
111112
}
112113

114+
// GetCmdQueryCurrentRates creates a Cobra command to query current annual rewards for a reference amount
115+
// of a given bonded uToken.
116+
func GetCmdQueryCurrentRates() *cobra.Command {
117+
cmd := &cobra.Command{
118+
Use: "current-rates[denom]",
119+
Args: cobra.RangeArgs(0, 1),
120+
Short: "Query the current annual rewards for a reference amount of a given bonded uToken.",
121+
RunE: func(cmd *cobra.Command, args []string) error {
122+
clientCtx, err := client.GetClientQueryContext(cmd)
123+
if err != nil {
124+
return err
125+
}
126+
denom := ""
127+
if len(args) > 0 {
128+
denom = args[0]
129+
}
130+
131+
queryClient := incentive.NewQueryClient(clientCtx)
132+
resp, err := queryClient.CurrentRates(cmd.Context(), &incentive.QueryCurrentRates{UToken: denom})
133+
if err != nil {
134+
return err
135+
}
136+
137+
return cli.PrintOrErr(resp, err, clientCtx)
138+
},
139+
}
140+
141+
flags.AddQueryFlagsToCmd(cmd)
142+
return cmd
143+
}
144+
113145
// GetCmdQueryTotalBonded creates a Cobra command to query bonded tokens across all users.
114146
func GetCmdQueryTotalBonded() *cobra.Command {
115147
cmd := &cobra.Command{

x/incentive/keeper/grpc_query.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,48 @@ func (q Querier) TotalUnbonding(
232232

233233
return &incentive.QueryTotalUnbondingResponse{Unbonding: total}, nil
234234
}
235+
236+
func (q Querier) CurrentRates(
237+
goCtx context.Context,
238+
req *incentive.QueryCurrentRates,
239+
) (*incentive.QueryCurrentRatesResponse, error) {
240+
if req == nil {
241+
return nil, status.Error(codes.InvalidArgument, "empty request")
242+
}
243+
244+
k, ctx := q.Keeper, sdk.UnwrapSDKContext(goCtx)
245+
246+
programs, err := k.getAllIncentivePrograms(ctx, incentive.ProgramStatusOngoing)
247+
if err != nil {
248+
return nil, err
249+
}
250+
251+
// to compute the rewards a reference amount (10^exponent) of bonded uToken is currently earning,
252+
// we need to divide the total rewards being distributed by all ongoing incentive programs targeting
253+
// that uToken denom, by the ratio of the total bonded amount to the reference amount.
254+
bonded := k.getTotalBonded(ctx, req.UToken)
255+
rewards := sdk.NewCoins()
256+
exponent := k.getRewardAccumulator(ctx, req.UToken).Exponent
257+
for _, p := range programs {
258+
if p.UToken == req.UToken {
259+
// seconds per year / duration = programsPerYear (as this query assumes incentives will stay constant)
260+
programsPerYear := sdk.MustNewDecFromStr("31557600").Quo(sdk.NewDec(p.Duration))
261+
// reference amount / total bonded = rewardPortion (as the more uTokens bond, the fewer rewards each earns)
262+
rewardPortion := ten.Power(uint64(exponent)).QuoInt(bonded.Amount)
263+
// annual rewards for reference amount for this specific program, assuming current rates continue
264+
rewardCoin := sdk.NewCoin(
265+
p.TotalRewards.Denom,
266+
programsPerYear.Mul(rewardPortion).MulInt(p.TotalRewards.Amount).TruncateInt(),
267+
)
268+
// add this program's annual rewards to the total for all programs incentivizing this uToken denom
269+
rewards = rewards.Add(rewardCoin)
270+
}
271+
}
272+
return &incentive.QueryCurrentRatesResponse{
273+
ReferenceBond: sdk.NewCoin(
274+
req.UToken,
275+
ten.Power(uint64(exponent)).TruncateInt(),
276+
),
277+
Rewards: rewards,
278+
}, nil
279+
}

0 commit comments

Comments
 (0)