Merge pull request #378 from Kava-Labs/develop

Add custom supply endpoints
This commit is contained in:
Kevin Davis 2020-02-25 10:56:01 -05:00 committed by GitHub
commit 7e78f37788
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 310 additions and 23 deletions

View File

@ -1,8 +1,8 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/types/
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/keeper/
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/keeper
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/types
package validatorvesting
import (
@ -11,35 +11,37 @@ import (
)
const (
ModuleName = types.ModuleName
StoreKey = types.StoreKey
ModuleName = types.ModuleName
StoreKey = types.StoreKey
QuerierRoute = types.QuerierRoute
QueryCirculatingSupply = types.QueryCirculatingSupply
QueryTotalSupply = types.QueryTotalSupply
)
var (
// functions aliases
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
ValidatorVestingAccountKey = types.ValidatorVestingAccountKey
CreateTestAddrs = types.CreateTestAddrs
TestAddr = types.TestAddr
CreateTestPubKeys = types.CreateTestPubKeys
NewPubKey = types.NewPubKey
NewValidatorVestingAccountRaw = types.NewValidatorVestingAccountRaw
NewValidatorVestingAccount = types.NewValidatorVestingAccount
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
MakeTestCodec = keeper.MakeTestCodec
CreateTestInput = keeper.CreateTestInput
ValidatorVestingTestAccount = keeper.ValidatorVestingTestAccount
ValidatorVestingTestAccounts = keeper.ValidatorVestingTestAccounts
ValidatorVestingDelegatorTestAccount = keeper.ValidatorVestingDelegatorTestAccount
CreateValidators = keeper.CreateValidators
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
ValidatorVestingAccountKey = types.ValidatorVestingAccountKey
NewBaseQueryParams = types.NewBaseQueryParams
CreateTestAddrs = types.CreateTestAddrs
TestAddr = types.TestAddr
CreateTestPubKeys = types.CreateTestPubKeys
NewPubKey = types.NewPubKey
NewValidatorVestingAccountRaw = types.NewValidatorVestingAccountRaw
NewValidatorVestingAccount = types.NewValidatorVestingAccount
// variable aliases
ModuleCdc = types.ModuleCdc
BlocktimeKey = types.BlocktimeKey
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
ValOpPk1 = keeper.ValOpPk1
ValOpPk2 = keeper.ValOpPk2
ValOpPk3 = keeper.ValOpPk3
@ -53,12 +55,17 @@ var (
ValConsAddr2 = keeper.ValConsAddr2
ValConsAddr3 = keeper.ValConsAddr3
TestAddrs = keeper.TestAddrs
ModuleCdc = types.ModuleCdc
BlocktimeKey = types.BlocktimeKey
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
)
type (
Keeper = keeper.Keeper
GenesisState = types.GenesisState
BaseQueryParams = types.BaseQueryParams
VestingProgress = types.VestingProgress
CurrentPeriodProgress = types.CurrentPeriodProgress
ValidatorVestingAccount = types.ValidatorVestingAccount
Keeper = keeper.Keeper
TotalCirculatingSupply = types.TotalCirculatingSupply
)

View File

@ -0,0 +1,72 @@
package cli
import (
"fmt"
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
// Group nameservice queries under a subcommand
queryValidatorVestingCmd := &cobra.Command{
Use: "validator-vesting",
Short: "Querying commands for the validator vesting module",
}
queryValidatorVestingCmd.AddCommand(client.GetCommands(
QueryCirculatingSupplyCmd(queryRoute, cdc),
QueryTotalSupplyCmd(queryRoute, cdc),
)...)
return queryValidatorVestingCmd
}
// QueryCirculatingSupplyCmd queries the total circulating supply
func QueryCirculatingSupplyCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "circulating-supply",
Short: "Query circulating supply information",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryCirculatingSupply), nil)
if err != nil {
fmt.Printf("could not get total circulating supply\n")
return err
}
var out sdk.Dec
cdc.MustUnmarshalJSON(res, &out)
return cliCtx.PrintOutput(out)
},
}
}
// QueryTotalSupplyCmd queries the total supply of ukava
func QueryTotalSupplyCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "total-supply",
Short: "Query total supply information",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryTotalSupply), nil)
if err != nil {
fmt.Printf("could not get total supply\n")
return err
}
var out sdk.Dec
cdc.MustUnmarshalJSON(res, &out)
return cliCtx.PrintOutput(out)
},
}
}

View File

@ -0,0 +1,88 @@
package rest
import (
"fmt"
"net/http"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/gorilla/mux"
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
)
// define routes that get registered by the main application
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/vesting/circulatingsupply", getCirculatingSupplyHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/vesting/totalsupply", getTotalSupplyHandlerFn(cliCtx)).Methods("GET")
}
func getTotalSupplyHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewBaseQueryParams(page, limit)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryTotalSupply)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
// directly write output instead of putting in json
w.Write(res)
// rest.PostProcessResponse(w, cliCtx, res)
}
}
func getCirculatingSupplyHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewBaseQueryParams(page, limit)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryCirculatingSupply)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
// directly write output instead of putting in json
w.Write(res)
// rest.PostProcessResponse(w, cliCtx, res)
}
}

View File

@ -0,0 +1,13 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/gorilla/mux"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
registerQueryRoutes(cliCtx, r)
}

View File

@ -0,0 +1,74 @@
package keeper
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// NewQuerier returns a new querier function
func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) {
switch path[0] {
case types.QueryCirculatingSupply:
return queryGetCirculatingSupply(ctx, req, keeper)
case types.QueryTotalSupply:
return queryGetTotalSupply(ctx, req, keeper)
default:
return nil, sdk.ErrUnknownRequest("unknown cdp query endpoint")
}
}
}
func queryGetTotalSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
totalSupply := keeper.supplyKeeper.GetSupply(ctx).GetTotal().AmountOf("ukava")
supplyDec := sdk.NewDecFromInt(totalSupply).Mul(sdk.MustNewDecFromStr("0.000001"))
bz, err := codec.MarshalJSONIndent(keeper.cdc, supplyDec)
if err != nil {
return nil, sdk.ErrInternal(err.Error())
}
return bz, nil
}
func queryGetCirculatingSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
circulatingSupply := sdk.ZeroInt()
keeper.ak.IterateAccounts(ctx,
func(acc authexported.Account) (stop bool) {
// exclude module account
_, ok := acc.(supplyexported.ModuleAccountI)
if ok {
return false
}
// periodic vesting account
vacc, ok := acc.(vesting.PeriodicVestingAccount)
if ok {
balance := vacc.GetCoins().AmountOf("ukava")
if balance.IsZero() {
return false
}
spendableBalance := vacc.SpendableCoins(ctx.BlockTime()).AmountOf("ukava")
circulatingSupply = circulatingSupply.Add(sdk.MinInt(balance, spendableBalance))
return false
}
// base account
bacc, ok := acc.(*auth.BaseAccount)
if ok {
// add all coins
circulatingSupply = circulatingSupply.Add(bacc.GetCoins().AmountOf("ukava"))
}
return false
})
supplyDec := sdk.NewDecFromInt(circulatingSupply).Mul(sdk.MustNewDecFromStr("0.000001"))
bz, err := codec.MarshalJSONIndent(keeper.cdc, supplyDec)
if err != nil {
return nil, sdk.ErrInternal(err.Error())
}
return bz, nil
}

View File

@ -14,6 +14,7 @@ type AccountKeeper interface {
GetAccount(sdk.Context, sdk.AccAddress) authexported.Account
SetAccount(sdk.Context, authexported.Account)
GetAllAccounts(ctx sdk.Context) (accounts []authexported.Account)
IterateAccounts(ctx sdk.Context, cb func(account authexported.Account) (stop bool))
}
// BankKeeper defines the expected bank keeper (noalias)
@ -35,4 +36,5 @@ type SupplyKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI)
GetSupply(ctx sdk.Context) (supply supplyexported.SupplyI)
}

View File

@ -10,6 +10,9 @@ const (
// StoreKey to be used when creating the KVStore
StoreKey = ModuleName
// QuerierRoute should be set to module name
QuerierRoute = ModuleName
)
var (

View File

@ -0,0 +1,17 @@
package types
// Querier routes for the validator vesting module
const (
QueryCirculatingSupply = "circulating-supply"
QueryTotalSupply = "total-supply"
)
// QueryCirculatingSupplyParams defines the parameters necessary for querying for all Evidence.
type BaseQueryParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
}
func NewBaseQueryParams(page, limit int) BaseQueryParams {
return BaseQueryParams{Page: page, Limit: limit}
}

View File

@ -68,6 +68,11 @@ type ValidatorVestingAccount struct {
DebtAfterFailedVesting sdk.Coins `json:"debt_after_failed_vesting" yaml:"debt_after_failed_vesting"`
}
// TotalCirculatingSupply represents the total circulating supply of Kava
type TotalCirculatingSupply struct {
TotalSupply uint64 `json:"total_supply" yaml:"total_supply"` // total circulating supply
}
// NewValidatorVestingAccountRaw creates a new ValidatorVestingAccount object from BaseVestingAccount
func NewValidatorVestingAccountRaw(bva *vestingtypes.BaseVestingAccount,
startTime int64, periods vestingtypes.Periods, validatorAddress sdk.ConsAddress, returnAddress sdk.AccAddress, signingThreshold int64) *ValidatorVestingAccount {

View File

@ -13,6 +13,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
sim "github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/kava-labs/kava/x/validator-vesting/client/cli"
"github.com/kava-labs/kava/x/validator-vesting/client/rest"
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
"github.com/kava-labs/kava/x/validator-vesting/simulation"
)
@ -52,13 +54,17 @@ func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
}
// RegisterRESTRoutes registers no REST routes for the crisis module.
func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {}
func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) {
rest.RegisterRoutes(ctx, rtr)
}
// GetTxCmd returns no root tx command for the validator-vesting module.
func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil }
// GetQueryCmd returns no root query command for the validator-vesting module.
func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil }
func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
return cli.GetQueryCmd(StoreKey, cdc)
}
// AppModuleSimulation defines the module simulation functions used by the auth module.
type AppModuleSimulation struct{}
@ -112,12 +118,12 @@ func (AppModule) NewHandler() sdk.Handler { return nil }
// QuerierRoute returns the auth module's querier route name.
func (AppModule) QuerierRoute() string {
return ""
return ModuleName
}
// NewQuerierHandler returns the auth module sdk.Querier.
func (am AppModule) NewQuerierHandler() sdk.Querier {
return nil
return NewQuerier(am.keeper)
}
// InitGenesis performs genesis initialization for the auth module. It returns