diff --git a/CHANGELOG.md b/CHANGELOG.md index 0abe865018..a46ea81b20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features -- [2192](https://github.com/umee-network/umee/pull/2102) Add `MsgFastLiquidate` to `x/leverage` +- [2102](https://github.com/umee-network/umee/pull/2102) and [2106](https://github.com/umee-network/umee/pull/2106) Add `MsgLeveragedLiquidate` to `x/leverage` - [2085](https://github.com/umee-network/umee/pull/2085) Add `inspect` query to leverage module, which msut be enabled on a node by running with `-l` liquidator query flag. - [1952](https://github.com/umee-network/umee/pull/1952) Add `x/incentive` module. - [2015](https://github.com/umee-network/umee/pull/2015), [2050](https://github.com/umee-network/umee/pull/2050) Add `x/ugov` module. diff --git a/proto/umee/leverage/v1/tx.proto b/proto/umee/leverage/v1/tx.proto index b146d9d3e9..a4e62a0dfd 100644 --- a/proto/umee/leverage/v1/tx.proto +++ b/proto/umee/leverage/v1/tx.proto @@ -48,14 +48,15 @@ service Msg { // of the target's collateral. rpc Liquidate(MsgLiquidate) returns (MsgLiquidateResponse); - // FastLiquidate allows a user to repay a different user's borrowed coins in exchange for some - // of the target's collateral. For flash liquidations, the tokens to repay are borrowed instead of + // LeveragedLiquidate allows a user to repay a different user's borrowed coins in exchange for some + // of the target's collateral. For leveraged liquidations, the tokens to repay are borrowed instead of // being taken from the liquidator's wallet, and the reward is immediately collateralized. Borrow // limit checks for the liquidator are deferred until after the reward is collateralized, allowing // this initial borrow to exceed the liquidator's borrow limit as long as it is healthy by the end // of the transaction. Repay amount is calculated automatically, so the liquidator only specifies - // repay and reward token denoms. - rpc FastLiquidate(MsgFastLiquidate) returns (MsgFastLiquidateResponse); + // repay and reward token denoms. For safety, the liquidator cannot exceed 80% of their borrow limit when + // executing this transaction, instead of the regular 100%. + rpc LeveragedLiquidate(MsgLeveragedLiquidate) returns (MsgLeveragedLiquidateResponse); // SupplyCollateral combines the Supply and Collateralize actions. rpc SupplyCollateral(MsgSupplyCollateral) returns (MsgSupplyCollateralResponse); @@ -149,15 +150,15 @@ message MsgLiquidate { string reward_denom = 4; } -// MsgFastLiquidate is the request structure for the FastLiquidate RPC. -message MsgFastLiquidate { +// MsgLeveragedLiquidate is the request structure for the LeveragedLiquidate RPC. +message MsgLeveragedLiquidate { // Liquidator is the account address performing a liquidation and the signer // of the message. string liquidator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // Borrower is the account whose borrow is being repaid, and collateral consumed, // by the liquidation. It does not sign the message. string borrower = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // RepayDenom is the base token that the liquidator will borrow and repay on behalf of + // RepayDenom is the base token that the liquidator will borrow in order to repay on behalf of // the borrower. string repay_denom = 3; // RewardDenom is the uToken denom that the liquidator will receive as a liquidation reward @@ -226,8 +227,8 @@ message MsgLiquidateResponse { cosmos.base.v1beta1.Coin reward = 3 [(gogoproto.nullable) = false]; } -// MsgFastLiquidateResponse defines the Msg/FastLiquidate response type. -message MsgFastLiquidateResponse { +// MsgLeveragedLiquidateResponse defines the Msg/LeveragedLiquidate response type. +message MsgLeveragedLiquidateResponse { // Repaid is the amount of base tokens that the liquidator borrowed and repaid // to the module on behalf of the borrower. cosmos.base.v1beta1.Coin repaid = 1 [(gogoproto.nullable) = false]; diff --git a/x/leverage/README.md b/x/leverage/README.md index 99bf7fcac0..7b59cc6dc4 100644 --- a/x/leverage/README.md +++ b/x/leverage/README.md @@ -295,7 +295,34 @@ umeed start ## Messages -See [leverage tx proto](https://github.com/umee-network/umee/blob/main/proto/umee/leverage/v1/tx.proto#L11) for list of supported messages. +See [leverage tx proto](https://github.com/umee-network/umee/blob/main/proto/umee/leverage/v1/tx.proto#L11) for full documentation of supported messages. + +Here are their basic functions: + +### Supplying + +- `MsgSupply`: Supplies base tokens to the module and receives uTokens in exchange. UTokens can later be used to withdraw. +- `MsgWithdraw`: Exchanges uTokens for the base tokens originally supplied, plus interest. UTokens withdrawn can be any combination of wallet uTokens (from supply) or collateral uTokens. When withdrawing collateral, borrow limit cannot be exceeded or the withdrawal will fail. +- `MsgMaxWithdraw`: Withdraws the maximum allowed amount of uTokens, respecting the user's borrow limit and the module's liquidity requirements, if any. + +### Collateralizing + +- `MsgCollateralize`: Sends uTokens to the module as the collateral. Collateral increases a user's borrow limit, but can be siezed in a liquidation if borrowed value exceeds a certain threshold above borrow limit due to price movements or interest owed. Collateral tokens still earn supply interest while collateralized. +- `MsgSupplyCollateral`: Combines `MsgSupply` and `MsgCollateralize`. +- `MsgDecollateralize`: Returns some collateral uTokens to wallet balance, without withdrawing base tokens. Borrow limit cannot be exceeded or the decollateralize will fail. + +### Borrowing + +- `MsgBorrow` Borrows base tokens from the module. Borrow limit cannot be exceeded or the transaction will fail. +- `MsgRepay` Repays borrowed tokens to the module, plus interest owed. + +### Liquidation + +- `MsgLiquidate` Liquidates a borrower whose borrowed value has exceeded their liquidation threshold (which is a certain amount above their borrow limit). The liquidator repays a portion of their debt using base tokens, and receives uTokens from the target's collateral, or the equivalent base tokens. The maximum liquidation amount is restricted by both the liquidator's specified amount and the borrower's liquidation eligibility, which may be partial. +- `MsgLeveragedLiquidate` Liquidates a borrower, but instead of repaying with base tokens from the liquidator wallet balance, moves the debt from the borrower to the liquidator and creates a new borrow position for the liquidator. Liquidator receives uTokens from the bororwer's collateral, and immediately collateralizes them to secure the liquidator positoin. + +This transaction will succeed even if the liquidator could not afford to borrow the initial tokens (thanks to the new collateral position acquired from the borrower), as long as they are below 80% usage of their new borrow limit after the reward collateral is added. +The liquidator is left with a new borrow that they must pay off, and new collateral which can eventually be withdrawn. ## Update Registry Proposal diff --git a/x/leverage/client/cli/tx.go b/x/leverage/client/cli/tx.go index ffd2007ba6..4eeb43767a 100644 --- a/x/leverage/client/cli/tx.go +++ b/x/leverage/client/cli/tx.go @@ -33,6 +33,7 @@ func GetTxCmd() *cobra.Command { GetCmdMaxBorrow(), GetCmdRepay(), GetCmdLiquidate(), + GetCmdLeveragedLiquidate(), GetCmdSupplyCollateral(), ) @@ -316,6 +317,55 @@ $ umeed tx leverage liquidate %s 50000000uumee u/uumee --from mykey`, return cmd } +// GetCmdLeveragedLiquidate creates a Cobra command to generate or broadcast a +// transaction with a MsgLeveragedLiquidate message. +func GetCmdLeveragedLiquidate() *cobra.Command { + cmd := &cobra.Command{ + Use: "lev-liquidate [borrower] [repay-denom] [reward-denom]", + Args: cobra.ExactArgs(3), + Short: "Liquidates by moving borrower debt to the liquidator and immediately collateralizes the reward.", + Long: strings.TrimSpace( + fmt.Sprintf(` +Borrow tokens to liquidate a borrower's debt and immediately collateralize the reward. + +Will attempt to repay the maximum amount allowed by the targeted borrower's debt and collateral positions. + +The transaction will fail if the liquidator, with new borrow and collateral positions, would be above 0.8 borrow limit. + +Example: +$ umeed tx leverage lev-liquidate %s uumee uumee --from mykey`, + "umee1qqy7cst5qm83ldupph2dcq0wypprkfpc9l3jg2", + ), + ), + + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + borrowerAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + repayDenom := args[1] + rewardDenom := args[2] + + msg := types.NewMsgLeveragedLiquidate(clientCtx.GetFromAddress(), borrowerAddr, repayDenom, rewardDenom) + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + // GetCmdSupplyCollateral creates a Cobra command to generate or broadcast a // transaction with a MsgSupply message. func GetCmdSupplyCollateral() *cobra.Command { diff --git a/x/leverage/client/tests/tests.go b/x/leverage/client/tests/tests.go index 483c8f6054..8d7f2201d0 100644 --- a/x/leverage/client/tests/tests.go +++ b/x/leverage/client/tests/tests.go @@ -235,6 +235,16 @@ func (s *IntegrationTests) TestLeverageScenario() { }, ExpectedErr: types.ErrLiquidationIneligible, } + leveragedLiquidate := itestsuite.TestTransaction{ + Name: "liquidate", + Command: cli.GetCmdLeveragedLiquidate(), + Args: []string{ + val.Address.String(), + "uumee", // borrower attempts to liquidate itself, but is ineligible + "uumee", + }, + ExpectedErr: types.ErrLiquidationIneligible, + } repay := itestsuite.TestTransaction{ Name: "repay", @@ -483,6 +493,7 @@ func (s *IntegrationTests) TestLeverageScenario() { // These transactions run after nonzero queries are finished s.RunTestTransactions( liquidate, + leveragedLiquidate, repay, removeCollateral, withdraw, diff --git a/x/leverage/keeper/borrows.go b/x/leverage/keeper/borrows.go index 14723bd40a..de73228f12 100644 --- a/x/leverage/keeper/borrows.go +++ b/x/leverage/keeper/borrows.go @@ -14,7 +14,10 @@ import ( // unless the remaining collateral is enough to cover all borrows. // 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 { +// MaxUsage sets the maximum percent of a user's borrow limit that can be in use: set to 1 +// to allow up to 100% borrow limit, or a lower value (e.g. 0.9) if a transaction should fail +// if a safety margin is desired (e.g. <90% borrow limit). +func (k Keeper) assertBorrowerHealth(ctx sdk.Context, borrowerAddr sdk.AccAddress, maxUsage sdk.Dec) error { borrowed := k.GetBorrowerBorrows(ctx, borrowerAddr) collateral := k.GetBorrowerCollateral(ctx, borrowerAddr) @@ -26,9 +29,9 @@ func (k Keeper) assertBorrowerHealth(ctx sdk.Context, borrowerAddr sdk.AccAddres if err != nil { return err } - if value.GT(limit) { + if value.GT(limit.Mul(maxUsage)) { return types.ErrUndercollaterized.Wrapf( - "borrowed: %s, limit: %s", value, limit) + "borrowed: %s, limit: %s, max usage %s", value, limit, maxUsage) } return nil } @@ -52,6 +55,16 @@ func (k Keeper) repayBorrow(ctx sdk.Context, fromAddr, borrowAddr sdk.AccAddress return k.setBorrow(ctx, borrowAddr, k.GetBorrow(ctx, borrowAddr, repay.Denom).Sub(repay)) } +// moveBorrow transfers a debt from fromAddr to toAddr without moving any tokens. This occurs during +// fast liquidations, where a liquidator takes on a borrower's debt. +func (k Keeper) moveBorrow(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, repay sdk.Coin) error { + err := k.setBorrow(ctx, fromAddr, k.GetBorrow(ctx, fromAddr, repay.Denom).Sub(repay)) + if err != nil { + return err + } + return k.setBorrow(ctx, toAddr, k.GetBorrow(ctx, toAddr, repay.Denom).Add(repay)) +} + // setBorrow sets the amount borrowed by an address in a given denom. // If the amount is zero, any stored value is cleared. func (k Keeper) setBorrow(ctx sdk.Context, borrowerAddr sdk.AccAddress, borrow sdk.Coin) error { diff --git a/x/leverage/keeper/collateral.go b/x/leverage/keeper/collateral.go index 316076e24c..018bf7b52f 100644 --- a/x/leverage/keeper/collateral.go +++ b/x/leverage/keeper/collateral.go @@ -50,6 +50,16 @@ func (k Keeper) decollateralize(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, toAddr, sdk.NewCoins(uToken)) } +// moveCollateral moves collateral from one address to another while keeping the uTokens in the module. +// It occurs during fast liquidations. +func (k Keeper) moveCollateral(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, uToken sdk.Coin) error { + err := k.setCollateral(ctx, fromAddr, k.GetCollateral(ctx, fromAddr, uToken.Denom).Sub(uToken)) + if err != nil { + return err + } + return k.setCollateral(ctx, toAddr, k.GetCollateral(ctx, toAddr, uToken.Denom).Add(uToken)) +} + // GetTotalCollateral returns an sdk.Coin representing how much of a given uToken // the x/leverage module account currently holds as collateral. Non-uTokens return zero. func (k Keeper) GetTotalCollateral(ctx sdk.Context, denom string) sdk.Coin { diff --git a/x/leverage/keeper/keeper.go b/x/leverage/keeper/keeper.go index ae19d4a25e..b11563e5c2 100644 --- a/x/leverage/keeper/keeper.go +++ b/x/leverage/keeper/keeper.go @@ -330,6 +330,7 @@ func (k Keeper) Liquidate( requestedRepay, rewardDenom, directLiquidation, + false, ) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err @@ -355,16 +356,8 @@ func (k Keeper) Liquidate( return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } - // if borrower's collateral has reached zero, mark any remaining borrows as bad debt - if err := k.checkBadDebt(ctx, borrowerAddr); err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err - } - - // finally, force incentive module to update bond and unbonding amounts if required, - // by ending existing unbondings early or instantly unbonding some bonded tokens - // until bonded + unbonding for the account is not greater than its collateral amount - err = k.reduceBondTo(ctx, borrowerAddr, k.GetCollateral(ctx, borrowerAddr, uTokenLiquidate.Denom)) - if err != nil { + // check for bad debt and trigger forced unbond hooks + if err := k.postLiquidate(ctx, borrowerAddr, uTokenLiquidate.Denom); err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Coin{}, err } @@ -375,9 +368,44 @@ func (k Keeper) Liquidate( return tokenRepay, uTokenLiquidate, uTokenLiquidate, nil } -// FastLiquidate -func (k Keeper) FastLiquidate( - _ sdk.Context, _, _ sdk.AccAddress, _, _ string, +// LeveragedLiquidate +func (k Keeper) LeveragedLiquidate( + ctx sdk.Context, liquidatorAddr, borrowerAddr sdk.AccAddress, repayDenom, rewardDenom string, ) (repaid sdk.Coin, reward sdk.Coin, err error) { - return sdk.Coin{}, sdk.Coin{}, err + if err := k.validateAcceptedDenom(ctx, repayDenom); err != nil { + return sdk.Coin{}, sdk.Coin{}, err + } + if err := k.validateAcceptedDenom(ctx, rewardDenom); err != nil { + return sdk.Coin{}, sdk.Coin{}, err + } + uRewardDenom := types.ToUTokenDenom(rewardDenom) + + tokenRepay, uTokenReward, _, err := k.getLiquidationAmounts( + ctx, + liquidatorAddr, + borrowerAddr, + sdk.NewCoin(repayDenom, sdk.OneInt()), // amount is ignored for LeveragedLiquidate + rewardDenom, + false, + true, + ) + if err != nil { + return sdk.Coin{}, sdk.Coin{}, err + } + if tokenRepay.IsZero() || uTokenReward.IsZero() { + return sdk.Coin{}, sdk.Coin{}, types.ErrLiquidationRepayZero + } + + // directly move debt from borrower to liquidator without transferring any tokens between accounts + if err := k.moveBorrow(ctx, borrowerAddr, liquidatorAddr, tokenRepay); err != nil { + return sdk.Coin{}, sdk.Coin{}, err + } + + // directly move collateral from borrower to liquidator while keeping it collateralized + if err := k.moveCollateral(ctx, borrowerAddr, liquidatorAddr, uTokenReward); err != nil { + return sdk.Coin{}, sdk.Coin{}, err + } + + // check for bad debt and trigger forced unbond hooks + return tokenRepay, uTokenReward, k.postLiquidate(ctx, borrowerAddr, uRewardDenom) } diff --git a/x/leverage/keeper/liquidate.go b/x/leverage/keeper/liquidate.go index b441cbcfde..54100681e7 100644 --- a/x/leverage/keeper/liquidate.go +++ b/x/leverage/keeper/liquidate.go @@ -17,6 +17,7 @@ func (k Keeper) getLiquidationAmounts( requestedRepay sdk.Coin, rewardDenom string, directLiquidation bool, + leveragedLiquidate bool, ) (tokenRepay sdk.Coin, collateralLiquidate sdk.Coin, tokenReward sdk.Coin, err error) { repayDenom := requestedRepay.Denom collateralDenom := types.ToUTokenDenom(rewardDenom) @@ -24,7 +25,6 @@ func (k Keeper) getLiquidationAmounts( // get relevant liquidator, borrower, and module balances borrowerCollateral := k.GetBorrowerCollateral(ctx, targetAddr) totalBorrowed := k.GetBorrowerBorrows(ctx, targetAddr) - availableRepay := k.bankKeeper.SpendableCoins(ctx, liquidatorAddr).AmountOf(repayDenom) repayDenomBorrowed := sdk.NewCoin(repayDenom, totalBorrowed.AmountOf(repayDenom)) // calculate borrower health in USD values, using spot prices only (no historic) @@ -93,10 +93,15 @@ func (k Keeper) getLiquidationAmounts( } // max repayment amount is limited by a number of factors - maxRepay := requestedRepay.Amount // maximum allowed by liquidator - maxRepay = sdk.MinInt(maxRepay, availableRepay) // liquidator account balance - maxRepay = sdk.MinInt(maxRepay, totalBorrowed.AmountOf(repayDenom)) // borrower position - maxRepay = sdk.MinInt(maxRepay, maxRepayAfterCloseFactor) // close factor + maxRepay := totalBorrowed.AmountOf(repayDenom) // borrower position + if !leveragedLiquidate { + // for traditional liquidations, liquidator account balance limits repayment + availableRepay := k.bankKeeper.SpendableCoins(ctx, liquidatorAddr).AmountOf(repayDenom) + maxRepay = sdk.MinInt(maxRepay, availableRepay) + // maximum requested by liquidator + maxRepay = sdk.MinInt(maxRepay, requestedRepay.Amount) + } + maxRepay = sdk.MinInt(maxRepay, maxRepayAfterCloseFactor) // close factor // compute final liquidation amounts repay, burn, reward := ComputeLiquidation( @@ -137,7 +142,6 @@ func ComputeLiquidation( // Start with the maximum possible repayment amount, as a decimal maxRepay := toDec(availableRepay) // Determine the base maxReward amount that would result from maximum repayment - maxReward := maxRepay.Mul(priceRatio).Mul(sdk.OneDec().Add(liquidationIncentive)) // Determine the maxCollateral burn amount that corresponds to base reward amount maxCollateral := maxReward.Quo(uTokenExchangeRate) @@ -161,7 +165,9 @@ func ComputeLiquidation( toDec(availableReward).Quo(maxReward), ) // Catch edge cases - ratio = sdk.MaxDec(ratio, sdk.ZeroDec()) + if !ratio.IsPositive() { + return sdk.ZeroInt(), sdk.ZeroInt(), sdk.ZeroInt() + } // Reduce repay and collateral limits by the most severe limiting factor encountered maxRepay = maxRepay.Mul(ratio) @@ -175,16 +181,11 @@ func ComputeLiquidation( // the module. It also ensures borrow dust is always eliminated when encountered. tokenRepay = maxRepay.Ceil().RoundInt() - // Next, the amount of collateral uToken the borrower will lose is rounded down. - // This is favors the borrower over the liquidator, and also protects the module. - collateralBurn = maxCollateral.TruncateInt() - - // One danger to rounding collateral burn down is that of collateral dust. This - // can be considered in two scenarios: - // 1) If collateral was the limiting factor above, then it will have already been - // an integer amount and truncating is a no-op. - // 2) If collateral was not the limiting factor, then there will be a non-dust - // quantity left over anyway. + // Next, the amount of collateral uToken the borrower will lose is rounded up. + // This also eliminates dust, but favors the liquidator over the module slightly. + // This is safe as long as the gas price of a transaction is greater than the value + // of the smallest possible unit of the collateral token. + collateralBurn = maxCollateral.Ceil().RoundInt() // Finally, the base token reward amount is derived directly from the collateral // to burn. This will round down identically to MsgWithdraw, favoring the module @@ -215,11 +216,11 @@ func ComputeLiquidation( // Finally, if borrowedValue is less than smallLiquidationSize, // closeFactor will always be 1 as long as the borrower is eligible for liquidation. func ComputeCloseFactor( - borrowedValue sdk.Dec, - collateralValue sdk.Dec, - liquidationThreshold sdk.Dec, - smallLiquidationSize sdk.Dec, - minimumCloseFactor sdk.Dec, + borrowedValue, + collateralValue, + liquidationThreshold, + smallLiquidationSize, + minimumCloseFactor, completeLiquidationThreshold sdk.Dec, ) (closeFactor sdk.Dec) { if borrowedValue.LT(liquidationThreshold) { @@ -257,3 +258,17 @@ func ComputeCloseFactor( return closeFactor } + +// postLiquidate flags any bad debt and informs incentive module of any changes to an account's +// uToken collateral after a liquidation has occurred. +func (k Keeper) postLiquidate(ctx sdk.Context, borrowerAddr sdk.AccAddress, uDenom string) error { + // if borrower's collateral has reached zero, mark any remaining borrows as bad debt + if err := k.checkBadDebt(ctx, borrowerAddr); err != nil { + return err + } + + // finally, force incentive module to update bond and unbonding amounts if required, + // by ending existing unbondings early or instantly unbonding some bonded tokens + // until bonded + unbonding for the account is not greater than its collateral amount + return k.reduceBondTo(ctx, borrowerAddr, k.GetCollateral(ctx, borrowerAddr, uDenom)) +} diff --git a/x/leverage/keeper/liquidate_test.go b/x/leverage/keeper/liquidate_test.go index e62a8933fd..f8876d55c0 100644 --- a/x/leverage/keeper/liquidate_test.go +++ b/x/leverage/keeper/liquidate_test.go @@ -125,7 +125,7 @@ func TestComputeLiquidation(t *testing.T) { expensiveBorrowDustDown.repayTokenPrice = sdk.MustNewDecFromStr("39.9") expensiveBorrowDustDown.rewardTokenPrice = sdk.MustNewDecFromStr("2") expensiveBorrowDustDown.liquidationIncentive = sdk.MustNewDecFromStr("0") - runTestCase(expensiveBorrowDustDown, 1, 19, 19, "expensive borrow dust with price down") + runTestCase(expensiveBorrowDustDown, 1, 20, 20, "expensive borrow dust with price down") // borrow dust case, with high borrowed token value rounds collateral burn up expensiveBorrowDustUp := baseCase() @@ -133,7 +133,7 @@ func TestComputeLiquidation(t *testing.T) { expensiveBorrowDustUp.repayTokenPrice = sdk.MustNewDecFromStr("40.1") expensiveBorrowDustUp.rewardTokenPrice = sdk.MustNewDecFromStr("2") expensiveBorrowDustUp.liquidationIncentive = sdk.MustNewDecFromStr("0") - runTestCase(expensiveBorrowDustUp, 1, 20, 20, "expensive borrow dust with price up") + runTestCase(expensiveBorrowDustUp, 1, 21, 21, "expensive borrow dust with price up") // borrow dust case, with low borrowed token value rounds collateral burn and reward to zero cheapBorrowDust := baseCase() @@ -141,7 +141,7 @@ func TestComputeLiquidation(t *testing.T) { cheapBorrowDust.repayTokenPrice = sdk.MustNewDecFromStr("2") cheapBorrowDust.rewardTokenPrice = sdk.MustNewDecFromStr("40") cheapBorrowDust.liquidationIncentive = sdk.MustNewDecFromStr("0") - runTestCase(cheapBorrowDust, 1, 0, 0, "cheap borrow dust") + runTestCase(cheapBorrowDust, 1, 1, 1, "cheap borrow dust") // collateral dust case, with high collateral token value and no rounding expensiveCollateralDust := baseCase() @@ -157,7 +157,7 @@ func TestComputeLiquidation(t *testing.T) { expensiveCollateralDustUp.repayTokenPrice = sdk.MustNewDecFromStr("2") expensiveCollateralDustUp.rewardTokenPrice = sdk.MustNewDecFromStr("40.1") expensiveCollateralDustUp.liquidationIncentive = sdk.MustNewDecFromStr("0") - runTestCase(expensiveCollateralDustUp, 21, 0, 0, "expensive collateral dust with price up") + runTestCase(expensiveCollateralDustUp, 21, 1, 1, "expensive collateral dust with price up") // collateral dust case, with high collateral token value rounds required repayment up expensiveCollateralDustDown := baseCase() @@ -165,7 +165,7 @@ func TestComputeLiquidation(t *testing.T) { expensiveCollateralDustDown.repayTokenPrice = sdk.MustNewDecFromStr("2") expensiveCollateralDustDown.rewardTokenPrice = sdk.MustNewDecFromStr("39.9") expensiveCollateralDustDown.liquidationIncentive = sdk.MustNewDecFromStr("0") - runTestCase(expensiveCollateralDustDown, 20, 0, 0, "expensive collateral dust with price down") + runTestCase(expensiveCollateralDustDown, 20, 1, 1, "expensive collateral dust with price down") // collateral dust case, with low collateral token value rounds required repayment up cheapCollateralDust := baseCase() diff --git a/x/leverage/keeper/msg_server.go b/x/leverage/keeper/msg_server.go index 53f2bc51db..01d2973662 100644 --- a/x/leverage/keeper/msg_server.go +++ b/x/leverage/keeper/msg_server.go @@ -77,7 +77,7 @@ func (s msgServer) Withdraw( // Fail here if supplier ends up over their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the borrower's collateral can cover all borrows if isFromCollateral { - err = s.keeper.assertBorrowerHealth(ctx, supplierAddr) + err = s.keeper.assertBorrowerHealth(ctx, supplierAddr, sdk.OneDec()) if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (s msgServer) MaxWithdraw( // Fail here if supplier ends up over their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the borrower's collateral can cover all borrows if isFromCollateral { - err = s.keeper.assertBorrowerHealth(ctx, supplierAddr) + err = s.keeper.assertBorrowerHealth(ctx, supplierAddr, sdk.OneDec()) if err != nil { return nil, err } @@ -288,7 +288,7 @@ func (s msgServer) Decollateralize( // Fail here if borrower ends up over their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the borrower's collateral can cover all borrows - err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr) + err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr, sdk.OneDec()) if err != nil { return nil, err } @@ -321,7 +321,7 @@ func (s msgServer) Borrow( // Fail here if borrower ends up over their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the borrower's collateral can cover all borrows - err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr) + err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr, sdk.OneDec()) if err != nil { return nil, err } @@ -390,7 +390,7 @@ func (s msgServer) MaxBorrow( // Fail here if borrower ends up over their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the borrower's collateral can cover all borrows - err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr) + err = s.keeper.assertBorrowerHealth(ctx, borrowerAddr, sdk.OneDec()) if err != nil { return nil, err } @@ -488,10 +488,10 @@ func (s msgServer) Liquidate( }, nil } -func (s msgServer) FastLiquidate( +func (s msgServer) LeveragedLiquidate( goCtx context.Context, - msg *types.MsgFastLiquidate, -) (*types.MsgFastLiquidateResponse, error) { + msg *types.MsgLeveragedLiquidate, +) (*types.MsgLeveragedLiquidateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) liquidator, err := sdk.AccAddressFromBech32(msg.Liquidator) @@ -503,20 +503,20 @@ func (s msgServer) FastLiquidate( return nil, err } - repaid, reward, err := s.keeper.FastLiquidate(ctx, liquidator, borrower, msg.RepayDenom, msg.RewardDenom) + repaid, reward, err := s.keeper.LeveragedLiquidate(ctx, liquidator, borrower, msg.RepayDenom, msg.RewardDenom) if err != nil { return nil, err } - // Fail here if liquidator ends up over their borrow limit under current or historic prices + // Fail here if liquidator ends up over 80% their borrow limit under current or historic prices // Tolerates missing collateral prices if the rest of the liquidator's collateral can cover all borrows - err = s.keeper.assertBorrowerHealth(ctx, liquidator) + err = s.keeper.assertBorrowerHealth(ctx, liquidator, sdk.MustNewDecFromStr("0.8")) if err != nil { return nil, err } s.keeper.Logger(ctx).Debug( - "unhealthy borrower fast-liquidated", + "unhealthy borrower leverage-liquidated", "liquidator", msg.Liquidator, "borrower", msg.Borrower, "repaid", repaid.String(), @@ -527,7 +527,7 @@ func (s msgServer) FastLiquidate( Borrower: msg.Borrower, Liquidated: reward, }) - return &types.MsgFastLiquidateResponse{ + return &types.MsgLeveragedLiquidateResponse{ Repaid: repaid, Reward: reward, }, nil diff --git a/x/leverage/keeper/msg_server_test.go b/x/leverage/keeper/msg_server_test.go index 1766b14e8b..628a4b343c 100644 --- a/x/leverage/keeper/msg_server_test.go +++ b/x/leverage/keeper/msg_server_test.go @@ -1921,8 +1921,8 @@ func (s *IntegrationTestSuite) TestMsgLiquidate() { coin.New(umeeDenom, 200_000000), "u/" + atomDenom, coin.New(umeeDenom, 30_000000), - coin.New("u/"+atomDenom, 3_527932), - coin.New("u/"+atomDenom, 3_527932), + coin.New("u/"+atomDenom, 3_527933), + coin.New("u/"+atomDenom, 3_527933), nil, }, { "close factor < 1", @@ -1931,8 +1931,8 @@ func (s *IntegrationTestSuite) TestMsgLiquidate() { coin.New(umeeDenom, 200_000000), "u/" + umeeDenom, coin.New(umeeDenom, 8_150541), - coin.New("u/"+umeeDenom, 8_965595), - coin.New("u/"+umeeDenom, 8_965595), + coin.New("u/"+umeeDenom, 8_965596), + coin.New("u/"+umeeDenom, 8_965596), nil, }, } @@ -2031,6 +2031,236 @@ func (s *IntegrationTestSuite) TestMsgLiquidate() { } } +func (s *IntegrationTestSuite) TestMsgLeveragedLiquidate() { + app, ctx, srv, require := s.app, s.ctx, s.msgSrvr, s.Require() + + // create and fund a liquidator which supplies plenty of UMEE and ATOM to the module + liquidator := s.newAccount(coin.New(umeeDenom, 10000_000000), coin.New(atomDenom, 10000_000000)) + s.supply(liquidator, coin.New(umeeDenom, 10000_000000), coin.New(atomDenom, 10000_000000)) + s.collateralize(liquidator, coin.New("u/"+umeeDenom, 10000_000000), coin.New("u/"+atomDenom, 10000_000000)) + + // create a healthy borrower + healthyBorrower := s.newAccount(coin.New(umeeDenom, 100_000000)) + s.supply(healthyBorrower, coin.New(umeeDenom, 100_000000)) + s.collateralize(healthyBorrower, coin.New("u/"+umeeDenom, 100_000000)) + s.borrow(healthyBorrower, coin.New(umeeDenom, 10_000000)) + + // create a borrower which supplies and collateralizes 1000 ATOM + atomBorrower := s.newAccount(coin.New(atomDenom, 1000_000000)) + s.supply(atomBorrower, coin.New(atomDenom, 1000_000000)) + s.collateralize(atomBorrower, coin.New("u/"+atomDenom, 1000_000000)) + // artificially borrow 500 ATOM - this can be liquidated without bad debt + s.forceBorrow(atomBorrower, coin.New(atomDenom, 500_000000)) + + // create a borrower which collateralizes 110 UMEE + umeeBorrower := s.newAccount(coin.New(umeeDenom, 300_000000)) + s.supply(umeeBorrower, coin.New(umeeDenom, 200_000000)) + s.collateralize(umeeBorrower, coin.New("u/"+umeeDenom, 110_000000)) + // artificially borrow 200 UMEE - this will create a bad debt when liquidated + s.forceBorrow(umeeBorrower, coin.New(umeeDenom, 200_000000)) + + // creates a complex borrower with multiple denoms active + complexBorrower := s.newAccount(coin.New(umeeDenom, 100_000000), coin.New(atomDenom, 100_000000)) + s.supply(complexBorrower, coin.New(umeeDenom, 100_000000), coin.New(atomDenom, 100_000000)) + s.collateralize(complexBorrower, coin.New("u/"+umeeDenom, 100_000000), coin.New("u/"+atomDenom, 100_000000)) + // artificially borrow multiple denoms + s.forceBorrow(complexBorrower, coin.New(atomDenom, 30_000000), coin.New(umeeDenom, 30_000000)) + + // creates a realistic borrower with 400 UMEE collateral which will have a close factor < 1 + closeBorrower := s.newAccount(coin.New(umeeDenom, 400_000000)) + s.supply(closeBorrower, coin.New(umeeDenom, 400_000000)) + s.collateralize(closeBorrower, coin.New("u/"+umeeDenom, 400_000000)) + // artificially borrow just barely above liquidation threshold to simulate interest accruing + s.forceBorrow(closeBorrower, coin.New(umeeDenom, 106_000000)) + + tcs := []struct { + msg string + liquidator sdk.AccAddress + borrower sdk.AccAddress + repayDenom string + rewardDenom string + expectedRepay sdk.Coin + expectedReward sdk.Coin + err error + }{ + { + "healthy borrower", + liquidator, + healthyBorrower, + atomDenom, + atomDenom, + sdk.Coin{}, + sdk.Coin{}, + types.ErrLiquidationIneligible, + }, { + "uToken repay", + liquidator, + umeeBorrower, + "u/" + umeeDenom, + umeeDenom, + sdk.Coin{}, + sdk.Coin{}, + types.ErrUToken, + }, { + "uToken reward", + liquidator, + umeeBorrower, + umeeDenom, + "u/" + umeeDenom, + sdk.Coin{}, + sdk.Coin{}, + types.ErrUToken, + }, { + "not registered repay", + liquidator, + umeeBorrower, + "foo", + umeeDenom, + sdk.Coin{}, + sdk.Coin{}, + types.ErrNotRegisteredToken, + }, { + "not registered reward", + liquidator, + umeeBorrower, + atomDenom, + "foo", + sdk.Coin{}, + sdk.Coin{}, + types.ErrNotRegisteredToken, + }, { + "not borrowed denom", + liquidator, + umeeBorrower, + atomDenom, + atomDenom, + sdk.Coin{}, + sdk.Coin{}, + types.ErrLiquidationRepayZero, + }, { + "complete u/atom liquidation", + liquidator, + atomBorrower, + atomDenom, + atomDenom, + coin.New(atomDenom, 500_000000), + coin.New("u/"+atomDenom, 550_000000), + nil, + }, { + "bad debt u/umee liquidation", + liquidator, + umeeBorrower, + umeeDenom, + umeeDenom, + coin.New(umeeDenom, 100_000000), + coin.New("u/"+umeeDenom, 110_000000), + nil, + }, { + "complex borrower", + liquidator, + complexBorrower, + umeeDenom, + atomDenom, + coin.New(umeeDenom, 30_000000), + coin.New("u/"+atomDenom, 3_527933), + nil, + }, { + "close factor < 1", + liquidator, + closeBorrower, + umeeDenom, + umeeDenom, + coin.New(umeeDenom, 8_150541), + coin.New("u/"+umeeDenom, 8_965596), + nil, + }, + } + + for _, tc := range tcs { + msg := &types.MsgLeveragedLiquidate{ + Liquidator: tc.liquidator.String(), + Borrower: tc.borrower.String(), + RepayDenom: tc.repayDenom, + RewardDenom: tc.rewardDenom, + } + if tc.err != nil { + _, err := srv.LeveragedLiquidate(ctx, msg) + require.ErrorIs(err, tc.err, tc.msg) + } else { + baseRewardDenom := types.ToTokenDenom(tc.expectedReward.Denom) + + // initial state (borrowed denom) + biUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + biExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, tc.repayDenom) + + // initial state (liquidated denom) + liUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + liExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, baseRewardDenom) + + // borrower initial state + biBalance := app.BankKeeper.GetAllBalances(ctx, tc.borrower) + biCollateral := app.LeverageKeeper.GetBorrowerCollateral(ctx, tc.borrower) + biBorrowed := app.LeverageKeeper.GetBorrowerBorrows(ctx, tc.borrower) + + // liquidator initial state + liBalance := app.BankKeeper.GetAllBalances(ctx, tc.liquidator) + liCollateral := app.LeverageKeeper.GetBorrowerCollateral(ctx, tc.liquidator) + liBorrowed := app.LeverageKeeper.GetBorrowerBorrows(ctx, tc.liquidator) + + // verify the output of fast-liquidate function + resp, err := srv.LeveragedLiquidate(ctx, msg) + require.NoError(err, tc.msg) + require.Equal(tc.expectedRepay.String(), resp.Repaid.String(), tc.msg) + require.Equal(tc.expectedReward.String(), resp.Reward.String(), tc.msg) + + // final state (liquidated denom) + lfUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + lfExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, baseRewardDenom) + + // borrower final state + bfBalance := app.BankKeeper.GetAllBalances(ctx, tc.borrower) + bfCollateral := app.LeverageKeeper.GetBorrowerCollateral(ctx, tc.borrower) + bfBorrowed := app.LeverageKeeper.GetBorrowerBorrows(ctx, tc.borrower) + + // liquidator final state + lfBalance := app.BankKeeper.GetAllBalances(ctx, tc.liquidator) + lfCollateral := app.LeverageKeeper.GetBorrowerCollateral(ctx, tc.liquidator) + lfBorrowed := app.LeverageKeeper.GetBorrowerBorrows(ctx, tc.liquidator) + + // final state (borrowed denom) + bfUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + bfExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, tc.repayDenom) + + // verify borrowed denom uToken supply is unchanged + require.Equal(biUTokenSupply, bfUTokenSupply, "%s: %s", tc.msg, "uToken supply (borrowed denom") + // verify borrowed denom uToken exchange rate is unchanged + require.Equal(biExchangeRate, bfExchangeRate, "%s: %s", tc.msg, "uToken exchange rate (borrowed denom") + + // verify liquidated denom uToken supply is unchanged + require.Equal(liUTokenSupply, lfUTokenSupply, "%s: %s", tc.msg, "uToken supply (liquidated denom") + // verify liquidated denom uToken exchange rate is unchanged + require.Equal(liExchangeRate, lfExchangeRate, "%s: %s", tc.msg, "uToken exchange rate (liquidated denom") + + // verify borrower balances unchanged + require.Equal(biBalance, bfBalance, "%s: %s", tc.msg, "borrower balances") + // verify borrower collateral reduced by the expected amount + s.requireEqualCoins(biCollateral.Sub(tc.expectedReward), bfCollateral, "%s: %s", tc.msg, "borrower collateral") + // verify borrowed coins decreased by expected amount + s.requireEqualCoins(biBorrowed.Sub(tc.expectedRepay), bfBorrowed, "borrowed coins") + + // verify liquidator balance unchanged + require.Equal(liBalance, lfBalance, tc.msg, "liquidator balances") + // verify liquidator collateral has increased + require.Equal(liCollateral.Add(tc.expectedReward), lfCollateral, "%s: %s", tc.msg, "liquidator collateral") + // verify liquidator borrowed coins has increased + s.requireEqualCoins(liBorrowed.Add(tc.expectedRepay), lfBorrowed, "liquidator borrowed coins") + + // check all available invariants + s.checkInvariants(tc.msg) + } + } +} + func (s *IntegrationTestSuite) TestMaxCollateralShare() { app, ctx, srv, require := s.app, s.ctx, s.msgSrvr, s.Require() diff --git a/x/leverage/types/tx.go b/x/leverage/types/tx.go index 2e6dbc935b..eb8a227d59 100644 --- a/x/leverage/types/tx.go +++ b/x/leverage/types/tx.go @@ -255,8 +255,9 @@ func (msg *MsgLiquidate) GetSignBytes() []byte { return sdk.MustSortJSON(bz) } -func NewMsgFastLiquidate(liquidator, borrower sdk.AccAddress, repayDenom, rewardDenom string) *MsgFastLiquidate { - return &MsgFastLiquidate{ +func NewMsgLeveragedLiquidate(liquidator, borrower sdk.AccAddress, repayDenom, rewardDenom string, +) *MsgLeveragedLiquidate { + return &MsgLeveragedLiquidate{ Liquidator: liquidator.String(), Borrower: borrower.String(), RepayDenom: repayDenom, @@ -264,10 +265,10 @@ func NewMsgFastLiquidate(liquidator, borrower sdk.AccAddress, repayDenom, reward } } -func (msg MsgFastLiquidate) Route() string { return sdk.MsgTypeURL(&msg) } -func (msg MsgFastLiquidate) Type() string { return sdk.MsgTypeURL(&msg) } +func (msg MsgLeveragedLiquidate) Route() string { return sdk.MsgTypeURL(&msg) } +func (msg MsgLeveragedLiquidate) Type() string { return sdk.MsgTypeURL(&msg) } -func (msg *MsgFastLiquidate) ValidateBasic() error { +func (msg *MsgLeveragedLiquidate) ValidateBasic() error { if err := validateSenderAndDenom(msg.Borrower, msg.RewardDenom); err != nil { return err } @@ -278,12 +279,12 @@ func (msg *MsgFastLiquidate) ValidateBasic() error { return err } -func (msg *MsgFastLiquidate) GetSigners() []sdk.AccAddress { +func (msg *MsgLeveragedLiquidate) GetSigners() []sdk.AccAddress { return checkers.Signers(msg.Liquidator) } // GetSignBytes get the bytes for the message signer to sign on -func (msg *MsgFastLiquidate) GetSignBytes() []byte { +func (msg *MsgLeveragedLiquidate) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } diff --git a/x/leverage/types/tx.pb.go b/x/leverage/types/tx.pb.go index ff19d1681f..962699b6f2 100644 --- a/x/leverage/types/tx.pb.go +++ b/x/leverage/types/tx.pb.go @@ -448,15 +448,15 @@ func (*MsgLiquidate) XXX_MessageName() string { return "umee.leverage.v1.MsgLiquidate" } -// MsgFastLiquidate is the request structure for the FastLiquidate RPC. -type MsgFastLiquidate struct { +// MsgLeveragedLiquidate is the request structure for the LeveragedLiquidate RPC. +type MsgLeveragedLiquidate struct { // Liquidator is the account address performing a liquidation and the signer // of the message. Liquidator string `protobuf:"bytes,1,opt,name=liquidator,proto3" json:"liquidator,omitempty"` // Borrower is the account whose borrow is being repaid, and collateral consumed, // by the liquidation. It does not sign the message. Borrower string `protobuf:"bytes,2,opt,name=borrower,proto3" json:"borrower,omitempty"` - // RepayDenom is the base token that the liquidator will borrow and repay on behalf of + // RepayDenom is the base token that the liquidator will borrow in order to repay on behalf of // the borrower. RepayDenom string `protobuf:"bytes,3,opt,name=repay_denom,json=repayDenom,proto3" json:"repay_denom,omitempty"` // RewardDenom is the uToken denom that the liquidator will receive as a liquidation reward @@ -464,18 +464,18 @@ type MsgFastLiquidate struct { RewardDenom string `protobuf:"bytes,4,opt,name=reward_denom,json=rewardDenom,proto3" json:"reward_denom,omitempty"` } -func (m *MsgFastLiquidate) Reset() { *m = MsgFastLiquidate{} } -func (m *MsgFastLiquidate) String() string { return proto.CompactTextString(m) } -func (*MsgFastLiquidate) ProtoMessage() {} -func (*MsgFastLiquidate) Descriptor() ([]byte, []int) { +func (m *MsgLeveragedLiquidate) Reset() { *m = MsgLeveragedLiquidate{} } +func (m *MsgLeveragedLiquidate) String() string { return proto.CompactTextString(m) } +func (*MsgLeveragedLiquidate) ProtoMessage() {} +func (*MsgLeveragedLiquidate) Descriptor() ([]byte, []int) { return fileDescriptor_72683128ee6e8843, []int{9} } -func (m *MsgFastLiquidate) XXX_Unmarshal(b []byte) error { +func (m *MsgLeveragedLiquidate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgFastLiquidate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgLeveragedLiquidate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgFastLiquidate.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgLeveragedLiquidate.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -485,20 +485,20 @@ func (m *MsgFastLiquidate) XXX_Marshal(b []byte, deterministic bool) ([]byte, er return b[:n], nil } } -func (m *MsgFastLiquidate) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgFastLiquidate.Merge(m, src) +func (m *MsgLeveragedLiquidate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgLeveragedLiquidate.Merge(m, src) } -func (m *MsgFastLiquidate) XXX_Size() int { +func (m *MsgLeveragedLiquidate) XXX_Size() int { return m.Size() } -func (m *MsgFastLiquidate) XXX_DiscardUnknown() { - xxx_messageInfo_MsgFastLiquidate.DiscardUnknown(m) +func (m *MsgLeveragedLiquidate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgLeveragedLiquidate.DiscardUnknown(m) } -var xxx_messageInfo_MsgFastLiquidate proto.InternalMessageInfo +var xxx_messageInfo_MsgLeveragedLiquidate proto.InternalMessageInfo -func (*MsgFastLiquidate) XXX_MessageName() string { - return "umee.leverage.v1.MsgFastLiquidate" +func (*MsgLeveragedLiquidate) XXX_MessageName() string { + return "umee.leverage.v1.MsgLeveragedLiquidate" } // MsgSupplyCollateral represents a user's request to supply and collateralize assets to the module. @@ -935,8 +935,8 @@ func (*MsgLiquidateResponse) XXX_MessageName() string { return "umee.leverage.v1.MsgLiquidateResponse" } -// MsgFastLiquidateResponse defines the Msg/FastLiquidate response type. -type MsgFastLiquidateResponse struct { +// MsgLeveragedLiquidateResponse defines the Msg/LeveragedLiquidate response type. +type MsgLeveragedLiquidateResponse struct { // Repaid is the amount of base tokens that the liquidator borrowed and repaid // to the module on behalf of the borrower. Repaid types.Coin `protobuf:"bytes,1,opt,name=repaid,proto3" json:"repaid"` @@ -945,18 +945,18 @@ type MsgFastLiquidateResponse struct { Reward types.Coin `protobuf:"bytes,2,opt,name=reward,proto3" json:"reward"` } -func (m *MsgFastLiquidateResponse) Reset() { *m = MsgFastLiquidateResponse{} } -func (m *MsgFastLiquidateResponse) String() string { return proto.CompactTextString(m) } -func (*MsgFastLiquidateResponse) ProtoMessage() {} -func (*MsgFastLiquidateResponse) Descriptor() ([]byte, []int) { +func (m *MsgLeveragedLiquidateResponse) Reset() { *m = MsgLeveragedLiquidateResponse{} } +func (m *MsgLeveragedLiquidateResponse) String() string { return proto.CompactTextString(m) } +func (*MsgLeveragedLiquidateResponse) ProtoMessage() {} +func (*MsgLeveragedLiquidateResponse) Descriptor() ([]byte, []int) { return fileDescriptor_72683128ee6e8843, []int{20} } -func (m *MsgFastLiquidateResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgLeveragedLiquidateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgFastLiquidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgLeveragedLiquidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgFastLiquidateResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgLeveragedLiquidateResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -966,20 +966,20 @@ func (m *MsgFastLiquidateResponse) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } -func (m *MsgFastLiquidateResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgFastLiquidateResponse.Merge(m, src) +func (m *MsgLeveragedLiquidateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgLeveragedLiquidateResponse.Merge(m, src) } -func (m *MsgFastLiquidateResponse) XXX_Size() int { +func (m *MsgLeveragedLiquidateResponse) XXX_Size() int { return m.Size() } -func (m *MsgFastLiquidateResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgFastLiquidateResponse.DiscardUnknown(m) +func (m *MsgLeveragedLiquidateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgLeveragedLiquidateResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgFastLiquidateResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgLeveragedLiquidateResponse proto.InternalMessageInfo -func (*MsgFastLiquidateResponse) XXX_MessageName() string { - return "umee.leverage.v1.MsgFastLiquidateResponse" +func (*MsgLeveragedLiquidateResponse) XXX_MessageName() string { + return "umee.leverage.v1.MsgLeveragedLiquidateResponse" } // MsgSupplyCollateralResponse defines the Msg/SupplyCollateral response type. @@ -1123,7 +1123,7 @@ func init() { proto.RegisterType((*MsgMaxBorrow)(nil), "umee.leverage.v1.MsgMaxBorrow") proto.RegisterType((*MsgRepay)(nil), "umee.leverage.v1.MsgRepay") proto.RegisterType((*MsgLiquidate)(nil), "umee.leverage.v1.MsgLiquidate") - proto.RegisterType((*MsgFastLiquidate)(nil), "umee.leverage.v1.MsgFastLiquidate") + proto.RegisterType((*MsgLeveragedLiquidate)(nil), "umee.leverage.v1.MsgLeveragedLiquidate") proto.RegisterType((*MsgSupplyCollateral)(nil), "umee.leverage.v1.MsgSupplyCollateral") proto.RegisterType((*MsgSupplyResponse)(nil), "umee.leverage.v1.MsgSupplyResponse") proto.RegisterType((*MsgWithdrawResponse)(nil), "umee.leverage.v1.MsgWithdrawResponse") @@ -1134,7 +1134,7 @@ func init() { proto.RegisterType((*MsgMaxBorrowResponse)(nil), "umee.leverage.v1.MsgMaxBorrowResponse") proto.RegisterType((*MsgRepayResponse)(nil), "umee.leverage.v1.MsgRepayResponse") proto.RegisterType((*MsgLiquidateResponse)(nil), "umee.leverage.v1.MsgLiquidateResponse") - proto.RegisterType((*MsgFastLiquidateResponse)(nil), "umee.leverage.v1.MsgFastLiquidateResponse") + proto.RegisterType((*MsgLeveragedLiquidateResponse)(nil), "umee.leverage.v1.MsgLeveragedLiquidateResponse") proto.RegisterType((*MsgSupplyCollateralResponse)(nil), "umee.leverage.v1.MsgSupplyCollateralResponse") proto.RegisterType((*MsgGovUpdateRegistry)(nil), "umee.leverage.v1.MsgGovUpdateRegistry") proto.RegisterType((*MsgGovUpdateRegistryResponse)(nil), "umee.leverage.v1.MsgGovUpdateRegistryResponse") @@ -1143,73 +1143,73 @@ func init() { func init() { proto.RegisterFile("umee/leverage/v1/tx.proto", fileDescriptor_72683128ee6e8843) } var fileDescriptor_72683128ee6e8843 = []byte{ - // 1042 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xbf, 0x8f, 0xe3, 0x54, - 0x10, 0x8e, 0xb3, 0x3f, 0x94, 0x4c, 0x76, 0x8f, 0x3d, 0xdf, 0x8a, 0xcb, 0xfa, 0x0e, 0x27, 0x18, - 0x0e, 0xad, 0x4e, 0xac, 0xcd, 0x2e, 0x1c, 0x20, 0xe0, 0x04, 0xe4, 0x4e, 0x9c, 0x74, 0x10, 0xe9, - 0x94, 0x05, 0x21, 0x90, 0x20, 0x38, 0xf1, 0xc3, 0xb1, 0x36, 0xf1, 0x0b, 0x7e, 0x2f, 0xc9, 0x86, - 0x92, 0x8a, 0x82, 0x82, 0x82, 0x82, 0x72, 0x0b, 0x4a, 0x0a, 0x0a, 0x5a, 0x5a, 0xb4, 0x74, 0x27, - 0x2a, 0x2a, 0x04, 0x9b, 0x02, 0xfe, 0x0c, 0xe4, 0xe7, 0xe7, 0x67, 0x3b, 0x71, 0xb2, 0x3e, 0xf6, - 0xd2, 0xe5, 0xbd, 0x99, 0xf9, 0xe6, 0x9b, 0x99, 0x37, 0x93, 0x31, 0xec, 0x0c, 0x7a, 0x08, 0x19, - 0x5d, 0x34, 0x44, 0x9e, 0x69, 0x23, 0x63, 0xb8, 0x6f, 0xd0, 0x63, 0xbd, 0xef, 0x61, 0x8a, 0xe5, - 0x2d, 0x5f, 0xa4, 0x87, 0x22, 0x7d, 0xb8, 0xaf, 0xa8, 0x6d, 0x4c, 0x7a, 0x98, 0x18, 0x2d, 0x93, - 0xf8, 0xaa, 0x2d, 0x44, 0xcd, 0x7d, 0xa3, 0x8d, 0x1d, 0x37, 0xb0, 0x50, 0xae, 0x72, 0x79, 0x8f, - 0xd8, 0x3e, 0x52, 0x8f, 0xd8, 0x5c, 0xb0, 0x13, 0x08, 0x9a, 0xec, 0x64, 0x04, 0x07, 0x2e, 0xda, - 0xb6, 0xb1, 0x8d, 0x83, 0x7b, 0xff, 0x17, 0xbf, 0xad, 0xcc, 0xd0, 0x12, 0x3c, 0x98, 0x82, 0xf6, - 0x29, 0x14, 0xeb, 0xc4, 0x3e, 0x1c, 0xf4, 0xfb, 0xdd, 0xb1, 0xac, 0x40, 0x81, 0xf8, 0xbf, 0x1c, - 0xe4, 0x95, 0xa5, 0xaa, 0xb4, 0x5b, 0x6c, 0x88, 0xb3, 0x7c, 0x0b, 0xd6, 0x4c, 0x42, 0x10, 0x2d, - 0xe7, 0xab, 0xd2, 0x6e, 0xe9, 0x60, 0x47, 0xe7, 0xde, 0xfd, 0x18, 0x74, 0x1e, 0x83, 0x7e, 0x07, - 0x3b, 0x6e, 0x6d, 0xf5, 0xf4, 0xcf, 0x4a, 0xae, 0x11, 0x68, 0x6b, 0x9f, 0x41, 0xa9, 0x4e, 0xec, - 0x0f, 0x1d, 0xda, 0xb1, 0x3c, 0x73, 0xb4, 0x0c, 0x0f, 0x35, 0xb8, 0x54, 0x27, 0x76, 0xdd, 0x3c, - 0xce, 0xe4, 0x64, 0x1b, 0xd6, 0x2c, 0xe4, 0xe2, 0x1e, 0x73, 0x52, 0x6c, 0x04, 0x07, 0x0d, 0xc1, - 0x56, 0x9d, 0xd8, 0x77, 0x70, 0xb7, 0x6b, 0x52, 0xe4, 0x99, 0x5d, 0xe7, 0x4b, 0xe4, 0xa3, 0xb4, - 0xb0, 0xe7, 0xe1, 0x51, 0x84, 0x12, 0x9e, 0xff, 0x2f, 0x55, 0x1b, 0xe4, 0x3a, 0xb1, 0xef, 0xa2, - 0xf6, 0xb2, 0x1d, 0x05, 0x55, 0xad, 0x31, 0x94, 0x65, 0xe0, 0xbf, 0x05, 0x1b, 0x41, 0xce, 0x33, - 0xb8, 0x48, 0xcf, 0xf8, 0x27, 0x50, 0xa8, 0x13, 0xbb, 0x81, 0xfa, 0xe6, 0x78, 0x19, 0x04, 0x7f, - 0x94, 0x18, 0xc3, 0xf7, 0x9c, 0x2f, 0x06, 0x8e, 0x65, 0x52, 0x24, 0xab, 0x00, 0x5d, 0x7e, 0xc0, - 0xa1, 0x97, 0xd8, 0x4d, 0x82, 0x43, 0x7e, 0x8a, 0xc3, 0x6d, 0x28, 0x7a, 0x3e, 0xd1, 0x1e, 0x72, - 0x69, 0x79, 0x25, 0x1b, 0x8f, 0xc8, 0x42, 0x7e, 0x1a, 0x36, 0x3c, 0x34, 0x32, 0x3d, 0xab, 0x19, - 0xe4, 0x61, 0x95, 0xc1, 0x97, 0x82, 0xbb, 0xbb, 0x2c, 0x1b, 0xbf, 0x4a, 0xec, 0x01, 0xbe, 0x63, - 0x12, 0x1a, 0x51, 0x7e, 0x75, 0x96, 0x72, 0xad, 0xfc, 0xfb, 0xcf, 0x7b, 0xdb, 0xdc, 0xf5, 0xdb, - 0x96, 0xe5, 0x21, 0x42, 0x0e, 0xa9, 0xe7, 0xb8, 0x76, 0x22, 0x98, 0x97, 0xa6, 0x83, 0x59, 0x60, - 0x17, 0x85, 0x59, 0x81, 0x12, 0x23, 0xcd, 0x69, 0xae, 0x04, 0x39, 0x62, 0x57, 0x8c, 0x65, 0x96, - 0x40, 0x3a, 0x70, 0x45, 0x8c, 0x93, 0xa8, 0x9d, 0x96, 0xd1, 0xf6, 0x0f, 0xe0, 0xb2, 0xf0, 0xd4, - 0x40, 0xa4, 0x8f, 0x5d, 0x82, 0xe4, 0xd7, 0xa1, 0xe0, 0xa1, 0x36, 0x72, 0x86, 0xc8, 0x62, 0x7e, - 0x32, 0xc0, 0x09, 0x03, 0xad, 0xc1, 0xb8, 0x87, 0x53, 0xe4, 0xf1, 0x60, 0x7e, 0x27, 0xc1, 0x93, - 0xc9, 0xe9, 0x24, 0x70, 0x6f, 0x43, 0x71, 0xc4, 0xef, 0xdc, 0xac, 0xc0, 0x91, 0x45, 0x82, 0x56, - 0xfe, 0x51, 0x69, 0x29, 0x50, 0x9e, 0x9e, 0x77, 0x21, 0x2f, 0xed, 0x3a, 0x28, 0xb3, 0x43, 0x4a, - 0x48, 0xaf, 0xb0, 0xb4, 0x07, 0x6d, 0x2f, 0x2e, 0x0f, 0x61, 0x3b, 0x3e, 0x0e, 0xe2, 0xa9, 0xe3, - 0xaf, 0x2b, 0x7b, 0xea, 0x42, 0x03, 0xed, 0x5d, 0xd6, 0x12, 0x6c, 0x42, 0x08, 0xc0, 0x57, 0x60, - 0xdd, 0x7f, 0x8f, 0x4e, 0x66, 0x38, 0xae, 0xae, 0xfd, 0x26, 0x31, 0x8a, 0xa2, 0xb9, 0x2e, 0x8c, - 0x28, 0xbf, 0x09, 0x10, 0x65, 0x28, 0x6b, 0x05, 0x62, 0x26, 0x81, 0x67, 0xbf, 0x73, 0xb2, 0x8e, - 0x14, 0xae, 0xae, 0x7d, 0x23, 0xb1, 0xea, 0x25, 0x86, 0xc5, 0xc5, 0xe3, 0x89, 0xe8, 0xe4, 0x1f, - 0x8d, 0xce, 0xe7, 0x70, 0x2d, 0xa5, 0xe5, 0x05, 0xa1, 0x7b, 0x70, 0x29, 0xf1, 0x92, 0x32, 0x13, - 0x9b, 0x32, 0xd3, 0x7e, 0xc8, 0xb3, 0x12, 0xde, 0xc3, 0xc3, 0x0f, 0xfa, 0x41, 0xc8, 0xb6, 0x43, - 0xa8, 0x37, 0x96, 0x5f, 0x86, 0xa2, 0x39, 0xa0, 0x1d, 0xec, 0x39, 0x74, 0x7c, 0xee, 0x98, 0x8c, - 0x54, 0xfd, 0x3f, 0x26, 0xea, 0xd0, 0x2e, 0x0a, 0xff, 0x98, 0xd8, 0x41, 0xae, 0x42, 0xc9, 0x42, - 0xa4, 0xed, 0x39, 0x7d, 0xea, 0x60, 0x97, 0x4f, 0xc1, 0xf8, 0x95, 0xfc, 0x06, 0x80, 0x69, 0x59, - 0x4d, 0x8a, 0x8f, 0x90, 0x4b, 0xca, 0xab, 0xd5, 0x95, 0xdd, 0xd2, 0xc1, 0x55, 0x7d, 0x7a, 0xc9, - 0xd3, 0xdf, 0xf7, 0xe5, 0x61, 0xdf, 0x9a, 0x96, 0xc5, 0xce, 0x44, 0xae, 0xc1, 0xe6, 0x80, 0xf1, - 0x0f, 0x01, 0xd6, 0xb2, 0x00, 0x6c, 0x04, 0x36, 0x01, 0xc6, 0x6b, 0xca, 0xd7, 0x27, 0x95, 0xdc, - 0xf7, 0x27, 0x95, 0xdc, 0xbf, 0x27, 0x15, 0xe9, 0xab, 0x7f, 0x7e, 0xba, 0x19, 0x45, 0xa5, 0xa9, - 0x70, 0x3d, 0x2d, 0x4b, 0x61, 0x3d, 0x0e, 0x7e, 0x29, 0xc0, 0x4a, 0x9d, 0xd8, 0xf2, 0x7d, 0x58, - 0xe7, 0x5b, 0xdf, 0xb5, 0x59, 0xd7, 0xa2, 0xa0, 0xca, 0x33, 0x0b, 0x84, 0xa2, 0xc6, 0x0f, 0xa0, - 0x20, 0x96, 0xaf, 0xa7, 0x52, 0x0d, 0x42, 0xb1, 0x72, 0x63, 0xa1, 0x58, 0x20, 0x7e, 0x04, 0xa5, - 0xf8, 0x46, 0x57, 0x4d, 0xb5, 0x8a, 0x69, 0x28, 0xbb, 0xe7, 0x69, 0x08, 0xe8, 0x26, 0x6c, 0x26, - 0x17, 0x3d, 0x2d, 0xd5, 0x34, 0xa1, 0xa3, 0xdc, 0x3c, 0x5f, 0x47, 0x38, 0x40, 0xf0, 0xc4, 0xf4, - 0x8a, 0xf7, 0x6c, 0xaa, 0xf9, 0x94, 0x96, 0xf2, 0x7c, 0x16, 0x2d, 0xe1, 0xe6, 0x3e, 0xac, 0xf3, - 0xed, 0x2b, 0xbd, 0x80, 0x81, 0x70, 0x4e, 0x01, 0xa7, 0x06, 0xf5, 0x21, 0x14, 0xa3, 0x65, 0x4e, - 0x9d, 0x97, 0x4a, 0x8e, 0xf8, 0xdc, 0x62, 0x79, 0xac, 0xf3, 0xd7, 0xf8, 0x7e, 0x97, 0x6a, 0xc0, - 0x64, 0x8a, 0x36, 0x5f, 0x16, 0x67, 0x17, 0x5b, 0xe4, 0x52, 0x0d, 0x84, 0x7c, 0x0e, 0xbb, 0xd9, - 0x41, 0xd9, 0x84, 0xcd, 0xe4, 0xba, 0x95, 0xce, 0x24, 0xa1, 0x33, 0xe7, 0x19, 0xa4, 0x4f, 0xe2, - 0x0e, 0x6c, 0xcd, 0xec, 0x41, 0x37, 0x16, 0x74, 0x53, 0xa4, 0xa6, 0xec, 0x65, 0x52, 0x13, 0x9e, - 0x8e, 0xe0, 0xf2, 0xec, 0x54, 0x4c, 0xcf, 0xc3, 0x8c, 0x9e, 0xa2, 0x67, 0xd3, 0x0b, 0x9d, 0xd5, - 0x1a, 0xa7, 0x7f, 0xab, 0xb9, 0xd3, 0x33, 0x55, 0x7a, 0x78, 0xa6, 0x4a, 0x7f, 0x9d, 0xa9, 0xd2, - 0xb7, 0x13, 0x35, 0x77, 0x3a, 0x51, 0xa5, 0x87, 0x13, 0x35, 0xf7, 0xc7, 0x44, 0xcd, 0x7d, 0xfc, - 0x82, 0xed, 0xd0, 0xce, 0xa0, 0xa5, 0xb7, 0x71, 0xcf, 0xf0, 0xb1, 0xf7, 0x5c, 0x44, 0x47, 0xd8, - 0x3b, 0x62, 0x07, 0x63, 0x78, 0xcb, 0x38, 0x8e, 0x3e, 0x48, 0xe9, 0xb8, 0x8f, 0x48, 0x6b, 0x9d, - 0x7d, 0x8b, 0xbe, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x51, 0xd0, 0xc3, 0x5c, 0x45, 0x0f, - 0x00, 0x00, + // 1044 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x8f, 0xdb, 0xc4, + 0x17, 0x8f, 0xb3, 0x3f, 0x94, 0xbc, 0x6c, 0xfb, 0xdd, 0xba, 0xfb, 0xa5, 0x59, 0xb7, 0x75, 0x82, + 0xa1, 0xb0, 0xaa, 0x58, 0x9b, 0x5d, 0x28, 0x20, 0xa0, 0x02, 0xd2, 0x4a, 0x95, 0x0a, 0x91, 0xaa, + 0x2c, 0x08, 0x81, 0x04, 0x8b, 0x13, 0x0f, 0x8e, 0xb5, 0x89, 0x27, 0x78, 0x26, 0xc9, 0x86, 0x23, + 0x27, 0x8e, 0x20, 0x71, 0xe0, 0xb8, 0x07, 0x8e, 0x1c, 0x38, 0xf0, 0x47, 0x2c, 0x82, 0x43, 0xc5, + 0x89, 0x13, 0x82, 0xdd, 0x03, 0xfc, 0x19, 0xc8, 0x33, 0xe3, 0xb1, 0x13, 0x7b, 0xb3, 0x2e, 0x25, + 0xb7, 0xcc, 0xbc, 0xcf, 0xfb, 0xbc, 0xcf, 0x7b, 0x93, 0xf7, 0xf2, 0x02, 0x9b, 0xc3, 0x3e, 0x42, + 0x56, 0x0f, 0x8d, 0x50, 0x60, 0xbb, 0xc8, 0x1a, 0xed, 0x58, 0xf4, 0xd0, 0x1c, 0x04, 0x98, 0x62, + 0x75, 0x3d, 0x34, 0x99, 0x91, 0xc9, 0x1c, 0xed, 0x68, 0x7a, 0x07, 0x93, 0x3e, 0x26, 0x56, 0xdb, + 0x26, 0x21, 0xb4, 0x8d, 0xa8, 0xbd, 0x63, 0x75, 0xb0, 0xe7, 0x73, 0x0f, 0xed, 0x8a, 0xb0, 0xf7, + 0x89, 0x1b, 0x32, 0xf5, 0x89, 0x2b, 0x0c, 0x9b, 0xdc, 0xb0, 0xcf, 0x4e, 0x16, 0x3f, 0x08, 0xd3, + 0x86, 0x8b, 0x5d, 0xcc, 0xef, 0xc3, 0x4f, 0xe2, 0xb6, 0x96, 0x92, 0x25, 0x75, 0x30, 0x80, 0xf1, + 0x31, 0x94, 0x9b, 0xc4, 0xdd, 0x1b, 0x0e, 0x06, 0xbd, 0x89, 0xaa, 0x41, 0x89, 0x84, 0x9f, 0x3c, + 0x14, 0x54, 0x95, 0xba, 0xb2, 0x55, 0x6e, 0xc9, 0xb3, 0x7a, 0x0b, 0x56, 0x6c, 0x42, 0x10, 0xad, + 0x16, 0xeb, 0xca, 0x56, 0x65, 0x77, 0xd3, 0x14, 0xd1, 0xc3, 0x1c, 0x4c, 0x91, 0x83, 0x79, 0x07, + 0x7b, 0x7e, 0x63, 0xf9, 0xf8, 0xf7, 0x5a, 0xa1, 0xc5, 0xd1, 0xc6, 0x27, 0x50, 0x69, 0x12, 0xf7, + 0x7d, 0x8f, 0x76, 0x9d, 0xc0, 0x1e, 0x2f, 0x22, 0x42, 0x03, 0x2e, 0x36, 0x89, 0xdb, 0xb4, 0x0f, + 0x73, 0x05, 0xd9, 0x80, 0x15, 0x07, 0xf9, 0xb8, 0xcf, 0x82, 0x94, 0x5b, 0xfc, 0x60, 0x20, 0x58, + 0x6f, 0x12, 0xf7, 0x0e, 0xee, 0xf5, 0x6c, 0x8a, 0x02, 0xbb, 0xe7, 0x7d, 0x8e, 0x42, 0x96, 0x36, + 0x0e, 0x02, 0x3c, 0x8e, 0x59, 0xa2, 0xf3, 0xbf, 0x95, 0xea, 0x82, 0xda, 0x24, 0xee, 0x5d, 0xd4, + 0x59, 0x74, 0x20, 0xfe, 0xaa, 0x0d, 0xc6, 0xb2, 0x08, 0xfe, 0x37, 0x61, 0x8d, 0xd7, 0x3c, 0x47, + 0x88, 0xec, 0x8a, 0x7f, 0x04, 0xa5, 0x26, 0x71, 0x5b, 0x68, 0x60, 0x4f, 0x16, 0x21, 0xf0, 0x7b, + 0x85, 0x29, 0x7c, 0xc7, 0xfb, 0x6c, 0xe8, 0x39, 0x36, 0x45, 0xaa, 0x0e, 0xd0, 0x13, 0x07, 0x1c, + 0x45, 0x49, 0xdc, 0x4c, 0x69, 0x28, 0xce, 0x68, 0xb8, 0x0d, 0xe5, 0x20, 0x14, 0xda, 0x47, 0x3e, + 0xad, 0x2e, 0xe5, 0xd3, 0x11, 0x7b, 0xa8, 0x4f, 0xc2, 0x5a, 0x80, 0xc6, 0x76, 0xe0, 0xec, 0xf3, + 0x3a, 0x2c, 0x33, 0xfa, 0x0a, 0xbf, 0xbb, 0xcb, 0xaa, 0xf1, 0xb3, 0x02, 0xff, 0x0f, 0xe5, 0x8a, + 0xde, 0x74, 0x62, 0xdd, 0xaf, 0xa4, 0x75, 0x37, 0xaa, 0xbf, 0xfe, 0xb8, 0xbd, 0x21, 0xe2, 0xbf, + 0xe5, 0x38, 0x01, 0x22, 0x64, 0x8f, 0x06, 0x9e, 0xef, 0x4e, 0x65, 0xf4, 0xe2, 0x6c, 0x46, 0x73, + 0xfc, 0xe2, 0x5c, 0x6b, 0x50, 0x61, 0xca, 0x85, 0xd6, 0x25, 0x5e, 0x28, 0x76, 0xc5, 0xa4, 0xe6, + 0xc9, 0xa6, 0x0b, 0x97, 0xe5, 0x4c, 0x89, 0x7b, 0x6a, 0x11, 0xbd, 0xff, 0x00, 0x2e, 0xc9, 0x48, + 0x2d, 0x44, 0x06, 0xd8, 0x27, 0x48, 0x7d, 0x0d, 0x4a, 0x01, 0xea, 0x20, 0x6f, 0x84, 0x1c, 0x16, + 0x27, 0x07, 0x9d, 0x74, 0x30, 0x5a, 0x4c, 0x7b, 0x34, 0x4a, 0xfe, 0x1b, 0xce, 0x6f, 0x14, 0x78, + 0x62, 0x7a, 0x44, 0x49, 0xde, 0xdb, 0x50, 0x1e, 0x8b, 0x3b, 0x3f, 0x2f, 0x71, 0xec, 0x31, 0x25, + 0xab, 0xf8, 0xa8, 0xb2, 0x34, 0xa8, 0xce, 0x0e, 0xbd, 0x48, 0x97, 0x71, 0x0d, 0xb4, 0xf4, 0xa4, + 0x92, 0xd6, 0xcb, 0xac, 0xec, 0xbc, 0xf7, 0xe5, 0xe5, 0x1e, 0x6c, 0x24, 0x67, 0x42, 0xb2, 0x74, + 0xe2, 0xdb, 0x95, 0xbf, 0x74, 0x91, 0x83, 0xf1, 0x36, 0x1b, 0xcc, 0x6c, 0x4c, 0x48, 0xc2, 0x97, + 0x61, 0x35, 0xfc, 0x3e, 0x7a, 0xb9, 0xe9, 0x04, 0xdc, 0xf8, 0x49, 0x61, 0x12, 0x65, 0x73, 0x3d, + 0x36, 0xa3, 0xfa, 0x06, 0x40, 0x5c, 0xa1, 0xbc, 0x2f, 0x90, 0x70, 0xe1, 0x91, 0xc3, 0xce, 0xc9, + 0x3b, 0x57, 0x04, 0xdc, 0xf8, 0x5a, 0x81, 0xeb, 0x99, 0x13, 0xe3, 0xf1, 0x93, 0x8a, 0x35, 0x15, + 0x1f, 0x4d, 0xd3, 0xa7, 0x70, 0x35, 0xa3, 0xef, 0xa5, 0xa0, 0x7b, 0x70, 0x71, 0xea, 0xeb, 0x94, + 0x5b, 0xd8, 0x8c, 0x9b, 0xf1, 0x5d, 0x91, 0xbd, 0xe3, 0x3d, 0x3c, 0x7a, 0x6f, 0xc0, 0x53, 0x76, + 0x3d, 0x42, 0x83, 0x89, 0xfa, 0x12, 0x94, 0xed, 0x21, 0xed, 0xe2, 0xc0, 0xa3, 0x93, 0x73, 0x67, + 0x65, 0x0c, 0x0d, 0x7f, 0xa2, 0xa8, 0x47, 0x7b, 0x28, 0xfa, 0x89, 0x62, 0x07, 0xb5, 0x0e, 0x15, + 0x07, 0x91, 0x4e, 0xe0, 0x0d, 0xa8, 0x87, 0x7d, 0x31, 0x0a, 0x93, 0x57, 0xea, 0xeb, 0x00, 0xb6, + 0xe3, 0xec, 0x53, 0x7c, 0x80, 0x7c, 0x52, 0x5d, 0xae, 0x2f, 0x6d, 0x55, 0x76, 0xaf, 0x98, 0xb3, + 0xeb, 0x9e, 0xf9, 0x6e, 0x68, 0x8f, 0x9a, 0xd7, 0x76, 0x1c, 0x76, 0x26, 0x6a, 0x03, 0x2e, 0x0c, + 0x99, 0xfe, 0x88, 0x60, 0x25, 0x0f, 0xc1, 0x1a, 0xf7, 0xe1, 0x1c, 0xaf, 0x6a, 0x5f, 0x1e, 0xd5, + 0x0a, 0xdf, 0x1e, 0xd5, 0x0a, 0x7f, 0x1f, 0xd5, 0x94, 0x2f, 0xfe, 0xfa, 0xe1, 0x66, 0x9c, 0x95, + 0xa1, 0xc3, 0xb5, 0xac, 0x2a, 0x45, 0xef, 0xb1, 0xfb, 0x4b, 0x09, 0x96, 0x9a, 0xc4, 0x55, 0xef, + 0xc3, 0xaa, 0xd8, 0xff, 0xae, 0xa6, 0x43, 0xcb, 0x07, 0xd5, 0x9e, 0x9a, 0x63, 0x94, 0x6f, 0xfc, + 0x00, 0x4a, 0x72, 0x0d, 0xbb, 0x9e, 0xe9, 0x10, 0x99, 0xb5, 0x1b, 0x73, 0xcd, 0x92, 0xf1, 0x03, + 0xa8, 0x24, 0x77, 0xbb, 0x7a, 0xa6, 0x57, 0x02, 0xa1, 0x6d, 0x9d, 0x87, 0x90, 0xd4, 0xfb, 0x70, + 0x61, 0x7a, 0xe5, 0x33, 0x32, 0x5d, 0xa7, 0x30, 0xda, 0xcd, 0xf3, 0x31, 0x32, 0x00, 0x82, 0xff, + 0xcd, 0x2e, 0x7b, 0x4f, 0x67, 0xba, 0xcf, 0xa0, 0xb4, 0xe7, 0xf2, 0xa0, 0x64, 0x98, 0xfb, 0xb0, + 0x2a, 0xf6, 0xb0, 0xec, 0x07, 0xe4, 0xc6, 0x33, 0x1e, 0x70, 0x66, 0x5a, 0xef, 0x41, 0x39, 0x5e, + 0xeb, 0xf4, 0xb3, 0x4a, 0x29, 0x18, 0x9f, 0x99, 0x6f, 0x4f, 0x74, 0xfe, 0x8a, 0xd8, 0xf4, 0x32, + 0x1d, 0x98, 0x4d, 0x33, 0xce, 0xb6, 0x25, 0xd5, 0x25, 0x56, 0xba, 0x4c, 0x07, 0x69, 0x3f, 0x43, + 0x5d, 0x7a, 0x50, 0xfa, 0xa0, 0x66, 0x2c, 0x5e, 0xcf, 0x66, 0x7b, 0xa7, 0x80, 0x9a, 0x95, 0x13, + 0x28, 0xe3, 0x75, 0x61, 0x3d, 0xb5, 0x1b, 0xdd, 0x98, 0xd3, 0x5c, 0x31, 0x4c, 0xdb, 0xce, 0x05, + 0x93, 0x91, 0x0e, 0xe0, 0x52, 0x7a, 0x48, 0x66, 0x97, 0x25, 0x85, 0xd3, 0xcc, 0x7c, 0xb8, 0x28, + 0x58, 0xa3, 0x75, 0xfc, 0xa7, 0x5e, 0x38, 0x3e, 0xd1, 0x95, 0x87, 0x27, 0xba, 0xf2, 0xc7, 0x89, + 0xae, 0x7c, 0x75, 0xaa, 0x17, 0x8e, 0x4f, 0x75, 0xe5, 0xe1, 0xa9, 0x5e, 0xf8, 0xed, 0x54, 0x2f, + 0x7c, 0xf8, 0xbc, 0xeb, 0xd1, 0xee, 0xb0, 0x6d, 0x76, 0x70, 0xdf, 0x0a, 0xb9, 0xb7, 0x7d, 0x44, + 0xc7, 0x38, 0x38, 0x60, 0x07, 0x6b, 0x74, 0xcb, 0x3a, 0x8c, 0xff, 0xa9, 0xd2, 0xc9, 0x00, 0x91, + 0xf6, 0x2a, 0xfb, 0x93, 0xfa, 0xc2, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x31, 0xf4, 0x11, 0x45, + 0x5e, 0x0f, 0x00, 0x00, } func (this *MsgGovUpdateRegistry) Equal(that interface{}) bool { @@ -1296,14 +1296,15 @@ type MsgClient interface { // Liquidate allows a user to repay a different user's borrowed coins in exchange for some // of the target's collateral. Liquidate(ctx context.Context, in *MsgLiquidate, opts ...grpc.CallOption) (*MsgLiquidateResponse, error) - // FastLiquidate allows a user to repay a different user's borrowed coins in exchange for some - // of the target's collateral. For flash liquidations, the tokens to repay are borrowed instead of + // LeveragedLiquidate allows a user to repay a different user's borrowed coins in exchange for some + // of the target's collateral. For leveraged liquidations, the tokens to repay are borrowed instead of // being taken from the liquidator's wallet, and the reward is immediately collateralized. Borrow // limit checks for the liquidator are deferred until after the reward is collateralized, allowing // this initial borrow to exceed the liquidator's borrow limit as long as it is healthy by the end // of the transaction. Repay amount is calculated automatically, so the liquidator only specifies - // repay and reward token denoms. - FastLiquidate(ctx context.Context, in *MsgFastLiquidate, opts ...grpc.CallOption) (*MsgFastLiquidateResponse, error) + // repay and reward token denoms. For safety, the liquidator cannot exceed 80% of their borrow limit when + // executing this transaction, instead of the regular 100%. + LeveragedLiquidate(ctx context.Context, in *MsgLeveragedLiquidate, opts ...grpc.CallOption) (*MsgLeveragedLiquidateResponse, error) // SupplyCollateral combines the Supply and Collateralize actions. SupplyCollateral(ctx context.Context, in *MsgSupplyCollateral, opts ...grpc.CallOption) (*MsgSupplyCollateralResponse, error) // GovUpdateRegistry adds new tokens to the token registry or @@ -1400,9 +1401,9 @@ func (c *msgClient) Liquidate(ctx context.Context, in *MsgLiquidate, opts ...grp return out, nil } -func (c *msgClient) FastLiquidate(ctx context.Context, in *MsgFastLiquidate, opts ...grpc.CallOption) (*MsgFastLiquidateResponse, error) { - out := new(MsgFastLiquidateResponse) - err := c.cc.Invoke(ctx, "/umee.leverage.v1.Msg/FastLiquidate", in, out, opts...) +func (c *msgClient) LeveragedLiquidate(ctx context.Context, in *MsgLeveragedLiquidate, opts ...grpc.CallOption) (*MsgLeveragedLiquidateResponse, error) { + out := new(MsgLeveragedLiquidateResponse) + err := c.cc.Invoke(ctx, "/umee.leverage.v1.Msg/LeveragedLiquidate", in, out, opts...) if err != nil { return nil, err } @@ -1454,14 +1455,15 @@ type MsgServer interface { // Liquidate allows a user to repay a different user's borrowed coins in exchange for some // of the target's collateral. Liquidate(context.Context, *MsgLiquidate) (*MsgLiquidateResponse, error) - // FastLiquidate allows a user to repay a different user's borrowed coins in exchange for some - // of the target's collateral. For flash liquidations, the tokens to repay are borrowed instead of + // LeveragedLiquidate allows a user to repay a different user's borrowed coins in exchange for some + // of the target's collateral. For leveraged liquidations, the tokens to repay are borrowed instead of // being taken from the liquidator's wallet, and the reward is immediately collateralized. Borrow // limit checks for the liquidator are deferred until after the reward is collateralized, allowing // this initial borrow to exceed the liquidator's borrow limit as long as it is healthy by the end // of the transaction. Repay amount is calculated automatically, so the liquidator only specifies - // repay and reward token denoms. - FastLiquidate(context.Context, *MsgFastLiquidate) (*MsgFastLiquidateResponse, error) + // repay and reward token denoms. For safety, the liquidator cannot exceed 80% of their borrow limit when + // executing this transaction, instead of the regular 100%. + LeveragedLiquidate(context.Context, *MsgLeveragedLiquidate) (*MsgLeveragedLiquidateResponse, error) // SupplyCollateral combines the Supply and Collateralize actions. SupplyCollateral(context.Context, *MsgSupplyCollateral) (*MsgSupplyCollateralResponse, error) // GovUpdateRegistry adds new tokens to the token registry or @@ -1500,8 +1502,8 @@ func (*UnimplementedMsgServer) Repay(ctx context.Context, req *MsgRepay) (*MsgRe func (*UnimplementedMsgServer) Liquidate(ctx context.Context, req *MsgLiquidate) (*MsgLiquidateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Liquidate not implemented") } -func (*UnimplementedMsgServer) FastLiquidate(ctx context.Context, req *MsgFastLiquidate) (*MsgFastLiquidateResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FastLiquidate not implemented") +func (*UnimplementedMsgServer) LeveragedLiquidate(ctx context.Context, req *MsgLeveragedLiquidate) (*MsgLeveragedLiquidateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LeveragedLiquidate not implemented") } func (*UnimplementedMsgServer) SupplyCollateral(ctx context.Context, req *MsgSupplyCollateral) (*MsgSupplyCollateralResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SupplyCollateral not implemented") @@ -1676,20 +1678,20 @@ func _Msg_Liquidate_Handler(srv interface{}, ctx context.Context, dec func(inter return interceptor(ctx, in, info, handler) } -func _Msg_FastLiquidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgFastLiquidate) +func _Msg_LeveragedLiquidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgLeveragedLiquidate) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).FastLiquidate(ctx, in) + return srv.(MsgServer).LeveragedLiquidate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/umee.leverage.v1.Msg/FastLiquidate", + FullMethod: "/umee.leverage.v1.Msg/LeveragedLiquidate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).FastLiquidate(ctx, req.(*MsgFastLiquidate)) + return srv.(MsgServer).LeveragedLiquidate(ctx, req.(*MsgLeveragedLiquidate)) } return interceptor(ctx, in, info, handler) } @@ -1771,8 +1773,8 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Handler: _Msg_Liquidate_Handler, }, { - MethodName: "FastLiquidate", - Handler: _Msg_FastLiquidate_Handler, + MethodName: "LeveragedLiquidate", + Handler: _Msg_LeveragedLiquidate_Handler, }, { MethodName: "SupplyCollateral", @@ -2155,7 +2157,7 @@ func (m *MsgLiquidate) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgFastLiquidate) Marshal() (dAtA []byte, err error) { +func (m *MsgLeveragedLiquidate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2165,12 +2167,12 @@ func (m *MsgFastLiquidate) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgFastLiquidate) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgLeveragedLiquidate) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgFastLiquidate) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgLeveragedLiquidate) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2543,7 +2545,7 @@ func (m *MsgLiquidateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgFastLiquidateResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgLeveragedLiquidateResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2553,12 +2555,12 @@ func (m *MsgFastLiquidateResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgFastLiquidateResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgLeveragedLiquidateResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgFastLiquidateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgLeveragedLiquidateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2872,7 +2874,7 @@ func (m *MsgLiquidate) Size() (n int) { return n } -func (m *MsgFastLiquidate) Size() (n int) { +func (m *MsgLeveragedLiquidate) Size() (n int) { if m == nil { return 0 } @@ -3011,7 +3013,7 @@ func (m *MsgLiquidateResponse) Size() (n int) { return n } -func (m *MsgFastLiquidateResponse) Size() (n int) { +func (m *MsgLeveragedLiquidateResponse) Size() (n int) { if m == nil { return 0 } @@ -4180,7 +4182,7 @@ func (m *MsgLiquidate) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgFastLiquidate) Unmarshal(dAtA []byte) error { +func (m *MsgLeveragedLiquidate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4203,10 +4205,10 @@ func (m *MsgFastLiquidate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgFastLiquidate: wiretype end group for non-group") + return fmt.Errorf("proto: MsgLeveragedLiquidate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgFastLiquidate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgLeveragedLiquidate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5220,7 +5222,7 @@ func (m *MsgLiquidateResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgFastLiquidateResponse) Unmarshal(dAtA []byte) error { +func (m *MsgLeveragedLiquidateResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5243,10 +5245,10 @@ func (m *MsgFastLiquidateResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgFastLiquidateResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgLeveragedLiquidateResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgFastLiquidateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgLeveragedLiquidateResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/leverage/types/tx_test.go b/x/leverage/types/tx_test.go index 99a02ed072..2234cb98d7 100644 --- a/x/leverage/types/tx_test.go +++ b/x/leverage/types/tx_test.go @@ -34,7 +34,7 @@ func TestTxs(t *testing.T) { types.NewMsgMaxBorrow(testAddr, denom), types.NewMsgRepay(testAddr, token), types.NewMsgLiquidate(testAddr, testAddr, token, uDenom), - types.NewMsgFastLiquidate(testAddr, testAddr, token.Denom, uDenom), + types.NewMsgLeveragedLiquidate(testAddr, testAddr, token.Denom, uDenom), } for _, tx := range txs { @@ -65,7 +65,7 @@ func TestRoutes(t *testing.T) { types.NewMsgMaxBorrow(testAddr, denom), types.NewMsgRepay(testAddr, token), types.NewMsgLiquidate(testAddr, testAddr, token, uDenom), - types.NewMsgFastLiquidate(testAddr, testAddr, token.Denom, uDenom), + types.NewMsgLeveragedLiquidate(testAddr, testAddr, token.Denom, uDenom), } for _, tx := range txs {