Add incentive grpc query service (#1503)

* Add incentive grpc query service

* Register query server

* Add grpc query test

* Add grpc query test

* Fix proto lints

* Fix missing savings field, update tests

* Update proto docs

* Use consts for query reward types

* Add owner to queryRewards err

* Add empty reward type to be valid
This commit is contained in:
drklee3 2023-03-21 15:47:21 -07:00 committed by GitHub
parent c4bec21af7
commit 35c848dce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 4187 additions and 24 deletions

View File

@ -322,6 +322,9 @@
- [Msg](#kava.hard.v1beta1.Msg)
- [kava/incentive/v1beta1/apy.proto](#kava/incentive/v1beta1/apy.proto)
- [Apy](#kava.incentive.v1beta1.Apy)
- [kava/incentive/v1beta1/claims.proto](#kava/incentive/v1beta1/claims.proto)
- [BaseClaim](#kava.incentive.v1beta1.BaseClaim)
- [BaseMultiClaim](#kava.incentive.v1beta1.BaseMultiClaim)
@ -348,6 +351,18 @@
- [GenesisRewardState](#kava.incentive.v1beta1.GenesisRewardState)
- [GenesisState](#kava.incentive.v1beta1.GenesisState)
- [kava/incentive/v1beta1/query.proto](#kava/incentive/v1beta1/query.proto)
- [QueryApyRequest](#kava.incentive.v1beta1.QueryApyRequest)
- [QueryApyResponse](#kava.incentive.v1beta1.QueryApyResponse)
- [QueryParamsRequest](#kava.incentive.v1beta1.QueryParamsRequest)
- [QueryParamsResponse](#kava.incentive.v1beta1.QueryParamsResponse)
- [QueryRewardFactorsRequest](#kava.incentive.v1beta1.QueryRewardFactorsRequest)
- [QueryRewardFactorsResponse](#kava.incentive.v1beta1.QueryRewardFactorsResponse)
- [QueryRewardsRequest](#kava.incentive.v1beta1.QueryRewardsRequest)
- [QueryRewardsResponse](#kava.incentive.v1beta1.QueryRewardsResponse)
- [Query](#kava.incentive.v1beta1.Query)
- [kava/incentive/v1beta1/tx.proto](#kava/incentive/v1beta1/tx.proto)
- [MsgClaimDelegatorReward](#kava.incentive.v1beta1.MsgClaimDelegatorReward)
- [MsgClaimDelegatorRewardResponse](#kava.incentive.v1beta1.MsgClaimDelegatorRewardResponse)
@ -4617,6 +4632,39 @@ Msg defines the hard Msg service.
<a name="kava/incentive/v1beta1/apy.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## kava/incentive/v1beta1/apy.proto
<a name="kava.incentive.v1beta1.Apy"></a>
### Apy
Apy contains the calculated APY for a given collateral type at a specific
instant in time.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `collateral_type` | [string](#string) | | |
| `apy` | [string](#string) | | |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="kava/incentive/v1beta1/claims.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -5010,6 +5058,153 @@ GenesisState is the state that must be provided at genesis.
<a name="kava/incentive/v1beta1/query.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## kava/incentive/v1beta1/query.proto
<a name="kava.incentive.v1beta1.QueryApyRequest"></a>
### QueryApyRequest
QueryApysRequest is the request type for the Query/Apys RPC method.
<a name="kava.incentive.v1beta1.QueryApyResponse"></a>
### QueryApyResponse
QueryApysResponse is the response type for the Query/Apys RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `earn` | [Apy](#kava.incentive.v1beta1.Apy) | repeated | |
<a name="kava.incentive.v1beta1.QueryParamsRequest"></a>
### QueryParamsRequest
QueryParamsRequest is the request type for the Query/Params RPC method.
<a name="kava.incentive.v1beta1.QueryParamsResponse"></a>
### QueryParamsResponse
QueryParamsResponse is the response type for the Query/Params RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `params` | [Params](#kava.incentive.v1beta1.Params) | | |
<a name="kava.incentive.v1beta1.QueryRewardFactorsRequest"></a>
### QueryRewardFactorsRequest
QueryRewardFactorsRequest is the request type for the Query/RewardFactors RPC method.
<a name="kava.incentive.v1beta1.QueryRewardFactorsResponse"></a>
### QueryRewardFactorsResponse
QueryRewardFactorsResponse is the response type for the Query/RewardFactors RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `usdx_minting_reward_factors` | [RewardIndex](#kava.incentive.v1beta1.RewardIndex) | repeated | |
| `hard_supply_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
| `hard_borrow_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
| `delegator_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
| `swap_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
| `savings_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
| `earn_reward_factors` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | |
<a name="kava.incentive.v1beta1.QueryRewardsRequest"></a>
### QueryRewardsRequest
QueryRewardsRequest is the request type for the Query/Rewards RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `owner` | [string](#string) | | owner is the address of the user to query rewards for. |
| `reward_type` | [string](#string) | | reward_type is the type of reward to query rewards for, e.g. hard, earn, swap. |
| `unsynchronized` | [bool](#bool) | | unsynchronized is a flag to query rewards that are not simulated for reward synchronized for the current block. |
<a name="kava.incentive.v1beta1.QueryRewardsResponse"></a>
### QueryRewardsResponse
QueryRewardsResponse is the response type for the Query/Rewards RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `usdx_minting_claims` | [USDXMintingClaim](#kava.incentive.v1beta1.USDXMintingClaim) | repeated | |
| `hard_liquidity_provider_claims` | [HardLiquidityProviderClaim](#kava.incentive.v1beta1.HardLiquidityProviderClaim) | repeated | |
| `delegator_claims` | [DelegatorClaim](#kava.incentive.v1beta1.DelegatorClaim) | repeated | |
| `swap_claims` | [SwapClaim](#kava.incentive.v1beta1.SwapClaim) | repeated | |
| `savings_claims` | [SavingsClaim](#kava.incentive.v1beta1.SavingsClaim) | repeated | |
| `earn_claims` | [EarnClaim](#kava.incentive.v1beta1.EarnClaim) | repeated | |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<a name="kava.incentive.v1beta1.Query"></a>
### Query
Query defines the gRPC querier service for incentive module.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Params` | [QueryParamsRequest](#kava.incentive.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#kava.incentive.v1beta1.QueryParamsResponse) | Params queries module params. | GET|/kava/incentive/v1beta1/params|
| `Rewards` | [QueryRewardsRequest](#kava.incentive.v1beta1.QueryRewardsRequest) | [QueryRewardsResponse](#kava.incentive.v1beta1.QueryRewardsResponse) | Rewards queries reward information for a given user. | GET|/kava/incentive/v1beta1/rewards|
| `RewardFactors` | [QueryRewardFactorsRequest](#kava.incentive.v1beta1.QueryRewardFactorsRequest) | [QueryRewardFactorsResponse](#kava.incentive.v1beta1.QueryRewardFactorsResponse) | Rewards queries the reward factors. | GET|/kava/incentive/v1beta1/reward_factors|
| `Apy` | [QueryApyRequest](#kava.incentive.v1beta1.QueryApyRequest) | [QueryApyResponse](#kava.incentive.v1beta1.QueryApyResponse) | Apy queries incentive reward apy for a reward. | GET|/kava/incentive/v1beta1/apy|
<!-- end services -->
<a name="kava/incentive/v1beta1/tx.proto"></a>
<p align="right"><a href="#top">Top</a></p>

View File

@ -0,0 +1,18 @@
syntax = "proto3";
package kava.incentive.v1beta1;
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/kava-labs/kava/x/incentive/types";
// Apy contains the calculated APY for a given collateral type at a specific
// instant in time.
message Apy {
string collateral_type = 1;
string apy = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

View File

@ -0,0 +1,130 @@
syntax = "proto3";
package kava.incentive.v1beta1;
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "kava/incentive/v1beta1/apy.proto";
import "kava/incentive/v1beta1/claims.proto";
import "kava/incentive/v1beta1/params.proto";
option go_package = "github.com/kava-labs/kava/x/incentive/types";
// Query defines the gRPC querier service for incentive module.
service Query {
// Params queries module params.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/kava/incentive/v1beta1/params";
}
// Rewards queries reward information for a given user.
rpc Rewards(QueryRewardsRequest) returns (QueryRewardsResponse) {
option (google.api.http).get = "/kava/incentive/v1beta1/rewards";
}
// Rewards queries the reward factors.
rpc RewardFactors(QueryRewardFactorsRequest) returns (QueryRewardFactorsResponse) {
option (google.api.http).get = "/kava/incentive/v1beta1/reward_factors";
}
// Apy queries incentive reward apy for a reward.
rpc Apy(QueryApyRequest) returns (QueryApyResponse) {
option (google.api.http).get = "/kava/incentive/v1beta1/apy";
}
}
// QueryParamsRequest is the request type for the Query/Params RPC method.
message QueryParamsRequest {}
// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
Params params = 1 [(gogoproto.nullable) = false];
}
// QueryRewardsRequest is the request type for the Query/Rewards RPC method.
message QueryRewardsRequest {
// owner is the address of the user to query rewards for.
string owner = 1;
// reward_type is the type of reward to query rewards for, e.g. hard, earn,
// swap.
string reward_type = 2;
// unsynchronized is a flag to query rewards that are not simulated for reward
// synchronized for the current block.
bool unsynchronized = 3;
}
// QueryRewardsResponse is the response type for the Query/Rewards RPC method.
message QueryRewardsResponse {
repeated USDXMintingClaim usdx_minting_claims = 1 [
(gogoproto.customname) = "USDXMintingClaims",
(gogoproto.castrepeated) = "USDXMintingClaims",
(gogoproto.nullable) = false
];
repeated HardLiquidityProviderClaim hard_liquidity_provider_claims = 2 [
(gogoproto.castrepeated) = "HardLiquidityProviderClaims",
(gogoproto.nullable) = false
];
repeated DelegatorClaim delegator_claims = 3 [
(gogoproto.castrepeated) = "DelegatorClaims",
(gogoproto.nullable) = false
];
repeated SwapClaim swap_claims = 4 [
(gogoproto.castrepeated) = "SwapClaims",
(gogoproto.nullable) = false
];
repeated SavingsClaim savings_claims = 5 [
(gogoproto.castrepeated) = "SavingsClaims",
(gogoproto.nullable) = false
];
repeated EarnClaim earn_claims = 6 [
(gogoproto.castrepeated) = "EarnClaims",
(gogoproto.nullable) = false
];
}
// QueryRewardFactorsRequest is the request type for the Query/RewardFactors RPC method.
message QueryRewardFactorsRequest {}
// QueryRewardFactorsResponse is the response type for the Query/RewardFactors RPC method.
message QueryRewardFactorsResponse {
repeated RewardIndex usdx_minting_reward_factors = 1 [
(gogoproto.castrepeated) = "RewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex hard_supply_reward_factors = 2 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex hard_borrow_reward_factors = 3 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex delegator_reward_factors = 4 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex swap_reward_factors = 5 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex savings_reward_factors = 6 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
repeated MultiRewardIndex earn_reward_factors = 7 [
(gogoproto.castrepeated) = "MultiRewardIndexes",
(gogoproto.nullable) = false
];
}
// QueryApysRequest is the request type for the Query/Apys RPC method.
message QueryApyRequest {}
// QueryApysResponse is the response type for the Query/Apys RPC method.
message QueryApyResponse {
repeated Apy earn = 1 [(gogoproto.nullable) = false];
}

View File

@ -0,0 +1,342 @@
package keeper
import (
"context"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/kava-labs/kava/x/incentive/types"
liquidtypes "github.com/kava-labs/kava/x/liquid/types"
)
const (
RewardTypeHard = "hard"
RewardTypeUSDXMinting = "usdx_minting"
RewardTypeDelegator = "delegator"
RewardTypeSwap = "swap"
RewardTypeSavings = "savings"
RewardTypeEarn = "earn"
)
type queryServer struct {
keeper Keeper
}
var _ types.QueryServer = queryServer{}
// NewQueryServerImpl creates a new server for handling gRPC queries.
func NewQueryServerImpl(keeper Keeper) types.QueryServer {
return &queryServer{
keeper: keeper,
}
}
func (s queryServer) Params(
ctx context.Context,
req *types.QueryParamsRequest,
) (*types.QueryParamsResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
return &types.QueryParamsResponse{
Params: s.keeper.GetParams(sdkCtx),
}, nil
}
func (s queryServer) Rewards(
ctx context.Context,
req *types.QueryRewardsRequest,
) (*types.QueryRewardsResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
res := types.QueryRewardsResponse{}
hasOwner := req.Owner != ""
var owner sdk.AccAddress
if hasOwner {
addr, err := sdk.AccAddressFromBech32(req.Owner)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid address: %s", err)
}
owner = addr
}
if err := s.queryRewards(sdkCtx, &res, owner, hasOwner, req.RewardType); err != nil {
return nil, err
}
if !req.Unsynchronized {
if err := s.synchronizeRewards(sdkCtx, &res); err != nil {
return nil, err
}
}
return &res, nil
}
func (s queryServer) RewardFactors(
ctx context.Context,
req *types.QueryRewardFactorsRequest,
) (*types.QueryRewardFactorsResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
var usdxFactors types.RewardIndexes
s.keeper.IterateUSDXMintingRewardFactors(sdkCtx, func(collateralType string, factor sdk.Dec) (stop bool) {
usdxFactors = usdxFactors.With(collateralType, factor)
return false
})
var supplyFactors types.MultiRewardIndexes
s.keeper.IterateHardSupplyRewardIndexes(sdkCtx, func(denom string, indexes types.RewardIndexes) (stop bool) {
supplyFactors = supplyFactors.With(denom, indexes)
return false
})
var borrowFactors types.MultiRewardIndexes
s.keeper.IterateHardBorrowRewardIndexes(sdkCtx, func(denom string, indexes types.RewardIndexes) (stop bool) {
borrowFactors = borrowFactors.With(denom, indexes)
return false
})
var delegatorFactors types.MultiRewardIndexes
s.keeper.IterateDelegatorRewardIndexes(sdkCtx, func(denom string, indexes types.RewardIndexes) (stop bool) {
delegatorFactors = delegatorFactors.With(denom, indexes)
return false
})
var swapFactors types.MultiRewardIndexes
s.keeper.IterateSwapRewardIndexes(sdkCtx, func(poolID string, indexes types.RewardIndexes) (stop bool) {
swapFactors = swapFactors.With(poolID, indexes)
return false
})
var savingsFactors types.MultiRewardIndexes
s.keeper.IterateSavingsRewardIndexes(sdkCtx, func(denom string, indexes types.RewardIndexes) (stop bool) {
savingsFactors = savingsFactors.With(denom, indexes)
return false
})
var earnFactors types.MultiRewardIndexes
s.keeper.IterateEarnRewardIndexes(sdkCtx, func(denom string, indexes types.RewardIndexes) (stop bool) {
earnFactors = earnFactors.With(denom, indexes)
return false
})
return &types.QueryRewardFactorsResponse{
UsdxMintingRewardFactors: usdxFactors,
HardSupplyRewardFactors: supplyFactors,
HardBorrowRewardFactors: borrowFactors,
DelegatorRewardFactors: delegatorFactors,
SwapRewardFactors: swapFactors,
SavingsRewardFactors: savingsFactors,
EarnRewardFactors: earnFactors,
}, nil
}
func (s queryServer) Apy(
ctx context.Context,
req *types.QueryApyRequest,
) (*types.QueryApyResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
params := s.keeper.GetParams(sdkCtx)
var apys types.APYs
// bkava APY (staking + incentive rewards)
stakingAPR, err := GetStakingAPR(sdkCtx, s.keeper, params)
if err != nil {
return nil, err
}
apys = append(apys, types.NewAPY(liquidtypes.DefaultDerivativeDenom, stakingAPR))
// Incentive only APYs
for _, param := range params.EarnRewardPeriods {
// Skip bkava as it's calculated earlier with staking rewards
if param.CollateralType == liquidtypes.DefaultDerivativeDenom {
continue
}
// Value in the vault in the same denom as CollateralType
vaultTotalValue, err := s.keeper.earnKeeper.GetVaultTotalValue(sdkCtx, param.CollateralType)
if err != nil {
return nil, err
}
apy, err := GetAPYFromMultiRewardPeriod(sdkCtx, s.keeper, param.CollateralType, param, vaultTotalValue.Amount)
if err != nil {
return nil, err
}
apys = append(apys, types.NewAPY(param.CollateralType, apy))
}
return &types.QueryApyResponse{
Earn: apys,
}, nil
}
// queryRewards queries the rewards for a given owner and reward type, updating
// the response with the results in place.
func (s queryServer) queryRewards(
ctx sdk.Context,
res *types.QueryRewardsResponse,
owner sdk.AccAddress,
hasOwner bool,
rewardType string,
) error {
rewardType = strings.ToLower(rewardType)
isAllRewards := rewardType == ""
if !rewardTypeIsValid(rewardType) {
return status.Errorf(codes.InvalidArgument, "invalid reward type for owner %s: %s", owner, rewardType)
}
if isAllRewards || rewardType == RewardTypeUSDXMinting {
if hasOwner {
usdxMintingClaim, foundUsdxMintingClaim := s.keeper.GetUSDXMintingClaim(ctx, owner)
if foundUsdxMintingClaim {
res.USDXMintingClaims = append(res.USDXMintingClaims, usdxMintingClaim)
}
} else {
usdxMintingClaims := s.keeper.GetAllUSDXMintingClaims(ctx)
res.USDXMintingClaims = append(res.USDXMintingClaims, usdxMintingClaims...)
}
}
if isAllRewards || rewardType == RewardTypeHard {
if hasOwner {
hardClaim, foundHardClaim := s.keeper.GetHardLiquidityProviderClaim(ctx, owner)
if foundHardClaim {
res.HardLiquidityProviderClaims = append(res.HardLiquidityProviderClaims, hardClaim)
}
} else {
hardClaims := s.keeper.GetAllHardLiquidityProviderClaims(ctx)
res.HardLiquidityProviderClaims = append(res.HardLiquidityProviderClaims, hardClaims...)
}
}
if isAllRewards || rewardType == RewardTypeDelegator {
if hasOwner {
delegatorClaim, foundDelegatorClaim := s.keeper.GetDelegatorClaim(ctx, owner)
if foundDelegatorClaim {
res.DelegatorClaims = append(res.DelegatorClaims, delegatorClaim)
}
} else {
delegatorClaims := s.keeper.GetAllDelegatorClaims(ctx)
res.DelegatorClaims = append(res.DelegatorClaims, delegatorClaims...)
}
}
if isAllRewards || rewardType == RewardTypeSwap {
if hasOwner {
swapClaim, foundSwapClaim := s.keeper.GetSwapClaim(ctx, owner)
if foundSwapClaim {
res.SwapClaims = append(res.SwapClaims, swapClaim)
}
} else {
swapClaims := s.keeper.GetAllSwapClaims(ctx)
res.SwapClaims = append(res.SwapClaims, swapClaims...)
}
}
if isAllRewards || rewardType == RewardTypeSavings {
if hasOwner {
savingsClaim, foundSavingsClaim := s.keeper.GetSavingsClaim(ctx, owner)
if foundSavingsClaim {
res.SavingsClaims = append(res.SavingsClaims, savingsClaim)
}
} else {
savingsClaims := s.keeper.GetAllSavingsClaims(ctx)
res.SavingsClaims = append(res.SavingsClaims, savingsClaims...)
}
}
if isAllRewards || rewardType == RewardTypeEarn {
if hasOwner {
earnClaim, foundEarnClaim := s.keeper.GetEarnClaim(ctx, owner)
if foundEarnClaim {
res.EarnClaims = append(res.EarnClaims, earnClaim)
}
} else {
earnClaims := s.keeper.GetAllEarnClaims(ctx)
res.EarnClaims = append(res.EarnClaims, earnClaims...)
}
}
return nil
}
// synchronizeRewards synchronizes all non-empty rewards in place.
func (s queryServer) synchronizeRewards(
ctx sdk.Context,
res *types.QueryRewardsResponse,
) error {
// Synchronize all non-empty rewards
for i, claim := range res.USDXMintingClaims {
res.USDXMintingClaims[i] = s.keeper.SimulateUSDXMintingSynchronization(ctx, claim)
}
for i, claim := range res.HardLiquidityProviderClaims {
res.HardLiquidityProviderClaims[i] = s.keeper.SimulateHardSynchronization(ctx, claim)
}
for i, claim := range res.DelegatorClaims {
res.DelegatorClaims[i] = s.keeper.SimulateDelegatorSynchronization(ctx, claim)
}
for i, claim := range res.SwapClaims {
syncedClaim, found := s.keeper.GetSynchronizedSwapClaim(ctx, claim.Owner)
if !found {
return status.Errorf(codes.Internal, "previously found swap claim for owner %s should still be found", claim.Owner)
}
res.SwapClaims[i] = syncedClaim
}
for i, claim := range res.SavingsClaims {
syncedClaim, found := s.keeper.GetSynchronizedSavingsClaim(ctx, claim.Owner)
if !found {
return status.Errorf(codes.Internal, "previously found savings claim for owner %s should still be found", claim.Owner)
}
res.SavingsClaims[i] = syncedClaim
}
for i, claim := range res.EarnClaims {
syncedClaim, found := s.keeper.GetSynchronizedEarnClaim(ctx, claim.Owner)
if !found {
return status.Errorf(codes.Internal, "previously found earn claim for owner %s should still be found", claim.Owner)
}
res.EarnClaims[i] = syncedClaim
}
return nil
}
func rewardTypeIsValid(rewardType string) bool {
return rewardType == "" ||
rewardType == RewardTypeHard ||
rewardType == RewardTypeUSDXMinting ||
rewardType == RewardTypeDelegator ||
rewardType == RewardTypeSwap ||
rewardType == RewardTypeSavings ||
rewardType == RewardTypeEarn
}

View File

@ -0,0 +1,318 @@
package keeper_test
import (
"testing"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app"
hardtypes "github.com/kava-labs/kava/x/hard/types"
"github.com/kava-labs/kava/x/incentive/keeper"
"github.com/kava-labs/kava/x/incentive/types"
"github.com/stretchr/testify/suite"
tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types"
)
const (
oneYear time.Duration = 365 * 24 * time.Hour
)
type grpcQueryTestSuite struct {
suite.Suite
tApp app.TestApp
ctx sdk.Context
keeper keeper.Keeper
queryClient types.QueryClient
addrs []sdk.AccAddress
genesisTime time.Time
genesisState types.GenesisState
}
func (suite *grpcQueryTestSuite) SetupTest() {
suite.tApp = app.NewTestApp()
cdc := suite.tApp.AppCodec()
_, addrs := app.GeneratePrivKeyAddressPairs(5)
suite.genesisTime = time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.addrs = addrs
suite.ctx = suite.tApp.NewContext(true, tmprototypes.Header{}).
WithBlockTime(time.Now().UTC())
suite.keeper = suite.tApp.GetIncentiveKeeper()
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.tApp.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, keeper.NewQueryServerImpl(suite.keeper))
suite.queryClient = types.NewQueryClient(queryHelper)
loanToValue, _ := sdk.NewDecFromStr("0.6")
borrowLimit := sdk.NewDec(1000000000000000)
hardGS := hardtypes.NewGenesisState(
hardtypes.NewParams(
hardtypes.MoneyMarkets{
hardtypes.NewMoneyMarket("ukava", hardtypes.NewBorrowLimit(false, borrowLimit, loanToValue), "kava:usd", sdk.NewInt(1000000), hardtypes.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
hardtypes.NewMoneyMarket("bnb", hardtypes.NewBorrowLimit(false, borrowLimit, loanToValue), "bnb:usd", sdk.NewInt(1000000), hardtypes.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
sdk.NewDec(10),
),
hardtypes.DefaultAccumulationTimes,
hardtypes.DefaultDeposits,
hardtypes.DefaultBorrows,
hardtypes.DefaultTotalSupplied,
hardtypes.DefaultTotalBorrowed,
hardtypes.DefaultTotalReserves,
)
suite.genesisState = types.NewGenesisState(
types.NewParams(
types.RewardPeriods{types.NewRewardPeriod(true, "bnb-a", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), c("ukava", 122354))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "bnb", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "bnb", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "btcb/usdx", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("swp", 122354)))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))},
types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))},
types.MultipliersPerDenoms{
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 12, d("1.0")),
},
},
{
Denom: "hard",
Multipliers: types.Multipliers{
types.NewMultiplier("small", 1, d("0.25")),
types.NewMultiplier("large", 12, d("1.0")),
},
},
{
Denom: "swp",
Multipliers: types.Multipliers{
types.NewMultiplier("small", 1, d("0.25")),
types.NewMultiplier("medium", 6, d("0.8")),
},
},
},
suite.genesisTime.Add(5*oneYear),
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("bnb-a", suite.genesisTime),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("bnb-a", types.RewardIndexes{{CollateralType: "ukava", RewardFactor: d("0.3")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("bnb", suite.genesisTime.Add(-1*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("bnb", types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.1")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("bnb", suite.genesisTime.Add(-2*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("bnb", types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.05")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("ukava", suite.genesisTime.Add(-3*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("ukava", types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.2")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("bctb/usdx", suite.genesisTime.Add(-4*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("btcb/usdx", types.RewardIndexes{{CollateralType: "swap", RewardFactor: d("0.001")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("ukava", suite.genesisTime.Add(-3*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("ukava", types.RewardIndexes{{CollateralType: "ukava", RewardFactor: d("0.2")}}),
},
),
types.NewGenesisRewardState(
types.AccumulationTimes{
types.NewAccumulationTime("usdx", suite.genesisTime.Add(-3*time.Hour)),
},
types.MultiRewardIndexes{
types.NewMultiRewardIndex("usdx", types.RewardIndexes{{CollateralType: "usdx", RewardFactor: d("0.2")}}),
},
),
types.USDXMintingClaims{
types.NewUSDXMintingClaim(
suite.addrs[0],
c("ukava", 1e9),
types.RewardIndexes{{CollateralType: "bnb-a", RewardFactor: d("0.3")}},
),
types.NewUSDXMintingClaim(
suite.addrs[1],
c("ukava", 1),
types.RewardIndexes{{CollateralType: "bnb-a", RewardFactor: d("0.001")}},
),
},
types.HardLiquidityProviderClaims{
types.NewHardLiquidityProviderClaim(
suite.addrs[0],
cs(c("ukava", 1e9), c("hard", 1e9)),
types.MultiRewardIndexes{{CollateralType: "bnb", RewardIndexes: types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.01")}}}},
types.MultiRewardIndexes{{CollateralType: "bnb", RewardIndexes: types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.0")}}}},
),
types.NewHardLiquidityProviderClaim(
suite.addrs[1],
cs(c("hard", 1)),
types.MultiRewardIndexes{{CollateralType: "bnb", RewardIndexes: types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.1")}}}},
types.MultiRewardIndexes{{CollateralType: "bnb", RewardIndexes: types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.0")}}}},
),
},
types.DelegatorClaims{
types.NewDelegatorClaim(
suite.addrs[2],
cs(c("hard", 5)),
types.MultiRewardIndexes{{CollateralType: "ukava", RewardIndexes: types.RewardIndexes{{CollateralType: "hard", RewardFactor: d("0.2")}}}},
),
},
types.SwapClaims{
types.NewSwapClaim(
suite.addrs[3],
nil,
types.MultiRewardIndexes{{CollateralType: "btcb/usdx", RewardIndexes: types.RewardIndexes{{CollateralType: "swap", RewardFactor: d("0.0")}}}},
),
},
types.SavingsClaims{
types.NewSavingsClaim(
suite.addrs[3],
nil,
types.MultiRewardIndexes{{CollateralType: "ukava", RewardIndexes: types.RewardIndexes{{CollateralType: "ukava", RewardFactor: d("0.0")}}}},
),
},
types.EarnClaims{
types.NewEarnClaim(
suite.addrs[3],
nil,
types.MultiRewardIndexes{{CollateralType: "usdx", RewardIndexes: types.RewardIndexes{{CollateralType: "usdx", RewardFactor: d("0.0")}}}},
),
},
)
err := suite.genesisState.Validate()
suite.Require().NoError(err)
suite.tApp = suite.tApp.InitializeFromGenesisStatesWithTime(
suite.genesisTime,
app.GenesisState{types.ModuleName: cdc.MustMarshalJSON(&suite.genesisState)},
app.GenesisState{hardtypes.ModuleName: cdc.MustMarshalJSON(&hardGS)},
NewCDPGenStateMulti(cdc),
NewPricefeedGenStateMultiFromTime(cdc, suite.genesisTime),
)
}
func (suite *grpcQueryTestSuite) TestGrpcQueryParams() {
res, err := suite.queryClient.Params(sdk.WrapSDKContext(suite.ctx), &types.QueryParamsRequest{})
suite.Require().NoError(err)
expected := suite.keeper.GetParams(suite.ctx)
suite.Equal(expected, res.Params, "params should equal default params")
}
func (suite *grpcQueryTestSuite) TestGrpcQueryRewards() {
res, err := suite.queryClient.Rewards(sdk.WrapSDKContext(suite.ctx), &types.QueryRewardsRequest{
Unsynchronized: true,
})
suite.Require().NoError(err)
suite.Equal(suite.genesisState.USDXMintingClaims, res.USDXMintingClaims)
suite.Equal(suite.genesisState.HardLiquidityProviderClaims, res.HardLiquidityProviderClaims)
suite.Equal(suite.genesisState.DelegatorClaims, res.DelegatorClaims)
suite.Equal(suite.genesisState.SwapClaims, res.SwapClaims)
suite.Equal(suite.genesisState.SavingsClaims, res.SavingsClaims)
suite.Equal(suite.genesisState.EarnClaims, res.EarnClaims)
}
func (suite *grpcQueryTestSuite) TestGrpcQueryRewards_Owner() {
res, err := suite.queryClient.Rewards(sdk.WrapSDKContext(suite.ctx), &types.QueryRewardsRequest{
Owner: suite.addrs[0].String(),
})
suite.Require().NoError(err)
suite.Len(res.USDXMintingClaims, 1)
suite.Len(res.HardLiquidityProviderClaims, 1)
suite.Equal(suite.genesisState.USDXMintingClaims[0], res.USDXMintingClaims[0])
suite.Equal(suite.genesisState.HardLiquidityProviderClaims[0], res.HardLiquidityProviderClaims[0])
// No other claims - owner has none
suite.Empty(res.DelegatorClaims)
suite.Empty(res.SwapClaims)
suite.Empty(res.SavingsClaims)
suite.Empty(res.EarnClaims)
}
func (suite *grpcQueryTestSuite) TestGrpcQueryRewards_RewardType() {
res, err := suite.queryClient.Rewards(sdk.WrapSDKContext(suite.ctx), &types.QueryRewardsRequest{
RewardType: keeper.RewardTypeHard,
Unsynchronized: true,
})
suite.Require().NoError(err)
suite.Equal(suite.genesisState.HardLiquidityProviderClaims, res.HardLiquidityProviderClaims)
// No other reward types when specifying rewardType
suite.Empty(res.USDXMintingClaims)
suite.Empty(res.DelegatorClaims)
suite.Empty(res.SwapClaims)
suite.Empty(res.SavingsClaims)
suite.Empty(res.EarnClaims)
}
func (suite *grpcQueryTestSuite) TestGrpcQueryRewards_RewardType_and_Owner() {
res, err := suite.queryClient.Rewards(sdk.WrapSDKContext(suite.ctx), &types.QueryRewardsRequest{
Owner: suite.addrs[0].String(),
RewardType: keeper.RewardTypeHard,
})
suite.Require().NoError(err)
suite.Len(res.HardLiquidityProviderClaims, 1)
suite.Equal(suite.genesisState.HardLiquidityProviderClaims[0], res.HardLiquidityProviderClaims[0])
suite.Empty(res.USDXMintingClaims)
suite.Empty(res.DelegatorClaims)
suite.Empty(res.SwapClaims)
suite.Empty(res.SavingsClaims)
suite.Empty(res.EarnClaims)
}
func (suite *grpcQueryTestSuite) TestGrpcQueryRewardFactors() {
res, err := suite.queryClient.RewardFactors(sdk.WrapSDKContext(suite.ctx), &types.QueryRewardFactorsRequest{})
suite.Require().NoError(err)
suite.NotEmpty(res.UsdxMintingRewardFactors)
suite.NotEmpty(res.HardSupplyRewardFactors)
suite.NotEmpty(res.HardBorrowRewardFactors)
suite.NotEmpty(res.DelegatorRewardFactors)
suite.NotEmpty(res.SwapRewardFactors)
suite.NotEmpty(res.SavingsRewardFactors)
suite.NotEmpty(res.EarnRewardFactors)
}
func TestGrpcQueryTestSuite(t *testing.T) {
suite.Run(t, new(grpcQueryTestSuite))
}

View File

@ -1,6 +1,7 @@
package incentive
import (
"context"
"encoding/json"
"github.com/gorilla/mux"
@ -68,10 +69,9 @@ func (a AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Ro
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the incentive module.
func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
// TODO:
// if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
// panic(err)
// }
if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
panic(err)
}
}
// LegacyQuerierHandler returns sdk.Querier.
@ -136,7 +136,7 @@ func (AppModule) QuerierRoute() string {
// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
// TODO: types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper, am.accountKeeper, am.bankKeeper))
types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper))
}
// InitGenesis performs genesis initialization for the incentive module. It returns no validator updates.

14
x/incentive/types/apy.go Normal file
View File

@ -0,0 +1,14 @@
package types
import sdk "github.com/cosmos/cosmos-sdk/types"
// NewAPY returns a new instance of APY
func NewAPY(collateralType string, apy sdk.Dec) Apy {
return Apy{
CollateralType: collateralType,
Apy: apy,
}
}
// APYs is a slice of APY
type APYs []Apy

372
x/incentive/types/apy.pb.go Normal file
View File

@ -0,0 +1,372 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: kava/incentive/v1beta1/apy.proto
package types
import (
fmt "fmt"
_ "github.com/cosmos/cosmos-proto"
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// Apy contains the calculated APY for a given collateral type at a specific
// instant in time.
type Apy struct {
CollateralType string `protobuf:"bytes,1,opt,name=collateral_type,json=collateralType,proto3" json:"collateral_type,omitempty"`
Apy github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=apy,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"apy"`
}
func (m *Apy) Reset() { *m = Apy{} }
func (m *Apy) String() string { return proto.CompactTextString(m) }
func (*Apy) ProtoMessage() {}
func (*Apy) Descriptor() ([]byte, []int) {
return fileDescriptor_b2c1ad571f25cae9, []int{0}
}
func (m *Apy) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Apy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Apy.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 *Apy) XXX_Merge(src proto.Message) {
xxx_messageInfo_Apy.Merge(m, src)
}
func (m *Apy) XXX_Size() int {
return m.Size()
}
func (m *Apy) XXX_DiscardUnknown() {
xxx_messageInfo_Apy.DiscardUnknown(m)
}
var xxx_messageInfo_Apy proto.InternalMessageInfo
func (m *Apy) GetCollateralType() string {
if m != nil {
return m.CollateralType
}
return ""
}
func init() {
proto.RegisterType((*Apy)(nil), "kava.incentive.v1beta1.Apy")
}
func init() { proto.RegisterFile("kava/incentive/v1beta1/apy.proto", fileDescriptor_b2c1ad571f25cae9) }
var fileDescriptor_b2c1ad571f25cae9 = []byte{
// 248 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc8, 0x4e, 0x2c, 0x4b,
0xd4, 0xcf, 0xcc, 0x4b, 0x4e, 0xcd, 0x2b, 0xc9, 0x2c, 0x4b, 0xd5, 0x2f, 0x33, 0x4c, 0x4a, 0x2d,
0x49, 0x34, 0xd4, 0x4f, 0x2c, 0xa8, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x03, 0xa9,
0xd0, 0x83, 0xab, 0xd0, 0x83, 0xaa, 0x90, 0x92, 0x4c, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0x8e, 0x07,
0xab, 0xd2, 0x87, 0x70, 0x20, 0x5a, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16,
0x44, 0x54, 0xa9, 0x8e, 0x8b, 0xd9, 0xb1, 0xa0, 0x52, 0x48, 0x9d, 0x8b, 0x3f, 0x39, 0x3f, 0x27,
0x27, 0xb1, 0x24, 0xb5, 0x28, 0x31, 0x27, 0xbe, 0xa4, 0xb2, 0x20, 0x55, 0x82, 0x51, 0x81, 0x51,
0x83, 0x33, 0x88, 0x0f, 0x21, 0x1c, 0x52, 0x59, 0x90, 0x2a, 0xe4, 0xc7, 0xc5, 0x9c, 0x58, 0x50,
0x29, 0xc1, 0x04, 0x92, 0x74, 0xb2, 0x39, 0x71, 0x4f, 0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0xb5, 0xf4,
0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xa8, 0x9d, 0x50, 0x4a, 0xb7, 0x38, 0x25,
0x5b, 0x1f, 0x64, 0x5a, 0xb1, 0x9e, 0x4b, 0x6a, 0xf2, 0xa5, 0x2d, 0xba, 0x5c, 0x50, 0x27, 0xb9,
0xa4, 0x26, 0x07, 0x81, 0x0c, 0x72, 0x72, 0x3d, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6,
0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39,
0x86, 0x28, 0x6d, 0x24, 0x43, 0x41, 0xbe, 0xd5, 0xcd, 0x49, 0x4c, 0x2a, 0x06, 0xb3, 0xf4, 0x2b,
0x90, 0xc2, 0x06, 0x6c, 0x7a, 0x12, 0x1b, 0xd8, 0x37, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff,
0x95, 0x59, 0xa8, 0x77, 0x3a, 0x01, 0x00, 0x00,
}
func (m *Apy) 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 *Apy) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Apy) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
{
size := m.Apy.Size()
i -= size
if _, err := m.Apy.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintApy(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
if len(m.CollateralType) > 0 {
i -= len(m.CollateralType)
copy(dAtA[i:], m.CollateralType)
i = encodeVarintApy(dAtA, i, uint64(len(m.CollateralType)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintApy(dAtA []byte, offset int, v uint64) int {
offset -= sovApy(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Apy) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.CollateralType)
if l > 0 {
n += 1 + l + sovApy(uint64(l))
}
l = m.Apy.Size()
n += 1 + l + sovApy(uint64(l))
return n
}
func sovApy(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozApy(x uint64) (n int) {
return sovApy(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Apy) 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 ErrIntOverflowApy
}
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: Apy: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Apy: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CollateralType", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApy
}
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 ErrInvalidLengthApy
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthApy
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CollateralType = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Apy", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApy
}
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 ErrInvalidLengthApy
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthApy
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Apy.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipApy(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthApy
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipApy(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApy
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApy
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApy
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthApy
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupApy
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthApy
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthApy = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowApy = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupApy = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -66,30 +66,13 @@ func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFa
}
}
// APY contains the APY for a given collateral type
type APY struct {
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
APY sdk.Dec `json:"apy" yaml:"apy"`
}
// NewAPY returns a new instance of APY
func NewAPY(collateralType string, apy sdk.Dec) APY {
return APY{
CollateralType: collateralType,
APY: apy,
}
}
// APYs is a slice of APY
type APYs []APY
// QueryGetAPYsResponse holds the response to a APY query
type QueryGetAPYsResponse struct {
Earn []APY `json:"earn" yaml:"earn"`
Earn []Apy `json:"earn" yaml:"earn"`
}
// NewQueryGetAPYsResponse returns a new instance of QueryGetAPYsResponse
func NewQueryGetAPYsResponse(earn []APY) QueryGetAPYsResponse {
func NewQueryGetAPYsResponse(earn []Apy) QueryGetAPYsResponse {
return QueryGetAPYsResponse{
Earn: earn,
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,366 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: kava/incentive/v1beta1/query.proto
/*
Package types is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package types
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := server.Params(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Query_Rewards_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Query_Rewards_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRewardsRequest
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_Rewards_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Rewards(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Rewards_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRewardsRequest
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_Rewards_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Rewards(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_RewardFactors_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRewardFactorsRequest
var metadata runtime.ServerMetadata
msg, err := client.RewardFactors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_RewardFactors_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRewardFactorsRequest
var metadata runtime.ServerMetadata
msg, err := server.RewardFactors(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Apy_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryApyRequest
var metadata runtime.ServerMetadata
msg, err := client.Apy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Apy_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryApyRequest
var metadata runtime.ServerMetadata
msg, err := server.Apy(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.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Params_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 {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Rewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Rewards_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 {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Rewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_RewardFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_RewardFactors_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 {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_RewardFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Apy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Apy_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 {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Apy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterQueryHandler(ctx, mux, conn)
}
// RegisterQueryHandler registers the http handlers for service Query to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn))
}
// RegisterQueryHandlerClient registers the http handlers for service Query
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "QueryClient" to call the correct interceptors.
func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error {
mux.Handle("GET", pattern_Query_Params_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Rewards_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Rewards_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_Rewards_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_RewardFactors_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_RewardFactors_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_RewardFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Apy_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Apy_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_Apy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "incentive", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Query_Rewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "incentive", "v1beta1", "rewards"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Query_RewardFactors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "incentive", "v1beta1", "reward_factors"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Query_Apy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "incentive", "v1beta1", "apy"}, "", runtime.AssumeColonVerbOpt(false)))
)
var (
forward_Query_Params_0 = runtime.ForwardResponseMessage
forward_Query_Rewards_0 = runtime.ForwardResponseMessage
forward_Query_RewardFactors_0 = runtime.ForwardResponseMessage
forward_Query_Apy_0 = runtime.ForwardResponseMessage
)