mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-10 10:05:18 +00:00
fix: simplify collateral auction logic
This commit is contained in:
parent
d489bacfac
commit
89b63a3cba
@ -1,8 +1,6 @@
|
|||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/cdp/types"
|
"github.com/kava-labs/kava/x/cdp/types"
|
||||||
@ -13,100 +11,15 @@ const (
|
|||||||
dump = 100
|
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
|
// 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 {
|
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
|
auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
|
||||||
partialDep := newPartialDeposit(dep.Depositor, partialCollateral, partialDebt)
|
totalCollateral := deposits.SumCollateral()
|
||||||
// append it to the partial deposits
|
for _, deposit := range deposits {
|
||||||
partialAuctionDeposits = append(partialAuctionDeposits, partialDep)
|
|
||||||
// create an auction from the partial deposits
|
debtCoveredByDeposit := (sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
||||||
debtChange, collateralChange, err := k.CreateAuctionFromPartialDeposits(ctx, partialAuctionDeposits, debt, totalCollateral, auctionSize, bidDenom)
|
err := k.CreateAuctionsFromDeposit(ctx, deposit.Amount, deposit.Depositor, debtCoveredByDeposit, 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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -114,54 +27,37 @@ func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt
|
|||||||
return nil
|
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(
|
func (k Keeper) CreateAuctionsFromDeposit(
|
||||||
ctx sdk.Context, dep types.Deposit, debt sdk.Int, totalCollateral sdk.Int, auctionSize sdk.Int,
|
ctx sdk.Context, collateral sdk.Coin, returnAddr sdk.AccAddress, debt, auctionSize sdk.Int,
|
||||||
principalDenom string) (debtChange sdk.Int, collateralChange sdk.Int, err error) {
|
principalDenom string) (err error) {
|
||||||
debtChange = sdk.ZeroInt()
|
|
||||||
collateralChange = sdk.ZeroInt()
|
amountToAuction := sdk.NewInt(collateral.Amount.Int64())
|
||||||
depositAmount := dep.Amount.Amount
|
totalCollateralAmount := sdk.NewInt(collateral.Amount.Int64())
|
||||||
depositDenom := dep.Amount.Denom
|
remainingDebt := sdk.NewInt(debt.Int64())
|
||||||
for depositAmount.GTE(auctionSize) {
|
for amountToAuction.GT(sdk.ZeroInt()) {
|
||||||
// figure out how much debt is covered by one lots worth of collateral
|
for amountToAuction.GT(auctionSize) {
|
||||||
depositDebtAmount := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
debtCoveredByAuction := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateralAmount))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
||||||
penalty := k.ApplyLiquidationPenalty(ctx, depositDenom, depositDebtAmount)
|
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, debtCoveredByAuction)
|
||||||
// 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(collateral.Denom, auctionSize), sdk.NewCoin(principalDenom, debtCoveredByAuction.Add(penalty)), []sdk.AccAddress{returnAddr},
|
||||||
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), debtCoveredByAuction))
|
||||||
[]sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), depositDebtAmount))
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return sdk.ZeroInt(), sdk.ZeroInt(), err
|
}
|
||||||
|
amountToAuction = amountToAuction.Sub(auctionSize)
|
||||||
|
remainingDebt = remainingDebt.Sub(debtCoveredByAuction)
|
||||||
}
|
}
|
||||||
depositAmount = depositAmount.Sub(auctionSize)
|
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, remainingDebt)
|
||||||
totalCollateral = totalCollateral.Sub(auctionSize)
|
_, err := k.auctionKeeper.StartCollateralAuction(
|
||||||
debt = debt.Sub(depositDebtAmount)
|
ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, amountToAuction), sdk.NewCoin(principalDenom, remainingDebt.Add(penalty)), []sdk.AccAddress{returnAddr},
|
||||||
// subtract one lot's worth of debt from the total debt covered by this deposit
|
[]sdk.Int{amountToAuction}, sdk.NewCoin(k.GetDebtDenom(ctx), remainingDebt))
|
||||||
debtChange = debtChange.Add(depositDebtAmount)
|
if err != nil {
|
||||||
collateralChange = collateralChange.Add(auctionSize)
|
return err
|
||||||
|
}
|
||||||
|
amountToAuction = sdk.ZeroInt()
|
||||||
}
|
}
|
||||||
return debtChange, collateralChange, nil
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("SeizeCollateral:liquidator: %s\n", k.supplyKeeper.GetModuleAccount(ctx, types.LiquidatorMacc))
|
|
||||||
|
|
||||||
// liquidate deposits and send collateral from cdp to liquidator
|
// liquidate deposits and send collateral from cdp to liquidator
|
||||||
for _, dep := range deposits {
|
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)
|
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)
|
err = k.AuctionCollateral(ctx, deposits, debt, cdp.Principal.Denom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2,7 +2,6 @@ package keeper_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -167,10 +166,6 @@ func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
|
|||||||
p := cdp.Principal.Amount
|
p := cdp.Principal.Amount
|
||||||
cl := cdp.Collateral.Amount
|
cl := cdp.Collateral.Amount
|
||||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
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)
|
err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||||
|
Loading…
Reference in New Issue
Block a user