From 13c2a199dd71dd89acccf9e161cecce53f96cd63 Mon Sep 17 00:00:00 2001 From: Adam Moser <63419657+toteki@users.noreply.github.com> Date: Thu, 19 Jan 2023 09:31:29 -0700 Subject: [PATCH] feat!: compute borrow limit and borrowed value using safer logic during mixed price movement (#1723) * feat: add spot_borrow_limit to account summary and switch borrow limit to the minimum of spot and historic * cl++ * ++ * feat: compute borrow limit and borrowed value using safer logic during mixed price movements * -- * cl+- * ++ * lint++ * tests++ * typo * Update x/leverage/types/oracle.go Co-authored-by: Adam Wozniak <29418299+adamewozniak@users.noreply.github.com> * suggestion * suggestion * simplify CalculateBorrowLimit args * gofmt * make proto-all Co-authored-by: Adam Wozniak <29418299+adamewozniak@users.noreply.github.com> --- CHANGELOG.md | 5 +- Makefile | 6 + proto/umee/leverage/v1/query.proto | 20 +- swagger/swagger.yaml | 50 +--- x/leverage/client/tests/tests.go | 6 - x/leverage/keeper/borrows.go | 40 +--- x/leverage/keeper/borrows_test.go | 10 +- x/leverage/keeper/collateral.go | 4 +- x/leverage/keeper/grpc_query.go | 59 ++--- x/leverage/keeper/grpc_query_test.go | 6 - x/leverage/keeper/iter.go | 2 +- x/leverage/keeper/limits.go | 41 ++-- x/leverage/keeper/liquidate.go | 6 +- x/leverage/keeper/msg_server.go | 22 +- x/leverage/keeper/oracle.go | 125 +++++----- x/leverage/keeper/oracle_test.go | 142 ++++++++---- x/leverage/simulation/operations.go | 2 +- x/leverage/types/errors.go | 9 +- x/leverage/types/oracle.go | 15 ++ x/leverage/types/query.pb.go | 334 ++++++++------------------- 20 files changed, 354 insertions(+), 550 deletions(-) create mode 100644 x/leverage/types/oracle.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a623a380fc..239d046683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,8 +66,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ - [1685](https://github.com/umee-network/umee/pull/1685) Add medians param to Token registry. - [1683](https://github.com/umee-network/umee/pull/1683) Add MaxBorrow query and allow returning all denoms from MaxWithdraw. - [1690](https://github.com/umee-network/umee/pull/1690) Add MaxBorrow message type. -- [1711](https://github.com/umee-network/umee/pull/1711) Add historic pricing information to leverage MarketSummary and AccountSummary queries. -- [1715](https://github.com/umee-network/umee/pull/1715) Add spot borrow limit to AccountSummary query, and switch returned borrow limit to the minimum of spot and historic borrow limits. +- [1711](https://github.com/umee-network/umee/pull/1711) Add historic pricing information to leverage MarketSummary query +- [1715](https://github.com/umee-network/umee/pull/1715) Reverted. +- [1723](https://github.com/umee-network/umee/pull/1723) Compute borrow limits using the lower of either spot or historic price for each collateral token, and the higher of said prices for borrowed tokens. Remove extra spot/historic only fields in account summary. ## [v3.3.0](https://github.com/umee-network/umee/releases/tag/v3.3.0) - 2022-12-20 diff --git a/Makefile b/Makefile index 18ca853f79..67f5cbbfb2 100644 --- a/Makefile +++ b/Makefile @@ -186,6 +186,12 @@ lint: @echo "--> Running linter with revive" @go install github.com/mgechev/revive @revive -config .revive.toml -formatter friendly ./... +# note: on new OSX, might require brew install diffutils + @echo "--> Running regular linter" + @go install mvdan.cc/gofumpt + @go install github.com/golangci/golangci-lint/cmd/golangci-lint + @$(golangci_lint_cmd) run + @cd price-feeder && $(golangci_lint_cmd) run lint-fix: @echo "--> Running linter to fix the lint issues" diff --git a/proto/umee/leverage/v1/query.proto b/proto/umee/leverage/v1/query.proto index 5ecfcb4e42..f9516fb96b 100644 --- a/proto/umee/leverage/v1/query.proto +++ b/proto/umee/leverage/v1/query.proto @@ -237,7 +237,7 @@ message QueryAccountSummaryResponse { (gogoproto.nullable) = false ]; // Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing. - // It uses the lower of two borrow limits: spot_borrow_limit and historic_borrow_limit. + // The lower of spot or historic price for each collateral token is used when calculating borrow limits. string borrow_limit = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false @@ -247,24 +247,6 @@ message QueryAccountSummaryResponse { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - // Historic Borrowed Value is the sum of the USD value of all tokens the account has borrowed, - // including interest owed, using historic prices. - string historic_borrowed_value = 6 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - // Historic Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing, - // using historic prices. - string historic_borrow_limit = 7 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - // Spot Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing, - // using spot prices. - string spot_borrow_limit = 8 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; } // QueryLiquidationTargets defines the request structure for the LiquidationTargets gRPC service handler. diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index 1a2bffcac5..f59fcdc263 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -150,34 +150,13 @@ paths: Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing. - It uses the lower of two borrow limits: spot_borrow_limit and - historic_borrow_limit. + The lower of spot or historic price for each collateral token + is used when calculating borrow limits. liquidation_threshold: type: string description: >- Liquidation Threshold is the Borrowed Value at which the account becomes eligible for liquidation. - historic_borrowed_value: - type: string - description: >- - Historic Borrowed Value is the sum of the USD value of all - tokens the account has borrowed, - - including interest owed, using historic prices. - historic_borrow_limit: - type: string - description: >- - Historic Borrow Limit is the maximum Borrowed Value the - account is allowed to reach through direct borrowing, - - using historic prices. - spot_borrow_limit: - type: string - description: >- - Spot Borrow Limit is the maximum Borrowed Value the account is - allowed to reach through direct borrowing, - - using spot prices. description: >- QueryAccountSummaryResponse defines the response structure for the AccountSummary gRPC service handler. @@ -2056,34 +2035,13 @@ definitions: Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing. - It uses the lower of two borrow limits: spot_borrow_limit and - historic_borrow_limit. + The lower of spot or historic price for each collateral token is used + when calculating borrow limits. liquidation_threshold: type: string description: >- Liquidation Threshold is the Borrowed Value at which the account becomes eligible for liquidation. - historic_borrowed_value: - type: string - description: >- - Historic Borrowed Value is the sum of the USD value of all tokens the - account has borrowed, - - including interest owed, using historic prices. - historic_borrow_limit: - type: string - description: >- - Historic Borrow Limit is the maximum Borrowed Value the account is - allowed to reach through direct borrowing, - - using historic prices. - spot_borrow_limit: - type: string - description: >- - Spot Borrow Limit is the maximum Borrowed Value the account is allowed - to reach through direct borrowing, - - using spot prices. description: >- QueryAccountSummaryResponse defines the response structure for the AccountSummary gRPC service handler. diff --git a/x/leverage/client/tests/tests.go b/x/leverage/client/tests/tests.go index b735a05364..d1d81b79b7 100644 --- a/x/leverage/client/tests/tests.go +++ b/x/leverage/client/tests/tests.go @@ -293,12 +293,6 @@ func (s *IntegrationTestSuite) TestLeverageScenario() { BorrowedValue: sdk.MustNewDecFromStr("0.00858671"), // (1001 / 1000000) * 34.21 * 0.25 = 0.0085610525 BorrowLimit: sdk.MustNewDecFromStr("0.0085610525"), - // (251 / 1000000) * 34.21 = 0.00858671 - HistoricBorrowedValue: sdk.MustNewDecFromStr("0.00858671"), - // (1001 / 1000000) * 34.21 * 0.25 = 0.0085610525 - HistoricBorrowLimit: sdk.MustNewDecFromStr("0.0085610525"), - // (1001 / 1000000) * 34.21 * 0.25 = 0.0085610525 - SpotBorrowLimit: sdk.MustNewDecFromStr("0.0085610525"), // (1001 / 1000000) * 0.25 * 34.21 = 0.0085610525 LiquidationThreshold: sdk.MustNewDecFromStr("0.0085610525"), }, diff --git a/x/leverage/keeper/borrows.go b/x/leverage/keeper/borrows.go index 2048c636b1..02af472cf8 100644 --- a/x/leverage/keeper/borrows.go +++ b/x/leverage/keeper/borrows.go @@ -8,43 +8,25 @@ import ( ) // assertBorrowerHealth returns an error if a borrower is currently above their borrow limit, -// under either recent (historic median) or current prices. It returns an error if current -// prices cannot be calculated, but will use current prices (without returning an error) -// for any token whose historic prices cannot be calculated. +// under either recent (historic median) or current prices. It returns an error if +// prices cannot be calculated. // This should be checked in msg_server.go at the end of any transaction which is restricted // by borrow limits, i.e. Borrow, Decollateralize, Withdraw, MaxWithdraw. func (k Keeper) assertBorrowerHealth(ctx sdk.Context, borrowerAddr sdk.AccAddress) error { borrowed := k.GetBorrowerBorrows(ctx, borrowerAddr) collateral := k.GetBorrowerCollateral(ctx, borrowerAddr) - // Check using current prices - err := k.checkPositionHealth(ctx, borrowed, collateral, false) + value, err := k.TotalTokenValue(ctx, borrowed, types.PriceModeHigh) if err != nil { return err } - - // Check using historic prices - return k.checkPositionHealth(ctx, borrowed, collateral, true) -} - -// checkPositionHealth returns an error if a borrow + collateral position is not healthy. uses either -// current or historic prices. -func (k Keeper) checkPositionHealth(ctx sdk.Context, borrowed, collateral sdk.Coins, historic bool) error { - value, err := k.TotalTokenValue(ctx, borrowed, historic) - if err != nil { - return err - } - limit, err := k.CalculateBorrowLimit(ctx, collateral, historic) + limit, err := k.CalculateBorrowLimit(ctx, collateral) if err != nil { return err } if value.GT(limit) { - desc := "current" - if historic { - desc = "historic" - } return types.ErrUndercollaterized.Wrapf( - "borrowed: %s, limit: %s (%s prices)", value, limit, desc) + "borrowed: %s, limit: %s", value, limit) } return nil } @@ -113,9 +95,9 @@ func (k Keeper) SupplyUtilization(ctx sdk.Context, denom string) sdk.Dec { // CalculateBorrowLimit uses the price oracle to determine the borrow limit (in USD) provided by // collateral sdk.Coins, using each token's uToken exchange rate and collateral weight. +// The lower of spot price or historic price is used for each collateral token. // An error is returned if any input coins are not uTokens or if value calculation fails. -// If the historic parameter is true, uses medians of recent prices instead of current prices. -func (k Keeper) CalculateBorrowLimit(ctx sdk.Context, collateral sdk.Coins, historic bool) (sdk.Dec, error) { +func (k Keeper) CalculateBorrowLimit(ctx sdk.Context, collateral sdk.Coins) (sdk.Dec, error) { limit := sdk.ZeroDec() for _, coin := range collateral { @@ -132,8 +114,8 @@ func (k Keeper) CalculateBorrowLimit(ctx sdk.Context, collateral sdk.Coins, hist // ignore blacklisted tokens if !ts.Blacklist { - // get USD value of base assets - v, err := k.TokenValue(ctx, baseAsset, historic) + // get USD value of base assets using the chosen price mode + v, err := k.TokenValue(ctx, baseAsset, types.PriceModeLow) if err != nil { return sdk.ZeroDec(), err } @@ -149,7 +131,7 @@ func (k Keeper) CalculateBorrowLimit(ctx sdk.Context, collateral sdk.Coins, hist // borrower with given collateral could reach before being eligible for liquidation, using // each token's oracle price, uToken exchange rate, and liquidation threshold. // An error is returned if any input coins are not uTokens or if value -// calculation fails. +// calculation fails. Always uses spot prices. func (k Keeper) CalculateLiquidationThreshold(ctx sdk.Context, collateral sdk.Coins) (sdk.Dec, error) { totalThreshold := sdk.ZeroDec() @@ -168,7 +150,7 @@ func (k Keeper) CalculateLiquidationThreshold(ctx sdk.Context, collateral sdk.Co // ignore blacklisted tokens if !ts.Blacklist { // get USD value of base assets - v, err := k.TokenValue(ctx, baseAsset, false) + v, err := k.TokenValue(ctx, baseAsset, types.PriceModeSpot) if err != nil { return sdk.ZeroDec(), err } diff --git a/x/leverage/keeper/borrows_test.go b/x/leverage/keeper/borrows_test.go index 7b548fc041..98490e7bc1 100644 --- a/x/leverage/keeper/borrows_test.go +++ b/x/leverage/keeper/borrows_test.go @@ -202,13 +202,13 @@ func (s *IntegrationTestSuite) TestCalculateBorrowLimit() { app, ctx, require := s.app, s.ctx, s.Require() // Empty coins - borrowLimit, err := app.LeverageKeeper.CalculateBorrowLimit(ctx, sdk.NewCoins(), false) + borrowLimit, err := app.LeverageKeeper.CalculateBorrowLimit(ctx, sdk.NewCoins()) require.NoError(err) require.Equal(sdk.ZeroDec(), borrowLimit) // Unregistered asset invalidCoins := sdk.NewCoins(coin("abcd", 1000)) - _, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, invalidCoins, false) + _, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, invalidCoins) require.ErrorIs(err, types.ErrNotUToken) // Create collateral uTokens (1k u/umee) @@ -222,7 +222,7 @@ func (s *IntegrationTestSuite) TestCalculateBorrowLimit() { Mul(sdk.MustNewDecFromStr("0.25")) // Check borrow limit vs. manually computed value - borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, umeeCollateral, false) + borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, umeeCollateral) require.NoError(err) require.Equal(expectedUmeeLimit, borrowLimit) @@ -237,7 +237,7 @@ func (s *IntegrationTestSuite) TestCalculateBorrowLimit() { Mul(sdk.MustNewDecFromStr("0.25")) // Check borrow limit vs. manually computed value - borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, atomCollateral, false) + borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, atomCollateral) require.NoError(err) require.Equal(expectedAtomLimit, borrowLimit) @@ -246,7 +246,7 @@ func (s *IntegrationTestSuite) TestCalculateBorrowLimit() { combinedCollateral := umeeCollateral.Add(atomCollateral...) // Check borrow limit vs. manually computed value - borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, combinedCollateral, false) + borrowLimit, err = app.LeverageKeeper.CalculateBorrowLimit(ctx, combinedCollateral) require.NoError(err) require.Equal(expectedCombinedLimit, borrowLimit) } diff --git a/x/leverage/keeper/collateral.go b/x/leverage/keeper/collateral.go index 6933b1e3fc..decc4291ad 100644 --- a/x/leverage/keeper/collateral.go +++ b/x/leverage/keeper/collateral.go @@ -53,7 +53,7 @@ func (k Keeper) GetTotalCollateral(ctx sdk.Context, denom string) sdk.Coin { } // CalculateCollateralValue uses the price oracle to determine the value (in USD) provided by -// collateral sdk.Coins, using each token's uToken exchange rate. +// collateral sdk.Coins, using each token's uToken exchange rate. Always uses spot price. // An error is returned if any input coins are not uTokens or if value calculation fails. func (k Keeper) CalculateCollateralValue(ctx sdk.Context, collateral sdk.Coins) (sdk.Dec, error) { total := sdk.ZeroDec() @@ -66,7 +66,7 @@ func (k Keeper) CalculateCollateralValue(ctx sdk.Context, collateral sdk.Coins) } // get USD value of base assets - v, err := k.TokenValue(ctx, baseAsset, false) + v, err := k.TokenValue(ctx, baseAsset, types.PriceModeSpot) if err != nil { return sdk.ZeroDec(), err } diff --git a/x/leverage/keeper/grpc_query.go b/x/leverage/keeper/grpc_query.go index 86711f6717..b573aa524a 100644 --- a/x/leverage/keeper/grpc_query.go +++ b/x/leverage/keeper/grpc_query.go @@ -135,10 +135,10 @@ func (q Querier) MarketSummary( } // Oracle prices in response will be nil if it is unavailable - if oraclePrice, _, oracleErr := q.Keeper.TokenDefaultDenomPrice(ctx, req.Denom, false); oracleErr == nil { + if oraclePrice, _, oracleErr := q.Keeper.TokenPrice(ctx, req.Denom, types.PriceModeSpot); oracleErr == nil { resp.OraclePrice = &oraclePrice } - if historicPrice, _, historicErr := q.Keeper.TokenDefaultDenomPrice(ctx, req.Denom, true); historicErr == nil { + if historicPrice, _, historicErr := q.Keeper.TokenPrice(ctx, req.Denom, types.PriceModeHistoric); historicErr == nil { resp.OracleHistoricPrice = &historicPrice } @@ -202,43 +202,41 @@ func (q Querier) AccountSummary( collateral := q.Keeper.GetBorrowerCollateral(ctx, addr) borrowed := q.Keeper.GetBorrowerBorrows(ctx, addr) - suppliedValue, err := q.Keeper.TotalTokenValue(ctx, supplied, false) + // supplied value always uses spot prices + suppliedValue, err := q.Keeper.TotalTokenValue(ctx, supplied, types.PriceModeSpot) if err != nil { return nil, err } - borrowedValue, err := q.Keeper.TotalTokenValue(ctx, borrowed, false) + // borrowed value here is shown using spot prices, but leverage logic instead uses + // the higher of spot or historic prices for each borrowed token when comparing it + // to borrow limit. + borrowedValue, err := q.Keeper.TotalTokenValue(ctx, borrowed, types.PriceModeSpot) if err != nil { return nil, err } + // collateral value always uses spot prices collateralValue, err := q.Keeper.CalculateCollateralValue(ctx, collateral) if err != nil { return nil, err } - spotBorrowLimit, err := q.Keeper.CalculateBorrowLimit(ctx, collateral, false) + // borrow limit shown here as it is used in leverage logic: + // using the lower of spot or historic prices for each collateral token + borrowLimit, err := q.Keeper.CalculateBorrowLimit(ctx, collateral) if err != nil { return nil, err } + // liquidation always uses spot prices liquidationThreshold, err := q.Keeper.CalculateLiquidationThreshold(ctx, collateral) if err != nil { return nil, err } - // must still return current values if historic prices are down - they will display as zero - historicBorrowedValue, _ := q.Keeper.TotalTokenValue(ctx, borrowed, true) - historicBorrowLimit, _ := q.Keeper.CalculateBorrowLimit(ctx, collateral, true) - - // borrow limit is the minimum of either spot or historic borrow limit - zero if historic prices are down - borrowLimit := sdk.MinDec(historicBorrowLimit, spotBorrowLimit) - return &types.QueryAccountSummaryResponse{ - SuppliedValue: suppliedValue, - CollateralValue: collateralValue, - BorrowedValue: borrowedValue, - BorrowLimit: borrowLimit, - LiquidationThreshold: liquidationThreshold, - HistoricBorrowedValue: historicBorrowedValue, - HistoricBorrowLimit: historicBorrowLimit, - SpotBorrowLimit: spotBorrowLimit, + SuppliedValue: suppliedValue, + CollateralValue: collateralValue, + BorrowedValue: borrowedValue, + BorrowLimit: borrowLimit, + LiquidationThreshold: liquidationThreshold, }, nil } @@ -318,19 +316,10 @@ func (q Querier) MaxWithdraw( } for _, denom := range denoms { - maxCurrentWithdraw, err := q.Keeper.maxWithdraw(ctx, addr, denom, false) - if err != nil { - return nil, err - } - maxHistoricWithdraw, err := q.Keeper.maxWithdraw(ctx, addr, denom, true) + uToken, err := q.Keeper.maxWithdraw(ctx, addr, denom) if err != nil { return nil, err } - - uToken := sdk.NewCoin( - maxCurrentWithdraw.Denom, - sdk.MinInt(maxCurrentWithdraw.Amount, maxHistoricWithdraw.Amount), - ) if uToken.IsPositive() { token, err := q.Keeper.ExchangeUToken(ctx, uToken) if err != nil { @@ -381,18 +370,10 @@ func (q Querier) MaxBorrow( } for _, denom := range denoms { - currentMaxBorrow, err := q.Keeper.maxBorrow(ctx, addr, denom, false) - if err != nil { - return nil, err - } - historicMaxBorrow, err := q.Keeper.maxBorrow(ctx, addr, denom, true) + maxBorrow, err := q.Keeper.maxBorrow(ctx, addr, denom) if err != nil { return nil, err } - maxBorrow := sdk.NewCoin( - currentMaxBorrow.Denom, - sdk.MinInt(currentMaxBorrow.Amount, historicMaxBorrow.Amount), - ) if maxBorrow.IsPositive() { maxTokens = maxTokens.Add(maxBorrow) } diff --git a/x/leverage/keeper/grpc_query_test.go b/x/leverage/keeper/grpc_query_test.go index 7053ad4a60..ae19d28c86 100644 --- a/x/leverage/keeper/grpc_query_test.go +++ b/x/leverage/keeper/grpc_query_test.go @@ -110,12 +110,6 @@ func (s *IntegrationTestSuite) TestQuerier_AccountSummary() { BorrowedValue: sdk.ZeroDec(), // (1000) * 4.21 * 0.25 = 1052.5 BorrowLimit: sdk.MustNewDecFromStr("1052.5"), - // Nothing borrowed - HistoricBorrowedValue: sdk.ZeroDec(), - // (1000) * 4.21 * 0.25 = 1052.5 - HistoricBorrowLimit: sdk.MustNewDecFromStr("1052.5"), - // (1000) * 4.21 * 0.25 = 1052.5 - SpotBorrowLimit: sdk.MustNewDecFromStr("1052.5"), // (1000) * 4.21 * 0.25 = 1052.5 LiquidationThreshold: sdk.MustNewDecFromStr("1052.5"), } diff --git a/x/leverage/keeper/iter.go b/x/leverage/keeper/iter.go index 0dbdadf53e..0721040165 100644 --- a/x/leverage/keeper/iter.go +++ b/x/leverage/keeper/iter.go @@ -182,7 +182,7 @@ func (k Keeper) GetEligibleLiquidationTargets(ctx sdk.Context) ([]sdk.AccAddress collateral := k.GetBorrowerCollateral(ctx, addr) // use oracle helper functions to find total borrowed value in USD - borrowValue, err := k.TotalTokenValue(ctx, borrowed, false) + borrowValue, err := k.TotalTokenValue(ctx, borrowed, types.PriceModeSpot) if err != nil { return err } diff --git a/x/leverage/keeper/limits.go b/x/leverage/keeper/limits.go index e95690bed4..db2dde9b97 100644 --- a/x/leverage/keeper/limits.go +++ b/x/leverage/keeper/limits.go @@ -7,8 +7,8 @@ import ( ) // maxWithdraw calculates the maximum amount of uTokens an account can currently withdraw. -// input denom should be a base token. Uses either real or historic prices. -func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string, historic bool) (sdk.Coin, error) { +// input denom should be a base token. +func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string) (sdk.Coin, error) { if types.HasUTokenPrefix(denom) { return sdk.Coin{}, types.ErrUToken } @@ -24,8 +24,8 @@ func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string, totalCollateral := k.GetBorrowerCollateral(ctx, addr) specificCollateral := sdk.NewCoin(uDenom, totalCollateral.AmountOf(uDenom)) - // calculate borrowed value for the account - borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, historic) + // calculate borrowed value for the account, using the higher of spot or historic prices for each token + borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, types.PriceModeHigh) if err != nil { return sdk.Coin{}, err } @@ -38,7 +38,7 @@ func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string, } // for nonzero borrows, calculations are based on unused borrow limit - borrowLimit, err := k.CalculateBorrowLimit(ctx, totalCollateral, historic) + borrowLimit, err := k.CalculateBorrowLimit(ctx, totalCollateral) if err != nil { return sdk.Coin{}, err } @@ -52,7 +52,7 @@ func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string, unusedBorrowLimit := borrowLimit.Sub(borrowedValue) // calculate the contribution to borrow limit made by only the type of collateral being withdrawn - specificBorrowLimit, err := k.CalculateBorrowLimit(ctx, sdk.NewCoins(specificCollateral), historic) + specificBorrowLimit, err := k.CalculateBorrowLimit(ctx, sdk.NewCoins(specificCollateral)) if err != nil { return sdk.Coin{}, err } @@ -77,8 +77,8 @@ func (k *Keeper) maxWithdraw(ctx sdk.Context, addr sdk.AccAddress, denom string, } // maxBorrow calculates the maximum amount of a given token an account can currently borrow. -// input denom should be a base token. Uses either current or historic prices. -func (k *Keeper) maxBorrow(ctx sdk.Context, addr sdk.AccAddress, denom string, historic bool) (sdk.Coin, error) { +// input denom should be a base token. +func (k *Keeper) maxBorrow(ctx sdk.Context, addr sdk.AccAddress, denom string) (sdk.Coin, error) { if types.HasUTokenPrefix(denom) { return sdk.Coin{}, types.ErrUToken } @@ -87,14 +87,14 @@ func (k *Keeper) maxBorrow(ctx sdk.Context, addr sdk.AccAddress, denom string, h totalBorrowed := k.GetBorrowerBorrows(ctx, addr) totalCollateral := k.GetBorrowerCollateral(ctx, addr) - // calculate borrowed value for the account - borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, historic) + // calculate borrowed value for the account, using the higher of spot or historic prices + borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, types.PriceModeHigh) if err != nil { return sdk.Coin{}, err } // calculate borrow limit for the account - borrowLimit, err := k.CalculateBorrowLimit(ctx, totalCollateral, historic) + borrowLimit, err := k.CalculateBorrowLimit(ctx, totalCollateral) if err != nil { return sdk.Coin{}, err } @@ -106,8 +106,8 @@ func (k *Keeper) maxBorrow(ctx sdk.Context, addr sdk.AccAddress, denom string, h // determine the USD amount of borrow limit that is currently unused unusedBorrowLimit := borrowLimit.Sub(borrowedValue) - // determine max borrow using current or historic prices - maxBorrow, err := k.TokenWithValue(ctx, denom, unusedBorrowLimit, historic) + // determine max borrow, using the higher of spot or historic prices for the token to borrow + maxBorrow, err := k.TokenWithValue(ctx, denom, unusedBorrowLimit, types.PriceModeHigh) if err != nil { return sdk.Coin{}, err } @@ -150,19 +150,14 @@ func (k *Keeper) maxCollateralFromShare(ctx sdk.Context, denom string) (sdkmath. // determine the max USD value this uToken's collateral is allowed to have by MaxCollateralShare maxValue := otherDenomsValue.Quo(sdk.OneDec().Sub(token.MaxCollateralShare)).Mul(token.MaxCollateralShare) - // determine the amount of uTokens which would be required to reach maxValue - tokenDenom := types.ToTokenDenom(denom) - tokenPrice, err := k.TokenBasePrice(ctx, tokenDenom) + // determine the amount of base tokens which would be required to reach maxValue, + // using the hgiher of spot or historic prices + udenom := types.ToUTokenDenom(denom) + maxUTokens, err := k.UTokenWithValue(ctx, udenom, maxValue, types.PriceModeHigh) if err != nil { return sdk.ZeroInt(), err } - uTokenExchangeRate := k.DeriveExchangeRate(ctx, tokenDenom) - - // in the case of a base token price smaller than the smallest sdk.Dec (10^-18), - // this maxCollateralAmount will use the price of 10^-18 and thus derive a lower - // (more cautious) limit than a precise price would produce - maxCollateralAmount := maxValue.Quo(tokenPrice).Quo(uTokenExchangeRate).TruncateInt() // return the computed maximum or the current uToken supply, whichever is smaller - return sdk.MinInt(k.GetUTokenSupply(ctx, denom).Amount, maxCollateralAmount), nil + return sdk.MinInt(k.GetUTokenSupply(ctx, denom).Amount, maxUTokens.Amount), nil } diff --git a/x/leverage/keeper/liquidate.go b/x/leverage/keeper/liquidate.go index 0edcdb131a..685b7b7141 100644 --- a/x/leverage/keeper/liquidate.go +++ b/x/leverage/keeper/liquidate.go @@ -28,7 +28,7 @@ func (k Keeper) getLiquidationAmounts( repayDenomBorrowed := sdk.NewCoin(repayDenom, totalBorrowed.AmountOf(repayDenom)) // calculate borrower health in USD values - borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, false) + borrowedValue, err := k.TotalTokenValue(ctx, totalBorrowed, types.PriceModeSpot) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } @@ -44,7 +44,7 @@ func (k Keeper) getLiquidationAmounts( // borrower is healthy and cannot be liquidated return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, types.ErrLiquidationIneligible } - repayDenomBorrowedValue, err := k.TokenValue(ctx, repayDenomBorrowed, false) + repayDenomBorrowedValue, err := k.TokenValue(ctx, repayDenomBorrowed, types.PriceModeSpot) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } @@ -75,7 +75,7 @@ func (k Keeper) getLiquidationAmounts( } // get precise (less rounding at high exponent) price ratio - priceRatio, err := k.PriceRatio(ctx, repayDenom, rewardDenom, false) + priceRatio, err := k.PriceRatio(ctx, repayDenom, rewardDenom, types.PriceModeSpot) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } diff --git a/x/leverage/keeper/msg_server.go b/x/leverage/keeper/msg_server.go index 36b4b1c01d..4500165199 100644 --- a/x/leverage/keeper/msg_server.go +++ b/x/leverage/keeper/msg_server.go @@ -99,19 +99,10 @@ func (s msgServer) MaxWithdraw( return nil, err } - maxCurrentWithdraw, err := s.keeper.maxWithdraw(ctx, supplierAddr, msg.Denom, false) + uToken, err := s.keeper.maxWithdraw(ctx, supplierAddr, msg.Denom) if err != nil { return nil, err } - maxHistoricWithdraw, err := s.keeper.maxWithdraw(ctx, supplierAddr, msg.Denom, true) - if err != nil { - return nil, err - } - - uToken := sdk.NewCoin( - maxCurrentWithdraw.Denom, - sdk.MinInt(maxCurrentWithdraw.Amount, maxHistoricWithdraw.Amount), - ) if uToken.IsZero() { return nil, types.ErrMaxWithdrawZero @@ -333,19 +324,10 @@ func (s msgServer) MaxBorrow( return nil, err } - currentMaxBorrow, err := s.keeper.maxBorrow(ctx, borrowerAddr, msg.Denom, false) + maxBorrow, err := s.keeper.maxBorrow(ctx, borrowerAddr, msg.Denom) if err != nil { return nil, err } - historicMaxBorrow, err := s.keeper.maxBorrow(ctx, borrowerAddr, msg.Denom, true) - if err != nil { - return nil, err - } - - maxBorrow := sdk.NewCoin( - msg.Denom, - sdk.MinInt(currentMaxBorrow.Amount, historicMaxBorrow.Amount), - ) if maxBorrow.IsZero() { return nil, types.ErrMaxBorrowZero } diff --git a/x/leverage/keeper/oracle.go b/x/leverage/keeper/oracle.go index e0a3c3dcac..f30f24352d 100644 --- a/x/leverage/keeper/oracle.go +++ b/x/leverage/keeper/oracle.go @@ -11,66 +11,59 @@ import ( var ten = sdk.MustNewDecFromStr("10") -// TokenBasePrice returns the USD value of a base token. Note, the token's denomination -// must be the base denomination, e.g. uumee. The x/oracle module must know of -// the base and display/symbol denominations for each exchange pair. E.g. it must -// know about the UMEE/USD exchange rate along with the uumee base denomination -// and the exponent. When error is nil, price is guaranteed to be positive. -func (k Keeper) TokenBasePrice(ctx sdk.Context, baseDenom string) (sdk.Dec, error) { - t, err := k.GetTokenSettings(ctx, baseDenom) - if err != nil { - return sdk.ZeroDec(), err - } - - if t.Blacklist { - return sdk.ZeroDec(), types.ErrBlacklisted - } - - price, err := k.oracleKeeper.GetExchangeRateBase(ctx, baseDenom) - if err != nil { - return sdk.ZeroDec(), sdkerrors.Wrap(err, "oracle") - } - - if price.IsNil() || !price.IsPositive() { - return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrInvalidOraclePrice, baseDenom) - } - - return price, nil -} - -// TokenDefaultDenomPrice returns the USD value of a token's symbol denom, e.g. `UMEE` (rather than `uumee`). +// TokenPrice returns the USD value of a token's symbol denom, e.g. `UMEE` (rather than `uumee`). // Note, the input denom must still be the base denomination, e.g. uumee. When error is nil, price is // guaranteed to be positive. Also returns the token's exponent to reduce redundant registry reads. -// If the historic parameter is true, uses a median of recent prices instead of current price. -func (k Keeper) TokenDefaultDenomPrice(ctx sdk.Context, baseDenom string, historic bool) (sdk.Dec, uint32, error) { +func (k Keeper) TokenPrice(ctx sdk.Context, baseDenom string, mode types.PriceMode) (sdk.Dec, uint32, error) { t, err := k.GetTokenSettings(ctx, baseDenom) if err != nil { return sdk.ZeroDec(), 0, err } - if t.Blacklist { return sdk.ZeroDec(), t.Exponent, types.ErrBlacklisted } - var price sdk.Dec + // if a token is exempt from historic pricing, all price modes return Spot price + if t.HistoricMedians == 0 { + mode = types.PriceModeSpot + } - if historic && t.HistoricMedians > 0 { - // historic price + var price, spotPrice, historicPrice sdk.Dec + if mode != types.PriceModeHistoric { + // spot price is required for modes other than historic + spotPrice, err = k.oracleKeeper.GetExchangeRate(ctx, t.SymbolDenom) + if err != nil { + return sdk.ZeroDec(), t.Exponent, sdkerrors.Wrap(err, "oracle") + } + } + if mode != types.PriceModeSpot { + // historic price is required for modes other than spot var numStamps uint32 - price, numStamps, err = k.oracleKeeper.MedianOfHistoricMedians(ctx, t.SymbolDenom, uint64(t.HistoricMedians)) - if err == nil && numStamps < t.HistoricMedians { + historicPrice, numStamps, err = k.oracleKeeper.MedianOfHistoricMedians( + ctx, t.SymbolDenom, uint64(t.HistoricMedians)) + if err != nil { + return sdk.ZeroDec(), t.Exponent, sdkerrors.Wrap(err, "oracle") + } + if numStamps < t.HistoricMedians { return sdk.ZeroDec(), t.Exponent, types.ErrNoHistoricMedians.Wrapf( "requested %d, got %d", t.HistoricMedians, numStamps, ) } - } else { - // current price - price, err = k.oracleKeeper.GetExchangeRate(ctx, t.SymbolDenom) } - if err != nil { - return sdk.ZeroDec(), t.Exponent, sdkerrors.Wrap(err, "oracle") + + switch mode { + case types.PriceModeSpot: + price = spotPrice + case types.PriceModeHistoric: + price = historicPrice + case types.PriceModeHigh: + price = sdk.MaxDec(spotPrice, historicPrice) + case types.PriceModeLow: + price = sdk.MinDec(spotPrice, historicPrice) + default: + return sdk.ZeroDec(), t.Exponent, types.ErrInvalidPriceMode.Wrapf("%d", mode) } if price.IsNil() || !price.IsPositive() { @@ -96,9 +89,8 @@ func exponent(input sdk.Dec, n int32) sdk.Dec { // returned if we cannot get the token's price or if it's not an accepted token. // Computation uses price of token's default denom to avoid rounding errors // for exponent >= 18 tokens. -// If the historic parameter is true, uses medians of recent prices instead of current prices. -func (k Keeper) TokenValue(ctx sdk.Context, coin sdk.Coin, historic bool) (sdk.Dec, error) { - p, exp, err := k.TokenDefaultDenomPrice(ctx, coin.Denom, historic) +func (k Keeper) TokenValue(ctx sdk.Context, coin sdk.Coin, mode types.PriceMode) (sdk.Dec, error) { + p, exp, err := k.TokenPrice(ctx, coin.Denom, mode) if err != nil { return sdk.ZeroDec(), err } @@ -108,14 +100,13 @@ func (k Keeper) TokenValue(ctx sdk.Context, coin sdk.Coin, historic bool) (sdk.D // TotalTokenValue returns the total value of all supplied tokens. It is // equivalent to the sum of TokenValue on each coin individually, except it // ignores unregistered and blacklisted tokens instead of returning an error. -// If the historic parameter is true, uses medians of recent prices instead of current prices. -func (k Keeper) TotalTokenValue(ctx sdk.Context, coins sdk.Coins, historic bool) (sdk.Dec, error) { +func (k Keeper) TotalTokenValue(ctx sdk.Context, coins sdk.Coins, mode types.PriceMode) (sdk.Dec, error) { total := sdk.ZeroDec() accepted := k.filterAcceptedCoins(ctx, coins) for _, c := range accepted { - v, err := k.TokenValue(ctx, c, historic) + v, err := k.TokenValue(ctx, c, mode) if err != nil { return sdk.ZeroDec(), err } @@ -126,11 +117,12 @@ func (k Keeper) TotalTokenValue(ctx sdk.Context, coins sdk.Coins, historic bool) return total, nil } -// TokenWithValue creates a token of a given denom with an given USD value, using either current -// or historic prices. Returns an error on invalid price or denom. -func (k Keeper) TokenWithValue(ctx sdk.Context, denom string, value sdk.Dec, historic bool) (sdk.Coin, error) { +// TokenWithValue creates a token of a given denom with an given USD value. +// Returns an error on invalid price or denom. Rounds down, i.e. the +// value of the token returned may be slightly less than the requested value. +func (k Keeper) TokenWithValue(ctx sdk.Context, denom string, value sdk.Dec, mode types.PriceMode) (sdk.Coin, error) { // get token price (guaranteed positive if nil error) and exponent - price, exp, err := k.TokenDefaultDenomPrice(ctx, denom, historic) + price, exp, err := k.TokenPrice(ctx, denom, mode) if err != nil { return sdk.Coin{}, err } @@ -140,17 +132,36 @@ func (k Keeper) TokenWithValue(ctx sdk.Context, denom string, value sdk.Dec, his return sdk.NewCoin(denom, amount.TruncateInt()), nil } +// UTokenWithValue creates a uToken of a given denom with an given USD value. +// Returns an error on invalid price or non-uToken denom. Rounds down, i.e. the +// value of the uToken returned may be slightly less than the requested value. +func (k Keeper) UTokenWithValue(ctx sdk.Context, denom string, value sdk.Dec, mode types.PriceMode) (sdk.Coin, error) { + base := types.ToTokenDenom(denom) + if base == "" { + return sdk.Coin{}, types.ErrNotUToken.Wrap(denom) + } + + token, err := k.TokenWithValue(ctx, base, value, mode) + if err != nil { + return sdk.Coin{}, err + } + + uTokenExchangeRate := k.DeriveExchangeRate(ctx, base) + uTokenAmount := sdk.NewDecFromInt(token.Amount).Quo(uTokenExchangeRate).TruncateInt() + + return sdk.NewCoin(denom, uTokenAmount), nil +} + // PriceRatio computes the ratio of the USD prices of two base tokens, as sdk.Dec(fromPrice/toPrice). // Will return an error if either token price is not positive, and guarantees a positive output. -// Computation uses price of token's default denom to avoid rounding errors for exponent >= 18 tokens, -// but returns in terms of base tokens. -// If the historic parameter is true, uses medians of recent prices instead of current prices. -func (k Keeper) PriceRatio(ctx sdk.Context, fromDenom, toDenom string, historic bool) (sdk.Dec, error) { - p1, e1, err := k.TokenDefaultDenomPrice(ctx, fromDenom, historic) +// Computation uses price of token's symbol denom to avoid rounding errors for exponent >= 18 tokens, +// but returns in terms of base tokens. Uses the same price mode for both token denoms involved. +func (k Keeper) PriceRatio(ctx sdk.Context, fromDenom, toDenom string, mode types.PriceMode) (sdk.Dec, error) { + p1, e1, err := k.TokenPrice(ctx, fromDenom, mode) if err != nil { return sdk.ZeroDec(), err } - p2, e2, err := k.TokenDefaultDenomPrice(ctx, toDenom, historic) + p2, e2, err := k.TokenPrice(ctx, toDenom, mode) if err != nil { return sdk.ZeroDec(), err } diff --git a/x/leverage/keeper/oracle_test.go b/x/leverage/keeper/oracle_test.go index 08d9d05e4e..73ee66c8be 100644 --- a/x/leverage/keeper/oracle_test.go +++ b/x/leverage/keeper/oracle_test.go @@ -78,118 +78,146 @@ func (m *mockOracleKeeper) Reset() { } } -func (s *IntegrationTestSuite) TestOracle_TokenBasePrice() { +func (s *IntegrationTestSuite) TestOracle_TokenPrice() { app, ctx, require := s.app, s.ctx, s.Require() - p, err := app.LeverageKeeper.TokenBasePrice(ctx, appparams.BondDenom) - require.NoError(err) - require.Equal(sdk.MustNewDecFromStr("0.00000421"), p) - - p, err = app.LeverageKeeper.TokenBasePrice(ctx, atomDenom) - require.NoError(err) - require.Equal(sdk.MustNewDecFromStr("0.00003938"), p) - - p, err = app.LeverageKeeper.TokenBasePrice(ctx, "foo") - require.ErrorIs(err, types.ErrNotRegisteredToken) - require.Equal(sdk.ZeroDec(), p) -} - -func (s *IntegrationTestSuite) TestOracle_TokenSymbolPrice() { - app, ctx, require := s.app, s.ctx, s.Require() - - p, e, err := app.LeverageKeeper.TokenDefaultDenomPrice(ctx, appparams.BondDenom, false) + p, e, err := app.LeverageKeeper.TokenPrice(ctx, appparams.BondDenom, types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("4.21"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, atomDenom, false) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, atomDenom, types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("39.38"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, "foo", false) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, "foo", types.PriceModeSpot) require.ErrorIs(err, types.ErrNotRegisteredToken) require.Equal(sdk.ZeroDec(), p) require.Equal(uint32(0), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, pumpDenom, false) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, pumpDenom, types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("2.0"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, dumpDenom, false) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, dumpDenom, types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("0.5"), p) require.Equal(uint32(6), e) // Now with historic = true - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, appparams.BondDenom, true) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, appparams.BondDenom, types.PriceModeHistoric) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("4.21"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, atomDenom, true) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, atomDenom, types.PriceModeHistoric) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("39.38"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, "foo", true) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, "foo", types.PriceModeHistoric) require.ErrorIs(err, types.ErrNotRegisteredToken) require.Equal(sdk.ZeroDec(), p) require.Equal(uint32(0), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, pumpDenom, true) + p, e, err = app.LeverageKeeper.TokenPrice(ctx, pumpDenom, types.PriceModeHistoric) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("1.00"), p) + require.Equal(uint32(6), e) + + p, e, err = app.LeverageKeeper.TokenPrice(ctx, dumpDenom, types.PriceModeHistoric) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("1.00"), p) require.Equal(uint32(6), e) - p, e, err = app.LeverageKeeper.TokenDefaultDenomPrice(ctx, dumpDenom, true) + // Additional high/low cases + + p, e, err = app.LeverageKeeper.TokenPrice(ctx, pumpDenom, types.PriceModeHigh) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("2.00"), p) + require.Equal(uint32(6), e) + + p, e, err = app.LeverageKeeper.TokenPrice(ctx, dumpDenom, types.PriceModeHigh) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("1.00"), p) + require.Equal(uint32(6), e) + + p, e, err = app.LeverageKeeper.TokenPrice(ctx, pumpDenom, types.PriceModeLow) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("1.00"), p) require.Equal(uint32(6), e) + + p, e, err = app.LeverageKeeper.TokenPrice(ctx, dumpDenom, types.PriceModeLow) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("0.50"), p) + require.Equal(uint32(6), e) } func (s *IntegrationTestSuite) TestOracle_TokenValue() { app, ctx, require := s.app, s.ctx, s.Require() // 2.4 UMEE * $4.21 - v, err := app.LeverageKeeper.TokenValue(ctx, coin(appparams.BondDenom, 2_400000), false) + v, err := app.LeverageKeeper.TokenValue(ctx, coin(appparams.BondDenom, 2_400000), types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("10.104"), v) - v, err = app.LeverageKeeper.TokenValue(ctx, coin("foo", 2_400000), false) + v, err = app.LeverageKeeper.TokenValue(ctx, coin("foo", 2_400000), types.PriceModeSpot) require.ErrorIs(err, types.ErrNotRegisteredToken) require.Equal(sdk.ZeroDec(), v) // 2.4 DUMP * $0.5 - v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), false) + v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("1.2"), v) // 2.4 PUMP * $2.00 - v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), false) + v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), types.PriceModeSpot) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("4.8"), v) // Now with historic = true // 2.4 UMEE * $4.21 - v, err = app.LeverageKeeper.TokenValue(ctx, coin(appparams.BondDenom, 2_400000), true) + v, err = app.LeverageKeeper.TokenValue(ctx, coin(appparams.BondDenom, 2_400000), types.PriceModeHistoric) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("10.104"), v) - v, err = app.LeverageKeeper.TokenValue(ctx, coin("foo", 2_400000), true) + v, err = app.LeverageKeeper.TokenValue(ctx, coin("foo", 2_400000), types.PriceModeHistoric) require.ErrorIs(err, types.ErrNotRegisteredToken) require.Equal(sdk.ZeroDec(), v) // 2.4 DUMP * $1.00 - v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), true) + v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), types.PriceModeHistoric) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("2.4"), v) // 2.4 PUMP * $1.00 - v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), true) + v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), types.PriceModeHistoric) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("2.4"), v) + + // Additional high/low cases + + // 2.4 DUMP * $1.00 + v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), types.PriceModeHigh) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("2.4"), v) + + // 2.4 PUMP * $2.00 + v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), types.PriceModeHigh) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("4.8"), v) + + // 2.4 DUMP * $0.50 + v, err = app.LeverageKeeper.TokenValue(ctx, coin(dumpDenom, 2_400000), types.PriceModeLow) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("1.2"), v) + + // 2.4 PUMP * $1.00 + v, err = app.LeverageKeeper.TokenValue(ctx, coin(pumpDenom, 2_400000), types.PriceModeLow) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("2.4"), v) } @@ -204,7 +232,7 @@ func (s *IntegrationTestSuite) TestOracle_TotalTokenValue() { coin(appparams.BondDenom, 2_400000), coin(atomDenom, 4_700000), ), - false, + types.PriceModeSpot, ) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("195.19"), v) @@ -217,7 +245,7 @@ func (s *IntegrationTestSuite) TestOracle_TotalTokenValue() { coin(atomDenom, 4_700000), coin("foo", 4_700000), ), - false, + types.PriceModeSpot, ) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("195.19"), v) @@ -231,43 +259,67 @@ func (s *IntegrationTestSuite) TestOracle_TotalTokenValue() { coin("foo", 4_700000), coin(dumpDenom, 2_000000), ), - true, + types.PriceModeHistoric, ) require.NoError(err) require.Equal(sdk.MustNewDecFromStr("197.19"), v) + + // uses the higher price for each token + v, err = app.LeverageKeeper.TotalTokenValue( + ctx, + sdk.NewCoins( + coin(pumpDenom, 1_000000), + coin(dumpDenom, 1_000000), + ), + types.PriceModeHigh, + ) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("3.00"), v) + + // uses the lower price for each token + v, err = app.LeverageKeeper.TotalTokenValue( + ctx, + sdk.NewCoins( + coin(pumpDenom, 1_000000), + coin(dumpDenom, 1_000000), + ), + types.PriceModeLow, + ) + require.NoError(err) + require.Equal(sdk.MustNewDecFromStr("1.50"), v) } func (s *IntegrationTestSuite) TestOracle_PriceRatio() { app, ctx, require := s.app, s.ctx, s.Require() - r, err := app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, atomDenom, false) + r, err := app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, atomDenom, types.PriceModeSpot) require.NoError(err) // $4.21 / $39.38 at same exponent require.Equal(sdk.MustNewDecFromStr("0.106907059421025901"), r) - r, err = app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, daiDenom, false) + r, err = app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, daiDenom, types.PriceModeSpot) require.NoError(err) // $4.21 / $1.00 at a difference of 12 exponent require.Equal(sdk.MustNewDecFromStr("4210000000000"), r) - r, err = app.LeverageKeeper.PriceRatio(ctx, daiDenom, appparams.BondDenom, false) + r, err = app.LeverageKeeper.PriceRatio(ctx, daiDenom, appparams.BondDenom, types.PriceModeSpot) require.NoError(err) // $1.00 / $4.21 at a difference of -12 exponent require.Equal(sdk.MustNewDecFromStr("0.000000000000237530"), r) - _, err = app.LeverageKeeper.PriceRatio(ctx, "foo", atomDenom, false) + _, err = app.LeverageKeeper.PriceRatio(ctx, "foo", atomDenom, types.PriceModeSpot) require.ErrorIs(err, types.ErrNotRegisteredToken) - _, err = app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, "foo", false) + _, err = app.LeverageKeeper.PriceRatio(ctx, appparams.BondDenom, "foo", types.PriceModeSpot) require.ErrorIs(err, types.ErrNotRegisteredToken) // current price of volatile assets - r, err = app.LeverageKeeper.PriceRatio(ctx, pumpDenom, dumpDenom, false) + r, err = app.LeverageKeeper.PriceRatio(ctx, pumpDenom, dumpDenom, types.PriceModeSpot) require.NoError(err) // $2.00 / $0.50 require.Equal(sdk.MustNewDecFromStr("4"), r) // historic price of volatile assets - r, err = app.LeverageKeeper.PriceRatio(ctx, pumpDenom, dumpDenom, true) + r, err = app.LeverageKeeper.PriceRatio(ctx, pumpDenom, dumpDenom, types.PriceModeHistoric) require.NoError(err) // $1.00 / $1.00 require.Equal(sdk.MustNewDecFromStr("1"), r) diff --git a/x/leverage/simulation/operations.go b/x/leverage/simulation/operations.go index ac4845cc9e..fc164b7287 100644 --- a/x/leverage/simulation/operations.go +++ b/x/leverage/simulation/operations.go @@ -409,7 +409,7 @@ func randomLiquidateFields( if err != nil { return liquidator, borrower, sdk.Coin{}, "", true } - borrowedValue, err := lk.TotalTokenValue(ctx, borrowed, false) + borrowedValue, err := lk.TotalTokenValue(ctx, borrowed, types.PriceModeSpot) if err != nil { return liquidator, borrower, sdk.Coin{}, "", true } diff --git a/x/leverage/types/errors.go b/x/leverage/types/errors.go index cb5481a086..b93ad179e5 100644 --- a/x/leverage/types/errors.go +++ b/x/leverage/types/errors.go @@ -8,10 +8,11 @@ import ( var ( // 1XX = General Validation - ErrEmptyAddress = sdkerrors.Register(ModuleName, 100, "empty address") - ErrNilAsset = sdkerrors.Register(ModuleName, 101, "nil asset") - ErrGetAmount = sdkerrors.Register(ModuleName, 102, "retrieved invalid amount") - ErrSetAmount = sdkerrors.Register(ModuleName, 103, "cannot set invalid amount") + ErrEmptyAddress = sdkerrors.Register(ModuleName, 100, "empty address") + ErrNilAsset = sdkerrors.Register(ModuleName, 101, "nil asset") + ErrGetAmount = sdkerrors.Register(ModuleName, 102, "retrieved invalid amount") + ErrSetAmount = sdkerrors.Register(ModuleName, 103, "cannot set invalid amount") + ErrInvalidPriceMode = sdkerrors.Register(ModuleName, 104, "invalid price mode") // 2XX = Token Registry ErrNotRegisteredToken = sdkerrors.Register(ModuleName, 200, "not a registered Token") diff --git a/x/leverage/types/oracle.go b/x/leverage/types/oracle.go new file mode 100644 index 0000000000..afed86226c --- /dev/null +++ b/x/leverage/types/oracle.go @@ -0,0 +1,15 @@ +package types + +// Enumerates different ways to request the price of a token +type PriceMode uint64 + +const ( + // Spot mode requests the most recent prices from oracle + PriceModeSpot PriceMode = iota + // Historic mode requests the median of the most recent historic medians + PriceModeHistoric + // High mode uses the higher of either Spot or Historic prices + PriceModeHigh + // Low mode uses the lower of either Spot or Historic prices + PriceModeLow +) diff --git a/x/leverage/types/query.pb.go b/x/leverage/types/query.pb.go index f573451294..de398fc371 100644 --- a/x/leverage/types/query.pb.go +++ b/x/leverage/types/query.pb.go @@ -427,19 +427,10 @@ type QueryAccountSummaryResponse struct { // It always uses spot prices. BorrowedValue github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=borrowed_value,json=borrowedValue,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"borrowed_value"` // Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing. - // It uses the lower of two borrow limits: spot_borrow_limit and historic_borrow_limit. + // The lower of spot or historic price for each collateral token is used when calculating borrow limits. BorrowLimit github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=borrow_limit,json=borrowLimit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"borrow_limit"` // Liquidation Threshold is the Borrowed Value at which the account becomes eligible for liquidation. LiquidationThreshold github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=liquidation_threshold,json=liquidationThreshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"liquidation_threshold"` - // Historic Borrowed Value is the sum of the USD value of all tokens the account has borrowed, - // including interest owed, using historic prices. - HistoricBorrowedValue github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=historic_borrowed_value,json=historicBorrowedValue,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"historic_borrowed_value"` - // Historic Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing, - // using historic prices. - HistoricBorrowLimit github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=historic_borrow_limit,json=historicBorrowLimit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"historic_borrow_limit"` - // Spot Borrow Limit is the maximum Borrowed Value the account is allowed to reach through direct borrowing, - // using spot prices. - SpotBorrowLimit github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,8,opt,name=spot_borrow_limit,json=spotBorrowLimit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"spot_borrow_limit"` } func (m *QueryAccountSummaryResponse) Reset() { *m = QueryAccountSummaryResponse{} } @@ -814,100 +805,97 @@ func init() { func init() { proto.RegisterFile("umee/leverage/v1/query.proto", fileDescriptor_1e8137dcabb0ccc7) } var fileDescriptor_1e8137dcabb0ccc7 = []byte{ - // 1476 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x98, 0x4d, 0x6f, 0x1b, 0x55, - 0x17, 0xc7, 0x33, 0x49, 0x9b, 0xc4, 0xc7, 0x71, 0x5e, 0x6e, 0x92, 0x66, 0xea, 0xa6, 0xb6, 0x3b, - 0x6d, 0xda, 0xb4, 0xcf, 0x13, 0x4f, 0xd3, 0xe7, 0x11, 0x12, 0x02, 0x09, 0xea, 0x16, 0x04, 0x28, - 0xad, 0x52, 0xb7, 0x05, 0xb5, 0x15, 0xb2, 0xae, 0x67, 0x2e, 0xce, 0x28, 0xf3, 0xe2, 0xce, 0x8c, - 0x1d, 0x1b, 0xa9, 0x1b, 0x24, 0xd8, 0x21, 0x81, 0x10, 0x0b, 0x96, 0x6c, 0xf9, 0x24, 0x59, 0x56, - 0x62, 0x83, 0x90, 0x08, 0xd0, 0x56, 0x2c, 0xfa, 0x05, 0xd8, 0xa2, 0xb9, 0x6f, 0x1e, 0x7b, 0xe2, - 0xd6, 0x19, 0x91, 0x55, 0x3c, 0x73, 0xcf, 0xf9, 0x9d, 0xff, 0x3d, 0x73, 0xef, 0xb9, 0xf7, 0x04, - 0x56, 0x5b, 0x0e, 0x21, 0xba, 0x4d, 0xda, 0xc4, 0xc7, 0x0d, 0xa2, 0xb7, 0x37, 0xf5, 0xc7, 0x2d, - 0xe2, 0x77, 0xcb, 0x4d, 0xdf, 0x0b, 0x3d, 0x34, 0x1f, 0x8d, 0x96, 0xc5, 0x68, 0xb9, 0xbd, 0x99, - 0x5f, 0x6d, 0x78, 0x5e, 0xc3, 0x26, 0x3a, 0x6e, 0x5a, 0x3a, 0x76, 0x5d, 0x2f, 0xc4, 0xa1, 0xe5, - 0xb9, 0x01, 0xb3, 0xcf, 0x17, 0x12, 0xb4, 0x06, 0x71, 0x49, 0x60, 0x89, 0xf1, 0x62, 0x62, 0x5c, - 0xb2, 0x99, 0xc1, 0x52, 0xc3, 0x6b, 0x78, 0xf4, 0xa7, 0x1e, 0xfd, 0x12, 0x58, 0xc3, 0x0b, 0x1c, - 0x2f, 0xd0, 0xeb, 0x38, 0x88, 0x9c, 0xea, 0x24, 0xc4, 0x9b, 0xba, 0xe1, 0x59, 0x2e, 0x1b, 0xd7, - 0x72, 0x90, 0xbd, 0x13, 0xa9, 0xde, 0xc6, 0x3e, 0x76, 0x02, 0xed, 0x16, 0x2c, 0xc6, 0x1e, 0xab, - 0x24, 0x68, 0x7a, 0x6e, 0x40, 0xd0, 0x1b, 0x30, 0xd9, 0xa4, 0x6f, 0x54, 0xa5, 0xa4, 0xac, 0x67, - 0xaf, 0xa9, 0xe5, 0xc1, 0xd9, 0x95, 0x99, 0x47, 0xe5, 0xc4, 0xfe, 0x41, 0x71, 0xac, 0xca, 0xad, - 0xb5, 0x15, 0x58, 0xa6, 0xb8, 0x2a, 0x69, 0x58, 0x41, 0x48, 0x7c, 0x62, 0xde, 0xf3, 0x76, 0x89, - 0x1b, 0x68, 0x0f, 0xe1, 0xec, 0xa1, 0x03, 0x32, 0xe2, 0x9b, 0x30, 0xed, 0xd3, 0x31, 0xbf, 0xab, - 0x2a, 0xa5, 0x89, 0xf5, 0xec, 0xb5, 0x95, 0x64, 0x4c, 0xea, 0xc3, 0x43, 0x4a, 0x73, 0xed, 0x0a, - 0x20, 0xca, 0xbe, 0x85, 0xfd, 0x5d, 0x12, 0xde, 0x6d, 0x39, 0x0e, 0xf6, 0xbb, 0x68, 0x09, 0x4e, - 0x9a, 0xc4, 0xf5, 0x1c, 0x3a, 0x83, 0x4c, 0x95, 0x3d, 0x68, 0x2f, 0x66, 0x20, 0x9f, 0x34, 0x96, - 0x2a, 0xce, 0xc1, 0x4c, 0xd0, 0x75, 0xea, 0x9e, 0x5d, 0x8b, 0xfb, 0x66, 0xd9, 0xbb, 0x9b, 0xd1, - 0x2b, 0x94, 0x87, 0x69, 0xd2, 0x69, 0x7a, 0x2e, 0x71, 0x43, 0x75, 0xbc, 0xa4, 0xac, 0xe7, 0xaa, - 0xf2, 0x19, 0xdd, 0x81, 0x19, 0xcf, 0xc7, 0x86, 0x4d, 0x6a, 0x4d, 0xdf, 0x32, 0x88, 0x3a, 0x11, - 0xb9, 0x57, 0xca, 0xfb, 0x07, 0x45, 0xe5, 0xd7, 0x83, 0xe2, 0xc5, 0x86, 0x15, 0xee, 0xb4, 0xea, - 0x65, 0xc3, 0x73, 0x74, 0xfe, 0x95, 0xd8, 0x9f, 0x8d, 0xc0, 0xdc, 0xd5, 0xc3, 0x6e, 0x93, 0x04, - 0xe5, 0x9b, 0xc4, 0xa8, 0x66, 0x19, 0x63, 0x3b, 0x42, 0xa0, 0x0e, 0x2c, 0xb5, 0xe8, 0xb4, 0x6b, - 0xa4, 0x63, 0xec, 0x60, 0xb7, 0x41, 0x6a, 0x3e, 0x0e, 0x89, 0x7a, 0x82, 0xa2, 0xdf, 0x8f, 0x52, - 0x31, 0x3a, 0xfa, 0xe5, 0x41, 0x71, 0xa9, 0x15, 0x26, 0x69, 0x55, 0xc4, 0x62, 0xbc, 0xc7, 0x5f, - 0x56, 0x71, 0x48, 0xd0, 0x23, 0x80, 0xa0, 0xd5, 0x6c, 0xda, 0xdd, 0xda, 0xf5, 0xed, 0x07, 0xea, - 0x49, 0x1a, 0xef, 0xed, 0x23, 0xc7, 0x13, 0x0c, 0xdc, 0xec, 0x56, 0x33, 0xec, 0xf7, 0xf5, 0xed, - 0x07, 0x11, 0xbc, 0xee, 0xf9, 0xbe, 0xb7, 0x47, 0xe1, 0x93, 0x69, 0xe1, 0x9c, 0x41, 0xe1, 0xec, - 0x77, 0x04, 0xff, 0x08, 0xa6, 0x69, 0x24, 0x8b, 0x98, 0xea, 0x94, 0xfc, 0x04, 0xa3, 0xa2, 0x3f, - 0x74, 0xc3, 0xaa, 0xf4, 0x8f, 0x58, 0x3e, 0x09, 0x88, 0xdf, 0x26, 0xa6, 0x3a, 0x9d, 0x8e, 0x25, - 0xfc, 0xd1, 0x6d, 0x00, 0xc3, 0xb3, 0x6d, 0x1c, 0x12, 0x1f, 0xdb, 0x6a, 0x26, 0x15, 0x2d, 0x46, - 0x88, 0xb4, 0xb1, 0x49, 0x13, 0x53, 0x85, 0x74, 0xda, 0x84, 0x3f, 0xda, 0x82, 0x8c, 0x6d, 0x3d, - 0x6e, 0x59, 0xa6, 0x15, 0x76, 0xd5, 0x6c, 0x2a, 0x58, 0x0f, 0x80, 0xee, 0xc3, 0xac, 0x83, 0x3b, - 0x96, 0xd3, 0x72, 0x6a, 0x2c, 0x82, 0x3a, 0x93, 0x0a, 0x99, 0xe3, 0x94, 0x0a, 0x85, 0xa0, 0x4f, - 0x01, 0x09, 0x6c, 0x2c, 0x91, 0xb9, 0x54, 0xe8, 0x05, 0x4e, 0xba, 0xd1, 0xcb, 0xe7, 0x23, 0x58, - 0x70, 0x2c, 0x97, 0xe2, 0x7b, 0xb9, 0x98, 0x4d, 0x45, 0x9f, 0xe7, 0xa0, 0x2d, 0x99, 0x12, 0x13, - 0x72, 0x7c, 0x23, 0xb3, 0x5d, 0xa0, 0xce, 0x51, 0xf0, 0x3b, 0x47, 0x03, 0xbf, 0x3c, 0x28, 0xe6, - 0xf8, 0x0e, 0x66, 0x98, 0xea, 0x0c, 0xa3, 0xde, 0xa5, 0x4f, 0xe8, 0x01, 0xcc, 0xe3, 0x36, 0xb6, - 0x6c, 0x5c, 0xb7, 0x89, 0x48, 0xfd, 0x7c, 0xaa, 0x19, 0xcc, 0x49, 0x4e, 0x2f, 0xf9, 0x3d, 0xf4, - 0x9e, 0x15, 0xee, 0x98, 0x3e, 0xde, 0x53, 0x17, 0xd2, 0x25, 0x5f, 0x92, 0x3e, 0xe1, 0x20, 0xd4, - 0x80, 0x95, 0x1e, 0xbe, 0xf7, 0x75, 0xad, 0xcf, 0x89, 0x8a, 0x52, 0xc5, 0x38, 0x25, 0x71, 0x37, - 0xe2, 0x34, 0x54, 0x87, 0x65, 0x5e, 0xa4, 0x77, 0xac, 0x20, 0xf4, 0x7c, 0xcb, 0xe0, 0xd5, 0x7a, - 0x31, 0x55, 0xb5, 0x5e, 0x64, 0xb0, 0x0f, 0x38, 0x8b, 0x56, 0x6d, 0xed, 0x2a, 0x2c, 0xd1, 0x53, - 0xe6, 0xba, 0x61, 0x78, 0x2d, 0x37, 0xac, 0x60, 0x1b, 0xbb, 0x06, 0x09, 0x90, 0x0a, 0x53, 0xd8, - 0x34, 0x7d, 0x12, 0x04, 0xfc, 0x68, 0x11, 0x8f, 0xda, 0x6f, 0xe3, 0xb0, 0x7a, 0x98, 0x8b, 0x3c, - 0x9a, 0x1a, 0xb1, 0xa2, 0xc6, 0x0e, 0xc8, 0xd3, 0x65, 0x26, 0xa8, 0x1c, 0x9d, 0xf5, 0x65, 0x7e, - 0xd6, 0x97, 0x6f, 0x78, 0x96, 0x5b, 0xb9, 0x1a, 0xe5, 0xea, 0xa7, 0xdf, 0x8b, 0xeb, 0x23, 0x4c, - 0x22, 0x72, 0x08, 0x62, 0x15, 0x6f, 0xb7, 0xaf, 0x4a, 0x8d, 0xff, 0xfb, 0xa1, 0xe2, 0x25, 0xac, - 0x11, 0x2b, 0x61, 0x13, 0xc7, 0x30, 0x2b, 0x01, 0xd7, 0x74, 0x7e, 0xd1, 0xe1, 0xe9, 0x15, 0xb7, - 0x84, 0xe1, 0x1f, 0xe4, 0xab, 0x49, 0x38, 0x73, 0x88, 0x87, 0xfc, 0x1e, 0xf7, 0x61, 0x56, 0xa4, - 0xac, 0xd6, 0xc6, 0x76, 0x8b, 0x30, 0xc0, 0x91, 0x96, 0x69, 0xb4, 0x7e, 0x72, 0x82, 0xf2, 0x71, - 0x04, 0x89, 0x36, 0x70, 0x2f, 0x3d, 0x1c, 0x3c, 0x9e, 0x0a, 0x3c, 0xd7, 0xe3, 0x30, 0xf4, 0x7d, - 0x98, 0x15, 0xe9, 0xe0, 0xe0, 0x89, 0x74, 0x8a, 0x05, 0x85, 0x61, 0xef, 0xc0, 0x0c, 0x3f, 0x86, - 0x6d, 0xcb, 0xb1, 0x42, 0x7e, 0x33, 0x39, 0x2a, 0x34, 0xcb, 0x18, 0x5b, 0x11, 0x02, 0x19, 0xb0, - 0xcc, 0x0a, 0x30, 0xbd, 0x31, 0xd7, 0xc2, 0x1d, 0x9f, 0x04, 0x3b, 0x9e, 0x6d, 0xf2, 0x5b, 0xc8, - 0x51, 0xd9, 0x4b, 0x31, 0xd8, 0x3d, 0xc1, 0x42, 0x9f, 0xc1, 0x8a, 0x2c, 0x00, 0x03, 0x79, 0x99, - 0x4c, 0x15, 0x66, 0x59, 0xe0, 0x2a, 0x7d, 0xf9, 0xa9, 0xc3, 0xf2, 0x40, 0x1c, 0x9e, 0xa8, 0xa9, - 0x54, 0x51, 0x16, 0xfb, 0xa3, 0xb0, 0x84, 0x3d, 0x84, 0x85, 0xa0, 0xe9, 0x85, 0xfd, 0xfc, 0xe9, - 0x74, 0xcb, 0x26, 0x02, 0xc5, 0xd8, 0xda, 0x69, 0x58, 0xa1, 0xfb, 0x60, 0x2b, 0x96, 0x44, 0xec, - 0x37, 0x48, 0x18, 0x68, 0x6f, 0x41, 0x71, 0xc8, 0x90, 0xdc, 0x26, 0x2a, 0x4c, 0x85, 0xec, 0x15, - 0xad, 0x5a, 0x99, 0xaa, 0x78, 0xd4, 0xe6, 0x20, 0x47, 0x9d, 0x2b, 0xd8, 0xbc, 0x49, 0xea, 0x61, - 0xa0, 0x55, 0x79, 0xf3, 0x20, 0x5e, 0xc4, 0x7a, 0x83, 0x3e, 0x46, 0x54, 0x23, 0x12, 0xad, 0x01, - 0x77, 0xe2, 0xcd, 0x81, 0x0c, 0x52, 0x81, 0x79, 0x7e, 0xdd, 0xef, 0xc8, 0x93, 0x66, 0xe8, 0x9e, - 0xef, 0xf5, 0x0c, 0xe3, 0xf1, 0x9e, 0xe1, 0x2f, 0x05, 0xd4, 0x41, 0x88, 0xd4, 0x46, 0x60, 0x8a, - 0x1d, 0xc0, 0xc1, 0x71, 0x54, 0x65, 0xc1, 0x46, 0x06, 0x4c, 0x86, 0x2c, 0xca, 0x31, 0x14, 0x64, - 0x8e, 0xd6, 0xde, 0x85, 0x59, 0x31, 0x4f, 0x7e, 0xe6, 0x1f, 0x35, 0x55, 0x4f, 0xe0, 0x54, 0x3f, - 0x41, 0xe6, 0xa9, 0x37, 0x01, 0xe5, 0xd8, 0x26, 0x70, 0xed, 0xef, 0x0c, 0x9c, 0xa4, 0xf1, 0x51, - 0x13, 0x26, 0x59, 0x83, 0x8a, 0xce, 0x26, 0xd7, 0x4a, 0xac, 0xe3, 0xcd, 0xaf, 0xbd, 0x72, 0x58, - 0xc8, 0xd7, 0x4a, 0x5f, 0xfc, 0xfc, 0xe2, 0xbb, 0xf1, 0x3c, 0x52, 0xf5, 0x44, 0x5b, 0xce, 0x5a, - 0x5f, 0xf4, 0x83, 0x02, 0xf3, 0x83, 0xdd, 0x2d, 0xba, 0x34, 0x84, 0x3e, 0x68, 0x98, 0xd7, 0x47, - 0x34, 0x94, 0x82, 0xfe, 0x43, 0x05, 0xad, 0xa1, 0xf3, 0x49, 0x41, 0xbe, 0xf4, 0xa9, 0xb1, 0xbc, - 0xa0, 0xaf, 0x15, 0xc8, 0xf5, 0x77, 0xc7, 0x17, 0x86, 0xc4, 0xeb, 0xb3, 0xca, 0xff, 0x77, 0x14, - 0x2b, 0x29, 0x69, 0x9d, 0x4a, 0xd2, 0x50, 0x29, 0x29, 0xc9, 0xa1, 0x0e, 0xb5, 0x80, 0x47, 0xff, - 0x5e, 0x81, 0xb9, 0xc1, 0xab, 0xd1, 0xc5, 0x21, 0xb1, 0x06, 0xec, 0xf2, 0xe5, 0xd1, 0xec, 0xa4, - 0xaa, 0x2b, 0x54, 0xd5, 0x05, 0xa4, 0x25, 0x55, 0x61, 0xe6, 0x52, 0xab, 0x0b, 0x0d, 0xdf, 0x2a, - 0x30, 0x3b, 0x70, 0x41, 0x58, 0x7b, 0x75, 0x38, 0x91, 0xa9, 0x8d, 0x91, 0xcc, 0xa4, 0xa8, 0xcb, - 0x54, 0xd4, 0x79, 0x74, 0x6e, 0xb8, 0x28, 0x91, 0xab, 0x1f, 0x15, 0x40, 0xc9, 0xfa, 0x8a, 0x2e, - 0x0f, 0x09, 0x98, 0x34, 0xcd, 0x6f, 0x8e, 0x6c, 0x2a, 0xf5, 0x6d, 0x50, 0x7d, 0x97, 0xd0, 0x5a, - 0x52, 0x5f, 0xdf, 0xc1, 0xcc, 0xc5, 0x74, 0x61, 0x5a, 0x14, 0x6d, 0x54, 0x1c, 0x12, 0x4d, 0x18, - 0xe4, 0x2f, 0xbd, 0xc6, 0x40, 0x8a, 0x38, 0x4f, 0x45, 0x9c, 0x45, 0x67, 0x92, 0x22, 0xea, 0xd8, - 0xac, 0x99, 0x34, 0xdc, 0x97, 0x0a, 0x64, 0xe3, 0xc5, 0x5d, 0x1b, 0xba, 0x64, 0xa5, 0x4d, 0xfe, - 0xca, 0xeb, 0x6d, 0xa4, 0x88, 0x8b, 0x54, 0x44, 0x09, 0x15, 0x0e, 0x5b, 0xd4, 0x1d, 0xd9, 0x07, - 0xa1, 0x27, 0x90, 0xe9, 0x95, 0xcd, 0xd2, 0xf0, 0x00, 0xcc, 0x22, 0xbf, 0xfe, 0x3a, 0x0b, 0x29, - 0xe0, 0x02, 0x15, 0x50, 0x40, 0xab, 0x87, 0x0b, 0x60, 0x27, 0x7e, 0xe5, 0xf6, 0xfe, 0x9f, 0x85, - 0xb1, 0xfd, 0x67, 0x05, 0xe5, 0xe9, 0xb3, 0x82, 0xf2, 0xc7, 0xb3, 0x82, 0xf2, 0xcd, 0xf3, 0xc2, - 0xd8, 0xd3, 0xe7, 0x85, 0xb1, 0x5f, 0x9e, 0x17, 0xc6, 0x1e, 0x5e, 0x8d, 0x55, 0xd2, 0x88, 0xb2, - 0xe1, 0x92, 0x70, 0xcf, 0xf3, 0x77, 0x19, 0xb2, 0xfd, 0x7f, 0xbd, 0xd3, 0xe3, 0xd2, 0xba, 0x5a, - 0x9f, 0xa4, 0xff, 0x2d, 0xfc, 0xdf, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x20, 0x47, 0x3c, - 0xf4, 0x14, 0x00, 0x00, + // 1425 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x98, 0xcf, 0x6f, 0x1b, 0x45, + 0x14, 0xc7, 0xb3, 0x49, 0x9b, 0xc4, 0xcf, 0x71, 0x92, 0x4e, 0xd3, 0x66, 0xeb, 0xa6, 0xb6, 0xbb, + 0x6d, 0xda, 0xb4, 0x10, 0x6f, 0x53, 0x10, 0x12, 0x02, 0x09, 0xea, 0x16, 0x04, 0x28, 0xad, 0x52, + 0xb7, 0x05, 0xb5, 0x15, 0xb2, 0xc6, 0xbb, 0x23, 0x67, 0x95, 0xfd, 0xe1, 0xee, 0xae, 0x1d, 0x1b, + 0xa9, 0x17, 0x24, 0x8e, 0x48, 0x20, 0xc4, 0x81, 0x23, 0x57, 0xfe, 0x92, 0x1c, 0x2b, 0x71, 0x41, + 0x48, 0x04, 0x68, 0x2b, 0x0e, 0xfd, 0x07, 0xb8, 0xa2, 0x9d, 0x5f, 0xbb, 0xf1, 0xc6, 0x8d, 0xb3, + 0x22, 0xa7, 0x78, 0x77, 0xde, 0xfb, 0xbc, 0xef, 0xbc, 0x99, 0x7d, 0xf3, 0x26, 0xb0, 0xd4, 0x71, + 0x08, 0xd1, 0x6d, 0xd2, 0x25, 0x3e, 0x6e, 0x11, 0xbd, 0xbb, 0xa6, 0x3f, 0xe9, 0x10, 0xbf, 0x5f, + 0x6d, 0xfb, 0x5e, 0xe8, 0xa1, 0xf9, 0x68, 0xb4, 0x2a, 0x46, 0xab, 0xdd, 0xb5, 0xe2, 0x52, 0xcb, + 0xf3, 0x5a, 0x36, 0xd1, 0x71, 0xdb, 0xd2, 0xb1, 0xeb, 0x7a, 0x21, 0x0e, 0x2d, 0xcf, 0x0d, 0x98, + 0x7d, 0xb1, 0x94, 0xa2, 0xb5, 0x88, 0x4b, 0x02, 0x4b, 0x8c, 0x97, 0x53, 0xe3, 0x92, 0xcd, 0x0c, + 0x16, 0x5a, 0x5e, 0xcb, 0xa3, 0x3f, 0xf5, 0xe8, 0x97, 0xc0, 0x1a, 0x5e, 0xe0, 0x78, 0x81, 0xde, + 0xc4, 0x41, 0xe4, 0xd4, 0x24, 0x21, 0x5e, 0xd3, 0x0d, 0xcf, 0x72, 0xd9, 0xb8, 0x56, 0x80, 0xfc, + 0xdd, 0x48, 0xf5, 0x06, 0xf6, 0xb1, 0x13, 0x68, 0xb7, 0xe1, 0x64, 0xe2, 0xb1, 0x4e, 0x82, 0xb6, + 0xe7, 0x06, 0x04, 0xbd, 0x03, 0x93, 0x6d, 0xfa, 0x46, 0x55, 0x2a, 0xca, 0x4a, 0xfe, 0xba, 0x5a, + 0x1d, 0x9c, 0x5d, 0x95, 0x79, 0xd4, 0x8e, 0xed, 0xec, 0x96, 0xc7, 0xea, 0xdc, 0x5a, 0x5b, 0x84, + 0x53, 0x14, 0x57, 0x27, 0x2d, 0x2b, 0x08, 0x89, 0x4f, 0xcc, 0xfb, 0xde, 0x16, 0x71, 0x03, 0xed, + 0x11, 0x9c, 0xdb, 0x77, 0x40, 0x46, 0x7c, 0x17, 0xa6, 0x7d, 0x3a, 0xe6, 0xf7, 0x55, 0xa5, 0x32, + 0xb1, 0x92, 0xbf, 0xbe, 0x98, 0x8e, 0x49, 0x7d, 0x78, 0x48, 0x69, 0xae, 0x5d, 0x05, 0x44, 0xd9, + 0xb7, 0xb1, 0xbf, 0x45, 0xc2, 0x7b, 0x1d, 0xc7, 0xc1, 0x7e, 0x1f, 0x2d, 0xc0, 0x71, 0x93, 0xb8, + 0x9e, 0x43, 0x67, 0x90, 0xab, 0xb3, 0x07, 0xed, 0xe5, 0x0c, 0x14, 0xd3, 0xc6, 0x52, 0xc5, 0x79, + 0x98, 0x09, 0xfa, 0x4e, 0xd3, 0xb3, 0x1b, 0x49, 0xdf, 0x3c, 0x7b, 0x77, 0x2b, 0x7a, 0x85, 0x8a, + 0x30, 0x4d, 0x7a, 0x6d, 0xcf, 0x25, 0x6e, 0xa8, 0x8e, 0x57, 0x94, 0x95, 0x42, 0x5d, 0x3e, 0xa3, + 0xbb, 0x30, 0xe3, 0xf9, 0xd8, 0xb0, 0x49, 0xa3, 0xed, 0x5b, 0x06, 0x51, 0x27, 0x22, 0xf7, 0x5a, + 0x75, 0x67, 0xb7, 0xac, 0xfc, 0xbe, 0x5b, 0xbe, 0xd4, 0xb2, 0xc2, 0xcd, 0x4e, 0xb3, 0x6a, 0x78, + 0x8e, 0xce, 0x57, 0x89, 0xfd, 0x59, 0x0d, 0xcc, 0x2d, 0x3d, 0xec, 0xb7, 0x49, 0x50, 0xbd, 0x45, + 0x8c, 0x7a, 0x9e, 0x31, 0x36, 0x22, 0x04, 0xea, 0xc1, 0x42, 0x87, 0x4e, 0xbb, 0x41, 0x7a, 0xc6, + 0x26, 0x76, 0x5b, 0xa4, 0xe1, 0xe3, 0x90, 0xa8, 0xc7, 0x28, 0xfa, 0xe3, 0x28, 0x15, 0xa3, 0xa3, + 0x5f, 0xed, 0x96, 0x17, 0x3a, 0x61, 0x9a, 0x56, 0x47, 0x2c, 0xc6, 0x47, 0xfc, 0x65, 0x1d, 0x87, + 0x04, 0x3d, 0x06, 0x08, 0x3a, 0xed, 0xb6, 0xdd, 0x6f, 0xdc, 0xd8, 0x78, 0xa8, 0x1e, 0xa7, 0xf1, + 0xde, 0x3f, 0x74, 0x3c, 0xc1, 0xc0, 0xed, 0x7e, 0x3d, 0xc7, 0x7e, 0xdf, 0xd8, 0x78, 0x18, 0xc1, + 0x9b, 0x9e, 0xef, 0x7b, 0xdb, 0x14, 0x3e, 0x99, 0x15, 0xce, 0x19, 0x14, 0xce, 0x7e, 0x47, 0xf0, + 0xcf, 0x60, 0x9a, 0x46, 0xb2, 0x88, 0xa9, 0x4e, 0xc9, 0x25, 0x18, 0x15, 0xfd, 0xa9, 0x1b, 0xd6, + 0xa5, 0x7f, 0xc4, 0xf2, 0x49, 0x40, 0xfc, 0x2e, 0x31, 0xd5, 0xe9, 0x6c, 0x2c, 0xe1, 0x8f, 0xee, + 0x00, 0x18, 0x9e, 0x6d, 0xe3, 0x90, 0xf8, 0xd8, 0x56, 0x73, 0x99, 0x68, 0x09, 0x42, 0xa4, 0x8d, + 0x4d, 0x9a, 0x98, 0x2a, 0x64, 0xd3, 0x26, 0xfc, 0xd1, 0x3a, 0xe4, 0x6c, 0xeb, 0x49, 0xc7, 0x32, + 0xad, 0xb0, 0xaf, 0xe6, 0x33, 0xc1, 0x62, 0x00, 0x7a, 0x00, 0xb3, 0x0e, 0xee, 0x59, 0x4e, 0xc7, + 0x69, 0xb0, 0x08, 0xea, 0x4c, 0x26, 0x64, 0x81, 0x53, 0x6a, 0x14, 0x82, 0xbe, 0x04, 0x24, 0xb0, + 0x89, 0x44, 0x16, 0x32, 0xa1, 0x4f, 0x70, 0xd2, 0xcd, 0x38, 0x9f, 0x8f, 0xe1, 0x84, 0x63, 0xb9, + 0x14, 0x1f, 0xe7, 0x62, 0x36, 0x13, 0x7d, 0x9e, 0x83, 0xd6, 0x65, 0x4a, 0x4c, 0x28, 0xf0, 0x0f, + 0x99, 0x7d, 0x05, 0xea, 0x1c, 0x05, 0x7f, 0x70, 0x38, 0xf0, 0xab, 0xdd, 0x72, 0x81, 0x7f, 0xc1, + 0x0c, 0x53, 0x9f, 0x61, 0xd4, 0x7b, 0xf4, 0x09, 0x3d, 0x84, 0x79, 0xdc, 0xc5, 0x96, 0x8d, 0x9b, + 0x36, 0x11, 0xa9, 0x9f, 0xcf, 0x34, 0x83, 0x39, 0xc9, 0x89, 0x93, 0x1f, 0xa3, 0xb7, 0xad, 0x70, + 0xd3, 0xf4, 0xf1, 0xb6, 0x7a, 0x22, 0x5b, 0xf2, 0x25, 0xe9, 0x0b, 0x0e, 0x42, 0x2d, 0x58, 0x8c, + 0xf1, 0xf1, 0xea, 0x5a, 0x5f, 0x11, 0x15, 0x65, 0x8a, 0x71, 0x5a, 0xe2, 0x6e, 0x26, 0x69, 0xa8, + 0x09, 0xa7, 0x78, 0x91, 0xde, 0xb4, 0x82, 0xd0, 0xf3, 0x2d, 0x83, 0x57, 0xeb, 0x93, 0x99, 0xaa, + 0xf5, 0x49, 0x06, 0xfb, 0x84, 0xb3, 0x68, 0xd5, 0xd6, 0xae, 0xc1, 0x02, 0x3d, 0x65, 0x6e, 0x18, + 0x86, 0xd7, 0x71, 0xc3, 0x1a, 0xb6, 0xb1, 0x6b, 0x90, 0x00, 0xa9, 0x30, 0x85, 0x4d, 0xd3, 0x27, + 0x41, 0xc0, 0x8f, 0x16, 0xf1, 0xa8, 0xfd, 0x31, 0x0e, 0x4b, 0xfb, 0xb9, 0xc8, 0xa3, 0xa9, 0x95, + 0x28, 0x6a, 0xec, 0x80, 0x3c, 0x53, 0x65, 0x82, 0xaa, 0xd1, 0x59, 0x5f, 0xe5, 0x67, 0x7d, 0xf5, + 0xa6, 0x67, 0xb9, 0xb5, 0x6b, 0x51, 0xae, 0x7e, 0xf9, 0xb3, 0xbc, 0x32, 0xc2, 0x24, 0x22, 0x87, + 0x20, 0x51, 0xf1, 0xb6, 0xf6, 0x54, 0xa9, 0xf1, 0xff, 0x3f, 0x54, 0xb2, 0x84, 0xb5, 0x12, 0x25, + 0x6c, 0xe2, 0x08, 0x66, 0x25, 0xe0, 0x9a, 0xce, 0x1b, 0x1d, 0x9e, 0x5e, 0xd1, 0x25, 0x0c, 0x5f, + 0x90, 0xdd, 0x09, 0x38, 0xbb, 0x8f, 0x87, 0x5c, 0x8f, 0x07, 0x30, 0x2b, 0x52, 0xd6, 0xe8, 0x62, + 0xbb, 0x43, 0x18, 0xe0, 0x50, 0xdb, 0x34, 0xda, 0x3f, 0x05, 0x41, 0xf9, 0x3c, 0x82, 0x44, 0x1f, + 0x70, 0x9c, 0x1e, 0x0e, 0x1e, 0xcf, 0x04, 0x9e, 0x8b, 0x39, 0x0c, 0xfd, 0x00, 0x66, 0x45, 0x3a, + 0x38, 0x78, 0x22, 0x9b, 0x62, 0x41, 0x61, 0xd8, 0xbb, 0x30, 0xc3, 0x8f, 0x61, 0xdb, 0x72, 0xac, + 0x90, 0x77, 0x26, 0x87, 0x85, 0xe6, 0x19, 0x63, 0x3d, 0x42, 0x20, 0x03, 0x4e, 0xb1, 0x02, 0x4c, + 0x3b, 0xe6, 0x46, 0xb8, 0xe9, 0x93, 0x60, 0xd3, 0xb3, 0x4d, 0xde, 0x85, 0x1c, 0x96, 0xbd, 0x90, + 0x80, 0xdd, 0x17, 0x2c, 0xed, 0x0c, 0x2c, 0xd2, 0xf5, 0x5d, 0x4f, 0x0c, 0x62, 0xbf, 0x45, 0xc2, + 0x40, 0x7b, 0x0f, 0xca, 0x43, 0x86, 0xe4, 0xf2, 0xab, 0x30, 0x15, 0xb2, 0x57, 0xf4, 0x6b, 0xcc, + 0xd5, 0xc5, 0xa3, 0x36, 0x07, 0x05, 0xea, 0x5c, 0xc3, 0xe6, 0x2d, 0xd2, 0x0c, 0x03, 0xad, 0xce, + 0x9b, 0x62, 0xf1, 0x22, 0xd1, 0xf3, 0xee, 0x61, 0x44, 0x7b, 0x3f, 0xd5, 0xf2, 0x72, 0x27, 0xde, + 0xf4, 0xca, 0x20, 0x35, 0x98, 0xe7, 0x6d, 0x6c, 0x4f, 0x56, 0xd0, 0xa1, 0x7b, 0x39, 0xee, 0x85, + 0xc7, 0x93, 0xbd, 0xf0, 0x3f, 0x0a, 0xa8, 0x83, 0x10, 0xa9, 0x8d, 0xc0, 0x14, 0x3b, 0x58, 0x82, + 0xa3, 0xa8, 0x36, 0x82, 0x8d, 0x0c, 0x98, 0x0c, 0x59, 0x94, 0x23, 0x28, 0x34, 0x1c, 0xad, 0x7d, + 0x08, 0xb3, 0x62, 0x9e, 0xfc, 0x2c, 0x3b, 0x6c, 0xaa, 0x9e, 0xc2, 0xe9, 0xbd, 0x04, 0x99, 0xa7, + 0x78, 0x02, 0xca, 0x91, 0x4d, 0xe0, 0xfa, 0xbf, 0x39, 0x38, 0x4e, 0xe3, 0xa3, 0x36, 0x4c, 0xb2, + 0x8b, 0x17, 0x3a, 0x97, 0xde, 0x2b, 0x89, 0x9b, 0x5c, 0x71, 0xf9, 0xb5, 0xc3, 0x42, 0xbe, 0x56, + 0xf9, 0xfa, 0xd7, 0x97, 0x3f, 0x8c, 0x17, 0x91, 0xaa, 0xa7, 0xae, 0x9b, 0xec, 0x4a, 0x87, 0x7e, + 0x52, 0x60, 0x7e, 0xf0, 0xd6, 0x86, 0x2e, 0x0f, 0xa1, 0x0f, 0x1a, 0x16, 0xf5, 0x11, 0x0d, 0xa5, + 0xa0, 0x37, 0xa8, 0xa0, 0x65, 0x74, 0x21, 0x2d, 0xc8, 0x97, 0x3e, 0x0d, 0x96, 0x17, 0xf4, 0xad, + 0x02, 0x85, 0xbd, 0xb7, 0xbe, 0x8b, 0x43, 0xe2, 0xed, 0xb1, 0x2a, 0xbe, 0x39, 0x8a, 0x95, 0x94, + 0xb4, 0x42, 0x25, 0x69, 0xa8, 0x92, 0x96, 0xe4, 0x50, 0x87, 0x46, 0xc0, 0xa3, 0xff, 0xa8, 0xc0, + 0xdc, 0xe0, 0x91, 0x7f, 0x69, 0x48, 0xac, 0x01, 0xbb, 0x62, 0x75, 0x34, 0x3b, 0xa9, 0xea, 0x2a, + 0x55, 0x75, 0x11, 0x69, 0x69, 0x55, 0x98, 0xb9, 0x34, 0x9a, 0x42, 0xc3, 0xf7, 0x0a, 0xcc, 0x0e, + 0x1c, 0x7c, 0xcb, 0xaf, 0x0f, 0x27, 0x32, 0xb5, 0x3a, 0x92, 0x99, 0x14, 0x75, 0x85, 0x8a, 0xba, + 0x80, 0xce, 0x0f, 0x17, 0x25, 0x72, 0xf5, 0xb3, 0x02, 0x28, 0x5d, 0x5f, 0xd1, 0x95, 0x21, 0x01, + 0xd3, 0xa6, 0xc5, 0xb5, 0x91, 0x4d, 0xa5, 0xbe, 0x55, 0xaa, 0xef, 0x32, 0x5a, 0x4e, 0xeb, 0xdb, + 0x73, 0xe0, 0x70, 0x31, 0x7d, 0x98, 0x16, 0x45, 0x1b, 0x95, 0x87, 0x44, 0x13, 0x06, 0xc5, 0xcb, + 0x07, 0x18, 0x48, 0x11, 0x17, 0xa8, 0x88, 0x73, 0xe8, 0x6c, 0x5a, 0x44, 0x13, 0x9b, 0x0d, 0x93, + 0x86, 0xfb, 0x46, 0x81, 0x7c, 0xb2, 0xb8, 0x6b, 0x43, 0xb7, 0xac, 0xb4, 0x29, 0x5e, 0x3d, 0xd8, + 0x46, 0x8a, 0xb8, 0x44, 0x45, 0x54, 0x50, 0x69, 0xbf, 0x4d, 0xdd, 0x93, 0xfd, 0x3d, 0x7a, 0x0a, + 0xb9, 0xb8, 0x6c, 0x56, 0x86, 0x07, 0x60, 0x16, 0xc5, 0x95, 0x83, 0x2c, 0xa4, 0x80, 0x8b, 0x54, + 0x40, 0x09, 0x2d, 0xed, 0x2f, 0x80, 0xb5, 0x03, 0xb5, 0x3b, 0x3b, 0x7f, 0x97, 0xc6, 0x76, 0x9e, + 0x97, 0x94, 0x67, 0xcf, 0x4b, 0xca, 0x5f, 0xcf, 0x4b, 0xca, 0x77, 0x2f, 0x4a, 0x63, 0xcf, 0x5e, + 0x94, 0xc6, 0x7e, 0x7b, 0x51, 0x1a, 0x7b, 0x74, 0x2d, 0x51, 0x49, 0x23, 0xca, 0xaa, 0x4b, 0xc2, + 0x6d, 0xcf, 0xdf, 0x62, 0xc8, 0xee, 0xdb, 0x7a, 0x2f, 0xe6, 0xd2, 0xba, 0xda, 0x9c, 0xa4, 0xff, + 0x05, 0x7b, 0xeb, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x3b, 0x6b, 0x8a, 0xcc, 0x13, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1804,36 +1792,6 @@ func (m *QueryAccountSummaryResponse) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l - { - size := m.SpotBorrowLimit.Size() - i -= size - if _, err := m.SpotBorrowLimit.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 - { - size := m.HistoricBorrowLimit.Size() - i -= size - if _, err := m.HistoricBorrowLimit.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a - { - size := m.HistoricBorrowedValue.Size() - i -= size - if _, err := m.HistoricBorrowedValue.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 { size := m.LiquidationThreshold.Size() i -= size @@ -2355,12 +2313,6 @@ func (m *QueryAccountSummaryResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) l = m.LiquidationThreshold.Size() n += 1 + l + sovQuery(uint64(l)) - l = m.HistoricBorrowedValue.Size() - n += 1 + l + sovQuery(uint64(l)) - l = m.HistoricBorrowLimit.Size() - n += 1 + l + sovQuery(uint64(l)) - l = m.SpotBorrowLimit.Size() - n += 1 + l + sovQuery(uint64(l)) return n } @@ -4035,108 +3987,6 @@ func (m *QueryAccountSummaryResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HistoricBorrowedValue", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.HistoricBorrowedValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HistoricBorrowLimit", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.HistoricBorrowLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SpotBorrowLimit", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.SpotBorrowLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:])