From 273efb448b1acf6758c33d5b76b45e116ed2022f Mon Sep 17 00:00:00 2001 From: Adam Moser <63419657+toteki@users.noreply.github.com> Date: Tue, 17 Oct 2023 10:02:59 -0600 Subject: [PATCH] fix leveraged liquidate not working during low liquidity (#2285) * fix leveraged liquidate not working during low liquidity * cl * empty commit * empty commit * ++ * fix govulncheck flow name * ++ --------- Co-authored-by: Robert Zaremba --- .github/workflows/govulncheck.yml | 2 +- CHANGELOG.md | 1 + x/leverage/keeper/liquidate.go | 16 +++++++++++----- x/leverage/keeper/liquidate_test.go | 9 +++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 9b7a20d157..da3799250f 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -1,4 +1,4 @@ -name: Tests +name: Vuln on: pull_request: types: [opened, synchronize, reopened, labeled] diff --git a/CHANGELOG.md b/CHANGELOG.md index 558b05d5a2..f8ecf401a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ - [2267](https://github.com/umee-network/umee/pull/2267) Leverage transactions accept spot prices up to 3 minutes old, and leverage queries use most recent spot price when required. - [2263](https://github.com/umee-network/umee/pull/2263) Add spot price fields to account summary. - [2270](https://github.com/umee-network/umee/pull/2270) Increase free oracle tx limit to 200k gas. +- [2285](https://github.com/umee-network/umee/pull/2285) Leveraged liquidate works during low liquidity. ### Features diff --git a/x/leverage/keeper/liquidate.go b/x/leverage/keeper/liquidate.go index 3e48b68283..bcb7f0ae65 100644 --- a/x/leverage/keeper/liquidate.go +++ b/x/leverage/keeper/liquidate.go @@ -108,6 +108,7 @@ func (k Keeper) getLiquidationAmounts( priceRatio, exchangeRate, liqudationIncentive, + leveragedLiquidate, ) return sdk.NewCoin(repayDenom, repay), sdk.NewCoin(collateralDenom, burn), sdk.NewCoin(rewardDenom, reward), nil @@ -123,6 +124,7 @@ func (k Keeper) getLiquidationAmounts( // - priceRatio: The ratio of repayPrice / rewardPrice, which is used when computing rewards // - uTokenExchangeRate: The uToken exchange rate from collateral uToken denom to reward base denom // - liquidationIncentive: The liquidation incentive of the token reward denomination +// - leverageLiquidate: whether liquidation is leveraged (in which case it can disregard availableReward) func ComputeLiquidation( availableRepay, availableCollateral, @@ -130,6 +132,7 @@ func ComputeLiquidation( priceRatio, uTokenExchangeRate, liquidationIncentive sdk.Dec, + leverageLiquidate bool, ) (tokenRepay sdkmath.Int, collateralBurn sdkmath.Int, tokenReward sdkmath.Int) { // Prevent division by zero if uTokenExchangeRate.IsZero() || priceRatio.IsZero() { @@ -157,12 +160,15 @@ func ComputeLiquidation( ratio = sdk.MinDec(ratio, toDec(availableCollateral).Quo(maxCollateral), ) - // Base token reward cannot exceed available unreserved module balance - ratio = sdk.MinDec(ratio, - toDec(availableReward).Quo(maxReward), - ) + if !leverageLiquidate { + // Base token reward cannot exceed available unreserved module balance + ratio = sdk.MinDec(ratio, + toDec(availableReward).Quo(maxReward), + ) + } + // Catch edge cases - if !ratio.IsPositive() { + if !ratio.IsPositive() || ratio.GT(sdk.OneDec()) { return sdk.ZeroInt(), sdk.ZeroInt(), sdk.ZeroInt() } diff --git a/x/leverage/keeper/liquidate_test.go b/x/leverage/keeper/liquidate_test.go index ca98c19a63..999384391e 100644 --- a/x/leverage/keeper/liquidate_test.go +++ b/x/leverage/keeper/liquidate_test.go @@ -19,6 +19,7 @@ func TestComputeLiquidation(t *testing.T) { rewardTokenPrice sdk.Dec uTokenExchangeRate sdk.Dec liquidationIncentive sdk.Dec + leveragedLiquidate bool } baseCase := func() testCase { @@ -30,6 +31,7 @@ func TestComputeLiquidation(t *testing.T) { sdk.OneDec(), // price(B) = $1 sdk.OneDec(), // utoken exchange rate 1 u/B => 1 B sdk.MustNewDecFromStr("0.1"), // reward value is 110% repay value + false, } } @@ -42,6 +44,7 @@ func TestComputeLiquidation(t *testing.T) { priceRatio, tc.uTokenExchangeRate, tc.liquidationIncentive, + tc.leveragedLiquidate, ) assert.Equal(t, true, sdkmath.NewInt(expectedRepay).Equal(repay), @@ -74,6 +77,12 @@ func TestComputeLiquidation(t *testing.T) { rewardLimited.availableReward = sdk.NewInt(330) runTestCase(rewardLimited, 300, 330, 330, "reward limited") + // limiting factor would be available reward, but leveraged liquidation is not limited by base tokens + rewardNotLimited := baseCase() + rewardNotLimited.availableReward = sdk.NewInt(330) + rewardNotLimited.leveragedLiquidate = true + runTestCase(rewardNotLimited, 1000, 1100, 1100, "reward not limited") + // repay token is worth more expensiveRepay := baseCase() expensiveRepay.repayTokenPrice = sdk.MustNewDecFromStr("2")