mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 23:35:19 +00:00
[R4R] Update fees for all cdps (#449)
* update cdp fees in begin block Co-authored-by: Federico Kunze <federico.kunze94@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Denali Marsh <denali@kava.io> Co-authored-by: John Maheswaran <john@noreply> Co-authored-by: Kevin Davis <kjydavis3@gmail.com>
This commit is contained in:
parent
23e23fdaaa
commit
5737f4fa19
@ -11,23 +11,17 @@ import (
|
|||||||
// BeginBlocker compounds the debt in outstanding cdps and liquidates cdps that are below the required collateralization ratio
|
// BeginBlocker compounds the debt in outstanding cdps and liquidates cdps that are below the required collateralization ratio
|
||||||
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) {
|
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) {
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
previousBlockTime, found := k.GetPreviousBlockTime(ctx)
|
|
||||||
if !found {
|
|
||||||
previousBlockTime = ctx.BlockTime()
|
|
||||||
}
|
|
||||||
previousDistTime, found := k.GetPreviousSavingsDistribution(ctx)
|
previousDistTime, found := k.GetPreviousSavingsDistribution(ctx)
|
||||||
if !found {
|
if !found {
|
||||||
previousDistTime = ctx.BlockTime()
|
previousDistTime = ctx.BlockTime()
|
||||||
k.SetPreviousSavingsDistribution(ctx, previousDistTime)
|
k.SetPreviousSavingsDistribution(ctx, previousDistTime)
|
||||||
}
|
}
|
||||||
blockTimeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousBlockTime.Unix())
|
|
||||||
for _, cp := range params.CollateralParams {
|
|
||||||
for _, dp := range params.DebtParams {
|
|
||||||
k.HandleNewDebt(ctx, cp.Denom, dp.Denom, blockTimeElapsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// call our update fees method for the risky cdps
|
for _, cp := range params.CollateralParams {
|
||||||
err := k.UpdateFeesForRiskyCdps(ctx, cp.Denom, cp.MarketID)
|
|
||||||
|
err := k.UpdateFeesForAllCdps(ctx, cp.Denom)
|
||||||
|
|
||||||
// handle if an error is returned then propagate up
|
// handle if an error is returned then propagate up
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
@ -76,6 +70,5 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) {
|
|||||||
}
|
}
|
||||||
k.SetPreviousSavingsDistribution(ctx, ctx.BlockTime())
|
k.SetPreviousSavingsDistribution(ctx, ctx.BlockTime())
|
||||||
}
|
}
|
||||||
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,8 +152,6 @@ func (suite *ModuleTestSuite) TestBeginBlock() {
|
|||||||
func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
||||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[0], cs(c("xrp", 10000000000)), cs(c("usdx", 1000000000)))
|
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[0], cs(c("xrp", 10000000000)), cs(c("usdx", 1000000000)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.keeper.SetPreviousBlockTime(suite.ctx, suite.ctx.BlockTime())
|
|
||||||
previousBlockTime, _ := suite.keeper.GetPreviousBlockTime(suite.ctx)
|
|
||||||
suite.Equal(i(1000000000), suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx"))
|
suite.Equal(i(1000000000), suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx"))
|
||||||
sk := suite.app.GetSupplyKeeper()
|
sk := suite.app.GetSupplyKeeper()
|
||||||
cdpMacc := sk.GetModuleAccount(suite.ctx, cdp.ModuleName)
|
cdpMacc := sk.GetModuleAccount(suite.ctx, cdp.ModuleName)
|
||||||
@ -167,13 +165,10 @@ func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
|||||||
suite.Equal(i(1000000900), (cdpMacc.GetCoins().AmountOf("debt")))
|
suite.Equal(i(1000000900), (cdpMacc.GetCoins().AmountOf("debt")))
|
||||||
cdp, _ := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
cdp, _ := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||||
|
|
||||||
timeElapsed := sdk.NewInt(suite.ctx.BlockTime().Unix() - previousBlockTime.Unix())
|
|
||||||
|
|
||||||
fees := suite.keeper.CalculateFees(suite.ctx, cdp.Principal, timeElapsed, "xrp")
|
|
||||||
suite.Equal(i(928), fees.AmountOf("usdx"))
|
|
||||||
|
|
||||||
err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
_, found := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||||
|
suite.False(found)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModuleTestSuite(t *testing.T) {
|
func TestModuleTestSuite(t *testing.T) {
|
||||||
|
@ -110,7 +110,6 @@ var (
|
|||||||
GovDenomKey = types.GovDenomKey
|
GovDenomKey = types.GovDenomKey
|
||||||
DepositKeyPrefix = types.DepositKeyPrefix
|
DepositKeyPrefix = types.DepositKeyPrefix
|
||||||
PrincipalKeyPrefix = types.PrincipalKeyPrefix
|
PrincipalKeyPrefix = types.PrincipalKeyPrefix
|
||||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
|
||||||
PreviousDistributionTimeKey = types.PreviousDistributionTimeKey
|
PreviousDistributionTimeKey = types.PreviousDistributionTimeKey
|
||||||
KeyGlobalDebtLimit = types.KeyGlobalDebtLimit
|
KeyGlobalDebtLimit = types.KeyGlobalDebtLimit
|
||||||
KeyCollateralParams = types.KeyCollateralParams
|
KeyCollateralParams = types.KeyCollateralParams
|
||||||
@ -128,7 +127,6 @@ var (
|
|||||||
DefaultGovDenom = types.DefaultGovDenom
|
DefaultGovDenom = types.DefaultGovDenom
|
||||||
DefaultSurplusThreshold = types.DefaultSurplusThreshold
|
DefaultSurplusThreshold = types.DefaultSurplusThreshold
|
||||||
DefaultDebtThreshold = types.DefaultDebtThreshold
|
DefaultDebtThreshold = types.DefaultDebtThreshold
|
||||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
|
||||||
DefaultPreviousDistributionTime = types.DefaultPreviousDistributionTime
|
DefaultPreviousDistributionTime = types.DefaultPreviousDistributionTime
|
||||||
DefaultSavingsDistributionFrequency = types.DefaultSavingsDistributionFrequency
|
DefaultSavingsDistributionFrequency = types.DefaultSavingsDistributionFrequency
|
||||||
MaxSortableDec = types.MaxSortableDec
|
MaxSortableDec = types.MaxSortableDec
|
||||||
|
@ -70,10 +70,6 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk PricefeedKeeper, sk SupplyKeeper,
|
|||||||
for _, d := range gs.Deposits {
|
for _, d := range gs.Deposits {
|
||||||
k.SetDeposit(ctx, d)
|
k.SetDeposit(ctx, d)
|
||||||
}
|
}
|
||||||
// only set the previous block time if it's different than default
|
|
||||||
if !gs.PreviousBlockTime.Equal(DefaultPreviousBlockTime) {
|
|
||||||
k.SetPreviousBlockTime(ctx, gs.PreviousBlockTime)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportGenesis export genesis state for cdp module
|
// ExportGenesis export genesis state for cdp module
|
||||||
@ -95,14 +91,10 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
|||||||
debtDenom := k.GetDebtDenom(ctx)
|
debtDenom := k.GetDebtDenom(ctx)
|
||||||
govDenom := k.GetGovDenom(ctx)
|
govDenom := k.GetGovDenom(ctx)
|
||||||
|
|
||||||
previousBlockTime, found := k.GetPreviousBlockTime(ctx)
|
|
||||||
if !found {
|
|
||||||
previousBlockTime = DefaultPreviousBlockTime
|
|
||||||
}
|
|
||||||
previousDistributionTime, found := k.GetPreviousSavingsDistribution(ctx)
|
previousDistributionTime, found := k.GetPreviousSavingsDistribution(ctx)
|
||||||
if !found {
|
if !found {
|
||||||
previousDistributionTime = DefaultPreviousDistributionTime
|
previousDistributionTime = DefaultPreviousDistributionTime
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewGenesisState(params, cdps, deposits, cdpID, debtDenom, govDenom, previousBlockTime, previousDistributionTime)
|
return NewGenesisState(params, cdps, deposits, cdpID, debtDenom, govDenom, previousDistributionTime)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
||||||
@ -153,7 +152,6 @@ func NewCDPGenStateMulti() app.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
||||||
@ -203,19 +201,16 @@ func badGenStates() []badGenState {
|
|||||||
g9.DebtDenom = ""
|
g9.DebtDenom = ""
|
||||||
|
|
||||||
g10 := baseGenState()
|
g10 := baseGenState()
|
||||||
g10.PreviousBlockTime = time.Time{}
|
g10.Params.CollateralParams[0].AuctionSize = i(-10)
|
||||||
|
|
||||||
g11 := baseGenState()
|
g11 := baseGenState()
|
||||||
g11.Params.CollateralParams[0].AuctionSize = i(-10)
|
g11.Params.CollateralParams[0].LiquidationPenalty = d("5.0")
|
||||||
|
|
||||||
g12 := baseGenState()
|
g12 := baseGenState()
|
||||||
g12.Params.CollateralParams[0].LiquidationPenalty = d("5.0")
|
g12.GovDenom = ""
|
||||||
|
|
||||||
g13 := baseGenState()
|
g13 := baseGenState()
|
||||||
g13.GovDenom = ""
|
g13.Params.DebtParams[0].SavingsRate = d("4.0")
|
||||||
|
|
||||||
g14 := baseGenState()
|
|
||||||
g14.Params.DebtParams[0].SavingsRate = d("4.0")
|
|
||||||
|
|
||||||
return []badGenState{
|
return []badGenState{
|
||||||
badGenState{Genesis: g1, Reason: "duplicate collateral denom"},
|
badGenState{Genesis: g1, Reason: "duplicate collateral denom"},
|
||||||
@ -226,11 +221,10 @@ func badGenStates() []badGenState {
|
|||||||
badGenState{Genesis: g6, Reason: "duplicate debt denom"},
|
badGenState{Genesis: g6, Reason: "duplicate debt denom"},
|
||||||
badGenState{Genesis: g8, Reason: "debt param not found in global debt limit"},
|
badGenState{Genesis: g8, Reason: "debt param not found in global debt limit"},
|
||||||
badGenState{Genesis: g9, Reason: "debt denom not set"},
|
badGenState{Genesis: g9, Reason: "debt denom not set"},
|
||||||
badGenState{Genesis: g10, Reason: "previous block time not set"},
|
badGenState{Genesis: g10, Reason: "negative auction size"},
|
||||||
badGenState{Genesis: g11, Reason: "negative auction size"},
|
badGenState{Genesis: g11, Reason: "invalid liquidation penalty"},
|
||||||
badGenState{Genesis: g12, Reason: "invalid liquidation penalty"},
|
badGenState{Genesis: g12, Reason: "gov denom not set"},
|
||||||
badGenState{Genesis: g13, Reason: "gov denom not set"},
|
badGenState{Genesis: g13, Reason: "invalid savings rate"},
|
||||||
badGenState{Genesis: g14, Reason: "invalid savings rate"},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +274,6 @@ func baseGenState() cdp.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,9 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner sdk.AccAddress, deposit
|
|||||||
|
|
||||||
k.SetDeposit(ctx, deposit)
|
k.SetDeposit(ctx, deposit)
|
||||||
|
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
|
||||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
|
||||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
|
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||||
|
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
cdp.FeesUpdated = ctx.BlockTime()
|
||||||
cdp.Collateral = cdp.Collateral.Add(collateral...)
|
cdp.Collateral = cdp.Collateral.Add(collateral...)
|
||||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
@ -71,15 +68,13 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, deposi
|
|||||||
return sdkerrors.Wrapf(types.ErrInvalidWithdrawAmount, "collateral %s, deposit %s", collateral, deposit.Amount)
|
return sdkerrors.Wrapf(types.ErrInvalidWithdrawAmount, "collateral %s, deposit %s", collateral, deposit.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Principal, cdp.AccumulatedFees)
|
||||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
|
||||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Principal, cdp.AccumulatedFees.Add(fees...))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
|
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
|
||||||
if collateralizationRatio.LT(liquidationRatio) {
|
if collateralizationRatio.LT(liquidationRatio) {
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "colateral %s, collateral ratio %s, liquidation ration %s", collateral[0].Denom, collateralizationRatio, liquidationRatio)
|
return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "collateral %s, collateral ratio %s, liquidation ration %s", collateral[0].Denom, collateralizationRatio, liquidationRatio)
|
||||||
}
|
}
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
@ -96,7 +91,6 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, deposi
|
|||||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
|
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||||
|
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
cdp.FeesUpdated = ctx.BlockTime()
|
||||||
cdp.Collateral = cdp.Collateral.Sub(collateral)
|
cdp.Collateral = cdp.Collateral.Sub(collateral)
|
||||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
|
@ -25,11 +25,7 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// fee calculation
|
err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal.Add(principal...), cdp.AccumulatedFees)
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
|
||||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
|
||||||
|
|
||||||
err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal.Add(principal...), cdp.AccumulatedFees.Add(fees...))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -65,7 +61,6 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
|||||||
|
|
||||||
// update cdp state
|
// update cdp state
|
||||||
cdp.Principal = cdp.Principal.Add(principal...)
|
cdp.Principal = cdp.Principal.Add(principal...)
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
cdp.FeesUpdated = ctx.BlockTime()
|
||||||
|
|
||||||
// increment total principal for the input collateral type
|
// increment total principal for the input collateral type
|
||||||
@ -87,16 +82,13 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
|
|||||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
|
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate fees
|
err := k.ValidatePaymentCoins(ctx, cdp, payment, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
|
||||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
|
||||||
err := k.ValidatePaymentCoins(ctx, cdp, payment, cdp.Principal.Add(cdp.AccumulatedFees...).Add(fees...))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate fee and principal payment
|
// calculate fee and principal payment
|
||||||
feePayment, principalPayment := k.calculatePayment(ctx, cdp.Principal.Add(cdp.AccumulatedFees...).Add(fees...), cdp.AccumulatedFees.Add(fees...), payment)
|
feePayment, principalPayment := k.calculatePayment(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), cdp.AccumulatedFees, payment)
|
||||||
|
|
||||||
// send the payment from the sender to the cpd module
|
// send the payment from the sender to the cpd module
|
||||||
err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, feePayment.Add(principalPayment...))
|
err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, feePayment.Add(principalPayment...))
|
||||||
@ -142,7 +134,7 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
|
|||||||
if !principalPayment.IsZero() {
|
if !principalPayment.IsZero() {
|
||||||
cdp.Principal = cdp.Principal.Sub(principalPayment)
|
cdp.Principal = cdp.Principal.Sub(principalPayment)
|
||||||
}
|
}
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...).Sub(feePayment)
|
cdp.AccumulatedFees = cdp.AccumulatedFees.Sub(feePayment)
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
cdp.FeesUpdated = ctx.BlockTime()
|
||||||
|
|
||||||
// decrement the total principal for the input collateral type
|
// decrement the total principal for the input collateral type
|
||||||
|
@ -159,11 +159,12 @@ func (suite *DrawTestSuite) TestAddRepayPrincipalFees() {
|
|||||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[2], cs(c("xrp", 1000000000000)), cs(c("usdx", 100000000000)))
|
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[2], cs(c("xrp", 1000000000000)), cs(c("usdx", 100000000000)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Minute * 10))
|
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Minute * 10))
|
||||||
|
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||||
|
suite.NoError(err)
|
||||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 10000000)))
|
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 10000000)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||||
suite.Equal(cs(c("usdx", 92827)), t.AccumulatedFees)
|
suite.Equal(cs(c("usdx", 92827)), t.AccumulatedFees)
|
||||||
_ = suite.keeper.MintDebtCoins(suite.ctx, types.ModuleName, "debt", cs(c("usdx", 92827)))
|
|
||||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 100)))
|
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 100)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||||
@ -176,7 +177,9 @@ func (suite *DrawTestSuite) TestAddRepayPrincipalFees() {
|
|||||||
err = suite.keeper.AddCdp(suite.ctx, suite.addrs[2], cs(c("xrp", 1000000000000)), cs(c("usdx", 100000000)))
|
err = suite.keeper.AddCdp(suite.ctx, suite.addrs[2], cs(c("xrp", 1000000000000)), cs(c("usdx", 100000000)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 31536000))
|
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 31536000)) // move forward one year in time
|
||||||
|
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||||
|
suite.NoError(err)
|
||||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 100000000)))
|
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", cs(c("usdx", 100000000)))
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(3))
|
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(3))
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||||
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"
|
||||||
@ -27,38 +25,53 @@ func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coins, periods sdk.
|
|||||||
return newFees
|
return newFees
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFeesForRiskyCdps calculates fees for risky CDPs
|
// UpdateFeesForAllCdps updates the fees for each of the CDPs
|
||||||
// The overall logic is first select the CDPs with 10% of the liquidation ratio
|
func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralDenom string) error {
|
||||||
// Then we call calculate fees on each of those CDPs
|
|
||||||
// Next we store the result of the fees in the cdp.AccumulatedFees field
|
|
||||||
// Finally we set the cdp.FeesUpdated time to the current block time (ctx.BlockTime()) since that
|
|
||||||
// is when we made the update
|
|
||||||
func (k Keeper) UpdateFeesForRiskyCdps(ctx sdk.Context, collateralDenom string, marketID string) error {
|
|
||||||
|
|
||||||
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
|
k.IterateCdpsByDenom(ctx, collateralDenom, func(cdp types.CDP) bool {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
liquidationRatio := k.getLiquidationRatio(ctx, collateralDenom)
|
|
||||||
priceDivLiqRatio := price.Price.Quo(liquidationRatio)
|
|
||||||
if priceDivLiqRatio.IsZero() {
|
|
||||||
priceDivLiqRatio = sdk.SmallestDec()
|
|
||||||
}
|
|
||||||
// NOTE - we have a fixed cutoff at 110% - this may or may not be changed in the future
|
|
||||||
normalizedRatio := sdk.OneDec().Quo(priceDivLiqRatio).Mul(sdk.MustNewDecFromStr("1.1"))
|
|
||||||
|
|
||||||
// now iterate over all the cdps based on collateral ratio
|
|
||||||
k.IterateCdpsByCollateralRatio(ctx, collateralDenom, normalizedRatio, func(cdp types.CDP) bool {
|
|
||||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||||
// get the number of periods
|
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
||||||
|
|
||||||
// now calculate and store additional fees
|
newFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralDenom)
|
||||||
additionalFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralDenom)
|
|
||||||
|
|
||||||
// now add the additional fees to the accumulated fees for the cdp
|
// exit without updating fees if amount has rounded down to zero
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(additionalFees...)
|
// cdp will get updated next block when newFees, newFeesSavings, newFeesSurplus >0
|
||||||
|
if newFees.IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// note - only works if principal length is one
|
||||||
|
for _, dc := range cdp.Principal {
|
||||||
|
dp, found := k.GetDebtParam(ctx, dc.Denom)
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
savingsRate := dp.SavingsRate
|
||||||
|
|
||||||
|
newFeesSavings := sdk.NewDecFromInt(newFees.AmountOf(dp.Denom)).Mul(savingsRate).RoundInt()
|
||||||
|
newFeesSurplus := newFees.AmountOf(dp.Denom).Sub(newFeesSavings)
|
||||||
|
|
||||||
|
// similar to checking for rounding to zero of all fees, but in this case we
|
||||||
|
// need to handle cases where we expect surplus or savings fees to be zero, namely
|
||||||
|
// if newFeesSavings = 0, check if savings rate is not zero
|
||||||
|
// if newFeesSurplus = 0, check if savings rate is not one
|
||||||
|
if (newFeesSavings.IsZero() && !savingsRate.IsZero()) || (newFeesSurplus.IsZero() && !savingsRate.Equal(sdk.OneDec())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// mint debt coins to the cdp account
|
||||||
|
k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), newFees)
|
||||||
|
previousDebt := k.GetTotalPrincipal(ctx, collateralDenom, dp.Denom)
|
||||||
|
feeCoins := sdk.NewCoins(sdk.NewCoin(dp.Denom, previousDebt))
|
||||||
|
k.SetTotalPrincipal(ctx, collateralDenom, dp.Denom, feeCoins.Add(newFees...).AmountOf(dp.Denom))
|
||||||
|
|
||||||
|
// mint surplus coins divided between the liquidator and savings module accounts.
|
||||||
|
k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSurplus)))
|
||||||
|
k.supplyKeeper.MintCoins(ctx, types.SavingsRateMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSavings)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// now add the new fees fees to the accumulated fees for the cdp
|
||||||
|
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(newFees...)
|
||||||
|
|
||||||
// and set the fees updated time to the current block time since we just updated it
|
// and set the fees updated time to the current block time since we just updated it
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
cdp.FeesUpdated = ctx.BlockTime()
|
||||||
@ -109,20 +122,3 @@ func (k Keeper) SetTotalPrincipal(ctx sdk.Context, collateralDenom string, princ
|
|||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix)
|
||||||
store.Set([]byte(collateralDenom+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total))
|
store.Set([]byte(collateralDenom+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreviousBlockTime get the blocktime for the previous block
|
|
||||||
func (k Keeper) GetPreviousBlockTime(ctx sdk.Context) (blockTime time.Time, found bool) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey)
|
|
||||||
b := store.Get([]byte{})
|
|
||||||
if b == nil {
|
|
||||||
return time.Time{}, false
|
|
||||||
}
|
|
||||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &blockTime)
|
|
||||||
return blockTime, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPreviousBlockTime set the time of the previous block
|
|
||||||
func (k Keeper) SetPreviousBlockTime(ctx sdk.Context, blockTime time.Time) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey)
|
|
||||||
store.Set([]byte{}, k.cdc.MustMarshalBinaryLengthPrefixed(blockTime))
|
|
||||||
}
|
|
||||||
|
@ -68,10 +68,6 @@ func (suite *FeeTestSuite) TestCalculateFeesPrecisionLoss() {
|
|||||||
|
|
||||||
absError := (sdk.OneDec().Sub(sdk.NewDecFromInt(bulkFees[0].Amount).Quo(sdk.NewDecFromInt(individualFees[0].Amount)))).Abs()
|
absError := (sdk.OneDec().Sub(sdk.NewDecFromInt(bulkFees[0].Amount).Quo(sdk.NewDecFromInt(individualFees[0].Amount)))).Abs()
|
||||||
|
|
||||||
suite.T().Log(bulkFees)
|
|
||||||
suite.T().Log(individualFees)
|
|
||||||
suite.T().Log(absError)
|
|
||||||
|
|
||||||
suite.True(d("0.00001").GTE(absError))
|
suite.True(d("0.00001").GTE(absError))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,28 +91,26 @@ func (suite *FeeTestSuite) createCdps() {
|
|||||||
|
|
||||||
// now create two cdps with the addresses we just created
|
// now create two cdps with the addresses we just created
|
||||||
// use the created account to create a cdp that SHOULD have fees updated
|
// use the created account to create a cdp that SHOULD have fees updated
|
||||||
// to get a ratio between 100 - 110% of liquidation ratio we can use 200xrp ($50) and 24 usdx (208% collateralization with liquidation ratio of 200%)
|
|
||||||
// create CDP for the first address
|
|
||||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("usdx", 24000000)))
|
err := suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("usdx", 24000000)))
|
||||||
suite.NoError(err) // check that no error was thrown
|
suite.NoError(err) // check that no error was thrown
|
||||||
|
|
||||||
// use the other account to create a cdp that SHOULD NOT have fees updated - 500% collateralization
|
// use the other account to create a cdp that SHOULD NOT have fees updated
|
||||||
// create CDP for the second address
|
|
||||||
err = suite.keeper.AddCdp(suite.ctx, addrs[1], cs(c("xrp", 200000000)), cs(c("usdx", 10000000)))
|
err = suite.keeper.AddCdp(suite.ctx, addrs[1], cs(c("xrp", 200000000)), cs(c("usdx", 10000000)))
|
||||||
suite.NoError(err) // check that no error was thrown
|
suite.NoError(err) // check that no error was thrown
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFeesForRiskyCdpsTest tests the functionality for updating the fees for risky CDPs
|
// TestUpdateFees tests the functionality for updating the fees for CDPs
|
||||||
func (suite *FeeTestSuite) TestUpdateFeesForRiskyCdps() {
|
func (suite *FeeTestSuite) TestUpdateFees() {
|
||||||
// this helper function creates two CDPs with id 1 and 2 respectively, each with zero fees
|
// this helper function creates two CDPs with id 1 and 2 respectively, each with zero fees
|
||||||
suite.createCdps()
|
suite.createCdps()
|
||||||
|
|
||||||
// move the context forward in time so that cdps will have fees accumulate if CalculateFees is called
|
// move the context forward in time so that cdps will have fees accumulate if CalculateFees is called
|
||||||
// note - time must be moved forward by a sufficient amount in order for additional
|
// note - time must be moved forward by a sufficient amount in order for additional
|
||||||
// fees to accumulate, in this example 60 seconds
|
// fees to accumulate, in this example 600 seconds
|
||||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 60))
|
oldtime := suite.ctx.BlockTime()
|
||||||
err := suite.keeper.UpdateFeesForRiskyCdps(suite.ctx, "xrp", "xrp:usd")
|
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 600))
|
||||||
|
err := suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||||
suite.NoError(err) // check that we don't have any error
|
suite.NoError(err) // check that we don't have any error
|
||||||
|
|
||||||
// cdp we expect fees to accumulate for
|
// cdp we expect fees to accumulate for
|
||||||
@ -124,29 +118,15 @@ func (suite *FeeTestSuite) TestUpdateFeesForRiskyCdps() {
|
|||||||
// check fees are not zero
|
// check fees are not zero
|
||||||
// check that the fees have been updated
|
// check that the fees have been updated
|
||||||
suite.False(cdp1.AccumulatedFees.Empty())
|
suite.False(cdp1.AccumulatedFees.Empty())
|
||||||
// now check that we have the correct amount of fees overall (2 USDX for this scenario)
|
// now check that we have the correct amount of fees overall (22 USDX for this scenario)
|
||||||
suite.Equal(sdk.NewInt(2), cdp1.AccumulatedFees.AmountOf("usdx"))
|
suite.Equal(sdk.NewInt(22), cdp1.AccumulatedFees.AmountOf("usdx"))
|
||||||
|
suite.Equal(suite.ctx.BlockTime(), cdp1.FeesUpdated)
|
||||||
// cdp we expect fees to not accumulate for
|
// cdp we expect fees to not accumulate for because of rounding to zero
|
||||||
cdp2, _ := suite.keeper.GetCDP(suite.ctx, "xrp", 2)
|
cdp2, _ := suite.keeper.GetCDP(suite.ctx, "xrp", 2)
|
||||||
|
|
||||||
// check fees are zero
|
// check fees are zero
|
||||||
suite.True(cdp2.AccumulatedFees.Empty())
|
suite.True(cdp2.AccumulatedFees.Empty())
|
||||||
|
suite.Equal(oldtime, cdp2.FeesUpdated)
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *FeeTestSuite) TestGetSetPreviousBlockTime() {
|
|
||||||
now := tmtime.Now()
|
|
||||||
|
|
||||||
_, f := suite.keeper.GetPreviousBlockTime(suite.ctx)
|
|
||||||
suite.False(f)
|
|
||||||
|
|
||||||
suite.NotPanics(func() { suite.keeper.SetPreviousBlockTime(suite.ctx, now) })
|
|
||||||
|
|
||||||
bpt, f := suite.keeper.GetPreviousBlockTime(suite.ctx)
|
|
||||||
suite.True(f)
|
|
||||||
suite.Equal(now, bpt)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFeeTestSuite(t *testing.T) {
|
func TestFeeTestSuite(t *testing.T) {
|
||||||
|
@ -70,7 +70,6 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
||||||
@ -153,7 +152,6 @@ func NewCDPGenStateMulti() app.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
||||||
@ -211,7 +209,6 @@ func NewCDPGenStateHighDebtLimit() app.GenesisState {
|
|||||||
DebtDenom: cdp.DefaultDebtDenom,
|
DebtDenom: cdp.DefaultDebtDenom,
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
GovDenom: cdp.DefaultGovDenom,
|
||||||
CDPs: cdp.CDPs{},
|
CDPs: cdp.CDPs{},
|
||||||
PreviousBlockTime: cdp.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: cdp.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
||||||
|
@ -18,11 +18,6 @@ import (
|
|||||||
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
|
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) 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...))
|
||||||
// Update fees
|
|
||||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
|
||||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
|
||||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
|
||||||
cdp.FeesUpdated = ctx.BlockTime()
|
|
||||||
|
|
||||||
// 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)
|
||||||
@ -80,29 +75,6 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleNewDebt compounds the accumulated fees for the input collateral and principal coins.
|
|
||||||
// the following operations are performed:
|
|
||||||
// 1. The fees accumulated since the last block are calculated
|
|
||||||
// 2. The fees are minted, split between the liquidator module account (surplus) and the savings rate module account (savings rate) according to the savings rate parameter.
|
|
||||||
// 2. An equal amount of debt coins are minted in the cdp module account
|
|
||||||
// 3. updates the total amount of principal for the input collateral type in the store,
|
|
||||||
func (k Keeper) HandleNewDebt(ctx sdk.Context, collateralDenom string, principalDenom string, periods sdk.Int) {
|
|
||||||
dp, _ := k.GetDebtParam(ctx, principalDenom)
|
|
||||||
savingsRate := dp.SavingsRate
|
|
||||||
previousDebt := k.GetTotalPrincipal(ctx, collateralDenom, principalDenom)
|
|
||||||
feeCoins := sdk.NewCoins(sdk.NewCoin(principalDenom, previousDebt))
|
|
||||||
newFees := k.CalculateFees(ctx, feeCoins, periods, collateralDenom)
|
|
||||||
if newFees.IsZero() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newFeesSavings := sdk.NewDecFromInt(newFees.AmountOf(principalDenom)).Mul(savingsRate).RoundInt()
|
|
||||||
newFeesSurplus := newFees.AmountOf(principalDenom).Sub(newFeesSavings)
|
|
||||||
k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), newFees)
|
|
||||||
k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSurplus)))
|
|
||||||
k.supplyKeeper.MintCoins(ctx, types.SavingsRateMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSavings)))
|
|
||||||
k.SetTotalPrincipal(ctx, collateralDenom, principalDenom, feeCoins.Add(newFees...).AmountOf(principalDenom))
|
|
||||||
}
|
|
||||||
|
|
||||||
// LiquidateCdps seizes collateral from all CDPs below the input liquidation ratio
|
// LiquidateCdps seizes collateral from all CDPs below the input liquidation ratio
|
||||||
func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, liquidationRatio sdk.Dec) error {
|
func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, liquidationRatio sdk.Dec) error {
|
||||||
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
|
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
|
||||||
|
@ -189,14 +189,6 @@ func (suite *SeizeTestSuite) TestLiquidateCdps() {
|
|||||||
suite.Equal(len(suite.liquidations.xrp), xrpLiquidations)
|
suite.Equal(len(suite.liquidations.xrp), xrpLiquidations)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SeizeTestSuite) TestHandleNewDebt() {
|
|
||||||
suite.createCdps()
|
|
||||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
|
||||||
suite.keeper.HandleNewDebt(suite.ctx, "xrp", "usdx", i(31536000))
|
|
||||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
|
||||||
suite.Equal(sdk.NewDec(tpb.Int64()).Mul(d("1.05")).TruncateInt().Int64(), tpa.Int64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *SeizeTestSuite) TestApplyLiquidationPenalty() {
|
func (suite *SeizeTestSuite) TestApplyLiquidationPenalty() {
|
||||||
penalty := suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(1000))
|
penalty := suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(1000))
|
||||||
suite.Equal(i(50), penalty)
|
suite.Equal(i(50), penalty)
|
||||||
|
@ -54,8 +54,7 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
|
|||||||
cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &totalB)
|
cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &totalB)
|
||||||
return fmt.Sprintf("%s\n%s", totalA, totalB)
|
return fmt.Sprintf("%s\n%s", totalA, totalB)
|
||||||
|
|
||||||
case bytes.Equal(kvA.Key[:1], types.PreviousBlockTimeKey),
|
case bytes.Equal(kvA.Key[:1], types.PreviousDistributionTimeKey):
|
||||||
bytes.Equal(kvA.Key[:1], types.PreviousDistributionTimeKey):
|
|
||||||
var timeA, timeB time.Time
|
var timeA, timeB time.Time
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &timeA)
|
cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &timeA)
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &timeB)
|
cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &timeB)
|
||||||
|
@ -42,7 +42,7 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
kv.Pair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
kv.Pair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
||||||
kv.Pair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)},
|
kv.Pair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)},
|
||||||
kv.Pair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)},
|
kv.Pair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)},
|
||||||
kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)},
|
kv.Pair{Key: []byte(types.PreviousDistributionTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)},
|
||||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,6 @@ func randomCdpGenState(selection int) types.GenesisState {
|
|||||||
DebtDenom: types.DefaultDebtDenom,
|
DebtDenom: types.DefaultDebtDenom,
|
||||||
GovDenom: types.DefaultGovDenom,
|
GovDenom: types.DefaultGovDenom,
|
||||||
CDPs: types.CDPs{},
|
CDPs: types.CDPs{},
|
||||||
PreviousBlockTime: types.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: types.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: types.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@ -158,7 +157,6 @@ func randomCdpGenState(selection int) types.GenesisState {
|
|||||||
DebtDenom: types.DefaultDebtDenom,
|
DebtDenom: types.DefaultDebtDenom,
|
||||||
GovDenom: types.DefaultGovDenom,
|
GovDenom: types.DefaultGovDenom,
|
||||||
CDPs: types.CDPs{},
|
CDPs: types.CDPs{},
|
||||||
PreviousBlockTime: types.DefaultPreviousBlockTime,
|
|
||||||
PreviousDistributionTime: types.DefaultPreviousDistributionTime,
|
PreviousDistributionTime: types.DefaultPreviousDistributionTime,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -14,12 +14,11 @@ type GenesisState struct {
|
|||||||
StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"`
|
StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"`
|
||||||
DebtDenom string `json:"debt_denom" yaml:"debt_denom"`
|
DebtDenom string `json:"debt_denom" yaml:"debt_denom"`
|
||||||
GovDenom string `json:"gov_denom" yaml:"gov_denom"`
|
GovDenom string `json:"gov_denom" yaml:"gov_denom"`
|
||||||
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
|
PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml:"previous_distribution_time"`
|
||||||
PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml"previous_distribution_time"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGenesisState returns a new genesis state
|
// NewGenesisState returns a new genesis state
|
||||||
func NewGenesisState(params Params, cdps CDPs, deposits Deposits, startingCdpID uint64, debtDenom, govDenom string, previousBlockTime time.Time, previousDistTime time.Time) GenesisState {
|
func NewGenesisState(params Params, cdps CDPs, deposits Deposits, startingCdpID uint64, debtDenom, govDenom string, previousDistTime time.Time) GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Params: params,
|
Params: params,
|
||||||
CDPs: cdps,
|
CDPs: cdps,
|
||||||
@ -27,23 +26,21 @@ func NewGenesisState(params Params, cdps CDPs, deposits Deposits, startingCdpID
|
|||||||
StartingCdpID: startingCdpID,
|
StartingCdpID: startingCdpID,
|
||||||
DebtDenom: debtDenom,
|
DebtDenom: debtDenom,
|
||||||
GovDenom: govDenom,
|
GovDenom: govDenom,
|
||||||
PreviousBlockTime: previousBlockTime,
|
|
||||||
PreviousDistributionTime: previousDistTime,
|
PreviousDistributionTime: previousDistTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultGenesisState returns a default genesis state
|
// DefaultGenesisState returns a default genesis state
|
||||||
func DefaultGenesisState() GenesisState {
|
func DefaultGenesisState() GenesisState {
|
||||||
return GenesisState{
|
return NewGenesisState(
|
||||||
Params: DefaultParams(),
|
DefaultParams(),
|
||||||
CDPs: CDPs{},
|
CDPs{},
|
||||||
Deposits: Deposits{},
|
Deposits{},
|
||||||
StartingCdpID: DefaultCdpStartingID,
|
DefaultCdpStartingID,
|
||||||
DebtDenom: DefaultDebtDenom,
|
DefaultDebtDenom,
|
||||||
GovDenom: DefaultGovDenom,
|
DefaultGovDenom,
|
||||||
PreviousBlockTime: DefaultPreviousBlockTime,
|
DefaultPreviousDistributionTime,
|
||||||
PreviousDistributionTime: DefaultPreviousDistributionTime,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate performs basic validation of genesis data returning an
|
// Validate performs basic validation of genesis data returning an
|
||||||
@ -54,10 +51,6 @@ func (gs GenesisState) Validate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if gs.PreviousBlockTime.Equal(time.Time{}) {
|
|
||||||
return fmt.Errorf("previous block time not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if gs.PreviousDistributionTime.Equal(time.Time{}) {
|
if gs.PreviousDistributionTime.Equal(time.Time{}) {
|
||||||
return fmt.Errorf("previous distribution time not set")
|
return fmt.Errorf("previous distribution time not set")
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,7 @@ var sep = []byte(":")
|
|||||||
// - 0x05<depositState>:<cdpID>:<depositorAddr_bytes>: Deposit
|
// - 0x05<depositState>:<cdpID>:<depositorAddr_bytes>: Deposit
|
||||||
// - 0x06<denom>:totalPrincipal
|
// - 0x06<denom>:totalPrincipal
|
||||||
// - 0x07<denom>:feeRate
|
// - 0x07<denom>:feeRate
|
||||||
// - 0x08:previousBlockTime
|
// - 0x08:previousDistributionTime
|
||||||
// - 0x09:previousDistributionTime
|
|
||||||
|
|
||||||
// KVStore key prefixes
|
// KVStore key prefixes
|
||||||
var (
|
var (
|
||||||
@ -58,8 +57,7 @@ var (
|
|||||||
GovDenomKey = []byte{0x05}
|
GovDenomKey = []byte{0x05}
|
||||||
DepositKeyPrefix = []byte{0x06}
|
DepositKeyPrefix = []byte{0x06}
|
||||||
PrincipalKeyPrefix = []byte{0x07}
|
PrincipalKeyPrefix = []byte{0x07}
|
||||||
PreviousBlockTimeKey = []byte{0x08}
|
PreviousDistributionTimeKey = []byte{0x08}
|
||||||
PreviousDistributionTimeKey = []byte{0x09}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var lenPositiveDec = len(SortableDecBytes(sdk.OneDec()))
|
var lenPositiveDec = len(SortableDecBytes(sdk.OneDec()))
|
||||||
|
@ -29,7 +29,6 @@ var (
|
|||||||
DefaultGovDenom = "ukava"
|
DefaultGovDenom = "ukava"
|
||||||
DefaultSurplusThreshold = sdk.NewInt(1000000000)
|
DefaultSurplusThreshold = sdk.NewInt(1000000000)
|
||||||
DefaultDebtThreshold = sdk.NewInt(1000000000)
|
DefaultDebtThreshold = sdk.NewInt(1000000000)
|
||||||
DefaultPreviousBlockTime = tmtime.Canonical(time.Unix(0, 0))
|
|
||||||
DefaultPreviousDistributionTime = tmtime.Canonical(time.Unix(0, 0))
|
DefaultPreviousDistributionTime = tmtime.Canonical(time.Unix(0, 0))
|
||||||
DefaultSavingsDistributionFrequency = time.Hour * 24 * 2
|
DefaultSavingsDistributionFrequency = time.Hour * 24 * 2
|
||||||
minCollateralPrefix = 0
|
minCollateralPrefix = 0
|
||||||
|
Loading…
Reference in New Issue
Block a user