mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 23:35:19 +00:00
[R4R] Add cdp simulations (#422)
feat: cdp sims Co-authored-by: rhuairahrighairigh <ruaridh.odonnell@gmail.com> Co-authored-by: John Maheswaran <john@kava.io>
This commit is contained in:
parent
004837d7fc
commit
1fab788fd5
@ -330,8 +330,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
|||||||
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
|
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
|
||||||
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
||||||
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
|
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),
|
pricefeed.NewAppModule(app.pricefeedKeeper),
|
||||||
|
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper),
|
||||||
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper),
|
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper),
|
||||||
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper),
|
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper),
|
||||||
kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper),
|
kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper),
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
|
|
||||||
auctionsimops "github.com/kava-labs/kava/x/auction/simulation/operations"
|
auctionsimops "github.com/kava-labs/kava/x/auction/simulation/operations"
|
||||||
bep3simops "github.com/kava-labs/kava/x/bep3/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"
|
pricefeedsimops "github.com/kava-labs/kava/x/pricefeed/simulation/operations"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ const (
|
|||||||
OpWeightMsgPlaceBid = "op_weight_msg_place_bid"
|
OpWeightMsgPlaceBid = "op_weight_msg_place_bid"
|
||||||
OpWeightMsgPricefeed = "op_weight_msg_pricefeed"
|
OpWeightMsgPricefeed = "op_weight_msg_pricefeed"
|
||||||
OpWeightMsgCreateAtomicSwap = "op_weight_msg_create_atomic_Swap"
|
OpWeightMsgCreateAtomicSwap = "op_weight_msg_create_atomic_Swap"
|
||||||
|
OpWeightMsgCdp = "op_weight_msg_cdp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestMain runs setup and teardown code before all tests.
|
// TestMain runs setup and teardown code before all tests.
|
||||||
@ -304,6 +306,17 @@ func testAndRunTxs(app *App, config simulation.Config) []simulation.WeightedOper
|
|||||||
}(nil),
|
}(nil),
|
||||||
pricefeedsimops.SimulateMsgUpdatePrices(app.pricefeedKeeper),
|
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),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
- 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
|
- for array jobs, click the job name to get details of the individual jobs
|
||||||
|
|
||||||
|
## Sims - TODO
|
@ -4,19 +4,164 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"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/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"
|
"github.com/kava-labs/kava/x/cdp/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomizedGenState generates a random GenesisState for cdp
|
// RandomizedGenState generates a random GenesisState for cdp
|
||||||
func RandomizedGenState(simState *module.SimulationState) {
|
func RandomizedGenState(simState *module.SimulationState) {
|
||||||
|
|
||||||
// TODO implement this fully
|
cdpGenesis := randomCdpGenState(simState.Rand.Intn(2))
|
||||||
// - randomly generating the genesis params
|
|
||||||
// - overwriting with genesis provided to simulation
|
// 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)
|
||||||
cdpGenesis := types.DefaultGenesisState()
|
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))
|
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)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
215
x/cdp/simulation/operations/msgs.go
Normal file
215
x/cdp/simulation/operations/msgs.go
Normal file
@ -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
|
||||||
|
}
|
26
x/cdp/simulation/operations/utils.go
Normal file
26
x/cdp/simulation/operations/utils.go
Normal file
@ -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
|
||||||
|
}
|
28
x/cdp/simulation/operations/utils_test.go
Normal file
28
x/cdp/simulation/operations/utils_test.go
Normal file
@ -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))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,5 @@ import (
|
|||||||
// ParamChanges defines the parameters that can be modified by param change proposals
|
// ParamChanges defines the parameters that can be modified by param change proposals
|
||||||
// on the simulation
|
// on the simulation
|
||||||
func ParamChanges(r *rand.Rand) []simulation.ParamChange {
|
func ParamChanges(r *rand.Rand) []simulation.ParamChange {
|
||||||
// TODO implement this
|
|
||||||
return []simulation.ParamChange{}
|
return []simulation.ParamChange{}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"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/types/module"
|
||||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/pricefeed/types"
|
"github.com/kava-labs/kava/x/pricefeed/types"
|
||||||
pricefeed "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
|
// RandomizedGenState generates a random GenesisState for pricefeed
|
||||||
@ -31,7 +29,6 @@ func RandomizedGenState(simState *module.SimulationState) {
|
|||||||
}
|
}
|
||||||
params = types.NewParams(markets)
|
params = types.NewParams(markets)
|
||||||
pricefeedGenesis := types.NewGenesisState(params, genPrices)
|
pricefeedGenesis := types.NewGenesisState(params, genPrices)
|
||||||
|
|
||||||
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, pricefeedGenesis))
|
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)
|
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(pricefeedGenesis)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user