diff --git a/x/cdp/keeper/auctions.go b/x/cdp/keeper/auctions.go index 7c8397b9..5e6e422b 100644 --- a/x/cdp/keeper/auctions.go +++ b/x/cdp/keeper/auctions.go @@ -118,9 +118,10 @@ func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep types.Deposit, de for depositAmount.GTE(auctionSize) { // figure out how much debt is covered by one lots worth of collateral depositDebtAmount := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt() - // start an auction for one lot, attempting to raise depositDebtAmount + penalty := k.ApplyLiquidationPenalty(ctx, depositDenom, depositDebtAmount) + // start an auction for one lot, attempting to raise depositDebtAmount plus the liquidation penalty _, err := k.auctionKeeper.StartCollateralAuction( - ctx, types.LiquidatorMacc, sdk.NewCoin(depositDenom, auctionSize), sdk.NewCoin(principalDenom, depositDebtAmount), []sdk.AccAddress{dep.Depositor}, + ctx, types.LiquidatorMacc, sdk.NewCoin(depositDenom, auctionSize), sdk.NewCoin(principalDenom, depositDebtAmount.Add(penalty)), []sdk.AccAddress{dep.Depositor}, []sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), depositDebtAmount)) if err != nil { return sdk.ZeroInt(), sdk.ZeroInt(), err diff --git a/x/cdp/keeper/seize.go b/x/cdp/keeper/seize.go index fcb15756..ca2efa52 100644 --- a/x/cdp/keeper/seize.go +++ b/x/cdp/keeper/seize.go @@ -10,11 +10,11 @@ import ( // SeizeCollateral liquidates the collateral in the input cdp. // the following operations are performed: // 1. updates the fees for the input cdp, -// 2. sends collateral for all deposits from the cdp module to the liquidator module, -// 3. moves debt coins from the cdp module to the liquidator module, +// 2. sends collateral for all deposits from the cdp module to the liquidator module account +// 3. Applies the liquidation penalty and mints the corresponding amount of debt coins in the cdp module +// 3. moves debt coins from the cdp module to the liquidator module account, // 4. decrements the total amount of principal outstanding for that collateral type -// (this is the equivalent of saying that fees are no longer accumulated by a cdp once it -// gets liquidated) +// (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated) func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error { // Calculate the previous collateral ratio oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) @@ -24,8 +24,6 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error { cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees) cdp.FeesUpdated = ctx.BlockTime() - // TODO implement liquidation penalty - // Move debt coins from cdp to liquidator account deposits := k.GetDeposits(ctx, cdp.ID) debt := sdk.ZeroInt() @@ -35,6 +33,7 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error { for _, dc := range cdp.AccumulatedFees { debt = debt.Add(dc.Amount) } + debtCoin := sdk.NewCoin(k.GetDebtDenom(ctx), debt) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.LiquidatorMacc, sdk.NewCoins(debtCoin)) if err != nil { @@ -108,3 +107,10 @@ func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, li } return nil } + +// ApplyLiquidationPenalty multiplies the input debt amount by the liquidation penalty and mints the debt coins in the cdp module account +func (k Keeper) ApplyLiquidationPenalty(ctx sdk.Context, denom string, debt sdk.Int) sdk.Int { + penalty := k.getLiquidationPenalty(ctx, denom) + penaltyAmount := sdk.NewDecFromInt(debt).Mul(penalty).RoundInt() + return penaltyAmount +} diff --git a/x/cdp/keeper/seize_test.go b/x/cdp/keeper/seize_test.go index 0c89db6b..e769826d 100644 --- a/x/cdp/keeper/seize_test.go +++ b/x/cdp/keeper/seize_test.go @@ -108,6 +108,9 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() { suite.NoError(err) tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx") suite.Equal(tpb.Sub(tpa), p) + auctionKeeper := suite.app.GetAuctionKeeper() + _, found := auctionKeeper.GetAuction(suite.ctx, 0) + suite.True(found) auctionMacc := sk.GetModuleAccount(suite.ctx, auction.ModuleName) suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins()) ak := suite.app.GetAccountKeeper() @@ -162,6 +165,16 @@ func (suite *SeizeTestSuite) TestHandleNewDebt() { suite.Equal(sdk.NewDec(tpb.Int64()).Mul(d("1.05")).TruncateInt().Int64(), tpa.Int64()) } +func (suite *SeizeTestSuite) TestApplyLiquidationPenalty() { + penalty := suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(1000)) + suite.Equal(i(50), penalty) + penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "btc", i(1000)) + suite.Equal(i(25), penalty) + penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(675760172)) + suite.Equal(i(33788009), penalty) + suite.Panics(func() { suite.keeper.ApplyLiquidationPenalty(suite.ctx, "lol", i(1000)) }) +} + func TestSeizeTestSuite(t *testing.T) { suite.Run(t, new(SeizeTestSuite)) }