From 1fab788fd50e792bc09c590f416db9fcf6b9511d Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Mon, 13 Apr 2020 21:29:46 -0400 Subject: [PATCH] [R4R] Add cdp simulations (#422) feat: cdp sims Co-authored-by: rhuairahrighairigh Co-authored-by: John Maheswaran --- app/app.go | 2 +- app/sim_test.go | 13 ++ simulations/README.md | 2 + x/cdp/simulation/genesis.go | 155 +++++++++++++++- x/cdp/simulation/operations/msgs.go | 215 ++++++++++++++++++++++ x/cdp/simulation/operations/utils.go | 26 +++ x/cdp/simulation/operations/utils_test.go | 28 +++ x/cdp/simulation/params.go | 1 - x/pricefeed/simulation/genesis.go | 5 +- 9 files changed, 436 insertions(+), 11 deletions(-) create mode 100644 x/cdp/simulation/operations/msgs.go create mode 100644 x/cdp/simulation/operations/utils.go create mode 100644 x/cdp/simulation/operations/utils_test.go diff --git a/app/app.go b/app/app.go index 6b7bcc98..7d1a4bec 100644 --- a/app/app.go +++ b/app/app.go @@ -330,8 +330,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, distr.NewAppModule(app.distrKeeper, app.supplyKeeper), staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper), - cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper), // TODO how is the order be decided here? Is this order correct? pricefeed.NewAppModule(app.pricefeedKeeper), + cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper), auction.NewAppModule(app.auctionKeeper, app.supplyKeeper), bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper), kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper), diff --git a/app/sim_test.go b/app/sim_test.go index 3881d398..37ad51a3 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -37,6 +37,7 @@ import ( auctionsimops "github.com/kava-labs/kava/x/auction/simulation/operations" bep3simops "github.com/kava-labs/kava/x/bep3/simulation/operations" + cdpsimops "github.com/kava-labs/kava/x/cdp/simulation/operations" pricefeedsimops "github.com/kava-labs/kava/x/pricefeed/simulation/operations" ) @@ -63,6 +64,7 @@ const ( OpWeightMsgPlaceBid = "op_weight_msg_place_bid" OpWeightMsgPricefeed = "op_weight_msg_pricefeed" OpWeightMsgCreateAtomicSwap = "op_weight_msg_create_atomic_Swap" + OpWeightMsgCdp = "op_weight_msg_cdp" ) // TestMain runs setup and teardown code before all tests. @@ -304,6 +306,17 @@ func testAndRunTxs(app *App, config simulation.Config) []simulation.WeightedOper }(nil), pricefeedsimops.SimulateMsgUpdatePrices(app.pricefeedKeeper), }, + { + func(_ *rand.Rand) int { + var v int + ap.GetOrGenerate(app.cdc, OpWeightMsgCdp, &v, nil, + func(_ *rand.Rand) { + v = 100 // TODO + }) + return v + }(nil), + cdpsimops.SimulateMsgCdp(app.accountKeeper, app.cdpKeeper, app.pricefeedKeeper), + }, } } diff --git a/simulations/README.md b/simulations/README.md index 69cbdab9..c4260146 100644 --- a/simulations/README.md +++ b/simulations/README.md @@ -41,3 +41,5 @@ AWS Batch allows for "array jobs" which are a way of specifying many duplicates - click on the compute environment name, to get details, then click the link ECS Cluster Name to get details on the actual machines running - for array jobs, click the job name to get details of the individual jobs + +## Sims - TODO \ No newline at end of file diff --git a/x/cdp/simulation/genesis.go b/x/cdp/simulation/genesis.go index 96bdfb21..a82104c9 100644 --- a/x/cdp/simulation/genesis.go +++ b/x/cdp/simulation/genesis.go @@ -4,19 +4,164 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - + "github.com/cosmos/cosmos-sdk/x/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/supply" + supplyExported "github.com/cosmos/cosmos-sdk/x/supply/exported" "github.com/kava-labs/kava/x/cdp/types" ) // RandomizedGenState generates a random GenesisState for cdp func RandomizedGenState(simState *module.SimulationState) { - // TODO implement this fully - // - randomly generating the genesis params - // - overwriting with genesis provided to simulation - cdpGenesis := types.DefaultGenesisState() + cdpGenesis := randomCdpGenState(simState.Rand.Intn(2)) + + // hacky way to give accounts coins so they can create cdps (coins includes usdx so it's possible to have sufficient balance to close a cdp) + var authGenesis auth.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[auth.ModuleName], &authGenesis) + totalCdpCoins := sdk.NewCoins() + for _, acc := range authGenesis.Accounts { + _, ok := acc.(supplyExported.ModuleAccountI) + if ok { + continue + } + coinsToAdd := sdk.NewCoins( + sdk.NewCoin("bnb", sdk.NewInt(int64(simState.Rand.Intn(100000000000)))), + sdk.NewCoin("xrp", sdk.NewInt(int64(simState.Rand.Intn(100000000000)))), + sdk.NewCoin("btc", sdk.NewInt(int64(simState.Rand.Intn(500000000)))), + sdk.NewCoin("usdx", sdk.NewInt(int64(simState.Rand.Intn(1000000000)))), + ) + err := acc.SetCoins(acc.GetCoins().Add(coinsToAdd)) + if err != nil { + panic(err) + } + totalCdpCoins = totalCdpCoins.Add(coinsToAdd) + authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, acc) + } + simState.GenState[auth.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis) + + var supplyGenesis supply.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis) + supplyGenesis.Supply = supplyGenesis.Supply.Add(totalCdpCoins) + simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis) fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, cdpGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(cdpGenesis) } + +// In a list of accounts, replace the first account found with the same address. If not found, append the account. +func replaceOrAppendAccount(accounts []authexported.GenesisAccount, acc authexported.GenesisAccount) []authexported.GenesisAccount { + newAccounts := accounts + for i, a := range accounts { + if a.GetAddress().Equals(acc.GetAddress()) { + newAccounts[i] = acc + return newAccounts + } + } + return append(newAccounts, acc) +} + +func randomCdpGenState(selection int) types.GenesisState { + switch selection { + case 0: + return types.GenesisState{ + Params: types.Params{ + GlobalDebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 100000000000000)), + SurplusAuctionThreshold: types.DefaultSurplusThreshold, + DebtAuctionThreshold: types.DefaultDebtThreshold, + SavingsDistributionFrequency: types.DefaultSavingsDistributionFrequency, + CollateralParams: types.CollateralParams{ + { + Denom: "xrp", + LiquidationRatio: sdk.MustNewDecFromStr("2.0"), + DebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 20000000000000)), + StabilityFee: sdk.MustNewDecFromStr("1.000000004431822130"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.075"), + AuctionSize: sdk.NewInt(10000000000), + Prefix: 0x20, + MarketID: "xrp:usd", + ConversionFactor: sdk.NewInt(6), + }, + { + Denom: "btc", + LiquidationRatio: sdk.MustNewDecFromStr("1.25"), + DebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 50000000000000)), + StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.05"), + AuctionSize: sdk.NewInt(50000000), + Prefix: 0x21, + MarketID: "btc:usd", + ConversionFactor: sdk.NewInt(8), + }, + { + Denom: "bnb", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 30000000000000)), + StabilityFee: sdk.MustNewDecFromStr("1.000000002293273137"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.15"), + AuctionSize: sdk.NewInt(10000000000), + Prefix: 0x22, + MarketID: "bnb:usd", + ConversionFactor: sdk.NewInt(8), + }, + }, + DebtParams: types.DebtParams{ + { + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: sdk.NewInt(6), + DebtFloor: sdk.NewInt(10000000), + SavingsRate: sdk.MustNewDecFromStr("0.95"), + }, + }, + }, + StartingCdpID: types.DefaultCdpStartingID, + DebtDenom: types.DefaultDebtDenom, + GovDenom: types.DefaultGovDenom, + CDPs: types.CDPs{}, + PreviousBlockTime: types.DefaultPreviousBlockTime, + PreviousDistributionTime: types.DefaultPreviousDistributionTime, + } + case 1: + return types.GenesisState{ + Params: types.Params{ + GlobalDebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 100000000000000)), + SurplusAuctionThreshold: types.DefaultSurplusThreshold, + DebtAuctionThreshold: types.DefaultDebtThreshold, + SavingsDistributionFrequency: types.DefaultSavingsDistributionFrequency, + CollateralParams: types.CollateralParams{ + { + Denom: "bnb", + LiquidationRatio: sdk.MustNewDecFromStr("1.5"), + DebtLimit: sdk.NewCoins(sdk.NewInt64Coin("usdx", 100000000000000)), + StabilityFee: sdk.MustNewDecFromStr("1.000000002293273137"), + LiquidationPenalty: sdk.MustNewDecFromStr("0.075"), + AuctionSize: sdk.NewInt(10000000000), + Prefix: 0x20, + MarketID: "bnb:usd", + ConversionFactor: sdk.NewInt(8), + }, + }, + DebtParams: types.DebtParams{ + { + Denom: "usdx", + ReferenceAsset: "usd", + ConversionFactor: sdk.NewInt(6), + DebtFloor: sdk.NewInt(10000000), + SavingsRate: sdk.MustNewDecFromStr("0.95"), + }, + }, + }, + StartingCdpID: types.DefaultCdpStartingID, + DebtDenom: types.DefaultDebtDenom, + GovDenom: types.DefaultGovDenom, + CDPs: types.CDPs{}, + PreviousBlockTime: types.DefaultPreviousBlockTime, + PreviousDistributionTime: types.DefaultPreviousDistributionTime, + } + default: + panic("invalid genesis state selector") + } +} diff --git a/x/cdp/simulation/operations/msgs.go b/x/cdp/simulation/operations/msgs.go new file mode 100644 index 00000000..29c6a6bf --- /dev/null +++ b/x/cdp/simulation/operations/msgs.go @@ -0,0 +1,215 @@ +package operations + +import ( + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/kava-labs/kava/x/cdp" + "github.com/kava-labs/kava/x/pricefeed" +) + +// SimulateMsgCdp generates a MsgCreateCdp or MsgDepositCdp with random values. +func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) simulation.Operation { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) ( + opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) { + + handler := cdp.NewHandler(k) + simacc := simulation.RandomAcc(r, accs) + acc := ak.GetAccount(ctx, simacc.Address) + if acc == nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, nil + } + coins := acc.GetCoins() + collateralParams := k.GetParams(ctx).CollateralParams + if len(collateralParams) == 0 { + return simulation.NoOpMsg(cdp.ModuleName), nil, nil + } + randCollateralParam := collateralParams[r.Intn(len(collateralParams))] + randDebtAsset := randCollateralParam.DebtLimit[r.Intn(len(randCollateralParam.DebtLimit))] + randDebtParam, _ := k.GetDebtParam(ctx, randDebtAsset.Denom) + if coins.AmountOf(randCollateralParam.Denom).IsZero() { + return simulation.NoOpMsg(cdp.ModuleName), nil, nil + } + + price, err := pfk.GetCurrentPrice(ctx, randCollateralParam.MarketID) + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, err + } + // convert the price to the same units as the debt param + priceShifted := ShiftDec(price.Price, randDebtParam.ConversionFactor) + + existingCDP, found := k.GetCdpByOwnerAndDenom(ctx, acc.GetAddress(), randCollateralParam.Denom) + if !found { + // calculate the minimum amount of collateral that is needed to create a cdp with the debt floor amount of debt and the minimum liquidation ratio + // (debtFloor * liquidationRatio)/priceShifted + minCollateralDeposit := (sdk.NewDecFromInt(randDebtParam.DebtFloor).Mul(randCollateralParam.LiquidationRatio)).Quo(priceShifted) + // convert to proper collateral units + minCollateralDeposit = ShiftDec(minCollateralDeposit, randCollateralParam.ConversionFactor) + // convert to integer and always round up + minCollateralDepositRounded := minCollateralDeposit.TruncateInt().Add(sdk.OneInt()) + // if the account has less than the min deposit, return + if coins.AmountOf(randCollateralParam.Denom).LT(minCollateralDepositRounded) { + return simulation.NoOpMsg(cdp.ModuleName), nil, nil + } + // set the max collateral deposit to the amount of coins in the account + maxCollateralDeposit := coins.AmountOf(randCollateralParam.Denom) + + // randomly select a collateral deposit amount + collateralDeposit := sdk.NewInt(int64(simulation.RandIntBetween(r, int(minCollateralDepositRounded.Int64()), int(maxCollateralDeposit.Int64())))) + // calculate how much the randomly selected deposit is worth + collateralDepositValue := ShiftDec(sdk.NewDecFromInt(collateralDeposit), randCollateralParam.ConversionFactor.Neg()).Mul(priceShifted) + // calculate the max amount of debt that could be drawn for the chosen deposit + maxDebtDraw := collateralDepositValue.Quo(randCollateralParam.LiquidationRatio).TruncateInt() + // randomly select a debt draw amount + debtDraw := sdk.NewInt(int64(simulation.RandIntBetween(r, int(randDebtParam.DebtFloor.Int64()), int(maxDebtDraw.Int64())))) + msg := cdp.NewMsgCreateCDP(acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, collateralDeposit)), sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, debtDraw))) + err := msg.ValidateBasic() + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected msg to pass ValidateBasic: %v", err) + } + ok := submitMsg(msg, handler, ctx) + if !ok { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit create cdp msg") + } + return simulation.NewOperationMsg(msg, ok, "create cdp"), nil, nil + } + + // a cdp already exists, deposit to it, draw debt from it, or repay debt to it + // close 25% of the time + if canClose(acc, existingCDP, randDebtParam.Denom) && shouldClose(r) { + repaymentAmount := coins.AmountOf(randDebtParam.Denom) + msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, repaymentAmount))) + err := msg.ValidateBasic() + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected repay (close) msg to pass ValidateBasic: %v", err) + } + ok := submitMsg(msg, handler, ctx) + if !ok { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit repay (close) msg") + } + return simulation.NewOperationMsg(msg, ok, "repay debt (close) cdp"), nil, nil + } + + // deposit 25% of the time + if hasCoins(acc, randCollateralParam.Denom) && shouldDeposit(r) { + randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(acc.GetCoins().AmountOf(randCollateralParam.Denom).Int64())))) + msg := cdp.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, randDepositAmount))) + err := msg.ValidateBasic() + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected deposit msg to pass ValidateBasic: %v", err) + } + ok := submitMsg(msg, handler, ctx) + if !ok { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit deposit msg") + } + return simulation.NewOperationMsg(msg, ok, "deposit to cdp"), nil, nil + } + + // draw debt 25% of the time + if shouldDraw(r) { + collateralShifted := ShiftDec(sdk.NewDecFromInt(existingCDP.Collateral.AmountOf(randCollateralParam.Denom)), randCollateralParam.ConversionFactor.Neg()) + collateralValue := collateralShifted.Mul(priceShifted) + debt := (existingCDP.Principal.Add(existingCDP.AccumulatedFees)).AmountOf(randDebtParam.Denom) + maxTotalDebt := collateralValue.Quo(randCollateralParam.LiquidationRatio) + maxDebt := maxTotalDebt.Sub(sdk.NewDecFromInt(debt)).TruncateInt().Sub(sdk.OneInt()) + randDrawAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxDebt.Int64())))) + msg := cdp.NewMsgDrawDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randDrawAmount))) + err := msg.ValidateBasic() + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected draw msg to pass ValidateBasic: %v", err) + } + ok := submitMsg(msg, handler, ctx) + if !ok { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit draw msg") + } + return simulation.NewOperationMsg(msg, ok, "draw debt from cdp"), nil, nil + + } + + // repay debt 25% of the time + if hasCoins(acc, randDebtParam.Denom) { + debt := (existingCDP.Principal.Add(existingCDP.AccumulatedFees)).AmountOf(randDebtParam.Denom) + maxRepay := acc.GetCoins().AmountOf(randDebtParam.Denom) + payableDebt := debt.Sub(randDebtParam.DebtFloor) + if maxRepay.GT(payableDebt) { + maxRepay = payableDebt + } + randRepayAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxRepay.Int64())))) + if debt.Equal(randDebtParam.DebtFloor) { + if acc.GetCoins().AmountOf(randDebtParam.Denom).GTE(debt) { + randRepayAmount = debt + } + } + msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randRepayAmount))) + err := msg.ValidateBasic() + if err != nil { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected repay msg to pass ValidateBasic: %v", err) + } + ok := submitMsg(msg, handler, ctx) + if !ok { + return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit repay msg") + } + return simulation.NewOperationMsg(msg, ok, "repay debt cdp"), nil, nil + } + + return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation (no valid actions)", "", false, nil), nil, nil + } +} + +func submitMsg(msg sdk.Msg, handler sdk.Handler, ctx sdk.Context) (ok bool) { + ctx, write := ctx.CacheContext() + res := handler(ctx, msg) + if res.IsOK() { + write() + } else { + fmt.Println(res.Log) + } + return res.IsOK() +} + +func shouldDraw(r *rand.Rand) bool { + threshold := 50 + value := simulation.RandIntBetween(r, 1, 100) + if value > threshold { + return true + } + return false +} + +func shouldDeposit(r *rand.Rand) bool { + threshold := 66 + value := simulation.RandIntBetween(r, 1, 100) + if value > threshold { + return true + } + return false +} + +func hasCoins(acc authexported.Account, denom string) bool { + if acc.GetCoins().AmountOf(denom).IsZero() { + return false + } + return true +} + +func shouldClose(r *rand.Rand) bool { + threshold := 75 + value := simulation.RandIntBetween(r, 1, 100) + if value > threshold { + return true + } + return false +} + +func canClose(acc authexported.Account, c cdp.CDP, denom string) bool { + repaymentAmount := c.Principal.Add(c.AccumulatedFees).AmountOf(denom) + if acc.GetCoins().AmountOf(denom).GTE(repaymentAmount) { + return true + } + return false +} diff --git a/x/cdp/simulation/operations/utils.go b/x/cdp/simulation/operations/utils.go new file mode 100644 index 00000000..bf8a804e --- /dev/null +++ b/x/cdp/simulation/operations/utils.go @@ -0,0 +1,26 @@ +package operations + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func ShiftDec(x sdk.Dec, places sdk.Int) sdk.Dec { + neg := places.IsNegative() + for i := 0; i < int(abs(places.Int64())); i++ { + if neg { + x = x.Mul(sdk.MustNewDecFromStr("0.1")) + } else { + x = x.Mul(sdk.NewDecFromInt(sdk.NewInt(10))) + } + + } + return x +} + +// abs returns the absolute value of x. +func abs(x int64) int64 { + if x < 0 { + return -x + } + return x +} diff --git a/x/cdp/simulation/operations/utils_test.go b/x/cdp/simulation/operations/utils_test.go new file mode 100644 index 00000000..5fedbef0 --- /dev/null +++ b/x/cdp/simulation/operations/utils_test.go @@ -0,0 +1,28 @@ +package operations_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/cdp/simulation/operations" + "github.com/stretchr/testify/require" +) + +func TestShiftDec(t *testing.T) { + tests := []struct { + value sdk.Dec + shift sdk.Int + expected sdk.Dec + }{ + {sdk.MustNewDecFromStr("5.5"), sdk.NewInt(1), sdk.MustNewDecFromStr("55")}, + {sdk.MustNewDecFromStr("5.5"), sdk.NewInt(-1), sdk.MustNewDecFromStr("0.55")}, + {sdk.MustNewDecFromStr("5.5"), sdk.NewInt(2), sdk.MustNewDecFromStr("550")}, + {sdk.MustNewDecFromStr("5.5"), sdk.NewInt(-2), sdk.MustNewDecFromStr("0.055")}, + } + + for _, tt := range tests { + t.Run(tt.value.String(), func(t *testing.T) { + require.Equal(t, tt.expected, operations.ShiftDec(tt.value, tt.shift)) + }) + } +} diff --git a/x/cdp/simulation/params.go b/x/cdp/simulation/params.go index 8c1f7aff..36ff612a 100644 --- a/x/cdp/simulation/params.go +++ b/x/cdp/simulation/params.go @@ -9,6 +9,5 @@ import ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation func ParamChanges(r *rand.Rand) []simulation.ParamChange { - // TODO implement this return []simulation.ParamChange{} } diff --git a/x/pricefeed/simulation/genesis.go b/x/pricefeed/simulation/genesis.go index 9a84d291..bcbbff01 100644 --- a/x/pricefeed/simulation/genesis.go +++ b/x/pricefeed/simulation/genesis.go @@ -5,13 +5,11 @@ import ( "time" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/kava-labs/kava/x/pricefeed/types" pricefeed "github.com/kava-labs/kava/x/pricefeed/types" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // RandomizedGenState generates a random GenesisState for pricefeed @@ -31,7 +29,6 @@ func RandomizedGenState(simState *module.SimulationState) { } params = types.NewParams(markets) pricefeedGenesis := types.NewGenesisState(params, genPrices) - fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, pricefeedGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(pricefeedGenesis) }