mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
wip: cdp params and types
This commit is contained in:
parent
d5da161dd8
commit
e85d2f880b
@ -2,10 +2,12 @@ package cdp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/pricefeed"
|
"github.com/kava-labs/kava/x/pricefeed"
|
||||||
)
|
)
|
||||||
@ -19,7 +21,7 @@ func TestApp_CreateModifyDeleteCDP(t *testing.T) {
|
|||||||
mock.SetGenesis(mapp, genAccs)
|
mock.SetGenesis(mapp, genAccs)
|
||||||
mock.CheckBalance(t, mapp, testAddr, cs(c("xrp", 100)))
|
mock.CheckBalance(t, mapp, testAddr, cs(c("xrp", 100)))
|
||||||
// setup pricefeed, TODO can this be shortened a bit?
|
// setup pricefeed, TODO can this be shortened a bit?
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
ctx := mapp.BaseApp.NewContext(false, header)
|
||||||
params := CdpParams{
|
params := CdpParams{
|
||||||
@ -35,15 +37,19 @@ func TestApp_CreateModifyDeleteCDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
keeper.SetParams(ctx, params)
|
keeper.SetParams(ctx, params)
|
||||||
keeper.SetGlobalDebt(ctx, sdk.NewInt(0))
|
keeper.SetGlobalDebt(ctx, sdk.NewInt(0))
|
||||||
ap := pricefeed.AssetParams{
|
ap := pricefeed.Params{
|
||||||
Assets: []pricefeed.Asset{pricefeed.Asset{AssetCode: "xrp", Description: ""}},
|
Assets: []pricefeed.Asset{
|
||||||
|
pricefeed.Asset{
|
||||||
|
AssetCode: "xrp", BaseAsset: "xrp",
|
||||||
|
QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
pfKeeper.SetAssetParams(ctx, ap)
|
pfKeeper.SetParams(ctx, ap)
|
||||||
pfKeeper.SetPrice(
|
pfKeeper.SetPrice(
|
||||||
ctx, sdk.AccAddress{}, "xrp",
|
ctx, sdk.AccAddress{}, "xrp",
|
||||||
sdk.MustNewDecFromStr("1.00"),
|
sdk.MustNewDecFromStr("1.00"),
|
||||||
sdk.NewInt(10))
|
header.Time.Add(time.Hour*1))
|
||||||
pfKeeper.SetCurrentPrices(ctx)
|
pfKeeper.SetCurrentPrices(ctx, "xrp")
|
||||||
mapp.EndBlock(abci.RequestEndBlock{})
|
mapp.EndBlock(abci.RequestEndBlock{})
|
||||||
mapp.Commit()
|
mapp.Commit()
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
func InitGenesis(ctx sdk.Context, k Keeper, pk PricefeedKeeper, data GenesisState) {
|
func InitGenesis(ctx sdk.Context, k Keeper, pk PricefeedKeeper, data GenesisState) {
|
||||||
// validate denoms - check that any collaterals in the CdpParams are in the pricefeed, pricefeed needs to initgenesis before cdp
|
// validate denoms - check that any collaterals in the CdpParams are in the pricefeed, pricefeed needs to initgenesis before cdp
|
||||||
collateralMap := make(map[string]int)
|
collateralMap := make(map[string]int)
|
||||||
ap := pk.GetAssetParams(ctx)
|
ap := pk.GetParams(ctx)
|
||||||
for _, a := range ap.Assets {
|
for _, a := range ap.Assets {
|
||||||
collateralMap[a.AssetCode] = 1
|
collateralMap[a.AssetCode] = 1
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/kava-labs/kava/x/pricefeed"
|
"github.com/kava-labs/kava/x/pricefeed"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// How could one reduce the number of params in the test cases. Create a table driven test for each of the 4 add/withdraw collateral/debt?
|
// How could one reduce the number of params in the test cases. Create a table driven test for each of the 4 add/withdraw collateral/debt?
|
||||||
@ -103,27 +105,29 @@ func TestKeeper_ModifyCDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
mock.SetGenesis(mapp, []authexported.Account{&genAcc})
|
mock.SetGenesis(mapp, []authexported.Account{&genAcc})
|
||||||
// create a new context
|
// create a new context
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
ctx := mapp.BaseApp.NewContext(false, header)
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
keeper.SetParams(ctx, defaultParamsSingle())
|
||||||
// setup store state
|
// setup store state
|
||||||
ap := pricefeed.AssetParams{
|
ap := pricefeed.Params{
|
||||||
Assets: []pricefeed.Asset{
|
Assets: []pricefeed.Asset{
|
||||||
pricefeed.Asset{AssetCode: "xrp", Description: ""},
|
pricefeed.Asset{
|
||||||
|
AssetCode: "xrp", BaseAsset: "xrp",
|
||||||
|
QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
keeper.pricefeedKeeper.SetAssetParams(ctx, ap)
|
keeper.pricefeedKeeper.SetParams(ctx, ap)
|
||||||
_, err := keeper.pricefeedKeeper.SetPrice(
|
_, err := keeper.pricefeedKeeper.SetPrice(
|
||||||
ctx, ownerAddr, "xrp",
|
ctx, ownerAddr, "xrp",
|
||||||
sdk.MustNewDecFromStr(tc.price),
|
sdk.MustNewDecFromStr(tc.price),
|
||||||
sdk.NewInt(ctx.BlockHeight()+10))
|
header.Time.Add(time.Hour*1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log("test context height", ctx.BlockHeight())
|
t.Log("test context height", ctx.BlockHeight())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.Log(tc.name)
|
t.Log(tc.name)
|
||||||
}
|
}
|
||||||
err = keeper.pricefeedKeeper.SetCurrentPrices(ctx)
|
err = keeper.pricefeedKeeper.SetCurrentPrices(ctx, "xrp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log("test context height", ctx.BlockHeight())
|
t.Log("test context height", ctx.BlockHeight())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -144,9 +148,6 @@ func TestKeeper_ModifyCDP(t *testing.T) {
|
|||||||
|
|
||||||
// get new state for verification
|
// get new state for verification
|
||||||
actualCDP, found := keeper.GetCDP(ctx, tc.args.owner, tc.args.collateralDenom)
|
actualCDP, found := keeper.GetCDP(ctx, tc.args.owner, tc.args.collateralDenom)
|
||||||
if tc.name == "removeTooMuchCollateral" {
|
|
||||||
t.Log(actualCDP.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for err
|
// check for err
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
@ -180,21 +181,23 @@ func TestKeeper_PartialSeizeCDP(t *testing.T) {
|
|||||||
testAddr := addrs[0]
|
testAddr := addrs[0]
|
||||||
mock.SetGenesis(mapp, genAccs)
|
mock.SetGenesis(mapp, genAccs)
|
||||||
// setup pricefeed
|
// setup pricefeed
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
ctx := mapp.BaseApp.NewContext(false, header)
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
keeper.SetParams(ctx, defaultParamsSingle())
|
||||||
ap := pricefeed.AssetParams{
|
ap := pricefeed.Params{
|
||||||
Assets: []pricefeed.Asset{
|
Assets: []pricefeed.Asset{
|
||||||
pricefeed.Asset{AssetCode: "xrp", Description: ""},
|
pricefeed.Asset{
|
||||||
|
AssetCode: "xrp", BaseAsset: "xrp",
|
||||||
|
QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
keeper.pricefeedKeeper.SetAssetParams(ctx, ap)
|
keeper.pricefeedKeeper.SetParams(ctx, ap)
|
||||||
keeper.pricefeedKeeper.SetPrice(
|
keeper.pricefeedKeeper.SetPrice(
|
||||||
ctx, sdk.AccAddress{}, collateral,
|
ctx, sdk.AccAddress{}, collateral,
|
||||||
sdk.MustNewDecFromStr("1.00"),
|
sdk.MustNewDecFromStr("1.00"),
|
||||||
i(10))
|
header.Time.Add(time.Hour*1))
|
||||||
keeper.pricefeedKeeper.SetCurrentPrices(ctx)
|
keeper.pricefeedKeeper.SetCurrentPrices(ctx, collateral)
|
||||||
// Create CDP
|
// Create CDP
|
||||||
keeper.SetGlobalDebt(ctx, i(0))
|
keeper.SetGlobalDebt(ctx, i(0))
|
||||||
err := keeper.ModifyCDP(ctx, testAddr, collateral, i(10), i(5))
|
err := keeper.ModifyCDP(ctx, testAddr, collateral, i(10), i(5))
|
||||||
@ -203,8 +206,8 @@ func TestKeeper_PartialSeizeCDP(t *testing.T) {
|
|||||||
keeper.pricefeedKeeper.SetPrice(
|
keeper.pricefeedKeeper.SetPrice(
|
||||||
ctx, sdk.AccAddress{}, collateral,
|
ctx, sdk.AccAddress{}, collateral,
|
||||||
sdk.MustNewDecFromStr("0.90"),
|
sdk.MustNewDecFromStr("0.90"),
|
||||||
i(10))
|
header.Time.Add(time.Hour*1))
|
||||||
keeper.pricefeedKeeper.SetCurrentPrices(ctx)
|
keeper.pricefeedKeeper.SetCurrentPrices(ctx, collateral)
|
||||||
|
|
||||||
// Seize entire CDP
|
// Seize entire CDP
|
||||||
err = keeper.PartialSeizeCDP(ctx, testAddr, collateral, i(10), i(5))
|
err = keeper.PartialSeizeCDP(ctx, testAddr, collateral, i(10), i(5))
|
||||||
|
@ -30,7 +30,7 @@ func setUpMockAppWithoutGenesis() (*mock.App, Keeper, []sdk.AccAddress, []crypto
|
|||||||
keyCDP := sdk.NewKVStoreKey("cdp")
|
keyCDP := sdk.NewKVStoreKey("cdp")
|
||||||
keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
|
keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
|
||||||
pk := mapp.ParamsKeeper
|
pk := mapp.ParamsKeeper
|
||||||
priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace).WithKeyTable(pricefeed.ParamKeyTable()), pricefeed.DefaultCodespace)
|
priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace), pricefeed.DefaultCodespace)
|
||||||
blacklistedAddrs := make(map[string]bool)
|
blacklistedAddrs := make(map[string]bool)
|
||||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
|
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
|
||||||
cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(types.DefaultParamspace), priceFeedKeeper, bankKeeper)
|
cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(types.DefaultParamspace), priceFeedKeeper, bankKeeper)
|
||||||
|
@ -28,7 +28,7 @@ func setUpMockAppWithoutGenesis() (*mock.App, Keeper, PricefeedKeeper) {
|
|||||||
keyCDP := sdk.NewKVStoreKey("cdp")
|
keyCDP := sdk.NewKVStoreKey("cdp")
|
||||||
keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
|
keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
|
||||||
pk := mapp.ParamsKeeper
|
pk := mapp.ParamsKeeper
|
||||||
priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace).WithKeyTable(pricefeed.ParamKeyTable()), pricefeed.DefaultCodespace)
|
priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace), pricefeed.DefaultCodespace)
|
||||||
blacklistedAddrs := make(map[string]bool)
|
blacklistedAddrs := make(map[string]bool)
|
||||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
|
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
|
||||||
cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(DefaultParamspace), priceFeedKeeper, bankKeeper)
|
cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(DefaultParamspace), priceFeedKeeper, bankKeeper)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
pftypes "github.com/kava-labs/kava/x/pricefeed/types"
|
pftypes "github.com/kava-labs/kava/x/pricefeed/types"
|
||||||
)
|
)
|
||||||
@ -14,9 +16,9 @@ type BankKeeper interface {
|
|||||||
|
|
||||||
type PricefeedKeeper interface {
|
type PricefeedKeeper interface {
|
||||||
GetCurrentPrice(sdk.Context, string) pftypes.CurrentPrice
|
GetCurrentPrice(sdk.Context, string) pftypes.CurrentPrice
|
||||||
GetAssetParams(sdk.Context) pftypes.AssetParams
|
GetParams(sdk.Context) pftypes.Params
|
||||||
// These are used for testing TODO replace mockApp with keeper in tests to remove these
|
// These are used for testing TODO replace mockApp with keeper in tests to remove these
|
||||||
SetAssetParams(sdk.Context, pftypes.AssetParams)
|
SetParams(sdk.Context, pftypes.Params)
|
||||||
SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, sdk.Int) (pftypes.PostedPrice, sdk.Error)
|
SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, time.Time) (pftypes.PostedPrice, sdk.Error)
|
||||||
SetCurrentPrices(sdk.Context) sdk.Error
|
SetCurrentPrices(sdk.Context, string) sdk.Error
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenesisState is the state that must be provided at genesis.
|
// GenesisState is the state that must be provided at genesis.
|
||||||
// TODO What is globaldebt and is is separate from the global debt limit in CdpParams
|
// TODO What is globaldebt and is is separate from the global debt limit in CdpParams
|
||||||
|
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Params CdpParams `json:"params" yaml:"params"`
|
Params Params `json:"params" yaml:"params"`
|
||||||
GlobalDebt sdk.Int `json:"global_debt" yaml:"global_debt"`
|
CDPs CDPs `json:"cdps" yaml:"cdps"`
|
||||||
CDPs CDPs `json:"cdps" yaml:"cdps"`
|
|
||||||
// don't need to setup CollateralStates as they are created as needed
|
// don't need to setup CollateralStates as they are created as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,9 +13,8 @@ type GenesisState struct {
|
|||||||
// TODO make this empty, load test values independent
|
// TODO make this empty, load test values independent
|
||||||
func DefaultGenesisState() GenesisState {
|
func DefaultGenesisState() GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Params: DefaultParams(),
|
Params: DefaultParams(),
|
||||||
GlobalDebt: sdk.ZeroInt(),
|
CDPs: CDPs{},
|
||||||
CDPs: CDPs{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,135 +4,166 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/params/subspace"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
How this uses the sdk params module:
|
|
||||||
- Put all the params for this module in one struct `CDPModuleParams`
|
|
||||||
- Store this in the keeper's paramSubspace under one key
|
|
||||||
- Provide a function to load the param struct all at once `keeper.GetParams(ctx)`
|
|
||||||
It's possible to set individual key value pairs within a paramSubspace, but reading and setting them is awkward (an empty variable needs to be created, then Get writes the value into it)
|
|
||||||
This approach will be awkward if we ever need to write individual parameters (because they're stored all together). If this happens do as the sdk modules do - store parameters separately with custom get/set func for each.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// CdpParams governance parameters for cdp module
|
|
||||||
type CdpParams struct {
|
|
||||||
GlobalDebtLimit sdk.Int
|
|
||||||
CollateralParams []CollateralParams
|
|
||||||
StableDenoms []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// CollateralParams governance parameters for each collateral type within the cdp module
|
|
||||||
type CollateralParams struct {
|
|
||||||
Denom string // Coin name of collateral type
|
|
||||||
LiquidationRatio sdk.Dec // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated
|
|
||||||
DebtLimit sdk.Int // Maximum amount of debt allowed to be drawn from this collateral type
|
|
||||||
//DebtFloor sdk.Int // used to prevent dust
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parameter keys
|
// Parameter keys
|
||||||
var (
|
var (
|
||||||
// ParamStoreKeyAuctionParams Param store key for auction params
|
// ParamStoreKeyAuctionParams Param store key for auction params
|
||||||
KeyGlobalDebtLimit = []byte("GlobalDebtLimit")
|
KeyGlobalDebtLimit = []byte("GlobalDebtLimit")
|
||||||
KeyCollateralParams = []byte("CollateralParams")
|
KeyCollateralParams = []byte("CollateralParams")
|
||||||
KeyStableDenoms = []byte("StableDenoms")
|
KeyDebtParams = []byte("DebtParams")
|
||||||
|
DefaultGlobalDebt = sdk.Coins{}
|
||||||
|
DefaultCircuitBreaker = false
|
||||||
|
DefaultCollateralParams = CollateralParams{}
|
||||||
|
DefaultDebtParams = DebtParams{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Params governance parameters for cdp module
|
||||||
|
type Params struct {
|
||||||
|
CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"`
|
||||||
|
DebtParams DebtParams `json:"debt_params" yaml:"debt_params"`
|
||||||
|
GlobalDebtLimit sdk.Coins `json:"global_debt_limit" yaml:"global_debt_limit"`
|
||||||
|
CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (p Params) String() string {
|
||||||
|
return fmt.Sprintf(`Params:
|
||||||
|
Global Debt Limit: %s
|
||||||
|
Collateral Params: %s
|
||||||
|
Debt Params: %s
|
||||||
|
Circuit Breaker: %t`,
|
||||||
|
p.GlobalDebtLimit, p.CollateralParams, p.DebtParams, p.CircuitBreaker,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewParams returns a new params object
|
||||||
|
func NewParams(debtLimit sdk.Coins, collateralParams CollateralParams, debtParams DebtParams, breaker bool) Params {
|
||||||
|
return Params{
|
||||||
|
GlobalDebtLimit: debtLimit,
|
||||||
|
CollateralParams: collateralParams,
|
||||||
|
DebtParams: debtParams,
|
||||||
|
CircuitBreaker: breaker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultParams returns default params for cdp module
|
||||||
|
func DefaultParams() Params {
|
||||||
|
return NewParams(DefaultGlobalDebt, DefaultCollateralParams, DefaultDebtParams, DefaultCircuitBreaker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollateralParam governance parameters for each collateral type within the cdp module
|
||||||
|
type CollateralParam struct {
|
||||||
|
Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type
|
||||||
|
LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated
|
||||||
|
DebtLimit sdk.Coins `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type
|
||||||
|
//DebtFloor sdk.Int // used to prevent dust
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (cp CollateralParam) String() string {
|
||||||
|
return fmt.Sprintf(`Collateral:
|
||||||
|
Denom: %s
|
||||||
|
LiquidationRatio: %s
|
||||||
|
DebtLimit: %s`, cp.Denom, cp.LiquidationRatio, cp.DebtLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollateralParams array of CollateralParam
|
||||||
|
type CollateralParams []CollateralParam
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (cps CollateralParams) String() string {
|
||||||
|
out := "Collateral Params\n"
|
||||||
|
for _, cp := range cps {
|
||||||
|
out += fmt.Sprintf("%s\n", cp)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebtParam governance params for debt assets
|
||||||
|
type DebtParam struct {
|
||||||
|
Denom string `json:"denom" yaml:"denom"`
|
||||||
|
ReferenceAsset string `json:"reference_asset" yaml:"reference_asset"`
|
||||||
|
DebtLimit sdk.Coins `json:"debt_limit" yaml:"debt_limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dp DebtParam) String() string {
|
||||||
|
return fmt.Sprintf(`Debt:
|
||||||
|
Denom: %s
|
||||||
|
ReferenceAsset: %s
|
||||||
|
DebtLimit: %s`, dp.Denom, dp.ReferenceAsset, dp.DebtLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebtParams array of DebtParam
|
||||||
|
type DebtParams []DebtParam
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (dps DebtParams) String() string {
|
||||||
|
out := "Debt Params\n"
|
||||||
|
for _, dp := range dps {
|
||||||
|
out += fmt.Sprintf("%s\n", dp)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// ParamKeyTable Key declaration for parameters
|
// ParamKeyTable Key declaration for parameters
|
||||||
func ParamKeyTable() subspace.KeyTable {
|
func ParamKeyTable() params.KeyTable {
|
||||||
return subspace.NewKeyTable().RegisterParamSet(&CdpParams{})
|
return params.NewKeyTable().RegisterParamSet(&Params{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
|
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
|
||||||
// pairs of auth module's parameters.
|
// pairs of auth module's parameters.
|
||||||
// nolint
|
// nolint
|
||||||
func (p *CdpParams) ParamSetPairs() subspace.ParamSetPairs {
|
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||||
return subspace.ParamSetPairs{
|
return params.ParamSetPairs{
|
||||||
{KeyGlobalDebtLimit, &p.GlobalDebtLimit},
|
{KeyGlobalDebtLimit, &p.GlobalDebtLimit},
|
||||||
{KeyCollateralParams, &p.CollateralParams},
|
{KeyCollateralParams, &p.CollateralParams},
|
||||||
{KeyStableDenoms, &p.StableDenoms},
|
{KeyDebtParams, &p.DebtParams},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
|
||||||
func (p CdpParams) String() string {
|
|
||||||
out := fmt.Sprintf(`Params:
|
|
||||||
Global Debt Limit: %s
|
|
||||||
Collateral Params:`,
|
|
||||||
p.GlobalDebtLimit,
|
|
||||||
)
|
|
||||||
for _, cp := range p.CollateralParams {
|
|
||||||
out += fmt.Sprintf(`
|
|
||||||
%s
|
|
||||||
Liquidation Ratio: %s
|
|
||||||
Debt Limit: %s`,
|
|
||||||
cp.Denom,
|
|
||||||
cp.LiquidationRatio,
|
|
||||||
cp.DebtLimit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollateralParams returns params for a specific collateral denom
|
|
||||||
func (p CdpParams) GetCollateralParams(collateralDenom string) CollateralParams {
|
|
||||||
// search for matching denom, return
|
|
||||||
for _, cp := range p.CollateralParams {
|
|
||||||
if cp.Denom == collateralDenom {
|
|
||||||
return cp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// panic if not found, to be safe
|
|
||||||
panic("collateral params not found in module params")
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCollateralPresent returns true if the denom is among the collaterals in cdp module
|
|
||||||
func (p CdpParams) IsCollateralPresent(collateralDenom string) bool {
|
|
||||||
// search for matching denom, return
|
|
||||||
for _, cp := range p.CollateralParams {
|
|
||||||
if cp.Denom == collateralDenom {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks that the parameters have valid values.
|
// Validate checks that the parameters have valid values.
|
||||||
func (p CdpParams) Validate() error {
|
func (p Params) Validate() error {
|
||||||
|
debtDenoms := make(map[string]int)
|
||||||
|
debtParamsDebtLimit := sdk.Coins{}
|
||||||
|
for _, dp := range p.DebtParams {
|
||||||
|
_, found := debtDenoms[dp.Denom]
|
||||||
|
if found {
|
||||||
|
return fmt.Errorf("duplicate debt denom: %s", dp.Denom)
|
||||||
|
}
|
||||||
|
debtDenoms[dp.Denom] = 1
|
||||||
|
if dp.DebtLimit.IsAnyNegative() {
|
||||||
|
return fmt.Errorf("debt limit for all debt tokens should be positive, is %s for %s", dp.DebtLimit, dp.Denom)
|
||||||
|
}
|
||||||
|
debtParamsDebtLimit = debtParamsDebtLimit.Add(dp.DebtLimit)
|
||||||
|
}
|
||||||
|
if debtParamsDebtLimit.IsAnyGT(p.GlobalDebtLimit) {
|
||||||
|
fmt.Errorf("debt limit exceeds global debt limit:\n\tglobal debt limit: %s\n\tdebt limits: %s",
|
||||||
|
p.GlobalDebtLimit, debtParamsDebtLimit)
|
||||||
|
}
|
||||||
|
|
||||||
collateralDupMap := make(map[string]int)
|
collateralDupMap := make(map[string]int)
|
||||||
denomDupMap := make(map[string]int)
|
collateralParamsDebtLimit := sdk.Coins{}
|
||||||
for _, collateral := range p.CollateralParams {
|
for _, cp := range p.CollateralParams {
|
||||||
_, found := collateralDupMap[collateral.Denom]
|
_, found := collateralDupMap[cp.Denom]
|
||||||
if found {
|
if found {
|
||||||
return fmt.Errorf("duplicate denom: %s", collateral.Denom)
|
return fmt.Errorf("duplicate collateral denom: %s", cp.Denom)
|
||||||
}
|
}
|
||||||
collateralDupMap[collateral.Denom] = 1
|
collateralDupMap[cp.Denom] = 1
|
||||||
|
|
||||||
if collateral.DebtLimit.IsNegative() {
|
if cp.DebtLimit.IsAnyNegative() {
|
||||||
return fmt.Errorf("debt limit should be positive, is %s for %s", collateral.DebtLimit, collateral.Denom)
|
return fmt.Errorf("debt limit for all collaterals should be positive, is %s for %s", cp.DebtLimit, cp.Denom)
|
||||||
}
|
}
|
||||||
|
collateralParamsDebtLimit = collateralParamsDebtLimit.Add(cp.DebtLimit)
|
||||||
// TODO do we want to enforce overcollateralization at this level? -- probably not, as it's technically a governance thing (kevin)
|
|
||||||
}
|
}
|
||||||
if p.GlobalDebtLimit.IsNegative() {
|
if collateralParamsDebtLimit.IsAnyGT(p.GlobalDebtLimit) {
|
||||||
return fmt.Errorf("global debt limit should be positive, is %s", p.GlobalDebtLimit)
|
fmt.Errorf("collateral debt limit exceeds global debt limit:\n\tglobal debt limit: %s\n\tcollateral debt limits: %s",
|
||||||
|
p.GlobalDebtLimit, collateralParamsDebtLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, denom := range p.StableDenoms {
|
if p.GlobalDebtLimit.IsAnyNegative() {
|
||||||
_, found := denomDupMap[denom]
|
return fmt.Errorf("global debt limit should be positive for all debt tokens, is %s", p.GlobalDebtLimit)
|
||||||
if found {
|
|
||||||
return fmt.Errorf("duplicate stable denom: %s", denom)
|
|
||||||
}
|
|
||||||
denomDupMap[denom] = 1
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultParams() CdpParams {
|
|
||||||
return CdpParams{
|
|
||||||
GlobalDebtLimit: sdk.NewInt(0),
|
|
||||||
CollateralParams: []CollateralParams{},
|
|
||||||
StableDenoms: []string{"usdx"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@ package types
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
@ -15,27 +16,41 @@ type CDP struct {
|
|||||||
//ID []byte // removing IDs for now to make things simpler
|
//ID []byte // removing IDs for now to make things simpler
|
||||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
||||||
CollateralDenom string `json:"collateral_denom" yaml:"collateral_denom"` // Type of collateral stored in this CDP
|
CollateralDenom string `json:"collateral_denom" yaml:"collateral_denom"` // Type of collateral stored in this CDP
|
||||||
CollateralAmount sdk.Int `json:"collateral_amount" yaml:"collateral_amount"` // Amount of collateral stored in this CDP
|
CollateralAmount sdk.Coins `json:"collateral_amount" yaml:"collateral_amount"` // Amount of collateral stored in this CDP
|
||||||
Debt sdk.Int `json:"debt" yaml:"debt"` // Amount of stable coin drawn from this CDP
|
Debt sdk.Coins `json:"debt" yaml:"debt"`
|
||||||
|
AccumulatedFees sdk.Coins `json:"accumulated_fees" yaml:"accumulated_fees"`
|
||||||
|
FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // Amount of stable coin drawn from this CDP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsUnderCollateralized checks if cdp is below the liquidation ratio
|
||||||
func (cdp CDP) IsUnderCollateralized(price sdk.Dec, liquidationRatio sdk.Dec) bool {
|
func (cdp CDP) IsUnderCollateralized(price sdk.Dec, liquidationRatio sdk.Dec) bool {
|
||||||
collateralValue := sdk.NewDecFromInt(cdp.CollateralAmount).Mul(price)
|
collateralValue := sdk.NewDecFromInt(cdp.CollateralAmount.AmountOf(cdp.CollateralDenom)).Mul(price)
|
||||||
minCollateralValue := liquidationRatio.Mul(sdk.NewDecFromInt(cdp.Debt))
|
minCollateralValue := sdk.NewDec(0)
|
||||||
|
for _, c := range cdp.Debt {
|
||||||
|
minCollateralValue = minCollateralValue.Add(liquidationRatio.Mul(c.Amount.ToDec()))
|
||||||
|
}
|
||||||
return collateralValue.LT(minCollateralValue) // TODO LT or LTE?
|
return collateralValue.LT(minCollateralValue) // TODO LT or LTE?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String implements fmt.stringer
|
||||||
func (cdp CDP) String() string {
|
func (cdp CDP) String() string {
|
||||||
return strings.TrimSpace(fmt.Sprintf(`CDP:
|
return strings.TrimSpace(fmt.Sprintf(`CDP:
|
||||||
Owner: %s
|
Owner: %s
|
||||||
Collateral: %s
|
Collateral Type: %s
|
||||||
Debt: %s`,
|
Collateral: %s
|
||||||
|
Debt: %s
|
||||||
|
Fees: %s
|
||||||
|
Fees Last Updated: %s`,
|
||||||
cdp.Owner,
|
cdp.Owner,
|
||||||
sdk.NewCoin(cdp.CollateralDenom, cdp.CollateralAmount),
|
cdp.CollateralDenom,
|
||||||
sdk.NewCoin("usdx", cdp.Debt),
|
cdp.CollateralAmount,
|
||||||
|
cdp.Debt,
|
||||||
|
cdp.AccumulatedFees,
|
||||||
|
cdp.FeesUpdated,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CDPs array of CDP
|
||||||
type CDPs []CDP
|
type CDPs []CDP
|
||||||
|
|
||||||
// String implements stringer
|
// String implements stringer
|
||||||
@ -52,22 +67,23 @@ type ByCollateralRatio CDPs
|
|||||||
|
|
||||||
func (cdps ByCollateralRatio) Len() int { return len(cdps) }
|
func (cdps ByCollateralRatio) Len() int { return len(cdps) }
|
||||||
func (cdps ByCollateralRatio) Swap(i, j int) { cdps[i], cdps[j] = cdps[j], cdps[i] }
|
func (cdps ByCollateralRatio) Swap(i, j int) { cdps[i], cdps[j] = cdps[j], cdps[i] }
|
||||||
func (cdps ByCollateralRatio) Less(i, j int) bool {
|
|
||||||
// Sort by "collateral ratio" ie collateralAmount/Debt
|
// func (cdps ByCollateralRatio) Less(i, j int) bool {
|
||||||
// The comparison is: collat_i/debt_i < collat_j/debt_j
|
// // Sort by "collateral ratio" ie collateralAmount/Debt
|
||||||
// But to avoid division this can be rearranged to: collat_i*debt_j < collat_j*debt_i
|
// // The comparison is: collat_i/debt_i < collat_j/debt_j
|
||||||
// Provided the values are positive, so check for positive values.
|
// // But to avoid division this can be rearranged to: collat_i*debt_j < collat_j*debt_i
|
||||||
if cdps[i].CollateralAmount.IsNegative() ||
|
// // Provided the values are positive, so check for positive values.
|
||||||
cdps[i].Debt.IsNegative() ||
|
// if cdps[i].CollateralAmount.IsNegative() ||
|
||||||
cdps[j].CollateralAmount.IsNegative() ||
|
// cdps[i].Debt.IsNegative() ||
|
||||||
cdps[j].Debt.IsNegative() {
|
// cdps[j].CollateralAmount.IsNegative() ||
|
||||||
panic("negative collateral and debt not supported in CDPs")
|
// cdps[j].Debt.IsNegative() {
|
||||||
}
|
// panic("negative collateral and debt not supported in CDPs")
|
||||||
// TODO overflows could cause panics
|
// }
|
||||||
left := cdps[i].CollateralAmount.Mul(cdps[j].Debt)
|
// // TODO overflows could cause panics
|
||||||
right := cdps[j].CollateralAmount.Mul(cdps[i].Debt)
|
// left := cdps[i].CollateralAmount.Mul(cdps[j].Debt)
|
||||||
return left.LT(right)
|
// right := cdps[j].CollateralAmount.Mul(cdps[i].Debt)
|
||||||
}
|
// return left.LT(right)
|
||||||
|
// }
|
||||||
|
|
||||||
// CollateralState stores global information tied to a particular collateral type.
|
// CollateralState stores global information tied to a particular collateral type.
|
||||||
type CollateralState struct {
|
type CollateralState struct {
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
params "github.com/cosmos/cosmos-sdk/x/params/subspace"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
Loading…
Reference in New Issue
Block a user