Skip to content

Commit

Permalink
feat: autofill empty denoms in MsgLeveragedLiquidate (#2121)
Browse files Browse the repository at this point in the history
* feat: autofill empty denoms in MsgLeveragedLiquidate

* cl++

* update proto comments

* update CLI

* Update x/leverage/client/cli/tx.go
  • Loading branch information
toteki authored Jun 30, 2023
1 parent 945b88c commit c813da8
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

- [2121](https://github.com/umee-network/umee/pull/2121) Allow `MsgLeveragedLiquidate` to auto-select repay and reward denoms if request fields left blank.
- [2114](https://github.com/umee-network/umee/pull/2114) Add borrow factor 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.
Expand Down
4 changes: 3 additions & 1 deletion proto/umee/leverage/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ service Msg {
// 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. For safety, the liquidator cannot exceed 80% of their borrow limit when
// executing this transaction, instead of the regular 100%.
// executing this transaction, instead of the regular 100%. Also allows repayment and reward denoms to
// be left blank - if not specified, the module will automatically select the first (alphabetically by denom)
// borrow and/or collateral on the target account and the proceed normally.
rpc LeveragedLiquidate(MsgLeveragedLiquidate) returns (MsgLeveragedLiquidateResponse);

// SupplyCollateral combines the Supply and Collateralize actions.
Expand Down
12 changes: 9 additions & 3 deletions x/leverage/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ $ umeed tx leverage liquidate %s 50000000uumee u/uumee --from mykey`,
func GetCmdLeveragedLiquidate() *cobra.Command {
cmd := &cobra.Command{
Use: "lev-liquidate [borrower] [repay-denom] [reward-denom]",
Args: cobra.ExactArgs(3),
Args: cobra.RangeArgs(1, 3),
Short: "Liquidates by moving borrower debt to the liquidator and immediately collateralizes the reward.",
Long: strings.TrimSpace(
fmt.Sprintf(`
Expand All @@ -349,8 +349,14 @@ $ umeed tx leverage lev-liquidate %s uumee uumee --from mykey`,
return err
}

repayDenom := args[1]
rewardDenom := args[2]
var repayDenom, rewardDenom string
if len(args) > 1 {
repayDenom = args[1]
}

if len(args) > 2 {
rewardDenom = args[2]
}

msg := types.NewMsgLeveragedLiquidate(clientCtx.GetFromAddress(), borrowerAddr, repayDenom, rewardDenom)
if err = msg.ValidateBasic(); err != nil {
Expand Down
15 changes: 15 additions & 0 deletions x/leverage/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,21 @@ func (k Keeper) Liquidate(
func (k Keeper) LeveragedLiquidate(
ctx sdk.Context, liquidatorAddr, borrowerAddr sdk.AccAddress, repayDenom, rewardDenom string,
) (repaid sdk.Coin, reward sdk.Coin, err error) {
// If the message did not specify repay or reward denoms, select one arbitrarily (first in
// denom alphabetical order) from borrower position. Then proceed normally with the transaction.
if repayDenom == "" {
borrowed := k.GetBorrowerBorrows(ctx, borrowerAddr)
if !borrowed.IsZero() {
repayDenom = borrowed[0].Denom
}
}
if rewardDenom == "" {
collateral := k.GetBorrowerCollateral(ctx, borrowerAddr)
if !collateral.IsZero() {
rewardDenom = types.ToTokenDenom(collateral[0].Denom)
}
}

if err := k.validateAcceptedDenom(ctx, repayDenom); err != nil {
return sdk.Coin{}, sdk.Coin{}, err
}
Expand Down
32 changes: 21 additions & 11 deletions x/leverage/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2226,11 +2226,11 @@ func (s *IntegrationTestSuite) TestMsgLeveragedLiquidate() {
coin.New("u/"+atomDenom, 3_527933),
nil,
}, {
"close factor < 1",
"close factor < 1 with auto-selected repay and reward denoms",
liquidator,
closeBorrower,
umeeDenom,
umeeDenom,
"",
"",
coin.New(umeeDenom, 8_150541),
coin.New("u/"+umeeDenom, 8_965596),
nil,
Expand All @@ -2248,20 +2248,30 @@ func (s *IntegrationTestSuite) TestMsgLeveragedLiquidate() {
_, err := srv.LeveragedLiquidate(ctx, msg)
require.ErrorIs(err, tc.err, tc.msg)
} else {
baseRewardDenom := types.ToTokenDenom(tc.expectedReward.Denom)
// borrower initial state
biBalance := app.BankKeeper.GetAllBalances(ctx, tc.borrower)
biCollateral := app.LeverageKeeper.GetBorrowerCollateral(ctx, tc.borrower)
biBorrowed := app.LeverageKeeper.GetBorrowerBorrows(ctx, tc.borrower)

// adjust test case in empty-input scenarios, while preserving the msg
if msg.RepayDenom == "" {
if !biBorrowed.IsZero() {
tc.repayDenom = biBorrowed[0].Denom
}
}
if msg.RewardDenom == "" {
if !biCollateral.IsZero() {
tc.rewardDenom = types.ToTokenDenom(biCollateral[0].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)
liExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, tc.rewardDenom)

// liquidator initial state
liBalance := app.BankKeeper.GetAllBalances(ctx, tc.liquidator)
Expand All @@ -2276,7 +2286,7 @@ func (s *IntegrationTestSuite) TestMsgLeveragedLiquidate() {

// final state (liquidated denom)
lfUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx)
lfExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, baseRewardDenom)
lfExchangeRate := app.LeverageKeeper.DeriveExchangeRate(ctx, tc.rewardDenom)

// borrower final state
bfBalance := app.BankKeeper.GetAllBalances(ctx, tc.borrower)
Expand Down
8 changes: 6 additions & 2 deletions x/leverage/types/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c813da8

Please sign in to comment.