diff --git a/client/docs/swagger-ui/swagger.yaml b/client/docs/swagger-ui/swagger.yaml index aaf7ac5b..fd2efe0e 100644 --- a/client/docs/swagger-ui/swagger.yaml +++ b/client/docs/swagger-ui/swagger.yaml @@ -7199,6 +7199,67 @@ paths: format: byte tags: - Earn + /kava/earn/v1beta1/total_supply: + get: + summary: >- + TotalSupply returns the total sum of all coins currently locked into the + earn module. + operationId: EarnTotalSupply + responses: + '200': + description: A successful response. + schema: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom + method + + signatures required by gogoproto. + title: Result is a list of coins supplied to earn + description: >- + TotalSupplyResponse defines the response type for the + Query/TotalSupply method. + default: + description: An unexpected error response. + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Earn /kava/earn/v1beta1/vaults: get: summary: Vaults queries all vaults @@ -10900,6 +10961,67 @@ paths: type: string tags: - Liquid + /kava/liquid/v1beta1/total_supply: + get: + summary: >- + TotalSupply returns the total sum of all coins currently locked into the + liquid module. + operationId: LiquidTotalSupply + responses: + '200': + description: A successful response. + schema: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom + method + + signatures required by gogoproto. + title: Result is a list of coins supplied to liquid + description: >- + TotalSupplyResponse defines the response type for the + Query/TotalSupply method. + default: + description: An unexpected error response. + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Liquid /kava/pricefeed/v1beta1/markets: get: summary: Markets queries all markets @@ -11811,6 +11933,67 @@ paths: format: byte tags: - Savings + /kava/savings/v1beta1/total_supply: + get: + summary: >- + TotalSupply returns the total sum of all coins currently locked into the + savings module. + operationId: SavingsTotalSupply + responses: + '200': + description: A successful response. + schema: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom + method + + signatures required by gogoproto. + title: Result is a list of coins supplied to savings + description: >- + TotalSupplyResponse defines the response type for the + Query/TotalSupply method. + default: + description: An unexpected error response. + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Savings /node_info: get: description: Information about the connected node @@ -55271,6 +55454,31 @@ definitions: description: >- QueryParamsResponse defines the response type for querying x/earn parameters. + kava.earn.v1beta1.QueryTotalSupplyResponse: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: Result is a list of coins supplied to earn + description: >- + TotalSupplyResponse defines the response type for the Query/TotalSupply + method. kava.earn.v1beta1.QueryVaultResponse: type: object properties: @@ -56832,6 +57040,31 @@ definitions: description: >- DelegatedBalanceResponse defines the response type for the Query/DelegatedBalance method. + kava.liquid.v1beta1.QueryTotalSupplyResponse: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: Result is a list of coins supplied to liquid + description: >- + TotalSupplyResponse defines the response type for the Query/TotalSupply + method. kava.pricefeed.v1beta1.CurrentPriceResponse: type: object properties: @@ -57362,6 +57595,31 @@ definitions: description: |- QueryParamsResponse defines the response type for querying x/savings parameters. + kava.savings.v1beta1.QueryTotalSupplyResponse: + type: object + properties: + height: + type: string + format: int64 + title: Height is the block height at which these totals apply + result: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: Result is a list of coins supplied to savings + description: >- + TotalSupplyResponse defines the response type for the Query/TotalSupply + method. CheckTxResult: type: object properties: diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 0d64ccf2..1d0724fe 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -205,6 +205,8 @@ - [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse) - [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest) - [QueryParamsResponse](#kava.earn.v1beta1.QueryParamsResponse) + - [QueryTotalSupplyRequest](#kava.earn.v1beta1.QueryTotalSupplyRequest) + - [QueryTotalSupplyResponse](#kava.earn.v1beta1.QueryTotalSupplyResponse) - [QueryVaultRequest](#kava.earn.v1beta1.QueryVaultRequest) - [QueryVaultResponse](#kava.earn.v1beta1.QueryVaultResponse) - [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest) @@ -405,6 +407,8 @@ - [kava/liquid/v1beta1/query.proto](#kava/liquid/v1beta1/query.proto) - [QueryDelegatedBalanceRequest](#kava.liquid.v1beta1.QueryDelegatedBalanceRequest) - [QueryDelegatedBalanceResponse](#kava.liquid.v1beta1.QueryDelegatedBalanceResponse) + - [QueryTotalSupplyRequest](#kava.liquid.v1beta1.QueryTotalSupplyRequest) + - [QueryTotalSupplyResponse](#kava.liquid.v1beta1.QueryTotalSupplyResponse) - [Query](#kava.liquid.v1beta1.Query) @@ -474,6 +478,8 @@ - [QueryDepositsResponse](#kava.savings.v1beta1.QueryDepositsResponse) - [QueryParamsRequest](#kava.savings.v1beta1.QueryParamsRequest) - [QueryParamsResponse](#kava.savings.v1beta1.QueryParamsResponse) + - [QueryTotalSupplyRequest](#kava.savings.v1beta1.QueryTotalSupplyRequest) + - [QueryTotalSupplyResponse](#kava.savings.v1beta1.QueryTotalSupplyResponse) - [Query](#kava.savings.v1beta1.Query) @@ -3149,6 +3155,32 @@ QueryParamsResponse defines the response type for querying x/earn parameters. + + +### QueryTotalSupplyRequest +QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. + + + + + + + + +### QueryTotalSupplyResponse +TotalSupplyResponse defines the response type for the Query/TotalSupply method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | Height is the block height at which these totals apply | +| `result` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Result is a list of coins supplied to earn | + + + + + + ### QueryVaultRequest @@ -3241,6 +3273,7 @@ Query defines the gRPC querier service for earn module | `Vaults` | [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest) | [QueryVaultsResponse](#kava.earn.v1beta1.QueryVaultsResponse) | Vaults queries all vaults | GET|/kava/earn/v1beta1/vaults| | `Vault` | [QueryVaultRequest](#kava.earn.v1beta1.QueryVaultRequest) | [QueryVaultResponse](#kava.earn.v1beta1.QueryVaultResponse) | Vault queries a single vault based on the vault denom | GET|/kava/earn/v1beta1/vaults/{denom}| | `Deposits` | [QueryDepositsRequest](#kava.earn.v1beta1.QueryDepositsRequest) | [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse) | Deposits queries deposit details based on depositor address and vault | GET|/kava/earn/v1beta1/deposits| +| `TotalSupply` | [QueryTotalSupplyRequest](#kava.earn.v1beta1.QueryTotalSupplyRequest) | [QueryTotalSupplyResponse](#kava.earn.v1beta1.QueryTotalSupplyResponse) | TotalSupply returns the total sum of all coins currently locked into the earn module. | GET|/kava/earn/v1beta1/total_supply| @@ -5723,6 +5756,32 @@ DelegatedBalanceResponse defines the response type for the Query/DelegatedBalanc + + + +### QueryTotalSupplyRequest +QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. + + + + + + + + +### QueryTotalSupplyResponse +TotalSupplyResponse defines the response type for the Query/TotalSupply method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | Height is the block height at which these totals apply | +| `result` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Result is a list of coins supplied to liquid | + + + + + @@ -5738,6 +5797,7 @@ Query defines the gRPC querier service for liquid module | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `DelegatedBalance` | [QueryDelegatedBalanceRequest](#kava.liquid.v1beta1.QueryDelegatedBalanceRequest) | [QueryDelegatedBalanceResponse](#kava.liquid.v1beta1.QueryDelegatedBalanceResponse) | DelegatedBalance returns an account's vesting and vested coins currently delegated to validators. It ignores coins in unbonding delegations. | GET|/kava/liquid/v1beta1/delegated_balance/{delegator}| +| `TotalSupply` | [QueryTotalSupplyRequest](#kava.liquid.v1beta1.QueryTotalSupplyRequest) | [QueryTotalSupplyResponse](#kava.liquid.v1beta1.QueryTotalSupplyResponse) | TotalSupply returns the total sum of all coins currently locked into the liquid module. | GET|/kava/liquid/v1beta1/total_supply| @@ -6544,6 +6604,32 @@ parameters. + + + +### QueryTotalSupplyRequest +QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. + + + + + + + + +### QueryTotalSupplyResponse +TotalSupplyResponse defines the response type for the Query/TotalSupply method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | Height is the block height at which these totals apply | +| `result` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Result is a list of coins supplied to savings | + + + + + @@ -6560,6 +6646,7 @@ Query defines the gRPC querier service for savings module | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `Params` | [QueryParamsRequest](#kava.savings.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#kava.savings.v1beta1.QueryParamsResponse) | Params queries all parameters of the savings module. | GET|/kava/savings/v1beta1/params| | `Deposits` | [QueryDepositsRequest](#kava.savings.v1beta1.QueryDepositsRequest) | [QueryDepositsResponse](#kava.savings.v1beta1.QueryDepositsResponse) | Deposits queries savings deposits. | GET|/kava/savings/v1beta1/deposits| +| `TotalSupply` | [QueryTotalSupplyRequest](#kava.savings.v1beta1.QueryTotalSupplyRequest) | [QueryTotalSupplyResponse](#kava.savings.v1beta1.QueryTotalSupplyResponse) | TotalSupply returns the total sum of all coins currently locked into the savings module. | GET|/kava/savings/v1beta1/total_supply| diff --git a/go.sum b/go.sum index 54c359da..d0c50c0c 100644 --- a/go.sum +++ b/go.sum @@ -195,8 +195,6 @@ github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpF github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/iavl v0.19.3 h1:cESO0OwTTxQm5rmyESKW+zESheDUYI7CcZDWWDwnuxg= -github.com/cosmos/iavl v0.19.3/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ibc-go/v3 v3.3.1 h1:i8o3iPSPN8fr7AjCPQnHEKz/VfeMrxc8mjvgAw6txWk= diff --git a/proto/kava/earn/v1beta1/query.proto b/proto/kava/earn/v1beta1/query.proto index cf025c6f..05ee1ff7 100644 --- a/proto/kava/earn/v1beta1/query.proto +++ b/proto/kava/earn/v1beta1/query.proto @@ -34,6 +34,11 @@ service Query { rpc Deposits(QueryDepositsRequest) returns (QueryDepositsResponse) { option (google.api.http).get = "/kava/earn/v1beta1/deposits"; } + + // TotalSupply returns the total sum of all coins currently locked into the earn module. + rpc TotalSupply(QueryTotalSupplyRequest) returns (QueryTotalSupplyResponse) { + option (google.api.http).get = "/kava/earn/v1beta1/total_supply"; + } } // QueryParamsRequest defines the request type for querying x/earn parameters. @@ -134,3 +139,15 @@ message DepositResponse { repeated cosmos.base.v1beta1.Coin value = 3 [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false]; } + +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +message QueryTotalSupplyRequest {} + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +message QueryTotalSupplyResponse { + // Height is the block height at which these totals apply + int64 height = 1; + // Result is a list of coins supplied to earn + repeated cosmos.base.v1beta1.Coin result = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} diff --git a/proto/kava/liquid/v1beta1/query.proto b/proto/kava/liquid/v1beta1/query.proto index 81b5bb60..0584af32 100644 --- a/proto/kava/liquid/v1beta1/query.proto +++ b/proto/kava/liquid/v1beta1/query.proto @@ -16,6 +16,11 @@ service Query { rpc DelegatedBalance(QueryDelegatedBalanceRequest) returns (QueryDelegatedBalanceResponse) { option (google.api.http).get = "/kava/liquid/v1beta1/delegated_balance/{delegator}"; } + + // TotalSupply returns the total sum of all coins currently locked into the liquid module. + rpc TotalSupply(QueryTotalSupplyRequest) returns (QueryTotalSupplyResponse) { + option (google.api.http).get = "/kava/liquid/v1beta1/total_supply"; + } } // QueryDelegatedBalanceRequest defines the request type for Query/DelegatedBalance method. @@ -31,3 +36,15 @@ message QueryDelegatedBalanceResponse { // vesting is the amount of all delegated coins that are still vesting (ie locked) cosmos.base.v1beta1.Coin vesting = 2 [(gogoproto.nullable) = false]; } + +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +message QueryTotalSupplyRequest {} + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +message QueryTotalSupplyResponse { + // Height is the block height at which these totals apply + int64 height = 1; + // Result is a list of coins supplied to liquid + repeated cosmos.base.v1beta1.Coin result = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} diff --git a/proto/kava/savings/v1beta1/query.proto b/proto/kava/savings/v1beta1/query.proto index 0a4e5320..b19c50cb 100644 --- a/proto/kava/savings/v1beta1/query.proto +++ b/proto/kava/savings/v1beta1/query.proto @@ -4,6 +4,7 @@ package kava.savings.v1beta1; import "kava/savings/v1beta1/store.proto"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "cosmos_proto/cosmos.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; @@ -20,6 +21,11 @@ service Query { rpc Deposits(QueryDepositsRequest) returns (QueryDepositsResponse) { option (google.api.http).get = "/kava/savings/v1beta1/deposits"; } + + // TotalSupply returns the total sum of all coins currently locked into the savings module. + rpc TotalSupply(QueryTotalSupplyRequest) returns (QueryTotalSupplyResponse) { + option (google.api.http).get = "/kava/savings/v1beta1/total_supply"; + } } // QueryParamsRequest defines the request type for querying x/savings @@ -50,3 +56,15 @@ message QueryDepositsResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } + +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +message QueryTotalSupplyRequest {} + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +message QueryTotalSupplyResponse { + // Height is the block height at which these totals apply + int64 height = 1; + // Result is a list of coins supplied to savings + repeated cosmos.base.v1beta1.Coin result = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} diff --git a/x/earn/client/cli/query.go b/x/earn/client/cli/query.go index 4eaebaac..129eb279 100644 --- a/x/earn/client/cli/query.go +++ b/x/earn/client/cli/query.go @@ -35,6 +35,7 @@ func GetQueryCmd() *cobra.Command { queryVaultsCmd(), queryVaultCmd(), queryDepositsCmd(), + queryTotalSupplyCmd(), } for _, cmd := range cmds { @@ -181,3 +182,27 @@ func queryDepositsCmd() *cobra.Command { return cmd } + +func queryTotalSupplyCmd() *cobra.Command { + return &cobra.Command{ + Use: "total-supply", + Short: "get total supply across all savings strategy vaults", + Long: "Get the sum of all denoms locking into vaults that allow the savings strategy.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.TotalSupply(context.Background(), &types.QueryTotalSupplyRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } +} diff --git a/x/earn/keeper/grpc_query.go b/x/earn/keeper/grpc_query.go index 0adec6bf..b3175c9b 100644 --- a/x/earn/keeper/grpc_query.go +++ b/x/earn/keeper/grpc_query.go @@ -156,7 +156,7 @@ func (s queryServer) Vault( } // Handle bkava separately to get total of **all** bkava vaults - if req.Denom == "bkava" { + if req.Denom == bkavaDenom { return s.getAggregateBkavaVault(sdkCtx, allowedVault) } @@ -198,7 +198,7 @@ func (s queryServer) getAggregateBkavaVault( var iterErr error s.keeper.IterateVaultRecords(ctx, func(record types.VaultRecord) (stop bool) { // Skip non bkava vaults - if !strings.HasPrefix(record.TotalShares.Denom, "bkava") { + if !strings.HasPrefix(record.TotalShares.Denom, bkavaPrefix) { return false } @@ -224,7 +224,7 @@ func (s queryServer) getAggregateBkavaVault( return &types.QueryVaultResponse{ Vault: types.VaultResponse{ - Denom: "bkava", + Denom: bkavaDenom, Strategies: allowedVault.Strategies, IsPrivateVault: allowedVault.IsPrivateVault, AllowedDepositors: addressSliceToStringSlice(allowedVault.AllowedDepositors), @@ -251,7 +251,7 @@ func (s queryServer) Deposits( sdkCtx := sdk.UnwrapSDKContext(ctx) // bkava aggregate total - if req.Denom == "bkava" { + if req.Denom == bkavaDenom { return s.getOneAccountBkavaVaultDeposit(sdkCtx, req) } @@ -264,6 +264,78 @@ func (s queryServer) Deposits( return s.getOneAccountAllDeposits(sdkCtx, req) } +// TotalSupply implements the gRPC service handler for querying x/earn total supply (TVL) +func (s queryServer) TotalSupply( + ctx context.Context, + req *types.QueryTotalSupplyRequest, +) (*types.QueryTotalSupplyResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + totalSupply := sdk.NewCoins() + liquidStakedDerivatives := sdk.NewCoins() + + // allowed vaults param contains info on allowed strategies, but bkava is aggregated + allowedVaults := s.keeper.GetAllowedVaults(sdkCtx) + allowedVaultByDenom := make(map[string]types.AllowedVault) + for _, av := range allowedVaults { + allowedVaultByDenom[av.Denom] = av + } + + var vaultRecordErr error + // iterate actual records to properly enumerate all denoms + s.keeper.IterateVaultRecords(sdkCtx, func(vault types.VaultRecord) (stop bool) { + isLiquidStakingDenom := false + // find allowed vault to get parameters. handle translating bkava denoms to allowed vault denom + allowedVaultDenom := vault.TotalShares.Denom + if strings.HasPrefix(vault.TotalShares.Denom, bkavaPrefix) { + isLiquidStakingDenom = true + allowedVaultDenom = bkavaDenom + } + allowedVault, found := allowedVaultByDenom[allowedVaultDenom] + if !found { + vaultRecordErr = fmt.Errorf("vault record not found for vault record denom %s", vault.TotalShares.Denom) + return true + } + + // only consider savings strategy vaults when determining supply + if !allowedVault.IsStrategyAllowed(types.STRATEGY_TYPE_SAVINGS) { + return false + } + + // vault has savings strategy! determine total value of vault and add to sum + vaultSupply, err := s.keeper.GetVaultTotalValue(sdkCtx, vault.TotalShares.Denom) + if err != nil { + vaultRecordErr = err + return true + } + + // liquid staked tokens must be converted to their underlying value + // aggregate them here and then we can convert to underlying values all at once at the end + if isLiquidStakingDenom { + liquidStakedDerivatives = liquidStakedDerivatives.Add(vaultSupply) + } else { + totalSupply = totalSupply.Add(vaultSupply) + } + return false + }) + + // determine underlying value of bkava denoms + if len(liquidStakedDerivatives) > 0 { + underlyingValue, err := s.keeper.liquidKeeper.GetStakedTokensForDerivatives( + sdkCtx, + liquidStakedDerivatives, + ) + if err != nil { + return nil, err + } + totalSupply = totalSupply.Add(sdk.NewCoin(bkavaDenom, underlyingValue.Amount)) + } + + return &types.QueryTotalSupplyResponse{ + Height: sdkCtx.BlockHeight(), + Result: totalSupply, + }, vaultRecordErr +} + // getOneAccountOneVaultDeposit returns deposits for a specific vault and a specific // account func (s queryServer) getOneAccountOneVaultDeposit( diff --git a/x/earn/keeper/grpc_query_test.go b/x/earn/keeper/grpc_query_test.go index f8e774e0..1de7b7be 100644 --- a/x/earn/keeper/grpc_query_test.go +++ b/x/earn/keeper/grpc_query_test.go @@ -689,6 +689,146 @@ func (suite *grpcQueryTestSuite) TestVault_bKava_Aggregate() { ) } +func (suite *grpcQueryTestSuite) TestTotalSupply() { + deposit := func(addr sdk.AccAddress, denom string, amount int64) { + err := suite.Keeper.Deposit( + suite.Ctx, + addr, + sdk.NewInt64Coin(denom, amount), + types.STRATEGY_TYPE_SAVINGS, + ) + suite.Require().NoError(err) + } + testCases := []struct { + name string + setup func() + expectedSupply sdk.Coins + }{ + { + name: "no vaults mean no supply", + setup: func() {}, + expectedSupply: nil, + }, + { + name: "no savings vaults mean no supply", + setup: func() { + suite.CreateVault("usdx", types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil) + suite.CreateVault("busd", types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil) + }, + expectedSupply: nil, + }, + { + name: "empty savings vaults mean no supply", + setup: func() { + suite.CreateVault("usdx", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil) + suite.CreateVault("busd", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil) + }, + expectedSupply: nil, + }, + { + name: "calculates supply of savings vaults", + setup: func() { + vault1Denom := "usdx" + vault2Denom := "busd" + suite.CreateVault(vault1Denom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil) + suite.CreateVault(vault2Denom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil) + + acc1 := suite.CreateAccount(sdk.NewCoins( + sdk.NewInt64Coin(vault1Denom, 1e6), + sdk.NewInt64Coin(vault2Denom, 1e6), + ), 0) + deposit(acc1.GetAddress(), vault1Denom, 1e5) + deposit(acc1.GetAddress(), vault2Denom, 1e5) + acc2 := suite.CreateAccount(sdk.NewCoins( + sdk.NewInt64Coin(vault1Denom, 1e6), + sdk.NewInt64Coin(vault2Denom, 1e6), + ), 0) + deposit(acc2.GetAddress(), vault1Denom, 2e5) + deposit(acc2.GetAddress(), vault2Denom, 2e5) + }, + expectedSupply: sdk.NewCoins( + sdk.NewInt64Coin("usdx", 3e5), + sdk.NewInt64Coin("busd", 3e5), + ), + }, + { + name: "calculates supply of savings vaults, even when private", + setup: func() { + vault1Denom := "ukava" + vault2Denom := "busd" + + acc1 := suite.CreateAccount(sdk.NewCoins( + sdk.NewInt64Coin(vault1Denom, 1e6), + sdk.NewInt64Coin(vault2Denom, 1e6), + ), 0) + acc2 := suite.CreateAccount(sdk.NewCoins( + sdk.NewInt64Coin(vault1Denom, 1e6), + sdk.NewInt64Coin(vault2Denom, 1e6), + ), 0) + + suite.CreateVault( + vault1Denom, + types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, + true, // private! + []sdk.AccAddress{acc1.GetAddress()}, // only acc1 can deposit. + ) + suite.CreateVault("busd", + types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, + false, + nil, + ) + + deposit(acc1.GetAddress(), vault1Denom, 1e5) + deposit(acc1.GetAddress(), vault2Denom, 1e5) + deposit(acc2.GetAddress(), vault2Denom, 2e5) + }, + expectedSupply: sdk.NewCoins( + sdk.NewInt64Coin("ukava", 1e5), + sdk.NewInt64Coin("busd", 3e5), + ), + }, + { + name: "aggregates supply of bkava vaults accounting for slashing", + setup: func() { + address1, derivatives1, _ := suite.createAccountWithDerivatives(testutil.TestBkavaDenoms[0], sdk.NewInt(1e9)) + address2, derivatives2, _ := suite.createAccountWithDerivatives(testutil.TestBkavaDenoms[1], sdk.NewInt(1e9)) + + // bond validators + staking.EndBlocker(suite.Ctx, suite.App.GetStakingKeeper()) + // slash val2 - its shares are now 80% as valuable! + err := suite.slashValidator(sdk.ValAddress(address2), sdk.MustNewDecFromStr("0.2")) + suite.Require().NoError(err) + + // create "bkava" vault. it holds all bkava denoms + suite.CreateVault("bkava", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, []sdk.AccAddress{}) + + // deposit bkava + deposit(address1, testutil.TestBkavaDenoms[0], derivatives1.Amount.Int64()) + deposit(address2, testutil.TestBkavaDenoms[1], derivatives2.Amount.Int64()) + }, + expectedSupply: sdk.NewCoins( + sdk.NewCoin( + "bkava", + sdk.NewIntFromUint64(1e9). // derivative 1 + Add(sdk.NewInt(1e9).MulRaw(80).QuoRaw(100))), // derivative 2: original value * 80% + ), + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + tc.setup() + res, err := suite.queryClient.TotalSupply( + sdk.WrapSDKContext(suite.Ctx), + &types.QueryTotalSupplyRequest{}, + ) + suite.Require().NoError(err) + suite.Require().Equal(tc.expectedSupply, res.Result) + }) + } +} + // createUnbondedValidator creates an unbonded validator with the given amount of self-delegation. func (suite *grpcQueryTestSuite) createUnbondedValidator(address sdk.ValAddress, selfDelegation sdk.Coin, minSelfDelegation sdk.Int) error { msg, err := stakingtypes.NewMsgCreateValidator( diff --git a/x/earn/testutil/suite.go b/x/earn/testutil/suite.go index 59191ddf..8e7f0970 100644 --- a/x/earn/testutil/suite.go +++ b/x/earn/testutil/suite.go @@ -155,6 +155,8 @@ func (suite *Suite) SetupTest() { savingstypes.NewParams( []string{ "ukava", + "busd", + "usdx", TestBkavaDenoms[0], TestBkavaDenoms[1], TestBkavaDenoms[2], diff --git a/x/earn/types/query.pb.go b/x/earn/types/query.pb.go index 26ccc6e7..78a4c5d1 100644 --- a/x/earn/types/query.pb.go +++ b/x/earn/types/query.pb.go @@ -448,6 +448,84 @@ func (m *DepositResponse) XXX_DiscardUnknown() { var xxx_messageInfo_DepositResponse proto.InternalMessageInfo +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +type QueryTotalSupplyRequest struct { +} + +func (m *QueryTotalSupplyRequest) Reset() { *m = QueryTotalSupplyRequest{} } +func (m *QueryTotalSupplyRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyRequest) ProtoMessage() {} +func (*QueryTotalSupplyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_63f8dee2f3192a6b, []int{10} +} +func (m *QueryTotalSupplyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyRequest.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 *QueryTotalSupplyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyRequest.Merge(m, src) +} +func (m *QueryTotalSupplyRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyRequest proto.InternalMessageInfo + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +type QueryTotalSupplyResponse struct { + // Height is the block height at which these totals apply + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + // Result is a list of coins supplied to earn + Result github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=result,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"result"` +} + +func (m *QueryTotalSupplyResponse) Reset() { *m = QueryTotalSupplyResponse{} } +func (m *QueryTotalSupplyResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyResponse) ProtoMessage() {} +func (*QueryTotalSupplyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_63f8dee2f3192a6b, []int{11} +} +func (m *QueryTotalSupplyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyResponse.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 *QueryTotalSupplyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyResponse.Merge(m, src) +} +func (m *QueryTotalSupplyResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "kava.earn.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "kava.earn.v1beta1.QueryParamsResponse") @@ -459,68 +537,75 @@ func init() { proto.RegisterType((*QueryDepositsRequest)(nil), "kava.earn.v1beta1.QueryDepositsRequest") proto.RegisterType((*QueryDepositsResponse)(nil), "kava.earn.v1beta1.QueryDepositsResponse") proto.RegisterType((*DepositResponse)(nil), "kava.earn.v1beta1.DepositResponse") + proto.RegisterType((*QueryTotalSupplyRequest)(nil), "kava.earn.v1beta1.QueryTotalSupplyRequest") + proto.RegisterType((*QueryTotalSupplyResponse)(nil), "kava.earn.v1beta1.QueryTotalSupplyResponse") } func init() { proto.RegisterFile("kava/earn/v1beta1/query.proto", fileDescriptor_63f8dee2f3192a6b) } var fileDescriptor_63f8dee2f3192a6b = []byte{ - // 883 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4b, 0x6f, 0xeb, 0x44, - 0x14, 0x8e, 0xf3, 0x52, 0x3b, 0xe1, 0x5e, 0xc8, 0x34, 0xa0, 0x24, 0x97, 0x3a, 0xa9, 0x2f, 0xb7, - 0xd7, 0x45, 0x8a, 0x4d, 0x53, 0x09, 0x36, 0x15, 0x12, 0xa1, 0xa2, 0x2a, 0x0b, 0x54, 0x9c, 0xd2, - 0x05, 0x12, 0xb2, 0x26, 0xcd, 0xc8, 0xb5, 0x92, 0x78, 0x52, 0xcf, 0x24, 0x50, 0x10, 0x42, 0xaa, - 0xc4, 0x1e, 0x89, 0xff, 0xc0, 0xa2, 0xeb, 0xfe, 0x88, 0x2e, 0xab, 0xb2, 0x41, 0x2c, 0x5a, 0xda, - 0xb2, 0x66, 0xcd, 0x12, 0xcd, 0xc3, 0x79, 0xa7, 0xa9, 0x58, 0x25, 0x73, 0x1e, 0xdf, 0xf7, 0x9d, - 0x99, 0x73, 0x8e, 0xc1, 0x6a, 0x0b, 0xf5, 0x91, 0x8d, 0x51, 0x18, 0xd8, 0xfd, 0xcd, 0x06, 0x66, - 0x68, 0xd3, 0x3e, 0xe9, 0xe1, 0xf0, 0xd4, 0xea, 0x86, 0x84, 0x11, 0x98, 0xe5, 0x6e, 0x8b, 0xbb, - 0x2d, 0xe5, 0x2e, 0x16, 0x8e, 0x08, 0xed, 0x10, 0xea, 0x8a, 0x00, 0x5b, 0x1e, 0x64, 0x74, 0xf1, - 0x7d, 0x79, 0xb2, 0x1b, 0x88, 0x62, 0x09, 0x33, 0x00, 0xed, 0x22, 0xcf, 0x0f, 0x10, 0xf3, 0x49, - 0xa0, 0x62, 0xf5, 0xd1, 0xd8, 0x28, 0xea, 0x88, 0xf8, 0x91, 0x3f, 0xe7, 0x11, 0x8f, 0x48, 0x0e, - 0xfe, 0x4f, 0x59, 0xdf, 0xf5, 0x08, 0xf1, 0xda, 0xd8, 0x46, 0x5d, 0xdf, 0x46, 0x41, 0x40, 0x98, - 0x80, 0x8c, 0xf8, 0xf5, 0xe9, 0x62, 0xba, 0x28, 0x44, 0x9d, 0xc8, 0x5f, 0x9e, 0xf6, 0x53, 0x16, - 0x22, 0x86, 0x3d, 0x55, 0x6f, 0x71, 0xc6, 0x75, 0xf4, 0x51, 0xaf, 0xcd, 0xa4, 0xdb, 0xc8, 0x01, - 0xf8, 0x25, 0x2f, 0x6b, 0x5f, 0xa0, 0x3a, 0xf8, 0xa4, 0x87, 0x29, 0x33, 0xbe, 0x00, 0x2b, 0x63, - 0x56, 0xda, 0x25, 0x01, 0xc5, 0xf0, 0x23, 0x90, 0x96, 0xec, 0x79, 0xad, 0xac, 0x99, 0x99, 0x6a, - 0xc1, 0x9a, 0xba, 0x4c, 0x4b, 0xa6, 0xd4, 0x92, 0x97, 0x37, 0xa5, 0x98, 0xa3, 0xc2, 0x07, 0x2c, - 0x87, 0x9c, 0x79, 0xc0, 0xf2, 0x95, 0x62, 0x89, 0xac, 0x8a, 0xe5, 0x63, 0x90, 0x16, 0x0a, 0x39, - 0x4b, 0xc2, 0xcc, 0x54, 0xcb, 0x33, 0x58, 0x44, 0x4a, 0x94, 0x11, 0x91, 0xc9, 0x2c, 0x63, 0x03, - 0x64, 0x87, 0xb0, 0x8a, 0x0b, 0xe6, 0x40, 0xaa, 0x89, 0x03, 0xd2, 0x11, 0xca, 0x97, 0x1d, 0x79, - 0x30, 0x9c, 0x51, 0x5d, 0x03, 0x01, 0xdb, 0x20, 0x25, 0xa0, 0x54, 0x95, 0x4f, 0xe5, 0x97, 0x49, - 0xc6, 0x3f, 0x71, 0xf0, 0x6c, 0x1c, 0x6f, 0x26, 0x37, 0x74, 0x00, 0x50, 0x4f, 0xe5, 0x63, 0x9a, - 0x8f, 0x97, 0x13, 0xe6, 0xf3, 0x6a, 0x69, 0x06, 0x55, 0x5d, 0xbd, 0xe7, 0xc1, 0x69, 0x17, 0xd7, - 0xb2, 0xe7, 0xb7, 0xa5, 0x67, 0xa3, 0x16, 0xea, 0x8c, 0xa0, 0x40, 0x13, 0xbc, 0xe5, 0xf3, 0x3e, - 0xf6, 0xfb, 0x88, 0x61, 0x57, 0x16, 0x91, 0x28, 0x6b, 0xe6, 0x92, 0xf3, 0xdc, 0xa7, 0xfb, 0xd2, - 0x2c, 0xb4, 0xc1, 0x5d, 0x00, 0x51, 0xbb, 0x4d, 0xbe, 0xc5, 0x4d, 0xb7, 0x89, 0xbb, 0x84, 0xfa, - 0x8c, 0x84, 0x34, 0x9f, 0x2c, 0x27, 0xcc, 0xe5, 0x5a, 0xfe, 0xfa, 0xa2, 0x92, 0x53, 0x63, 0xf0, - 0x49, 0xb3, 0x19, 0x62, 0x4a, 0xeb, 0x2c, 0xf4, 0x03, 0xcf, 0xc9, 0xaa, 0x9c, 0x9d, 0x41, 0x0a, - 0x5c, 0x03, 0x6f, 0x30, 0xc2, 0x50, 0xdb, 0xa5, 0xc7, 0x28, 0xc4, 0x34, 0x9f, 0x12, 0x35, 0x66, - 0x84, 0xad, 0x2e, 0x4c, 0xf0, 0x1b, 0x20, 0x8f, 0x6e, 0x1f, 0xb5, 0x7b, 0x38, 0x9f, 0xe6, 0x11, - 0xb5, 0x6d, 0x7e, 0x67, 0x7f, 0xde, 0x94, 0xd6, 0x3d, 0x9f, 0x1d, 0xf7, 0x1a, 0xd6, 0x11, 0xe9, - 0xa8, 0xd1, 0x53, 0x3f, 0x15, 0xda, 0x6c, 0xd9, 0x8c, 0x97, 0x68, 0xed, 0x05, 0xec, 0xfa, 0xa2, - 0x02, 0x94, 0xa4, 0xbd, 0x80, 0x39, 0x40, 0x00, 0x1e, 0x72, 0x3c, 0xe3, 0x4e, 0x03, 0x39, 0xf1, - 0x8a, 0x4a, 0x55, 0xd4, 0x5f, 0xf0, 0x43, 0xb0, 0x3c, 0xa8, 0x4d, 0xde, 0xfd, 0x23, 0xa5, 0x0d, - 0x43, 0x87, 0xef, 0x15, 0x1f, 0x7d, 0xaf, 0x2d, 0xf0, 0x8e, 0xd0, 0xef, 0xfa, 0x81, 0x4b, 0x19, - 0x6a, 0xe1, 0xa6, 0xcb, 0x48, 0x0b, 0x07, 0x54, 0xdd, 0xf0, 0x8a, 0xf0, 0xee, 0x05, 0x75, 0xe1, - 0x3b, 0x10, 0x2e, 0xf8, 0x19, 0x00, 0xc3, 0x3d, 0x91, 0x4f, 0x8a, 0x7e, 0x5a, 0xb7, 0x94, 0x00, - 0xbe, 0x28, 0x2c, 0xb9, 0x9b, 0x86, 0xd3, 0xe3, 0x61, 0x25, 0xdf, 0x19, 0xc9, 0x34, 0x7e, 0xd3, - 0xc0, 0xdb, 0x13, 0x35, 0xaa, 0xe6, 0xda, 0x01, 0x4b, 0x4a, 0x79, 0x34, 0x2f, 0xc6, 0x8c, 0x26, - 0x52, 0x69, 0x13, 0x1d, 0x3b, 0xc8, 0x84, 0xbb, 0x63, 0x3a, 0xe3, 0x42, 0xe7, 0xeb, 0x85, 0x3a, - 0x25, 0xd8, 0x98, 0xd0, 0x7f, 0x35, 0xf0, 0xe6, 0x04, 0xd9, 0xff, 0x7e, 0x87, 0xcf, 0x41, 0x5a, - 0x35, 0x55, 0x5c, 0x14, 0xb6, 0x3a, 0x6f, 0x10, 0x45, 0x9f, 0xd5, 0x56, 0x78, 0x4d, 0xe7, 0xb7, - 0xa5, 0xcc, 0xd0, 0x46, 0x1d, 0x85, 0x00, 0x11, 0x9f, 0x69, 0xde, 0x7d, 0x09, 0x01, 0x55, 0x18, - 0xab, 0x2d, 0x02, 0xfb, 0x94, 0xf8, 0x41, 0xed, 0x03, 0x05, 0x63, 0x3e, 0xa1, 0x31, 0x79, 0x02, - 0x75, 0x24, 0x72, 0xf5, 0xe7, 0x24, 0x48, 0x89, 0x37, 0x82, 0xdf, 0x83, 0xb4, 0x5c, 0x83, 0xf0, - 0xd5, 0x0c, 0xc9, 0xd3, 0xfb, 0xb6, 0xb8, 0xbe, 0x28, 0x4c, 0xde, 0xa4, 0xb1, 0x76, 0xf6, 0xfb, - 0xdf, 0xbf, 0xc6, 0x5f, 0xc0, 0x82, 0x3d, 0xef, 0xbb, 0xc0, 0xb9, 0xe5, 0x3e, 0x9d, 0xcf, 0x3d, - 0xb6, 0x85, 0xe7, 0x73, 0x8f, 0xaf, 0xe5, 0x47, 0xb9, 0xe5, 0xe6, 0x85, 0x3f, 0x81, 0x94, 0xdc, - 0x2e, 0xef, 0x3d, 0x8a, 0x19, 0x31, 0xbf, 0x5a, 0x10, 0xa5, 0x88, 0x37, 0x04, 0xf1, 0x4b, 0xb8, - 0x36, 0x97, 0xd8, 0xfe, 0x41, 0x8c, 0xe8, 0x8f, 0xf0, 0x4c, 0x03, 0x4b, 0xd1, 0x84, 0xc0, 0xd7, - 0xf3, 0xe0, 0x27, 0xf6, 0x44, 0xd1, 0x5c, 0x1c, 0xa8, 0xa4, 0xbc, 0x14, 0x52, 0x56, 0xe1, 0x8b, - 0x19, 0x52, 0xa2, 0x59, 0xaa, 0xed, 0x5c, 0xde, 0xe9, 0xb1, 0xcb, 0x7b, 0x5d, 0xbb, 0xba, 0xd7, - 0xb5, 0xbf, 0xee, 0x75, 0xed, 0x97, 0x07, 0x3d, 0x76, 0xf5, 0xa0, 0xc7, 0xfe, 0x78, 0xd0, 0x63, - 0x5f, 0x8f, 0xee, 0x3b, 0x0e, 0x52, 0x69, 0xa3, 0x06, 0x95, 0x70, 0xdf, 0x49, 0x40, 0xd1, 0x5a, - 0x8d, 0xb4, 0xf8, 0x3e, 0x6f, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0xea, 0x07, 0xa4, 0x14, 0xcf, - 0x08, 0x00, 0x00, + // 969 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0xda, 0xb1, 0x95, 0x3c, 0xd3, 0x42, 0x26, 0xa6, 0xd8, 0x2e, 0x59, 0x3b, 0x5b, 0x9a, + 0xb8, 0x45, 0xd9, 0xa5, 0xa9, 0x04, 0x97, 0x0a, 0x09, 0x13, 0x51, 0x85, 0x03, 0x2a, 0x9b, 0xd0, + 0x03, 0x12, 0xb2, 0xc6, 0xf1, 0x68, 0xb3, 0x8a, 0xb3, 0xb3, 0xdd, 0x19, 0x1b, 0x02, 0x42, 0x48, + 0xfd, 0x02, 0x20, 0x71, 0xe8, 0x37, 0xe0, 0xd0, 0x73, 0x3f, 0x44, 0x8e, 0x55, 0xb9, 0x20, 0x0e, + 0x2d, 0x49, 0x38, 0x73, 0xe6, 0x88, 0x66, 0xe6, 0xad, 0xff, 0xc4, 0x76, 0x12, 0xa1, 0x9e, 0x92, + 0x9d, 0xf7, 0xde, 0xef, 0xf7, 0x7b, 0x33, 0xef, 0x8f, 0x61, 0x79, 0x9f, 0xf6, 0xa9, 0xc7, 0x68, + 0x12, 0x79, 0xfd, 0x3b, 0x6d, 0x26, 0xe9, 0x1d, 0xef, 0x51, 0x8f, 0x25, 0x87, 0x6e, 0x9c, 0x70, + 0xc9, 0xc9, 0xa2, 0x32, 0xbb, 0xca, 0xec, 0xa2, 0xb9, 0x5a, 0xd9, 0xe5, 0xe2, 0x80, 0x8b, 0x96, + 0x76, 0xf0, 0xcc, 0x87, 0xf1, 0xae, 0xde, 0x36, 0x5f, 0x5e, 0x9b, 0x0a, 0x66, 0x60, 0x06, 0xa0, + 0x31, 0x0d, 0xc2, 0x88, 0xca, 0x90, 0x47, 0xe8, 0x6b, 0x8f, 0xfa, 0xa6, 0x5e, 0xbb, 0x3c, 0x4c, + 0xed, 0xa5, 0x80, 0x07, 0xdc, 0x70, 0xa8, 0xff, 0xf0, 0xf4, 0xdd, 0x80, 0xf3, 0xa0, 0xcb, 0x3c, + 0x1a, 0x87, 0x1e, 0x8d, 0x22, 0x2e, 0x35, 0x64, 0xca, 0x6f, 0x4f, 0x26, 0x13, 0xd3, 0x84, 0x1e, + 0xa4, 0xf6, 0xfa, 0xa4, 0x5d, 0xc8, 0x84, 0x4a, 0x16, 0x60, 0xbe, 0xd5, 0x29, 0xd7, 0xd1, 0xa7, + 0xbd, 0xae, 0x34, 0x66, 0xa7, 0x04, 0xe4, 0x4b, 0x95, 0xd6, 0x03, 0x8d, 0xea, 0xb3, 0x47, 0x3d, + 0x26, 0xa4, 0xf3, 0x05, 0x2c, 0x8d, 0x9d, 0x8a, 0x98, 0x47, 0x82, 0x91, 0x8f, 0xa0, 0x60, 0xd8, + 0xcb, 0x56, 0xdd, 0x6a, 0x14, 0x37, 0x2a, 0xee, 0xc4, 0x65, 0xba, 0x26, 0xa4, 0x39, 0x77, 0xf4, + 0xb2, 0x96, 0xf1, 0xd1, 0x7d, 0xc0, 0xf2, 0x50, 0x31, 0x0f, 0x58, 0xbe, 0x42, 0x96, 0xf4, 0x14, + 0x59, 0x3e, 0x86, 0x82, 0x56, 0xa8, 0x58, 0x72, 0x8d, 0xe2, 0x46, 0x7d, 0x0a, 0x8b, 0x0e, 0x49, + 0x23, 0x52, 0x32, 0x13, 0xe5, 0xdc, 0x82, 0xc5, 0x21, 0x2c, 0x72, 0x91, 0x12, 0xe4, 0x3b, 0x2c, + 0xe2, 0x07, 0x5a, 0xf9, 0x82, 0x6f, 0x3e, 0x1c, 0x7f, 0x54, 0xd7, 0x40, 0xc0, 0x3d, 0xc8, 0x6b, + 0x28, 0xcc, 0xf2, 0xb2, 0xfc, 0x26, 0xc8, 0xf9, 0x27, 0x0b, 0x57, 0xc6, 0xf1, 0xa6, 0x72, 0x13, + 0x1f, 0x00, 0x9f, 0x2a, 0x64, 0xa2, 0x9c, 0xad, 0xe7, 0x1a, 0x57, 0x37, 0x6a, 0x53, 0xa8, 0xb6, + 0xf1, 0x3d, 0x77, 0x0e, 0x63, 0xd6, 0x5c, 0x7c, 0xfa, 0xaa, 0x76, 0x65, 0xf4, 0x44, 0xf8, 0x23, + 0x28, 0xa4, 0x01, 0x6f, 0x85, 0xaa, 0x8e, 0xc3, 0x3e, 0x95, 0xac, 0x65, 0x92, 0xc8, 0xd5, 0xad, + 0xc6, 0xbc, 0x7f, 0x35, 0x14, 0x0f, 0xcc, 0xb1, 0xd6, 0x46, 0xee, 0x03, 0xa1, 0xdd, 0x2e, 0xff, + 0x96, 0x75, 0x5a, 0x1d, 0x16, 0x73, 0x11, 0x4a, 0x9e, 0x88, 0xf2, 0x5c, 0x3d, 0xd7, 0x58, 0x68, + 0x96, 0x5f, 0x3c, 0x5b, 0x2f, 0x61, 0x1b, 0x7c, 0xd2, 0xe9, 0x24, 0x4c, 0x88, 0x6d, 0x99, 0x84, + 0x51, 0xe0, 0x2f, 0x62, 0xcc, 0xe6, 0x20, 0x84, 0xac, 0xc0, 0x1b, 0x92, 0x4b, 0xda, 0x6d, 0x89, + 0x3d, 0x9a, 0x30, 0x51, 0xce, 0xeb, 0x1c, 0x8b, 0xfa, 0x6c, 0x5b, 0x1f, 0x91, 0x6f, 0xc0, 0x7c, + 0xb6, 0xfa, 0xb4, 0xdb, 0x63, 0xe5, 0x82, 0xf2, 0x68, 0xde, 0x53, 0x77, 0xf6, 0xe7, 0xcb, 0xda, + 0x6a, 0x10, 0xca, 0xbd, 0x5e, 0xdb, 0xdd, 0xe5, 0x07, 0xd8, 0x7a, 0xf8, 0x67, 0x5d, 0x74, 0xf6, + 0x3d, 0xa9, 0x52, 0x74, 0xb7, 0x22, 0xf9, 0xe2, 0xd9, 0x3a, 0xa0, 0xa4, 0xad, 0x48, 0xfa, 0xa0, + 0x01, 0x1f, 0x2a, 0x3c, 0xe7, 0xd8, 0x82, 0x92, 0x7e, 0x45, 0x54, 0x95, 0xd6, 0x17, 0xf9, 0x10, + 0x16, 0x06, 0xb9, 0x99, 0xbb, 0x3f, 0x27, 0xb5, 0xa1, 0xeb, 0xf0, 0xbd, 0xb2, 0xa3, 0xef, 0x75, + 0x17, 0xae, 0x69, 0xfd, 0xad, 0x30, 0x6a, 0x09, 0x49, 0xf7, 0x59, 0xa7, 0x25, 0xf9, 0x3e, 0x8b, + 0x04, 0xde, 0xf0, 0x92, 0xb6, 0x6e, 0x45, 0xdb, 0xda, 0xb6, 0xa3, 0x4d, 0xe4, 0x33, 0x80, 0xe1, + 0x9c, 0x28, 0xcf, 0xe9, 0x7a, 0x5a, 0x75, 0x51, 0x80, 0x1a, 0x14, 0xae, 0x99, 0x4d, 0xc3, 0xee, + 0x09, 0x18, 0xca, 0xf7, 0x47, 0x22, 0x9d, 0xdf, 0x2c, 0x78, 0xfb, 0x4c, 0x8e, 0x58, 0x5c, 0x9b, + 0x30, 0x8f, 0xca, 0xd3, 0x7e, 0x71, 0xa6, 0x14, 0x11, 0x86, 0x9d, 0xa9, 0xd8, 0x41, 0x24, 0xb9, + 0x3f, 0xa6, 0x33, 0xab, 0x75, 0xae, 0x5d, 0xa8, 0xd3, 0x80, 0x8d, 0x09, 0xfd, 0xd7, 0x82, 0x37, + 0xcf, 0x90, 0xfd, 0xef, 0x77, 0xf8, 0x1c, 0x0a, 0x58, 0x54, 0x59, 0x9d, 0xd8, 0xf2, 0xac, 0x46, + 0xd4, 0x75, 0xd6, 0x5c, 0x52, 0x39, 0x3d, 0x7d, 0x55, 0x2b, 0x0e, 0xcf, 0x84, 0x8f, 0x08, 0x84, + 0xaa, 0x9e, 0x56, 0xd5, 0x97, 0xd3, 0x50, 0x95, 0xb1, 0xdc, 0x52, 0xb0, 0x4f, 0x79, 0x18, 0x35, + 0x3f, 0x40, 0x98, 0xc6, 0x25, 0x0a, 0x53, 0x05, 0x08, 0xdf, 0x20, 0x3b, 0x15, 0x78, 0x47, 0x3f, + 0xd1, 0x8e, 0x2e, 0xfd, 0x5e, 0x1c, 0x77, 0x0f, 0xd3, 0x49, 0xf7, 0xc4, 0x82, 0xf2, 0xa4, 0x0d, + 0xaf, 0xe7, 0x1a, 0x14, 0xf6, 0x58, 0x18, 0xec, 0x99, 0x79, 0x93, 0xf3, 0xf1, 0x8b, 0xec, 0x42, + 0x21, 0x61, 0x42, 0xb5, 0x70, 0xf6, 0xf5, 0x6b, 0x46, 0xe8, 0x8d, 0x27, 0x79, 0xc8, 0x6b, 0x65, + 0xe4, 0x7b, 0x28, 0x98, 0xd9, 0x4d, 0x6e, 0x4e, 0xb9, 0xe7, 0xc9, 0x25, 0x51, 0x5d, 0xbd, 0xc8, + 0xcd, 0xe4, 0xe7, 0xac, 0x3c, 0xfe, 0xfd, 0xef, 0x5f, 0xb3, 0xd7, 0x49, 0xc5, 0x9b, 0xb5, 0xcc, + 0x14, 0xb7, 0x59, 0x02, 0xb3, 0xb9, 0xc7, 0x56, 0xc7, 0x6c, 0xee, 0xf1, 0x5d, 0x72, 0x2e, 0xb7, + 0x59, 0x17, 0xe4, 0x27, 0xc8, 0x9b, 0x91, 0xf8, 0xde, 0xb9, 0x98, 0x29, 0xf3, 0xcd, 0x0b, 0xbc, + 0x90, 0xf8, 0x96, 0x26, 0xbe, 0x41, 0x56, 0x66, 0x12, 0x7b, 0x3f, 0xe8, 0xb9, 0xf2, 0x23, 0x79, + 0x6c, 0xc1, 0x7c, 0xda, 0xd6, 0x64, 0x6d, 0x16, 0xfc, 0x99, 0xe1, 0x56, 0x6d, 0x5c, 0xec, 0x88, + 0x52, 0x6e, 0x68, 0x29, 0xcb, 0xe4, 0xfa, 0x14, 0x29, 0x83, 0x01, 0xf0, 0xb3, 0x05, 0xc5, 0x91, + 0xe2, 0x24, 0xb7, 0x67, 0xc1, 0x4f, 0x56, 0x77, 0xf5, 0xfd, 0x4b, 0xf9, 0xa2, 0x9a, 0x35, 0xad, + 0x66, 0x85, 0xd4, 0xa6, 0xa8, 0xc1, 0x45, 0xa2, 0x03, 0x9a, 0x9b, 0x47, 0xc7, 0x76, 0xe6, 0xe8, + 0xc4, 0xb6, 0x9e, 0x9f, 0xd8, 0xd6, 0x5f, 0x27, 0xb6, 0xf5, 0xcb, 0xa9, 0x9d, 0x79, 0x7e, 0x6a, + 0x67, 0xfe, 0x38, 0xb5, 0x33, 0x5f, 0x8f, 0xae, 0x0d, 0x05, 0xb4, 0xde, 0xa5, 0x6d, 0x61, 0x20, + 0xbf, 0x33, 0xa0, 0xba, 0xda, 0xdb, 0x05, 0xfd, 0x33, 0xe7, 0xee, 0x7f, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x8a, 0x93, 0xec, 0x8f, 0x16, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -543,6 +628,8 @@ type QueryClient interface { Vault(ctx context.Context, in *QueryVaultRequest, opts ...grpc.CallOption) (*QueryVaultResponse, error) // Deposits queries deposit details based on depositor address and vault Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the earn module. + TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) } type queryClient struct { @@ -589,6 +676,15 @@ func (c *queryClient) Deposits(ctx context.Context, in *QueryDepositsRequest, op return out, nil } +func (c *queryClient) TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) { + out := new(QueryTotalSupplyResponse) + err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Query/TotalSupply", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params queries all parameters of the earn module. @@ -599,6 +695,8 @@ type QueryServer interface { Vault(context.Context, *QueryVaultRequest) (*QueryVaultResponse, error) // Deposits queries deposit details based on depositor address and vault Deposits(context.Context, *QueryDepositsRequest) (*QueryDepositsResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the earn module. + TotalSupply(context.Context, *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -617,6 +715,9 @@ func (*UnimplementedQueryServer) Vault(ctx context.Context, req *QueryVaultReque func (*UnimplementedQueryServer) Deposits(ctx context.Context, req *QueryDepositsRequest) (*QueryDepositsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Deposits not implemented") } +func (*UnimplementedQueryServer) TotalSupply(ctx context.Context, req *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalSupply not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -694,6 +795,24 @@ func _Query_Deposits_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Query_TotalSupply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalSupplyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalSupply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.earn.v1beta1.Query/TotalSupply", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalSupply(ctx, req.(*QueryTotalSupplyRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "kava.earn.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -714,6 +833,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Deposits", Handler: _Query_Deposits_Handler, }, + { + MethodName: "TotalSupply", + Handler: _Query_TotalSupply_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kava/earn/v1beta1/query.proto", @@ -1148,6 +1271,71 @@ func (m *DepositResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryTotalSupplyRequest) 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 *QueryTotalSupplyRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryTotalSupplyResponse) 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 *QueryTotalSupplyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Result) > 0 { + for iNdEx := len(m.Result) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Result[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Height != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1330,6 +1518,33 @@ func (m *DepositResponse) Size() (n int) { return n } +func (m *QueryTotalSupplyRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryTotalSupplyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovQuery(uint64(m.Height)) + } + if len(m.Result) > 0 { + for _, e := range m.Result { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2477,6 +2692,159 @@ func (m *DepositResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryTotalSupplyRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalSupplyResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Result = append(m.Result, types.Coin{}) + if err := m.Result[len(m.Result)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/earn/types/query.pb.gw.go b/x/earn/types/query.pb.gw.go index 141f5cdc..1bc6f2ed 100644 --- a/x/earn/types/query.pb.gw.go +++ b/x/earn/types/query.pb.gw.go @@ -159,6 +159,24 @@ func local_request_Query_Deposits_0(ctx context.Context, marshaler runtime.Marsh } +func request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := client.TotalSupply(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := server.TotalSupply(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. @@ -257,6 +275,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -378,6 +419,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -389,6 +450,8 @@ var ( pattern_Query_Vault_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"kava", "earn", "v1beta1", "vaults", "denom"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "deposits"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TotalSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "total_supply"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -399,4 +462,6 @@ var ( forward_Query_Vault_0 = runtime.ForwardResponseMessage forward_Query_Deposits_0 = runtime.ForwardResponseMessage + + forward_Query_TotalSupply_0 = runtime.ForwardResponseMessage ) diff --git a/x/liquid/keeper/grpc_query.go b/x/liquid/keeper/grpc_query.go index cced576d..d43ec45b 100644 --- a/x/liquid/keeper/grpc_query.go +++ b/x/liquid/keeper/grpc_query.go @@ -50,6 +50,23 @@ func (s queryServer) DelegatedBalance( return &res, nil } +func (s queryServer) TotalSupply( + goCtx context.Context, + req *types.QueryTotalSupplyRequest, +) (*types.QueryTotalSupplyResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + totalValue, err := s.keeper.GetTotalDerivativeValue(ctx) + if err != nil { + return nil, err + } + + return &types.QueryTotalSupplyResponse{ + Height: ctx.BlockHeight(), + Result: []sdk.Coin{totalValue}, + }, nil +} + func (s queryServer) getDelegatedBalance(ctx sdk.Context, delegator sdk.AccAddress) sdk.Int { balance := sdk.ZeroDec() diff --git a/x/liquid/keeper/grpc_query_test.go b/x/liquid/keeper/grpc_query_test.go index 8f00939c..01aab368 100644 --- a/x/liquid/keeper/grpc_query_test.go +++ b/x/liquid/keeper/grpc_query_test.go @@ -166,3 +166,126 @@ func (suite *grpcQueryTestSuite) TestQueryDelegatedBalance() { }) } } + +func (suite *grpcQueryTestSuite) TestQueryTotalSupply() { + testCases := []struct { + name string + setup func() + expectedTotal sdk.Int + expectedErr error + }{ + { + name: "no liquid kava means no tvl", + setup: func() {}, + expectedTotal: sdk.ZeroInt(), + expectedErr: nil, + }, + { + name: "returns TVL from one bkava denom", + setup: func() { + initBalance := suite.NewBondCoin(i(1e9)) + valAcc := suite.CreateAccount(sdk.NewCoins(initBalance), 0) + delAcc := suite.CreateAccount(sdk.NewCoins(initBalance), 1) + + suite.CreateNewUnbondedValidator(valAcc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(valAcc.GetAddress().Bytes(), delAcc.GetAddress(), initBalance.Amount) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) // bond the validator + + _, err := suite.Keeper.MintDerivative( + suite.Ctx, + delAcc.GetAddress(), + valAcc.GetAddress().Bytes(), + initBalance, + ) + suite.Require().NoError(err) + }, + expectedTotal: i(1e9), + expectedErr: nil, + }, + { + name: "returns TVL from multiple bkava denoms", + setup: func() { + initBalance := suite.NewBondCoin(i(1e9)) + val1Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 0) + val2Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 1) + delAcc := suite.CreateAccount(sdk.NewCoins(initBalance.Add(initBalance)), 2) + + suite.CreateNewUnbondedValidator(val1Acc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(val1Acc.GetAddress().Bytes(), delAcc.GetAddress(), initBalance.Amount) + suite.CreateNewUnbondedValidator(val2Acc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(val2Acc.GetAddress().Bytes(), delAcc.GetAddress(), initBalance.Amount) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) // bond the validator + + _, err := suite.Keeper.MintDerivative(suite.Ctx, delAcc.GetAddress(), val1Acc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + _, err = suite.Keeper.MintDerivative(suite.Ctx, delAcc.GetAddress(), val2Acc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + }, + expectedTotal: i(2e9), + expectedErr: nil, + }, + { + name: "returns TVL from multiple delegators", + setup: func() { + initBalance := suite.NewBondCoin(i(1e9)) + valAcc := suite.CreateAccount(sdk.NewCoins(initBalance), 0) + del1Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 1) + del2Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 2) + + suite.CreateNewUnbondedValidator(valAcc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(valAcc.GetAddress().Bytes(), del1Acc.GetAddress(), initBalance.Amount) + suite.CreateDelegation(valAcc.GetAddress().Bytes(), del2Acc.GetAddress(), initBalance.Amount) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) // bond the validator + + _, err := suite.Keeper.MintDerivative(suite.Ctx, del1Acc.GetAddress(), valAcc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + _, err = suite.Keeper.MintDerivative(suite.Ctx, del2Acc.GetAddress(), valAcc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + }, + expectedTotal: i(2e9), + expectedErr: nil, + }, + { + name: "handles calculating tvl after slashing", + setup: func() { + initBalance := suite.NewBondCoin(i(1e9)) + val1Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 0) + val2Acc := suite.CreateAccount(sdk.NewCoins(initBalance), 1) + delAcc := suite.CreateAccount(sdk.NewCoins(initBalance.Add(initBalance)), 2) + + suite.CreateNewUnbondedValidator(val1Acc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(val1Acc.GetAddress().Bytes(), delAcc.GetAddress(), initBalance.Amount) + suite.CreateNewUnbondedValidator(val2Acc.GetAddress().Bytes(), initBalance.Amount) + suite.CreateDelegation(val2Acc.GetAddress().Bytes(), delAcc.GetAddress(), initBalance.Amount) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) // bond the validator + + _, err := suite.Keeper.MintDerivative(suite.Ctx, delAcc.GetAddress(), val1Acc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + _, err = suite.Keeper.MintDerivative(suite.Ctx, delAcc.GetAddress(), val2Acc.GetAddress().Bytes(), initBalance) + suite.Require().NoError(err) + + suite.SlashValidator(val2Acc.GetAddress().Bytes(), d("0.1")) + }, + // delegation + (delegation * 90%) + expectedTotal: i(1e9).Add(i(1e9).MulRaw(90).QuoRaw(100)), + expectedErr: nil, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + tc.setup() + + res, err := suite.queryClient.TotalSupply( + context.Background(), + &types.QueryTotalSupplyRequest{}, + ) + + suite.ErrorIs(err, tc.expectedErr) + if err == nil { + suite.Equal(tc.expectedTotal, res.Result[0].Amount) + } + }) + } +} diff --git a/x/liquid/types/query.pb.go b/x/liquid/types/query.pb.go index 9b0561c5..c35ccf61 100644 --- a/x/liquid/types/query.pb.go +++ b/x/liquid/types/query.pb.go @@ -7,6 +7,7 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" @@ -111,40 +112,127 @@ func (m *QueryDelegatedBalanceResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryDelegatedBalanceResponse proto.InternalMessageInfo +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +type QueryTotalSupplyRequest struct { +} + +func (m *QueryTotalSupplyRequest) Reset() { *m = QueryTotalSupplyRequest{} } +func (m *QueryTotalSupplyRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyRequest) ProtoMessage() {} +func (*QueryTotalSupplyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0d745428489be444, []int{2} +} +func (m *QueryTotalSupplyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyRequest.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 *QueryTotalSupplyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyRequest.Merge(m, src) +} +func (m *QueryTotalSupplyRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyRequest proto.InternalMessageInfo + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +type QueryTotalSupplyResponse struct { + // Height is the block height at which these totals apply + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + // Result is a list of coins supplied to liquid + Result github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=result,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"result"` +} + +func (m *QueryTotalSupplyResponse) Reset() { *m = QueryTotalSupplyResponse{} } +func (m *QueryTotalSupplyResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyResponse) ProtoMessage() {} +func (*QueryTotalSupplyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0d745428489be444, []int{3} +} +func (m *QueryTotalSupplyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyResponse.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 *QueryTotalSupplyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyResponse.Merge(m, src) +} +func (m *QueryTotalSupplyResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*QueryDelegatedBalanceRequest)(nil), "kava.liquid.v1beta1.QueryDelegatedBalanceRequest") proto.RegisterType((*QueryDelegatedBalanceResponse)(nil), "kava.liquid.v1beta1.QueryDelegatedBalanceResponse") + proto.RegisterType((*QueryTotalSupplyRequest)(nil), "kava.liquid.v1beta1.QueryTotalSupplyRequest") + proto.RegisterType((*QueryTotalSupplyResponse)(nil), "kava.liquid.v1beta1.QueryTotalSupplyResponse") } func init() { proto.RegisterFile("kava/liquid/v1beta1/query.proto", fileDescriptor_0d745428489be444) } var fileDescriptor_0d745428489be444 = []byte{ - // 389 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x3d, 0x6f, 0xd3, 0x40, - 0x1c, 0xc6, 0x7d, 0x11, 0x04, 0xe5, 0x58, 0x90, 0xc9, 0x90, 0x44, 0xe1, 0x82, 0x32, 0x65, 0xc9, - 0x9d, 0x62, 0x10, 0x08, 0x36, 0x0c, 0x62, 0x27, 0x48, 0x0c, 0x2c, 0xd1, 0xd9, 0x3e, 0x1d, 0x27, - 0x9c, 0x3b, 0xc7, 0x77, 0x8e, 0x88, 0x10, 0x0b, 0x9f, 0xa0, 0x52, 0xbe, 0x4a, 0x3b, 0x77, 0xcd, - 0x18, 0xb5, 0x4b, 0xa7, 0xaa, 0x4d, 0xfa, 0x41, 0x2a, 0xfb, 0xec, 0x54, 0xaa, 0xd2, 0xaa, 0xdd, - 0xce, 0x7a, 0x7e, 0xcf, 0xf3, 0x7f, 0x33, 0xec, 0xfd, 0xa6, 0x73, 0x4a, 0x62, 0x31, 0xcb, 0x44, - 0x44, 0xe6, 0xa3, 0x80, 0x19, 0x3a, 0x22, 0xb3, 0x8c, 0xa5, 0x0b, 0x9c, 0xa4, 0xca, 0x28, 0xf7, - 0x65, 0x0e, 0x60, 0x0b, 0xe0, 0x12, 0xe8, 0x34, 0xb9, 0xe2, 0xaa, 0xd0, 0x49, 0xfe, 0xb2, 0x68, - 0xa7, 0xcb, 0x95, 0xe2, 0x31, 0x23, 0x34, 0x11, 0x84, 0x4a, 0xa9, 0x0c, 0x35, 0x42, 0x49, 0x5d, - 0xaa, 0x28, 0x54, 0x7a, 0xaa, 0x34, 0x09, 0xa8, 0x66, 0xbb, 0x4a, 0xa1, 0x12, 0xb2, 0xd4, 0xdb, - 0x56, 0x9f, 0xd8, 0x58, 0xfb, 0x61, 0xa5, 0xfe, 0x0f, 0xd8, 0xfd, 0x96, 0xb7, 0xf4, 0x85, 0xc5, - 0x8c, 0x53, 0xc3, 0x22, 0x9f, 0xc6, 0x54, 0x86, 0x6c, 0xcc, 0x66, 0x19, 0xd3, 0xc6, 0x7d, 0x07, - 0x1b, 0x91, 0x95, 0x54, 0xda, 0x02, 0xaf, 0xc1, 0xa0, 0xe1, 0xb7, 0x4e, 0x0e, 0x87, 0xcd, 0x32, - 0xe4, 0x53, 0x14, 0xa5, 0x4c, 0xeb, 0xef, 0x26, 0x15, 0x92, 0x8f, 0x6f, 0xd0, 0xfe, 0x12, 0xc0, - 0x57, 0x77, 0x04, 0xeb, 0x44, 0x49, 0xcd, 0xdc, 0xf7, 0xb0, 0x3e, 0x67, 0xda, 0xb0, 0xa8, 0x88, - 0x7d, 0xee, 0xb5, 0x71, 0x99, 0x99, 0x4f, 0x51, 0xad, 0x03, 0x7f, 0x56, 0x42, 0xfa, 0x4f, 0x56, - 0xe7, 0x3d, 0x67, 0x5c, 0xe2, 0xee, 0x07, 0xf8, 0x2c, 0x7f, 0x09, 0xc9, 0x5b, 0xb5, 0x87, 0x39, - 0x2b, 0xde, 0x3b, 0x06, 0xf0, 0x69, 0xd1, 0x95, 0x7b, 0x04, 0xe0, 0x8b, 0xdb, 0xad, 0xb9, 0x23, - 0xbc, 0xe7, 0x22, 0xf8, 0xbe, 0xfd, 0x74, 0xbc, 0xc7, 0x58, 0xec, 0xe4, 0xfd, 0x8f, 0xff, 0x4f, - 0xaf, 0x96, 0xb5, 0xb7, 0xae, 0x47, 0xf6, 0xfd, 0x21, 0x51, 0x65, 0x9b, 0x04, 0xd6, 0x47, 0xfe, - 0xee, 0xd6, 0xfa, 0xcf, 0xff, 0xba, 0xba, 0x44, 0xce, 0x6a, 0x83, 0xc0, 0x7a, 0x83, 0xc0, 0xc5, - 0x06, 0x81, 0x83, 0x2d, 0x72, 0xd6, 0x5b, 0xe4, 0x9c, 0x6d, 0x91, 0xf3, 0x73, 0xc0, 0x85, 0xf9, - 0x95, 0x05, 0x38, 0x54, 0xd3, 0x22, 0x7b, 0x18, 0xd3, 0x40, 0xdb, 0x2a, 0x7f, 0xaa, 0x3a, 0x66, - 0x91, 0x30, 0x1d, 0xd4, 0x8b, 0xf3, 0xbf, 0xb9, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x32, 0x91, 0xae, - 0x51, 0xa5, 0x02, 0x00, 0x00, + // 498 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcf, 0x6e, 0xd3, 0x30, + 0x1c, 0x8e, 0x3b, 0x28, 0x9a, 0x77, 0x41, 0x66, 0x82, 0xac, 0x1a, 0xe9, 0x08, 0x97, 0x21, 0xd1, + 0x98, 0x16, 0x04, 0x82, 0x1b, 0x05, 0x71, 0x27, 0x43, 0x1c, 0xb8, 0x54, 0x4e, 0x62, 0xb9, 0xd6, + 0x32, 0x3b, 0x8d, 0x9d, 0x8a, 0x0a, 0x71, 0xe1, 0x09, 0x90, 0x26, 0xc4, 0x3b, 0x70, 0x86, 0x77, + 0xe8, 0x71, 0x82, 0x03, 0x9c, 0xf8, 0xd3, 0xf2, 0x20, 0x28, 0xb6, 0x3b, 0x26, 0xd6, 0x4d, 0xe3, + 0x14, 0x5b, 0xdf, 0x1f, 0x7f, 0xfe, 0x7d, 0x0e, 0x6c, 0xef, 0x92, 0x31, 0xc1, 0x39, 0x1f, 0x55, + 0x3c, 0xc3, 0xe3, 0x6e, 0x42, 0x35, 0xe9, 0xe2, 0x51, 0x45, 0xcb, 0x49, 0x54, 0x94, 0x52, 0x4b, + 0x74, 0xa9, 0x26, 0x44, 0x96, 0x10, 0x39, 0x42, 0x6b, 0x9d, 0x49, 0x26, 0x0d, 0x8e, 0xeb, 0x95, + 0xa5, 0xb6, 0x36, 0x99, 0x94, 0x2c, 0xa7, 0x98, 0x14, 0x1c, 0x13, 0x21, 0xa4, 0x26, 0x9a, 0x4b, + 0xa1, 0x1c, 0x1a, 0xa4, 0x52, 0xed, 0x49, 0x85, 0x13, 0xa2, 0xe8, 0xe1, 0x49, 0xa9, 0xe4, 0xc2, + 0xe1, 0x1b, 0x16, 0x1f, 0x58, 0x5b, 0xbb, 0xb1, 0x50, 0xf8, 0x1c, 0x6e, 0x3e, 0xad, 0x23, 0x3d, + 0xa6, 0x39, 0x65, 0x44, 0xd3, 0xac, 0x4f, 0x72, 0x22, 0x52, 0x1a, 0xd3, 0x51, 0x45, 0x95, 0x46, + 0x77, 0xe1, 0x6a, 0x66, 0x21, 0x59, 0xfa, 0x60, 0x0b, 0x6c, 0xaf, 0xf6, 0xfd, 0xcf, 0x1f, 0x3b, + 0xeb, 0xce, 0xe4, 0x61, 0x96, 0x95, 0x54, 0xa9, 0x1d, 0x5d, 0x72, 0xc1, 0xe2, 0xbf, 0xd4, 0x70, + 0x1f, 0xc0, 0xab, 0x27, 0x18, 0xab, 0x42, 0x0a, 0x45, 0xd1, 0x3d, 0xd8, 0x1c, 0x53, 0xa5, 0x69, + 0x66, 0x6c, 0xd7, 0x7a, 0x1b, 0x91, 0xf3, 0xac, 0x6f, 0xb1, 0x18, 0x47, 0xf4, 0x48, 0x72, 0xd1, + 0x3f, 0x37, 0xfd, 0xde, 0xf6, 0x62, 0x47, 0x47, 0xf7, 0xe1, 0x85, 0x7a, 0xc5, 0x05, 0xf3, 0x1b, + 0x67, 0x53, 0x2e, 0xf8, 0xe1, 0x06, 0xbc, 0x62, 0x42, 0x3d, 0x93, 0x9a, 0xe4, 0x3b, 0x55, 0x51, + 0xe4, 0x13, 0x77, 0xd1, 0xf0, 0x3d, 0x80, 0xfe, 0x71, 0xcc, 0x65, 0xbd, 0x0c, 0x9b, 0x43, 0xca, + 0xd9, 0x50, 0x9b, 0xac, 0x2b, 0xb1, 0xdb, 0xa1, 0x14, 0x36, 0x4b, 0xaa, 0xaa, 0x5c, 0xfb, 0x8d, + 0xad, 0x95, 0xd3, 0x93, 0xdc, 0xaa, 0x93, 0x7c, 0xf8, 0xd1, 0xde, 0x66, 0x5c, 0x0f, 0xab, 0x24, + 0x4a, 0xe5, 0x9e, 0x6b, 0xc2, 0x7d, 0x3a, 0x2a, 0xdb, 0xc5, 0x7a, 0x52, 0x50, 0x65, 0x04, 0x2a, + 0x76, 0xd6, 0xbd, 0xaf, 0x0d, 0x78, 0xde, 0x24, 0x43, 0x9f, 0x00, 0xbc, 0xf8, 0xef, 0x3c, 0x51, + 0x37, 0x5a, 0xf2, 0x8c, 0xa2, 0xd3, 0x4a, 0x6d, 0xf5, 0xfe, 0x47, 0x62, 0x47, 0x10, 0x3e, 0x78, + 0xf3, 0xe5, 0xf7, 0x7e, 0xe3, 0x0e, 0xea, 0xe1, 0x65, 0xcf, 0x3a, 0x5b, 0xc8, 0x06, 0x89, 0xd5, + 0xe1, 0x57, 0x87, 0x6f, 0xe1, 0x35, 0x7a, 0x07, 0xe0, 0xda, 0x91, 0xb1, 0xa2, 0x9b, 0x27, 0x9f, + 0x7f, 0xbc, 0x99, 0x56, 0xe7, 0x8c, 0x6c, 0x17, 0xf4, 0x86, 0x09, 0x7a, 0x1d, 0x5d, 0x5b, 0x1a, + 0x54, 0xd7, 0x8a, 0x81, 0x32, 0x92, 0xfe, 0x93, 0xe9, 0xaf, 0xc0, 0x9b, 0xce, 0x02, 0x70, 0x30, + 0x0b, 0xc0, 0xcf, 0x59, 0x00, 0xde, 0xce, 0x03, 0xef, 0x60, 0x1e, 0x78, 0xdf, 0xe6, 0x81, 0xf7, + 0xe2, 0x68, 0x53, 0xb5, 0x55, 0x27, 0x27, 0x89, 0xb2, 0xa6, 0x2f, 0x17, 0xb6, 0xa6, 0xaf, 0xa4, + 0x69, 0xfe, 0xa5, 0xdb, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x15, 0x79, 0xc0, 0xf2, 0x03, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -162,6 +250,8 @@ type QueryClient interface { // DelegatedBalance returns an account's vesting and vested coins currently delegated to validators. // It ignores coins in unbonding delegations. DelegatedBalance(ctx context.Context, in *QueryDelegatedBalanceRequest, opts ...grpc.CallOption) (*QueryDelegatedBalanceResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the liquid module. + TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) } type queryClient struct { @@ -181,11 +271,22 @@ func (c *queryClient) DelegatedBalance(ctx context.Context, in *QueryDelegatedBa return out, nil } +func (c *queryClient) TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) { + out := new(QueryTotalSupplyResponse) + err := c.cc.Invoke(ctx, "/kava.liquid.v1beta1.Query/TotalSupply", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // DelegatedBalance returns an account's vesting and vested coins currently delegated to validators. // It ignores coins in unbonding delegations. DelegatedBalance(context.Context, *QueryDelegatedBalanceRequest) (*QueryDelegatedBalanceResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the liquid module. + TotalSupply(context.Context, *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -195,6 +296,9 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) DelegatedBalance(ctx context.Context, req *QueryDelegatedBalanceRequest) (*QueryDelegatedBalanceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DelegatedBalance not implemented") } +func (*UnimplementedQueryServer) TotalSupply(ctx context.Context, req *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalSupply not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -218,6 +322,24 @@ func _Query_DelegatedBalance_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Query_TotalSupply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalSupplyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalSupply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.liquid.v1beta1.Query/TotalSupply", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalSupply(ctx, req.(*QueryTotalSupplyRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "kava.liquid.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -226,6 +348,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "DelegatedBalance", Handler: _Query_DelegatedBalance_Handler, }, + { + MethodName: "TotalSupply", + Handler: _Query_TotalSupply_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kava/liquid/v1beta1/query.proto", @@ -304,6 +430,71 @@ func (m *QueryDelegatedBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryTotalSupplyRequest) 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 *QueryTotalSupplyRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryTotalSupplyResponse) 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 *QueryTotalSupplyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Result) > 0 { + for iNdEx := len(m.Result) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Result[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Height != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -341,6 +532,33 @@ func (m *QueryDelegatedBalanceResponse) Size() (n int) { return n } +func (m *QueryTotalSupplyRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryTotalSupplyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovQuery(uint64(m.Height)) + } + if len(m.Result) > 0 { + for _, e := range m.Result { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -545,6 +763,159 @@ func (m *QueryDelegatedBalanceResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryTotalSupplyRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalSupplyResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Result = append(m.Result, types.Coin{}) + if err := m.Result[len(m.Result)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/liquid/types/query.pb.gw.go b/x/liquid/types/query.pb.gw.go index 8b27bb8d..b9134b62 100644 --- a/x/liquid/types/query.pb.gw.go +++ b/x/liquid/types/query.pb.gw.go @@ -87,6 +87,24 @@ func local_request_Query_DelegatedBalance_0(ctx context.Context, marshaler runti } +func request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := client.TotalSupply(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := server.TotalSupply(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. @@ -116,6 +134,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -177,13 +218,37 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_Query_DelegatedBalance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"kava", "liquid", "v1beta1", "delegated_balance", "delegator"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TotalSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "liquid", "v1beta1", "total_supply"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_DelegatedBalance_0 = runtime.ForwardResponseMessage + + forward_Query_TotalSupply_0 = runtime.ForwardResponseMessage ) diff --git a/x/savings/client/cli/query.go b/x/savings/client/cli/query.go index 033de27e..be39f98f 100644 --- a/x/savings/client/cli/query.go +++ b/x/savings/client/cli/query.go @@ -33,6 +33,7 @@ func GetQueryCmd() *cobra.Command { cmds := []*cobra.Command{ GetCmdQueryParams(), queryDepositsCmd(), + GetCmdTotalSupply(), } for _, cmd := range cmds { @@ -130,3 +131,28 @@ func queryDepositsCmd() *cobra.Command { return cmd } + +// GetCmdTotalSupply returns the command that queries total supply locked into savings module +func GetCmdTotalSupply() *cobra.Command { + return &cobra.Command{ + Use: "total-supply", + Short: "get total supply locked into savings module", + Long: "Get the sum of all denoms locked into the savings module.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.TotalSupply(context.Background(), &types.QueryTotalSupplyRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } +} diff --git a/x/savings/keeper/grpc_query.go b/x/savings/keeper/grpc_query.go index 6aa120aa..61f54fba 100644 --- a/x/savings/keeper/grpc_query.go +++ b/x/savings/keeper/grpc_query.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "strings" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -103,3 +104,38 @@ func (s queryServer) Deposits(ctx context.Context, req *types.QueryDepositsReque Pagination: nil, }, nil } + +func (s queryServer) TotalSupply(ctx context.Context, req *types.QueryTotalSupplyRequest) (*types.QueryTotalSupplyResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + totalSupply := sdk.NewCoins() + liquidStakedDerivatives := sdk.NewCoins() + + s.keeper.IterateDeposits(sdkCtx, func(deposit types.Deposit) (stop bool) { + for _, c := range deposit.Amount { + // separate out bkava denoms + if strings.HasPrefix(c.Denom, bkavaPrefix) { + liquidStakedDerivatives = liquidStakedDerivatives.Add(c) + } else { + totalSupply = totalSupply.Add(c) + } + } + return false + }) + + // determine underlying value of bkava denoms + if len(liquidStakedDerivatives) > 0 { + underlyingValue, err := s.keeper.liquidKeeper.GetStakedTokensForDerivatives( + sdkCtx, + liquidStakedDerivatives, + ) + if err != nil { + return nil, err + } + totalSupply = totalSupply.Add(sdk.NewCoin(bkavaDenom, underlyingValue.Amount)) + } + + return &types.QueryTotalSupplyResponse{ + Height: sdkCtx.BlockHeight(), + Result: totalSupply, + }, nil +} diff --git a/x/savings/keeper/grpcquery_test.go b/x/savings/keeper/grpcquery_test.go index 0f37b3a3..2510b0b6 100644 --- a/x/savings/keeper/grpcquery_test.go +++ b/x/savings/keeper/grpcquery_test.go @@ -6,14 +6,26 @@ import ( "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/kava-labs/kava/app" + liquidtypes "github.com/kava-labs/kava/x/liquid/types" "github.com/kava-labs/kava/x/savings/keeper" "github.com/kava-labs/kava/x/savings/types" ) +var dep = types.NewDeposit + +const ( + bkava1 = "bkava-kavavaloper15gqc744d05xacn4n6w2furuads9fu4pqn6zxlu" + bkava2 = "bkava-kavavaloper15qdefkmwswysgg4qxgqpqr35k3m49pkx8yhpte" +) + type grpcQueryTestSuite struct { suite.Suite @@ -46,7 +58,7 @@ func (suite *grpcQueryTestSuite) SetupTest() { suite.Require().NoError(err) savingsGenesis := types.GenesisState{ - Params: types.NewParams([]string{"bnb", "busd"}), + Params: types.NewParams([]string{"bnb", "busd", bkava1, bkava2}), } savingsGenState := app.GenesisState{types.ModuleName: suite.tApp.AppCodec().MustMarshalJSON(&savingsGenesis)} @@ -69,7 +81,7 @@ func (suite *grpcQueryTestSuite) TestGrpcQueryParams() { var expected types.GenesisState savingsGenesis := types.GenesisState{ - Params: types.NewParams([]string{"bnb", "busd"}), + Params: types.NewParams([]string{"bnb", "busd", bkava1, bkava2}), } savingsGenState := app.GenesisState{types.ModuleName: suite.tApp.AppCodec().MustMarshalJSON(&savingsGenesis)} suite.tApp.AppCodec().MustUnmarshalJSON(savingsGenState[types.ModuleName], &expected) @@ -78,7 +90,12 @@ func (suite *grpcQueryTestSuite) TestGrpcQueryParams() { } func (suite *grpcQueryTestSuite) TestGrpcQueryDeposits() { - suite.addDeposits() + suite.addDeposits([]types.Deposit{ + dep(suite.addrs[0], cs(c("bnb", 100000000))), + dep(suite.addrs[1], cs(c("bnb", 20000000))), + dep(suite.addrs[0], cs(c("busd", 20000000))), + dep(suite.addrs[0], cs(c("busd", 8000000))), + }) tests := []struct { giveName string @@ -161,37 +178,176 @@ func (suite *grpcQueryTestSuite) TestGrpcQueryDeposits() { } } -func (suite *grpcQueryTestSuite) addDeposits() { - deposits := []struct { - Address sdk.AccAddress - Coins sdk.Coins +func (suite *grpcQueryTestSuite) TestGrpcQueryTotalSupply() { + testCases := []struct { + name string + deposits types.Deposits + expectedSupply sdk.Coins }{ { - suite.addrs[0], - cs(c("bnb", 100000000)), + name: "returns zeros when there's no supply", + deposits: []types.Deposit{}, + expectedSupply: sdk.NewCoins(), }, { - suite.addrs[1], - cs(c("bnb", 20000000)), + name: "returns supply of one denom deposited from multiple accounts", + deposits: []types.Deposit{ + dep(suite.addrs[0], sdk.NewCoins(c("busd", 1e6))), + dep(suite.addrs[1], sdk.NewCoins(c("busd", 1e6))), + }, + expectedSupply: sdk.NewCoins(c("busd", 2e6)), }, { - suite.addrs[0], - cs(c("busd", 20000000)), + name: "returns supply of multiple denoms deposited from single account", + deposits: []types.Deposit{ + dep(suite.addrs[0], sdk.NewCoins(c("busd", 1e6), c("bnb", 1e6))), + }, + expectedSupply: sdk.NewCoins(c("busd", 1e6), c("bnb", 1e6)), }, { - suite.addrs[0], - cs(c("busd", 8000000)), + name: "returns supply of multiple denoms deposited from multiple accounts", + deposits: []types.Deposit{ + dep(suite.addrs[0], sdk.NewCoins(c("busd", 1e6), c("bnb", 1e6))), + dep(suite.addrs[1], sdk.NewCoins(c("busd", 1e6), c("bnb", 1e6))), + }, + expectedSupply: sdk.NewCoins(c("busd", 2e6), c("bnb", 2e6)), }, } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + // setup deposits + suite.addDeposits(tc.deposits) + + res, err := suite.queryServer.TotalSupply( + sdk.WrapSDKContext(suite.ctx), + &types.QueryTotalSupplyRequest{}, + ) + suite.Require().NoError(err) + suite.Require().Equal(tc.expectedSupply, res.Result) + }) + } + + suite.Run("aggregates bkava denoms, accounting for slashing", func() { + suite.SetupTest() + + address1, derivatives1, _ := suite.createAccountWithDerivatives(bkava1, sdk.NewInt(1e9)) + address2, derivatives2, _ := suite.createAccountWithDerivatives(bkava2, sdk.NewInt(1e9)) + + // bond validators + staking.EndBlocker(suite.ctx, suite.tApp.GetStakingKeeper()) + // slash val2 - its shares are now 80% as valuable! + err := suite.slashValidator(sdk.ValAddress(address2), sdk.MustNewDecFromStr("0.2")) + suite.Require().NoError(err) + + suite.addDeposits( + types.Deposits{ + dep(address1, cs(derivatives1)), + dep(address2, cs(derivatives2)), + }, + ) + + expectedSupply := sdk.NewCoins( + sdk.NewCoin( + "bkava", + sdk.NewIntFromUint64(1e9). // derivative 1 + Add(sdk.NewInt(1e9).MulRaw(80).QuoRaw(100))), // derivative 2: original value * 80% + ) + + res, err := suite.queryServer.TotalSupply( + sdk.WrapSDKContext(suite.ctx), + &types.QueryTotalSupplyRequest{}, + ) + suite.Require().NoError(err) + suite.Require().Equal(expectedSupply, res.Result) + }) +} + +func (suite *grpcQueryTestSuite) addDeposits(deposits types.Deposits) { for _, dep := range deposits { suite.NotPanics(func() { - err := suite.keeper.Deposit(suite.ctx, dep.Address, dep.Coins) + err := suite.keeper.Deposit(suite.ctx, dep.Depositor, dep.Amount) suite.Require().NoError(err) }) } } +// createUnbondedValidator creates an unbonded validator with the given amount of self-delegation. +func (suite *grpcQueryTestSuite) createUnbondedValidator(address sdk.ValAddress, selfDelegation sdk.Coin, minSelfDelegation sdk.Int) error { + msg, err := stakingtypes.NewMsgCreateValidator( + address, + ed25519.GenPrivKey().PubKey(), + selfDelegation, + stakingtypes.Description{}, + stakingtypes.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + minSelfDelegation, + ) + if err != nil { + return err + } + + msgServer := stakingkeeper.NewMsgServerImpl(suite.tApp.GetStakingKeeper()) + _, err = msgServer.CreateValidator(sdk.WrapSDKContext(suite.ctx), msg) + return err +} + +// createAccountWithDerivatives creates an account with the given amount and denom of derivative token. +// Internally, it creates a validator account and mints derivatives from the validator's self delegation. +func (suite *grpcQueryTestSuite) createAccountWithDerivatives(denom string, amount sdk.Int) (sdk.AccAddress, sdk.Coin, sdk.Coins) { + bondDenom := suite.tApp.GetStakingKeeper().BondDenom(suite.ctx) + valAddress, err := liquidtypes.ParseLiquidStakingTokenDenom(denom) + suite.Require().NoError(err) + address := sdk.AccAddress(valAddress) + + remainingSelfDelegation := sdk.NewInt(1e6) + selfDelegation := sdk.NewCoin( + bondDenom, + amount.Add(remainingSelfDelegation), + ) + + // create & fund account + // ak := suite.tApp.GetAccountKeeper() + // acc := ak.NewAccountWithAddress(suite.ctx, address) + // ak.SetAccount(suite.ctx, acc) + err = suite.tApp.FundAccount(suite.ctx, address, sdk.NewCoins(selfDelegation)) + suite.Require().NoError(err) + + err = suite.createUnbondedValidator(valAddress, selfDelegation, remainingSelfDelegation) + suite.Require().NoError(err) + + toConvert := sdk.NewCoin(bondDenom, amount) + derivatives, err := suite.tApp.GetLiquidKeeper().MintDerivative(suite.ctx, + address, + valAddress, + toConvert, + ) + suite.Require().NoError(err) + + fullBalance := suite.tApp.GetBankKeeper().GetAllBalances(suite.ctx, address) + + return address, derivatives, fullBalance +} + +// slashValidator slashes the validator with the given address by the given percentage. +func (suite *grpcQueryTestSuite) slashValidator(address sdk.ValAddress, slashFraction sdk.Dec) error { + stakingKeeper := suite.tApp.GetStakingKeeper() + + validator, found := stakingKeeper.GetValidator(suite.ctx, address) + suite.Require().True(found) + consAddr, err := validator.GetConsAddr() + suite.Require().NoError(err) + + // Assume infraction was at current height. Note unbonding delegations and redelegations are only slashed if created after + // the infraction height so none will be slashed. + infractionHeight := suite.ctx.BlockHeight() + + power := stakingKeeper.TokensToConsensusPower(suite.ctx, validator.GetTokens()) + + stakingKeeper.Slash(suite.ctx, consAddr, infractionHeight, power, slashFraction) + return nil +} + func TestGrpcQueryTestSuite(t *testing.T) { suite.Run(t, new(grpcQueryTestSuite)) } diff --git a/x/savings/keeper/params.go b/x/savings/keeper/params.go index 25928204..ad786130 100644 --- a/x/savings/keeper/params.go +++ b/x/savings/keeper/params.go @@ -7,6 +7,11 @@ import ( "github.com/kava-labs/kava/x/savings/types" ) +const ( + bkavaDenom = "bkava" + bkavaPrefix = bkavaDenom + "-" +) + // GetParams returns the params from the store func (k Keeper) GetParams(ctx sdk.Context) types.Params { var p types.Params diff --git a/x/savings/types/expected_keepers.go b/x/savings/types/expected_keepers.go index cc0a1959..7072936c 100644 --- a/x/savings/types/expected_keepers.go +++ b/x/savings/types/expected_keepers.go @@ -33,5 +33,6 @@ type SavingsHooks interface { } type LiquidKeeper interface { + GetStakedTokensForDerivatives(ctx sdk.Context, derivatives sdk.Coins) (sdk.Coin, error) IsDerivativeDenom(ctx sdk.Context, denom string) bool } diff --git a/x/savings/types/query.pb.go b/x/savings/types/query.pb.go index f23ee424..14540ce6 100644 --- a/x/savings/types/query.pb.go +++ b/x/savings/types/query.pb.go @@ -7,6 +7,8 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" @@ -224,49 +226,150 @@ func (m *QueryDepositsResponse) GetPagination() *query.PageResponse { return nil } +// QueryTotalSupplyRequest defines the request type for Query/TotalSupply method. +type QueryTotalSupplyRequest struct { +} + +func (m *QueryTotalSupplyRequest) Reset() { *m = QueryTotalSupplyRequest{} } +func (m *QueryTotalSupplyRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyRequest) ProtoMessage() {} +func (*QueryTotalSupplyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f78c91efc5db144f, []int{4} +} +func (m *QueryTotalSupplyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyRequest.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 *QueryTotalSupplyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyRequest.Merge(m, src) +} +func (m *QueryTotalSupplyRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyRequest proto.InternalMessageInfo + +// TotalSupplyResponse defines the response type for the Query/TotalSupply method. +type QueryTotalSupplyResponse struct { + // Height is the block height at which these totals apply + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + // Result is a list of coins supplied to savings + Result github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=result,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"result"` +} + +func (m *QueryTotalSupplyResponse) Reset() { *m = QueryTotalSupplyResponse{} } +func (m *QueryTotalSupplyResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalSupplyResponse) ProtoMessage() {} +func (*QueryTotalSupplyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f78c91efc5db144f, []int{5} +} +func (m *QueryTotalSupplyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalSupplyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalSupplyResponse.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 *QueryTotalSupplyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalSupplyResponse.Merge(m, src) +} +func (m *QueryTotalSupplyResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalSupplyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalSupplyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalSupplyResponse proto.InternalMessageInfo + +func (m *QueryTotalSupplyResponse) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *QueryTotalSupplyResponse) GetResult() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Result + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "kava.savings.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "kava.savings.v1beta1.QueryParamsResponse") proto.RegisterType((*QueryDepositsRequest)(nil), "kava.savings.v1beta1.QueryDepositsRequest") proto.RegisterType((*QueryDepositsResponse)(nil), "kava.savings.v1beta1.QueryDepositsResponse") + proto.RegisterType((*QueryTotalSupplyRequest)(nil), "kava.savings.v1beta1.QueryTotalSupplyRequest") + proto.RegisterType((*QueryTotalSupplyResponse)(nil), "kava.savings.v1beta1.QueryTotalSupplyResponse") } func init() { proto.RegisterFile("kava/savings/v1beta1/query.proto", fileDescriptor_f78c91efc5db144f) } var fileDescriptor_f78c91efc5db144f = []byte{ - // 499 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x3f, 0x6f, 0x13, 0x31, - 0x18, 0xc6, 0xcf, 0x69, 0x13, 0x15, 0x77, 0x41, 0xe6, 0x90, 0x8e, 0x28, 0x5c, 0xa2, 0x13, 0x2a, - 0x69, 0x51, 0x7d, 0x6a, 0xd8, 0xba, 0x11, 0x10, 0x0c, 0x2c, 0x70, 0x0c, 0x48, 0x2c, 0xc8, 0xd7, - 0x58, 0xe6, 0x44, 0x63, 0x5f, 0xef, 0x75, 0x02, 0x5d, 0x61, 0x41, 0x62, 0x41, 0x62, 0x64, 0x61, - 0x60, 0x42, 0x62, 0xe3, 0x43, 0x74, 0xac, 0x60, 0x61, 0x02, 0x94, 0xf0, 0x41, 0xd0, 0xd9, 0xee, - 0xf5, 0x0f, 0x27, 0x9a, 0xed, 0xfc, 0xfa, 0x79, 0x1e, 0xff, 0xde, 0xd7, 0x3e, 0xdc, 0x7b, 0xce, - 0xa6, 0x2c, 0x06, 0x36, 0xcd, 0xa4, 0x80, 0x78, 0xba, 0x95, 0x72, 0xcd, 0xb6, 0xe2, 0xbd, 0x09, - 0x2f, 0xf6, 0x69, 0x5e, 0x28, 0xad, 0x88, 0x5f, 0x2a, 0xa8, 0x53, 0x50, 0xa7, 0x68, 0xd7, 0xfb, - 0x40, 0xab, 0x82, 0x5b, 0x5f, 0xdb, 0x17, 0x4a, 0x28, 0xf3, 0x19, 0x97, 0x5f, 0xae, 0xda, 0x11, - 0x4a, 0x89, 0x5d, 0x1e, 0xb3, 0x3c, 0x8b, 0x99, 0x94, 0x4a, 0x33, 0x9d, 0x29, 0x09, 0x6e, 0xf7, - 0xca, 0x8e, 0x82, 0xb1, 0x82, 0xa7, 0xd6, 0x66, 0x17, 0x6e, 0x6b, 0xc3, 0xae, 0xe2, 0x94, 0x01, - 0xb7, 0x7c, 0xd5, 0xa9, 0x39, 0x13, 0x99, 0x34, 0x39, 0x56, 0x1b, 0xf9, 0x98, 0x3c, 0x2c, 0x15, - 0x0f, 0x58, 0xc1, 0xc6, 0x90, 0xf0, 0xbd, 0x09, 0x07, 0x1d, 0x3d, 0xc6, 0x97, 0x4e, 0x55, 0x21, - 0x57, 0x12, 0x38, 0xd9, 0xc6, 0xad, 0xdc, 0x54, 0x02, 0xd4, 0x43, 0xfd, 0xd5, 0x41, 0x87, 0xd6, - 0x35, 0x4c, 0xad, 0x6b, 0xb8, 0x7c, 0xf0, 0xb3, 0xeb, 0x25, 0xce, 0xb1, 0xbd, 0xfc, 0xe6, 0x63, - 0xd7, 0x8b, 0x3e, 0x21, 0xec, 0x9b, 0xe4, 0x3b, 0x3c, 0x57, 0x90, 0xe9, 0xa3, 0x13, 0x89, 0x8f, - 0x9b, 0x23, 0x2e, 0xd5, 0xd8, 0x24, 0x5f, 0x48, 0xec, 0x82, 0x50, 0xdc, 0x54, 0x2f, 0x24, 0x2f, - 0x82, 0x46, 0x59, 0x1d, 0x06, 0xdf, 0xbe, 0x6e, 0xfa, 0xae, 0xd5, 0x5b, 0xa3, 0x51, 0xc1, 0x01, - 0x1e, 0xe9, 0x22, 0x93, 0x22, 0xb1, 0x32, 0x72, 0x17, 0xe3, 0xe3, 0x0e, 0x83, 0x25, 0x03, 0xb9, - 0x46, 0x9d, 0xa3, 0x1c, 0x07, 0xb5, 0xd7, 0x75, 0x4c, 0x2a, 0xb8, 0x23, 0x48, 0x4e, 0x38, 0xa3, - 0x2f, 0x08, 0x5f, 0x3e, 0x83, 0xe9, 0x46, 0x70, 0x1f, 0xaf, 0x8c, 0x5c, 0x2d, 0x40, 0xbd, 0xa5, - 0xfe, 0xea, 0xe0, 0x6a, 0xfd, 0x10, 0x9c, 0x73, 0x78, 0xb1, 0x9c, 0xc2, 0xe7, 0x5f, 0xdd, 0x95, - 0x2a, 0xaa, 0x0a, 0x20, 0xf7, 0x4e, 0xe1, 0x36, 0x0c, 0xee, 0xf5, 0x73, 0x71, 0x2d, 0xc9, 0x49, - 0xde, 0xc1, 0x87, 0x06, 0x6e, 0x1a, 0x5e, 0xf2, 0x1a, 0xe1, 0x96, 0x9d, 0x3f, 0xe9, 0xd7, 0x83, - 0xfd, 0x7b, 0xdd, 0xed, 0xf5, 0x05, 0x94, 0xf6, 0xd4, 0xe8, 0xda, 0xab, 0xef, 0x7f, 0xde, 0x37, - 0x42, 0xd2, 0x89, 0x6b, 0x5f, 0xb5, 0xbd, 0x6c, 0xf2, 0x16, 0xe1, 0xaa, 0x5f, 0xb2, 0xf1, 0x9f, - 0xf4, 0x33, 0xcf, 0xa0, 0x7d, 0x63, 0x21, 0xad, 0x63, 0x59, 0x33, 0x2c, 0x3d, 0x12, 0xd6, 0xb3, - 0x1c, 0x8d, 0x79, 0x78, 0xfb, 0x60, 0x16, 0xa2, 0xc3, 0x59, 0x88, 0x7e, 0xcf, 0x42, 0xf4, 0x6e, - 0x1e, 0x7a, 0x87, 0xf3, 0xd0, 0xfb, 0x31, 0x0f, 0xbd, 0x27, 0xeb, 0x22, 0xd3, 0xcf, 0x26, 0x29, - 0xdd, 0x51, 0x63, 0x93, 0xb1, 0xb9, 0xcb, 0x52, 0xb0, 0x69, 0x2f, 0xab, 0x3c, 0xbd, 0x9f, 0x73, - 0x48, 0x5b, 0xe6, 0x7f, 0xb9, 0xf9, 0x37, 0x00, 0x00, 0xff, 0xff, 0x39, 0xd3, 0xcd, 0xf1, 0x06, - 0x04, 0x00, 0x00, + // 619 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0x4f, 0x6f, 0x12, 0x41, + 0x18, 0xc6, 0x19, 0x28, 0xa4, 0x0e, 0x17, 0x33, 0xae, 0xba, 0x10, 0x5c, 0xc8, 0xa6, 0xa9, 0x14, + 0xc3, 0xae, 0xc5, 0x5b, 0x6f, 0x52, 0xa3, 0x07, 0x2f, 0xba, 0x35, 0x31, 0xf1, 0xd2, 0x0c, 0x30, + 0x59, 0x36, 0x85, 0x99, 0xed, 0xce, 0x80, 0x72, 0xd5, 0x8b, 0x89, 0x17, 0x13, 0x0f, 0x7a, 0xf4, + 0xe0, 0xc9, 0xc4, 0x9b, 0xf1, 0x33, 0xf4, 0xd8, 0xe8, 0xc5, 0x93, 0x1a, 0xf0, 0x83, 0x98, 0x9d, + 0x19, 0xb6, 0x50, 0x36, 0x95, 0x53, 0x77, 0xe6, 0x7d, 0x9f, 0x67, 0x7e, 0xef, 0x9f, 0x02, 0x6b, + 0x47, 0x78, 0x8c, 0x5d, 0x8e, 0xc7, 0x01, 0xf5, 0xb9, 0x3b, 0xde, 0xed, 0x10, 0x81, 0x77, 0xdd, + 0xe3, 0x11, 0x89, 0x26, 0x4e, 0x18, 0x31, 0xc1, 0x90, 0x11, 0x67, 0x38, 0x3a, 0xc3, 0xd1, 0x19, + 0xe5, 0x74, 0x1d, 0x17, 0x2c, 0x22, 0x4a, 0x57, 0x36, 0x7c, 0xe6, 0x33, 0xf9, 0xe9, 0xc6, 0x5f, + 0xfa, 0xb6, 0xe2, 0x33, 0xe6, 0x0f, 0x88, 0x8b, 0xc3, 0xc0, 0xc5, 0x94, 0x32, 0x81, 0x45, 0xc0, + 0x28, 0xd7, 0x51, 0xab, 0xcb, 0xf8, 0x90, 0x71, 0xb7, 0x83, 0x39, 0x49, 0x4c, 0xbb, 0x2c, 0xa0, + 0x3a, 0x5e, 0x52, 0xf1, 0x43, 0x65, 0xab, 0x0e, 0x3a, 0xd4, 0x58, 0x94, 0x4a, 0xfe, 0xc4, 0x20, + 0xc4, 0x7e, 0x40, 0xe5, 0x3b, 0x2a, 0xd7, 0x36, 0x20, 0x7a, 0x1c, 0x67, 0x3c, 0xc2, 0x11, 0x1e, + 0x72, 0x8f, 0x1c, 0x8f, 0x08, 0x17, 0xf6, 0x53, 0x78, 0x65, 0xe9, 0x96, 0x87, 0x8c, 0x72, 0x82, + 0xf6, 0x60, 0x21, 0x94, 0x37, 0x26, 0xa8, 0x81, 0x7a, 0xb1, 0x55, 0x71, 0xd2, 0x1a, 0xe2, 0x28, + 0x55, 0x7b, 0xe3, 0xe4, 0x57, 0x35, 0xe3, 0x69, 0xc5, 0xde, 0xc6, 0xeb, 0x8f, 0xd5, 0x8c, 0xfd, + 0x09, 0x40, 0x43, 0x3a, 0xdf, 0x23, 0x21, 0xe3, 0x81, 0x98, 0xbf, 0x88, 0x0c, 0x98, 0xef, 0x11, + 0xca, 0x86, 0xd2, 0xf9, 0x92, 0xa7, 0x0e, 0xc8, 0x81, 0x79, 0xf6, 0x9c, 0x92, 0xc8, 0xcc, 0xc6, + 0xb7, 0x6d, 0xf3, 0xfb, 0xd7, 0xa6, 0xa1, 0x4b, 0xbd, 0xdb, 0xeb, 0x45, 0x84, 0xf3, 0x03, 0x11, + 0x05, 0xd4, 0xf7, 0x54, 0x1a, 0xba, 0x0f, 0xe1, 0x59, 0x85, 0x66, 0x4e, 0x42, 0x6e, 0x3b, 0x5a, + 0x11, 0xb7, 0xc3, 0x51, 0xe3, 0x3c, 0x23, 0xf5, 0x89, 0x26, 0xf0, 0x16, 0x94, 0xf6, 0x17, 0x00, + 0xaf, 0x9e, 0xc3, 0xd4, 0x2d, 0x78, 0x08, 0x37, 0x7b, 0xfa, 0xce, 0x04, 0xb5, 0x5c, 0xbd, 0xd8, + 0xba, 0x91, 0xde, 0x04, 0xad, 0x6c, 0x5f, 0x8e, 0xbb, 0xf0, 0xf9, 0x77, 0x75, 0x33, 0xb1, 0x4a, + 0x0c, 0xd0, 0x83, 0x25, 0xdc, 0xac, 0xc4, 0xbd, 0xf9, 0x5f, 0x5c, 0x45, 0xb2, 0xc4, 0x5b, 0x82, + 0xd7, 0x25, 0xee, 0x13, 0x26, 0xf0, 0xe0, 0x60, 0x14, 0x86, 0x83, 0xc9, 0x7c, 0x94, 0xef, 0x01, + 0x34, 0x57, 0x63, 0xba, 0x9a, 0x6b, 0xb0, 0xd0, 0x27, 0x81, 0xdf, 0x17, 0xb2, 0xed, 0x39, 0x4f, + 0x9f, 0x50, 0x17, 0x16, 0x22, 0xc2, 0x47, 0x03, 0x61, 0x66, 0x65, 0x8d, 0xa5, 0x25, 0xa8, 0x39, + 0xce, 0x3e, 0x0b, 0x68, 0xfb, 0xb6, 0xae, 0xaf, 0xee, 0x07, 0xa2, 0x3f, 0xea, 0x38, 0x5d, 0x36, + 0xd4, 0xdb, 0xa8, 0xff, 0x34, 0x79, 0xef, 0xc8, 0x15, 0x93, 0x90, 0x70, 0x29, 0xe0, 0x9e, 0xb6, + 0x6e, 0x7d, 0xcb, 0xc1, 0xbc, 0x24, 0x43, 0xaf, 0x00, 0x2c, 0xa8, 0xa5, 0x41, 0xf5, 0xf4, 0x6e, + 0xae, 0xee, 0x68, 0x79, 0x67, 0x8d, 0x4c, 0x55, 0xa6, 0xbd, 0xf5, 0xf2, 0xc7, 0xdf, 0x77, 0x59, + 0x0b, 0x55, 0xdc, 0xd4, 0x7f, 0x55, 0xb5, 0xa1, 0xe8, 0x0d, 0x80, 0xc9, 0x90, 0x50, 0xe3, 0x02, + 0xf7, 0x73, 0xbb, 0x5b, 0xbe, 0xb5, 0x56, 0xae, 0x66, 0xd9, 0x96, 0x2c, 0x35, 0x64, 0xa5, 0xb3, + 0x24, 0xbb, 0xf1, 0x01, 0xc0, 0xe2, 0xc2, 0xc8, 0x50, 0xf3, 0x82, 0x47, 0x56, 0xc7, 0x5e, 0x76, + 0xd6, 0x4d, 0xd7, 0x58, 0x0d, 0x89, 0xb5, 0x85, 0xec, 0x74, 0x2c, 0x11, 0x4b, 0x0e, 0xb9, 0xd4, + 0xb4, 0xf7, 0x4f, 0xa6, 0x16, 0x38, 0x9d, 0x5a, 0xe0, 0xcf, 0xd4, 0x02, 0x6f, 0x67, 0x56, 0xe6, + 0x74, 0x66, 0x65, 0x7e, 0xce, 0xac, 0xcc, 0xb3, 0x9d, 0x85, 0x25, 0x88, 0x7d, 0x9a, 0x03, 0xdc, + 0xe1, 0xca, 0xf1, 0x45, 0xe2, 0x29, 0x77, 0xa1, 0x53, 0x90, 0xbf, 0x3f, 0x77, 0xfe, 0x05, 0x00, + 0x00, 0xff, 0xff, 0xd4, 0xfc, 0xa1, 0x7b, 0x76, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -285,6 +388,8 @@ type QueryClient interface { Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) // Deposits queries savings deposits. Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the savings module. + TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) } type queryClient struct { @@ -313,12 +418,23 @@ func (c *queryClient) Deposits(ctx context.Context, in *QueryDepositsRequest, op return out, nil } +func (c *queryClient) TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error) { + out := new(QueryTotalSupplyResponse) + err := c.cc.Invoke(ctx, "/kava.savings.v1beta1.Query/TotalSupply", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params queries all parameters of the savings module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) // Deposits queries savings deposits. Deposits(context.Context, *QueryDepositsRequest) (*QueryDepositsResponse, error) + // TotalSupply returns the total sum of all coins currently locked into the savings module. + TotalSupply(context.Context, *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -331,6 +447,9 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq func (*UnimplementedQueryServer) Deposits(ctx context.Context, req *QueryDepositsRequest) (*QueryDepositsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Deposits not implemented") } +func (*UnimplementedQueryServer) TotalSupply(ctx context.Context, req *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalSupply not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -372,6 +491,24 @@ func _Query_Deposits_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Query_TotalSupply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalSupplyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalSupply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.savings.v1beta1.Query/TotalSupply", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalSupply(ctx, req.(*QueryTotalSupplyRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "kava.savings.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -384,6 +521,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Deposits", Handler: _Query_Deposits_Handler, }, + { + MethodName: "TotalSupply", + Handler: _Query_TotalSupply_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kava/savings/v1beta1/query.proto", @@ -543,6 +684,71 @@ func (m *QueryDepositsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryTotalSupplyRequest) 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 *QueryTotalSupplyRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryTotalSupplyResponse) 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 *QueryTotalSupplyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalSupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Result) > 0 { + for iNdEx := len(m.Result) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Result[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Height != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -614,6 +820,33 @@ func (m *QueryDepositsResponse) Size() (n int) { return n } +func (m *QueryTotalSupplyRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryTotalSupplyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovQuery(uint64(m.Height)) + } + if len(m.Result) > 0 { + for _, e := range m.Result { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1023,6 +1256,159 @@ func (m *QueryDepositsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryTotalSupplyRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalSupplyResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalSupplyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Result = append(m.Result, types.Coin{}) + if err := m.Result[len(m.Result)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/savings/types/query.pb.gw.go b/x/savings/types/query.pb.gw.go index 000b88a6..8a59f3da 100644 --- a/x/savings/types/query.pb.gw.go +++ b/x/savings/types/query.pb.gw.go @@ -87,6 +87,24 @@ func local_request_Query_Deposits_0(ctx context.Context, marshaler runtime.Marsh } +func request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := client.TotalSupply(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalSupplyRequest + var metadata runtime.ServerMetadata + + msg, err := server.TotalSupply(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. @@ -139,6 +157,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -220,6 +261,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_TotalSupply_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_TotalSupply_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_TotalSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -227,10 +288,14 @@ var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "savings", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "savings", "v1beta1", "deposits"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TotalSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "savings", "v1beta1", "total_supply"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_Params_0 = runtime.ForwardResponseMessage forward_Query_Deposits_0 = runtime.ForwardResponseMessage + + forward_Query_TotalSupply_0 = runtime.ForwardResponseMessage )