mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 00:35:18 +00:00
e2f515ba9e
* query auction by lot owner * add SavingsRateDistributed to store * v2cdps: filtered cdps query * update v2cdps cli examples * add savings rate dist counter to begin blocker * implement savings rate dist cli query * implement cdp REST queries * minor auction CLI/REST updates * fix auction querier bug * update REST endpoint to 'cdps' * update to savings-rate-dist * update SavingsRateDistributed get/set * update tests * fix savings rate dist rounding errors * 'collateralDenom' -> 'collateralType' * refactor 'v2cdps' -> 'cdps', add ratio param * fix augmented CDP type, msg string() method * fix cdp querier test * filter query results efficiently * querier tests * limit type iteration if owner defined * improve savings rate dist genesis validation * default sdk.Dec{} to sdk.ZeroDec in queries * update condition logic for finding intersection * fix cdp querier filtering * Update kava-4 swagger (#653) * add collateral_type, update cdp params * savings rate, auctions, get cdps * drop owner from AuctionResponse * remove duplicate collateral denom * update query paths with {collateral-type}
107 lines
4.0 KiB
Go
107 lines
4.0 KiB
Go
package keeper
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
|
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
|
|
|
"github.com/kava-labs/kava/x/cdp/types"
|
|
)
|
|
|
|
// DistributeSavingsRate distributes surplus that has accumulated in the liquidator account to address holding stable coins according the the savings rate
|
|
func (k Keeper) DistributeSavingsRate(ctx sdk.Context, debtDenom string) error {
|
|
dp, found := k.GetDebtParam(ctx, debtDenom)
|
|
if !found {
|
|
return sdkerrors.Wrap(types.ErrDebtNotSupported, debtDenom)
|
|
}
|
|
|
|
savingsRateMacc := k.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc)
|
|
surplusToDistribute := savingsRateMacc.GetCoins().AmountOf(dp.Denom)
|
|
if surplusToDistribute.IsZero() {
|
|
return nil
|
|
}
|
|
|
|
modAccountCoins := k.getModuleAccountCoins(ctx, dp.Denom)
|
|
totalSupplyLessModAccounts := k.supplyKeeper.GetSupply(ctx).GetTotal().Sub(modAccountCoins)
|
|
|
|
// values to use in interest calculation
|
|
totalSurplus := sdk.NewDecFromInt(surplusToDistribute)
|
|
totalSupply := sdk.NewDecFromInt(totalSupplyLessModAccounts.AmountOf(debtDenom))
|
|
|
|
var iterationErr error
|
|
// TODO: avoid iterating over all the accounts by keeping the stored stable coin
|
|
// holders' addresses separately.
|
|
k.accountKeeper.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) {
|
|
_, ok := acc.(supplyexported.ModuleAccountI)
|
|
if ok {
|
|
// don't distribute savings rate to module accounts
|
|
return false
|
|
}
|
|
|
|
debtAmount := acc.GetCoins().AmountOf(debtDenom)
|
|
if !debtAmount.IsPositive() {
|
|
return false
|
|
}
|
|
|
|
// (balance * rewardToDisribute) / totalSupply
|
|
// interest is the ratable fraction of savings rate owed to that account, rounded using bankers rounding
|
|
interest := (sdk.NewDecFromInt(debtAmount).Mul(totalSurplus)).Quo(totalSupply).RoundInt()
|
|
// sanity check, if we are going to over-distribute due to rounding, distribute only the remaining savings rate that hasn't been distributed.
|
|
interest = sdk.MinInt(interest, surplusToDistribute)
|
|
|
|
// sanity check - don't send saving rate if the rounded amount is zero
|
|
if !interest.IsPositive() {
|
|
return false
|
|
}
|
|
|
|
// update total savings rate distributed by surplus to distribute
|
|
previousSavingsDistributed := k.GetSavingsRateDistributed(ctx)
|
|
newTotalDistributed := previousSavingsDistributed.Add(interest)
|
|
k.SetSavingsRateDistributed(ctx, newTotalDistributed)
|
|
|
|
interestCoins := sdk.NewCoins(sdk.NewCoin(debtDenom, interest))
|
|
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.SavingsRateMacc, acc.GetAddress(), interestCoins)
|
|
if err != nil {
|
|
iterationErr = err
|
|
return true
|
|
}
|
|
surplusToDistribute = surplusToDistribute.Sub(interest)
|
|
return false
|
|
})
|
|
|
|
return iterationErr
|
|
}
|
|
|
|
// GetPreviousSavingsDistribution get the time of the previous savings rate distribution
|
|
func (k Keeper) GetPreviousSavingsDistribution(ctx sdk.Context) (distTime time.Time, found bool) {
|
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDistributionTimeKey)
|
|
b := store.Get([]byte{})
|
|
if b == nil {
|
|
return time.Time{}, false
|
|
}
|
|
k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &distTime)
|
|
return distTime, true
|
|
}
|
|
|
|
// SetPreviousSavingsDistribution set the time of the previous block
|
|
func (k Keeper) SetPreviousSavingsDistribution(ctx sdk.Context, distTime time.Time) {
|
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDistributionTimeKey)
|
|
store.Set([]byte{}, k.cdc.MustMarshalBinaryLengthPrefixed(distTime))
|
|
}
|
|
|
|
// getModuleAccountCoins gets the total coin balance of this coin currently held by module accounts
|
|
func (k Keeper) getModuleAccountCoins(ctx sdk.Context, denom string) sdk.Coins {
|
|
totalModCoinBalance := sdk.NewCoins(sdk.NewCoin(denom, sdk.ZeroInt()))
|
|
for macc := range k.maccPerms {
|
|
modCoinBalance := k.supplyKeeper.GetModuleAccount(ctx, macc).GetCoins().AmountOf(denom)
|
|
if modCoinBalance.IsPositive() {
|
|
totalModCoinBalance = totalModCoinBalance.Add(sdk.NewCoin(denom, modCoinBalance))
|
|
}
|
|
}
|
|
return totalModCoinBalance
|
|
}
|