Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Move liquidator functions to cdp module #280

Merged
merged 35 commits into from Jan 15, 2020
Merged

Conversation

karzak
Copy link
Member

@karzak karzak commented Jan 13, 2020

Features:

CollateralAuctions are created immediately when the cdp is seized
Implemented netting of surplus and debt
Implemented starting of surplus/debt auctions
Added gov denom to genesis state
Added params for surplus and debt auction thresholds

@karzak karzak added the R4R When a PR is ready for review label Jan 13, 2020
@karzak karzak added the cdp issues for cdp features label Jan 13, 2020
Copy link
Member

@rhuairahrighairidh rhuairahrighairidh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, left some comments on the mathy parts.

if balance.LT(netAmount) {
err = k.supplyKeeper.BurnCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, balance)))
if err != nil {
panic(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return error instead of panic? Then it's up to the caller to decide whether to panic or do something else.

remainingDebt := k.GetTotalDebt(ctx, types.LiquidatorMacc)
params := k.GetParams(ctx)
if remainingDebt.GTE(params.DebtAuctionThreshold) {
_, err := k.auctionKeeper.StartDebtAuction(ctx, types.LiquidatorMacc, sdk.NewCoin("usdx", sdk.NewInt(1)), sdk.NewCoin(k.GetGovDenom(ctx), remainingDebt.Mul(sdk.NewInt(100))), sdk.NewCoin(k.GetDebtDenom(ctx), remainingDebt))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the bid arg here should be remainingDebt as its a reverse auction and that is the amount you want to raise.
Also might be neater to move the 100x multiplier for the lot to a constant

}

// HandleSurplusAndDebtAuctions nets the surplus and debt balances and then creates surplus or debt auctions if the remaining balance is above the auction threshold parameter
func (k Keeper) HandleSurplusAndDebtAuctions(ctx sdk.Context) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunSurplusAndDebtAuctions? 'Handle' is a bit vague

Comment on lines 129 to 145
for _, dp := range k.GetParams(ctx).DebtParams {
for surplusToBurn.GT(sdk.ZeroInt()) {
balance := k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc).GetCoins().AmountOf(dp.Denom)
if balance.LT(netAmount) {
err = k.supplyKeeper.BurnCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, balance)))
if err != nil {
panic(err)
}
surplusToBurn = surplusToBurn.Sub(balance)
} else {
err = k.supplyKeeper.BurnCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, surplusToBurn)))
if err != nil {
panic(err)
}
surplusToBurn = sdk.ZeroInt()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this can get caught in a loop on the first dp (if it's balance is < netAmount)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! The outer and inner loops should be switched.

auctionSize := k.getAuctionSize(ctx, deposits[0].Amount[0].Denom)
partialAuctionDeposits := partialDeposits{}
totalCollateral := deposits.SumCollateral()
for deposits.SumCollateral().GTE(auctionSize) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If total deposits are < auctionSize then no auction will be started, but the cdp will still have been seized

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, should be checking for greater than zero.

for i, dep := range deposits {
// create auctions from individual deposits that are larger than the auction size
k.CreateAuctionsFromDeposit(ctx, &dep, &debt, &totalCollateral, auctionSize, bidDenom)
if !dep.Amount[0].Amount.IsZero() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found these loops a bit hard to understand, comments might help explain why things are happening

auctionSize := k.getAuctionSize(ctx, deposits[0].Amount[0].Denom)
partialAuctionDeposits := partialDeposits{}
totalCollateral := deposits.SumCollateral()
for deposits.SumCollateral().GTE(auctionSize) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace deposits.SumCollateral() with totalCollateral

Comment on lines +8 to +12
type partialDeposit struct {
Depositor sdk.AccAddress
Amount sdk.Coins
DebtShare sdk.Int
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth discussing if partialDeposit should be defined in a separate file or moved to cdp/types.

partialAuctionDeposits := partialDeposits{}
totalCollateral := deposits.SumCollateral()
for deposits.SumCollateral().GTE(auctionSize) {
for i, dep := range deposits {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder variables for denom, amount

}

// CreateAuctionsFromDeposit creates auctions from the input deposit until there is less than auctionSize left on the deposit
func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep *types.Deposit, debt *sdk.Int, totalCollateral *sdk.Int, auctionSize sdk.Int, principalDenom string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method would be simpler if it used local variables to keep track of the data instead of updating the state via ref in each iteration of the loop. Return local variables and use them to update the state back in the primary function.

func (k Keeper) getLiquidationPenalty(ctx sdk.Context, denom string) sdk.Dec {
cp, found := k.GetCollateral(ctx, denom)
if !found {
panic(fmt.Sprintf("collateral not found: %s", denom))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will panic if collateral type type 'random' is removed in between CDP deposit of 'random' and liquidation of the CDP.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will file an issue on this topic. It's worth documenting and thinking about how we want to handle it, but for now, it would be unlikely for governance to accept a proposal to remove a collateral that still had active cdps.

func (k Keeper) getAuctionSize(ctx sdk.Context, denom string) sdk.Int {
cp, found := k.GetCollateral(ctx, denom)
if !found {
panic(fmt.Sprintf("collateral not found: %s", denom))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor

@denalimarsh denalimarsh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor change requested, but approving the PR as it can be addressed later.

Comment on lines 62 to 63
collateralAmount := dep.Amount[0].Amount
collateralDenom := dep.Amount[0].Denom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can move these up a couple of lines and replace dep.Amount[0].Denom, dep.Amount[0].Amount on line 59 with the local variables.

@rhuairahrighairidh
Copy link
Member

nit: In seize_test.go in setup, a new rand source doesn't need to be set up for each loop iteration.

Copy link
Member

@rhuairahrighairidh rhuairahrighairidh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like there to be more tests of the mathy bits before testnet. But this could be a subsequent PR.

Comment on lines 165 to 170
if netAmount.GT(sdk.ZeroInt()) {
surplusToBurn := netAmount
err := k.supplyKeeper.BurnCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(k.GetDebtDenom(ctx), netAmount)))
if err != nil {
return err
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if could be

if netAmount.IsZero() {
    return nil
}
surplusToBurn := ...

It would remove a level of indentation from the subsequent section.

for surplusToBurn.GT(sdk.ZeroInt()) {
for _, dp := range k.GetParams(ctx).DebtParams {
balance := k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc).GetCoins().AmountOf(dp.Denom)
if balance.LT(netAmount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this beif balance.LT(surplusToBurn) {?
netAmount doesn't change in this loop.

if dep.Amount.IsZero() {
// remove the deposit from the slice if it is empty
deposits = append(deposits[:i], deposits[i+1:]...)
i--
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my editor is saying i-- is an ineffective assignment. Maye although it's updated here, the next for loop iteration overwrites it?
Could also be a false positive

Copy link
Member

@rhuairahrighairidh rhuairahrighairidh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@karzak karzak merged commit 9b1bf55 into develop Jan 15, 2020
@karzak karzak deleted the kd-move-liquidator branch January 15, 2020 14:19
denalimarsh pushed a commit that referenced this pull request Apr 3, 2020
* wip: tpyes and keeper methods

* wip: iterators

* wip: types and keeper methods

* wip: add msgs

* wip: client methods

* wip: rebase develop

* wip: types tests

* wip: keeper tests, small fixes

* wip: add cdp tests

* wip: deposit tests

* wip: keeper tests

* wip: tests and module methods

* feat: error when fetching expired price

* feat: conversion factor for external assets

* feat: debt floor for new cdps

* feat: save deposits on export genesis

* feat: ensure messages implement msg

* feat: index deposits by status

* fix: stray comment

* wip: address review comments

* address review comments

* wip: move liquidation to cdp module

* wip: handle liquidations directly

* wip: use new auction interface

* feat: auction collateral in cdp begin block

* feat: update param validation

* feat: surplus and debt auctions

* address review comments

* address review comments

* fix: auction multiple deposits

* clean up netting function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cdp issues for cdp features R4R When a PR is ready for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants