Apply Liquidation Penalty (#313)

* fix: remove redundant debt limit param

* wip: test pricefeed genesis

* fix: pricefeed querier

* fix: comments, naming

* fix: query path

* fix: store methods

* fix: query methods

* feat: Liquidation Penalty

* fix: remove debt from liquidation penalty
This commit is contained in:
Kevin Davis 2020-01-21 17:52:07 +00:00 committed by Ruaridh
parent f01a3f46ee
commit a74f63a8f2
3 changed files with 28 additions and 8 deletions

View File

@ -118,9 +118,10 @@ func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep types.Deposit, de
for depositAmount.GTE(auctionSize) { for depositAmount.GTE(auctionSize) {
// figure out how much debt is covered by one lots worth of collateral // 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() 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( _, 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)) []sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), depositDebtAmount))
if err != nil { if err != nil {
return sdk.ZeroInt(), sdk.ZeroInt(), err return sdk.ZeroInt(), sdk.ZeroInt(), err

View File

@ -10,11 +10,11 @@ import (
// SeizeCollateral liquidates the collateral in the input cdp. // SeizeCollateral liquidates the collateral in the input cdp.
// the following operations are performed: // the following operations are performed:
// 1. updates the fees for the input cdp, // 1. updates the fees for the input cdp,
// 2. sends collateral for all deposits from the cdp module to the liquidator module, // 2. sends collateral for all deposits from the cdp module to the liquidator module account
// 3. moves debt coins from the cdp module to the liquidator module, // 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 // 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 // (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated)
// gets liquidated)
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error { func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error {
// Calculate the previous collateral ratio // Calculate the previous collateral ratio
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) 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.AccumulatedFees = cdp.AccumulatedFees.Add(fees)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
// TODO implement liquidation penalty
// Move debt coins from cdp to liquidator account // Move debt coins from cdp to liquidator account
deposits := k.GetDeposits(ctx, cdp.ID) deposits := k.GetDeposits(ctx, cdp.ID)
debt := sdk.ZeroInt() debt := sdk.ZeroInt()
@ -35,6 +33,7 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error {
for _, dc := range cdp.AccumulatedFees { for _, dc := range cdp.AccumulatedFees {
debt = debt.Add(dc.Amount) debt = debt.Add(dc.Amount)
} }
debtCoin := sdk.NewCoin(k.GetDebtDenom(ctx), debt) debtCoin := sdk.NewCoin(k.GetDebtDenom(ctx), debt)
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.LiquidatorMacc, sdk.NewCoins(debtCoin)) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.LiquidatorMacc, sdk.NewCoins(debtCoin))
if err != nil { if err != nil {
@ -108,3 +107,10 @@ func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, li
} }
return nil 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
}

View File

@ -108,6 +108,9 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() {
suite.NoError(err) suite.NoError(err)
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx") tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
suite.Equal(tpb.Sub(tpa), p) 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) auctionMacc := sk.GetModuleAccount(suite.ctx, auction.ModuleName)
suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins()) suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins())
ak := suite.app.GetAccountKeeper() 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()) 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) { func TestSeizeTestSuite(t *testing.T) {
suite.Run(t, new(SeizeTestSuite)) suite.Run(t, new(SeizeTestSuite))
} }