mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 02:37:43 +00:00 
			
		
		
		
	fix: simplify collateral auction logic
This commit is contained in:
		
							parent
							
								
									d489bacfac
								
							
						
					
					
						commit
						89b63a3cba
					
				@ -1,8 +1,6 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp/types"
 | 
			
		||||
@ -13,100 +11,15 @@ const (
 | 
			
		||||
	dump = 100
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type partialDeposit struct {
 | 
			
		||||
	Depositor sdk.AccAddress
 | 
			
		||||
	Amount    sdk.Coin
 | 
			
		||||
	DebtShare sdk.Int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newPartialDeposit(depositor sdk.AccAddress, amount sdk.Coin, ds sdk.Int) partialDeposit {
 | 
			
		||||
	return partialDeposit{
 | 
			
		||||
		Depositor: depositor,
 | 
			
		||||
		Amount:    amount,
 | 
			
		||||
		DebtShare: ds,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type partialDeposits []partialDeposit
 | 
			
		||||
 | 
			
		||||
func (pd partialDeposits) SumCollateral() (sum sdk.Int) {
 | 
			
		||||
	sum = sdk.ZeroInt()
 | 
			
		||||
	for _, d := range pd {
 | 
			
		||||
		sum = sum.Add(d.Amount.Amount)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pd partialDeposits) SumDebt() (sum sdk.Int) {
 | 
			
		||||
	sum = sdk.ZeroInt()
 | 
			
		||||
	for _, d := range pd {
 | 
			
		||||
		sum = sum.Add(d.DebtShare)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt
 | 
			
		||||
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) error {
 | 
			
		||||
	auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
 | 
			
		||||
	partialAuctionDeposits := partialDeposits{}
 | 
			
		||||
	totalCollateral := deposits.SumCollateral()
 | 
			
		||||
	for totalCollateral.GT(sdk.ZeroInt()) {
 | 
			
		||||
		for i, dep := range deposits {
 | 
			
		||||
			if dep.Amount.IsZero() {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			collateralAmount := dep.Amount.Amount
 | 
			
		||||
			collateralDenom := dep.Amount.Denom
 | 
			
		||||
			// create auctions from individual deposits that are larger than the auction size
 | 
			
		||||
			debtChange, collateralChange, err := k.CreateAuctionsFromDeposit(ctx, dep, debt, totalCollateral, auctionSize, bidDenom)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Printf("AuctionCollateral:createFromD:loop%d:liquidator:%s\n", i, k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc))
 | 
			
		||||
			debt = debt.Sub(debtChange)
 | 
			
		||||
			totalCollateral = totalCollateral.Sub(collateralChange)
 | 
			
		||||
			dep.Amount = sdk.NewCoin(collateralDenom, collateralAmount.Sub(collateralChange))
 | 
			
		||||
			collateralAmount = collateralAmount.Sub(collateralChange)
 | 
			
		||||
			// if there is leftover collateral that is less than a lot
 | 
			
		||||
			if !dep.Amount.IsZero() {
 | 
			
		||||
				// figure out how much debt this deposit accounts for
 | 
			
		||||
				// (depositCollateral / totalCollateral) * totalDebtFromCDP
 | 
			
		||||
				debtCoveredByDeposit := collateralAmount.Mul(debt).Quo(totalCollateral) // integer division (ie rounds down)
 | 
			
		||||
				// if adding this deposit to the other partial deposits is less than a lot
 | 
			
		||||
				if (partialAuctionDeposits.SumCollateral().Add(collateralAmount)).LT(auctionSize) {
 | 
			
		||||
					// append the deposit to the partial deposits and zero out the deposit
 | 
			
		||||
					pd := newPartialDeposit(dep.Depositor, dep.Amount, debtCoveredByDeposit)
 | 
			
		||||
					partialAuctionDeposits = append(partialAuctionDeposits, pd)
 | 
			
		||||
					dep.Amount = sdk.NewCoin(collateralDenom, sdk.ZeroInt())
 | 
			
		||||
				} else {
 | 
			
		||||
					// if the sum of partial deposits now makes a lot
 | 
			
		||||
					partialCollateral := sdk.NewCoin(collateralDenom, auctionSize.Sub(partialAuctionDeposits.SumCollateral()))
 | 
			
		||||
					partialAmount := partialCollateral.Amount
 | 
			
		||||
					partialDebt := partialAmount.Mul(debtCoveredByDeposit).Quo(collateralAmount) // integer division (ie rounds down)
 | 
			
		||||
 | 
			
		||||
					// create a partial deposit from the deposit
 | 
			
		||||
					partialDep := newPartialDeposit(dep.Depositor, partialCollateral, partialDebt)
 | 
			
		||||
					// append it to the partial deposits
 | 
			
		||||
					partialAuctionDeposits = append(partialAuctionDeposits, partialDep)
 | 
			
		||||
					// create an auction from the partial deposits
 | 
			
		||||
					debtChange, collateralChange, err := k.CreateAuctionFromPartialDeposits(ctx, partialAuctionDeposits, debt, totalCollateral, auctionSize, bidDenom)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					fmt.Printf("AuctionCollateral:createFromPD:loop%d:liquidator:%s\n", i, k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc))
 | 
			
		||||
					debt = debt.Sub(debtChange)
 | 
			
		||||
					totalCollateral = totalCollateral.Sub(collateralChange)
 | 
			
		||||
					// reset partial deposits and update the deposit amount
 | 
			
		||||
					partialAuctionDeposits = partialDeposits{}
 | 
			
		||||
					dep.Amount = sdk.NewCoin(collateralDenom, collateralAmount.Sub(partialAmount))
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			deposits[i] = dep
 | 
			
		||||
			totalCollateral = deposits.SumCollateral()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if partialAuctionDeposits.SumCollateral().GT(sdk.ZeroInt()) {
 | 
			
		||||
		_, _, err := k.CreateAuctionFromPartialDeposits(ctx, partialAuctionDeposits, debt, totalCollateral, partialAuctionDeposits.SumCollateral(), bidDenom)
 | 
			
		||||
	auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
 | 
			
		||||
	totalCollateral := deposits.SumCollateral()
 | 
			
		||||
	for _, deposit := range deposits {
 | 
			
		||||
 | 
			
		||||
		debtCoveredByDeposit := (sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
 | 
			
		||||
		err := k.CreateAuctionsFromDeposit(ctx, deposit.Amount, deposit.Depositor, debtCoveredByDeposit, auctionSize, bidDenom)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@ -114,54 +27,37 @@ func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateAuctionsFromDeposit creates auctions from the input deposit until there is less than auctionSize left on the deposit
 | 
			
		||||
// CreateAuctionsFromDeposit creates auctions from the input deposit
 | 
			
		||||
func (k Keeper) CreateAuctionsFromDeposit(
 | 
			
		||||
	ctx sdk.Context, dep types.Deposit, debt sdk.Int, totalCollateral sdk.Int, auctionSize sdk.Int,
 | 
			
		||||
	principalDenom string) (debtChange sdk.Int, collateralChange sdk.Int, err error) {
 | 
			
		||||
	debtChange = sdk.ZeroInt()
 | 
			
		||||
	collateralChange = sdk.ZeroInt()
 | 
			
		||||
	depositAmount := dep.Amount.Amount
 | 
			
		||||
	depositDenom := dep.Amount.Denom
 | 
			
		||||
	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()
 | 
			
		||||
		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.Add(penalty)), []sdk.AccAddress{dep.Depositor},
 | 
			
		||||
			[]sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), depositDebtAmount))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return sdk.ZeroInt(), sdk.ZeroInt(), err
 | 
			
		||||
	ctx sdk.Context, collateral sdk.Coin, returnAddr sdk.AccAddress, debt, auctionSize sdk.Int,
 | 
			
		||||
	principalDenom string) (err error) {
 | 
			
		||||
 | 
			
		||||
	amountToAuction := sdk.NewInt(collateral.Amount.Int64())
 | 
			
		||||
	totalCollateralAmount := sdk.NewInt(collateral.Amount.Int64())
 | 
			
		||||
	remainingDebt := sdk.NewInt(debt.Int64())
 | 
			
		||||
	for amountToAuction.GT(sdk.ZeroInt()) {
 | 
			
		||||
		for amountToAuction.GT(auctionSize) {
 | 
			
		||||
			debtCoveredByAuction := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateralAmount))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
 | 
			
		||||
			penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, debtCoveredByAuction)
 | 
			
		||||
			_, err := k.auctionKeeper.StartCollateralAuction(
 | 
			
		||||
				ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, auctionSize), sdk.NewCoin(principalDenom, debtCoveredByAuction.Add(penalty)), []sdk.AccAddress{returnAddr},
 | 
			
		||||
				[]sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), debtCoveredByAuction))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			amountToAuction = amountToAuction.Sub(auctionSize)
 | 
			
		||||
			remainingDebt = remainingDebt.Sub(debtCoveredByAuction)
 | 
			
		||||
		}
 | 
			
		||||
		depositAmount = depositAmount.Sub(auctionSize)
 | 
			
		||||
		totalCollateral = totalCollateral.Sub(auctionSize)
 | 
			
		||||
		debt = debt.Sub(depositDebtAmount)
 | 
			
		||||
		// subtract one lot's worth of debt from the total debt covered by this deposit
 | 
			
		||||
		debtChange = debtChange.Add(depositDebtAmount)
 | 
			
		||||
		collateralChange = collateralChange.Add(auctionSize)
 | 
			
		||||
 | 
			
		||||
		penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, remainingDebt)
 | 
			
		||||
		_, err := k.auctionKeeper.StartCollateralAuction(
 | 
			
		||||
			ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, amountToAuction), sdk.NewCoin(principalDenom, remainingDebt.Add(penalty)), []sdk.AccAddress{returnAddr},
 | 
			
		||||
			[]sdk.Int{amountToAuction}, sdk.NewCoin(k.GetDebtDenom(ctx), remainingDebt))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		amountToAuction = sdk.ZeroInt()
 | 
			
		||||
	}
 | 
			
		||||
	return debtChange, collateralChange, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateAuctionFromPartialDeposits creates an auction from the input partial deposits
 | 
			
		||||
func (k Keeper) CreateAuctionFromPartialDeposits(ctx sdk.Context, partialDeps partialDeposits, debt sdk.Int, collateral sdk.Int, auctionSize sdk.Int, bidDenom string) (debtChange, collateralChange sdk.Int, err error) {
 | 
			
		||||
 | 
			
		||||
	returnAddrs := []sdk.AccAddress{}
 | 
			
		||||
	returnWeights := []sdk.Int{}
 | 
			
		||||
	depositDenom := partialDeps[0].Amount.Denom
 | 
			
		||||
	for _, pd := range partialDeps {
 | 
			
		||||
		returnAddrs = append(returnAddrs, pd.Depositor)
 | 
			
		||||
		returnWeights = append(returnWeights, pd.DebtShare)
 | 
			
		||||
	}
 | 
			
		||||
	penalty := k.ApplyLiquidationPenalty(ctx, depositDenom, partialDeps.SumDebt())
 | 
			
		||||
	_, err = k.auctionKeeper.StartCollateralAuction(ctx, types.LiquidatorMacc, sdk.NewCoin(partialDeps[0].Amount.Denom, auctionSize), sdk.NewCoin(bidDenom, partialDeps.SumDebt().Add(penalty)), returnAddrs, returnWeights, sdk.NewCoin(k.GetDebtDenom(ctx), partialDeps.SumDebt()))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return sdk.ZeroInt(), sdk.ZeroInt(), err
 | 
			
		||||
	}
 | 
			
		||||
	debtChange = partialDeps.SumDebt()
 | 
			
		||||
	collateralChange = partialDeps.SumCollateral()
 | 
			
		||||
	return debtChange, collateralChange, nil
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,6 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Printf("SeizeCollateral:liquidator: %s\n", k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc))
 | 
			
		||||
 | 
			
		||||
	// liquidate deposits and send collateral from cdp to liquidator
 | 
			
		||||
	for _, dep := range deposits {
 | 
			
		||||
@ -50,7 +49,6 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
 | 
			
		||||
		}
 | 
			
		||||
		k.DeleteDeposit(ctx, dep.CdpID, dep.Depositor)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Printf("SeizeCollateral:liquidator: %s\n", k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc))
 | 
			
		||||
	err = k.AuctionCollateral(ctx, deposits, debt, cdp.Principal.Denom)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
@ -167,10 +166,6 @@ func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
 | 
			
		||||
	p := cdp.Principal.Amount
 | 
			
		||||
	cl := cdp.Collateral.Amount
 | 
			
		||||
	tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
 | 
			
		||||
	fmt.Printf("%s\n", cdp)
 | 
			
		||||
	fmt.Printf("%s\n", deposits)
 | 
			
		||||
	fmt.Printf("cdpaccount: %s\n", suite.app.GetSupplyKeeper().GetModuleAccount(suite.ctx, types.ModuleName))
 | 
			
		||||
	fmt.Printf("liquidator: %s\n", suite.app.GetSupplyKeeper().GetModuleAccount(suite.ctx, types.LiquidatorMacc))
 | 
			
		||||
	err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
 | 
			
		||||
	suite.NoError(err)
 | 
			
		||||
	tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user