[R4R] This is the implementation of the total circulating supply (#376)

* adding empty query files where we will implement the cli and rest interfaces

* adding querier file

* adding aliases, querier, expected keepers, types, module updates

* starting to work on query

* adding alias for QueryCirculatingSupply

* adding TotalCirculatingSupply type

* adding alias for TotalCirculatingSupply type

* adding QueryCirculatingSupplyCmd to clieng query file

* adding register routes function

* adding rest query handling function, register endpoint

* fix types include statement

* remove unused mux include

* another import fix

* remove unused variable

* adding rest to module

* fix missing variable names

* another missing variable fix

* remove dead code comment

* fix typo in circulating-supply

* fix import

* fix querierroute return to return the module name instead of empty string

* rename function, fix build issue

* return error instead of nil if there is an error

* import types from cosmos sdk, fix return type

* set querier route to module name in key.go

* adding query and rest updates

* aliasing new querying circulating supply function

* directly write output

* fix routes

* adding total supply functionality

* converting from microkava to kava

* Update x/validator-vesting/client/cli/query.go

typo fix

Co-Authored-By: Kevin Davis <karzak@users.noreply.github.com>

Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
This commit is contained in:
John Maheswaran 2020-02-25 10:29:54 -05:00 committed by GitHub
parent 6e8e3f5bb9
commit 51fc70b5ac
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 // nolint
// autogenerated code using github.com/rigelrozanski/multitool // autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories: // 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 package validatorvesting
import ( import (
@ -11,35 +11,37 @@ import (
) )
const ( const (
ModuleName = types.ModuleName ModuleName = types.ModuleName
StoreKey = types.StoreKey StoreKey = types.StoreKey
QuerierRoute = types.QuerierRoute
QueryCirculatingSupply = types.QueryCirculatingSupply
QueryTotalSupply = types.QueryTotalSupply
) )
var ( var (
// functions aliases // 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 NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
MakeTestCodec = keeper.MakeTestCodec MakeTestCodec = keeper.MakeTestCodec
CreateTestInput = keeper.CreateTestInput CreateTestInput = keeper.CreateTestInput
ValidatorVestingTestAccount = keeper.ValidatorVestingTestAccount ValidatorVestingTestAccount = keeper.ValidatorVestingTestAccount
ValidatorVestingTestAccounts = keeper.ValidatorVestingTestAccounts ValidatorVestingTestAccounts = keeper.ValidatorVestingTestAccounts
ValidatorVestingDelegatorTestAccount = keeper.ValidatorVestingDelegatorTestAccount ValidatorVestingDelegatorTestAccount = keeper.ValidatorVestingDelegatorTestAccount
CreateValidators = keeper.CreateValidators 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 // variable aliases
ModuleCdc = types.ModuleCdc
BlocktimeKey = types.BlocktimeKey
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
ValOpPk1 = keeper.ValOpPk1 ValOpPk1 = keeper.ValOpPk1
ValOpPk2 = keeper.ValOpPk2 ValOpPk2 = keeper.ValOpPk2
ValOpPk3 = keeper.ValOpPk3 ValOpPk3 = keeper.ValOpPk3
@ -53,12 +55,17 @@ var (
ValConsAddr2 = keeper.ValConsAddr2 ValConsAddr2 = keeper.ValConsAddr2
ValConsAddr3 = keeper.ValConsAddr3 ValConsAddr3 = keeper.ValConsAddr3
TestAddrs = keeper.TestAddrs TestAddrs = keeper.TestAddrs
ModuleCdc = types.ModuleCdc
BlocktimeKey = types.BlocktimeKey
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
) )
type ( type (
Keeper = keeper.Keeper
GenesisState = types.GenesisState GenesisState = types.GenesisState
BaseQueryParams = types.BaseQueryParams
VestingProgress = types.VestingProgress VestingProgress = types.VestingProgress
CurrentPeriodProgress = types.CurrentPeriodProgress CurrentPeriodProgress = types.CurrentPeriodProgress
ValidatorVestingAccount = types.ValidatorVestingAccount 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 GetAccount(sdk.Context, sdk.AccAddress) authexported.Account
SetAccount(sdk.Context, authexported.Account) SetAccount(sdk.Context, authexported.Account)
GetAllAccounts(ctx sdk.Context) (accounts []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) // 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 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 BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) 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 to be used when creating the KVStore
StoreKey = ModuleName StoreKey = ModuleName
// QuerierRoute should be set to module name
QuerierRoute = ModuleName
) )
var ( 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"` 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 // NewValidatorVestingAccountRaw creates a new ValidatorVestingAccount object from BaseVestingAccount
func NewValidatorVestingAccountRaw(bva *vestingtypes.BaseVestingAccount, func NewValidatorVestingAccountRaw(bva *vestingtypes.BaseVestingAccount,
startTime int64, periods vestingtypes.Periods, validatorAddress sdk.ConsAddress, returnAddress sdk.AccAddress, signingThreshold int64) *ValidatorVestingAccount { 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" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
sim "github.com/cosmos/cosmos-sdk/x/simulation" 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/internal/types"
"github.com/kava-labs/kava/x/validator-vesting/simulation" "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. // 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. // GetTxCmd returns no root tx command for the validator-vesting module.
func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil }
// GetQueryCmd returns no root query command for the validator-vesting module. // 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. // AppModuleSimulation defines the module simulation functions used by the auth module.
type AppModuleSimulation struct{} type AppModuleSimulation struct{}
@ -112,12 +118,12 @@ func (AppModule) NewHandler() sdk.Handler { return nil }
// QuerierRoute returns the auth module's querier route name. // QuerierRoute returns the auth module's querier route name.
func (AppModule) QuerierRoute() string { func (AppModule) QuerierRoute() string {
return "" return ModuleName
} }
// NewQuerierHandler returns the auth module sdk.Querier. // NewQuerierHandler returns the auth module sdk.Querier.
func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) NewQuerierHandler() sdk.Querier {
return nil return NewQuerier(am.keeper)
} }
// InitGenesis performs genesis initialization for the auth module. It returns // InitGenesis performs genesis initialization for the auth module. It returns