Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(perp): simulate MsgOpenPosition #911

Merged
merged 24 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f74da72
fix: vpool twap calc
NibiruHeisenberg Sep 14, 2022
1e6d050
feat: add perp open position simulation
NibiruHeisenberg Sep 14, 2022
06065d1
refactor: run dex swap asset operations more frequently
NibiruHeisenberg Sep 14, 2022
f9d81e3
chore: rename sim test makefile recipe
NibiruHeisenberg Sep 14, 2022
f2f79d2
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 14, 2022
416ed47
fix: bad merge
NibiruHeisenberg Sep 15, 2022
56fa458
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 15, 2022
014ac46
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 15, 2022
a557176
chore: remove unused modules from simulation testing
NibiruHeisenberg Sep 15, 2022
d3c5902
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 15, 2022
a4aaa1b
chore: update changelog
NibiruHeisenberg Sep 15, 2022
c835946
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 16, 2022
a0fe75f
fix: fix merge issues
matthiasmatt Sep 16, 2022
a4dc682
Merge branch 'master' into perp/simulation-tests
AgentSmithMatrix Sep 16, 2022
ce1bc21
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 19, 2022
5024b20
chore: update changelog
NibiruHeisenberg Sep 19, 2022
e990db7
fix comment
NibiruHeisenberg Sep 19, 2022
47dfdea
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 22, 2022
6646e71
Merge branch 'master' into perp/simulation-tests
AgentSmithMatrix Sep 22, 2022
2be2b56
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 23, 2022
da7eead
fix: pointer type
NibiruHeisenberg Sep 23, 2022
b3635fd
chore: increase integration test timeout length
NibiruHeisenberg Sep 23, 2022
f6d10ff
Merge branch 'master' into perp/simulation-tests
NibiruHeisenberg Sep 24, 2022
ae14cd1
Merge remote-tracking branch 'origin/master' into perp/simulation-tests
AgentSmithMatrix Sep 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#901](https://github.com/NibiruChain/nibiru/pull/901) - refactor(vpool): remove `GetUnderlyingPrice` method
* [#902](https://github.com/NibiruChain/nibiru/pull/902) - refactor(common): improve usability of `common.AssetPair`
* [#913](https://github.com/NibiruChain/nibiru/pull/913) - chore(epochs): update x/epochs module
* [#911](https://github.com/NibiruChain/nibiru/pull/911) - test(perp): add `MsgOpenPosition` simulation tests
* [#917](https://github.com/NibiruChain/nibiru/pull/917) - refactor(proto): perp module files consistency
* [#920](https://github.com/NibiruChain/nibiru/pull/920) - refactor(proto): pricefeed module files consistency
* [#926](https://github.com/NibiruChain/nibiru/pull/926) - feat: use spot twap for funding rate calculation
Expand All @@ -98,6 +99,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#892](https://github.com/NibiruChain/nibiru/pull/892) - chore: fix localnet script
* [#925](https://github.com/NibiruChain/nibiru/pull/925) - fix(vpool): snapshot iteration
* [#930](https://github.com/NibiruChain/nibiru/pull/930) - fix(vpool): snapshot iteration on mark twap
* [#911](https://github.com/NibiruChain/nibiru/pull/911) - fix(perp): handle issue where no vpool snapshots are found
* [#961](https://github.com/NibiruChain/nibiru/pull/961) - fix(perp): wire the funding rate query
* [#968](https://github.com/NibiruChain/nibiru/pull/968) - fix(perp): compute correct funding rate

Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ test-sim-nondeterminism:
@go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h

test-sim-custom-genesis-fast:
@echo "Running custom genesis simulation..."
test-sim-default-genesis-fast:
@echo "Running default genesis simulation..."
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v

test-sim-custom-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
Expand Down
4 changes: 2 additions & 2 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,7 @@ func NewNibiruTestApp(
legacyAmino := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry

bApp := baseapp.NewBaseApp(
AppName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...)
bApp := baseapp.NewBaseApp(AppName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
Expand Down Expand Up @@ -748,6 +747,7 @@ func NewNibiruTestApp(
// native x/
pricefeedModule,
epochsModule,
perpModule,
// ibc
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
Expand Down
9 changes: 3 additions & 6 deletions simapp/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ import (
"io"
"io/ioutil"

tmjson "github.com/tendermint/tendermint/libs/json"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/NibiruChain/nibiru/app"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
tmjson "github.com/tendermint/tendermint/libs/json"
tmtypes "github.com/tendermint/tendermint/types"
)

// AppStateFromGenesisFileFn util function to generate the genesis AppState
Expand All @@ -31,7 +28,7 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str
panic(err)
}

var appState app.GenesisState
var appState GenesisState
err = json.Unmarshal(genesis.AppState, &appState)
if err != nil {
panic(err)
Expand Down
11 changes: 1 addition & 10 deletions x/dex/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,13 @@ func SimulateMsgCreatePool(ak types.AccountKeeper, bk types.BankKeeper, k keeper

/*
SimulateMsgSwap generates a MsgSwap with random values
This function has a 33% chance of swapping a random fraction of the balance of a random token
*/
func SimulateMsgSwap(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
msg := &types.MsgSwapAssets{}

// only run 1/3 of the time
if simtypes.RandomDecAmount(r, sdk.MustNewDecFromStr("1")).GTE(sdk.MustNewDecFromStr("0.33")) {
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "No swap done"), nil, nil
}

simAccount, _ := simtypes.RandomAcc(r, accs)
fundAccountWithTokens(ctx, simAccount.Address, bk)
spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)
Expand All @@ -116,10 +110,7 @@ func SimulateMsgSwap(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keepe
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "No tokens to swap in"), nil, nil
}

// choose some random amount of balanceIn to swap
intensityFactor := simtypes.RandomDecAmount(r, sdk.MustNewDecFromStr("0.05")).Add(sdk.MustNewDecFromStr("0.1"))
tokenIn := sdk.NewCoin(denomIn, intensityFactor.MulInt(balanceIn).TruncateInt())

tokenIn := sdk.NewCoin(denomIn, balanceIn)
msg = &types.MsgSwapAssets{
Sender: simAccount.Address.String(),
PoolId: poolId,
Expand Down
7 changes: 3 additions & 4 deletions x/perp/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import (
"encoding/json"
"fmt"

"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"

"github.com/NibiruChain/nibiru/x/perp/client/cli"
Expand Down
34 changes: 34 additions & 0 deletions x/perp/module_simulation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package perp

import (
"math/rand"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"

"github.com/NibiruChain/nibiru/x/perp/simulation"
)

// GenerateGenesisState creates a default GenState of the module
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}

// ProposalContents doesn't return any content functions for governance proposals
func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent {
return nil
}

// RandomizedParams creates randomized param changes for the simulator
func (am AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange {
return nil
}

// RegisterStoreDecoder registers a decoder
func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {}

// WeightedOperations returns the all the gov module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.ak, am.bk, am.keeper)
}
64 changes: 64 additions & 0 deletions x/perp/simulation/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package simulation

import (
"encoding/json"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/perp/types"
pricefeedtypes "github.com/NibiruChain/nibiru/x/pricefeed/types"
vpooltypes "github.com/NibiruChain/nibiru/x/vpool/types"
)

// RandomizedGenState generates a random GenesisState for the perp module
func RandomizedGenState(simState *module.SimulationState) {
vpoolGenesis := vpooltypes.GenesisState{
NibiruHeisenberg marked this conversation as resolved.
Show resolved Hide resolved
Vpools: []*vpooltypes.VPool{
{
Pair: common.Pair_BTC_NUSD,
TradeLimitRatio: sdk.OneDec(),
QuoteAssetReserve: sdk.NewDec(10e12),
BaseAssetReserve: sdk.NewDec(10e12),
FluctuationLimitRatio: sdk.OneDec(),
MaxOracleSpreadRatio: sdk.OneDec(),
MaintenanceMarginRatio: sdk.MustNewDecFromStr("0.0625"),
MaxLeverage: sdk.NewDec(10),
},
},
}

vpools, err := json.MarshalIndent(&vpoolGenesis.Vpools, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated vpools:\n%s\n", vpools)
simState.GenState[vpooltypes.ModuleName] = simState.Cdc.MustMarshalJSON(&vpoolGenesis)

pricefeedGenesis := pricefeedtypes.DefaultGenesis()

pricefeedGenesisBytes, err := json.MarshalIndent(&pricefeedGenesis, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated pricefeed genesis:\n%s\n", pricefeedGenesisBytes)
simState.GenState[pricefeedtypes.ModuleName] = simState.Cdc.MustMarshalJSON(pricefeedGenesis)

perpGenesis := types.GenesisState{
Params: types.DefaultParams(),
PairMetadata: []types.PairMetadata{
{
Pair: common.Pair_BTC_NUSD,
CumulativeFundingRates: []sdk.Dec{sdk.ZeroDec()},
},
},
}
perpGenesisBytes, err := json.MarshalIndent(&perpGenesis, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated perp genesis:\n%s\n", perpGenesisBytes)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&perpGenesis)
}
102 changes: 102 additions & 0 deletions x/perp/simulation/operations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package simulation

import (
"fmt"
"math/rand"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/perp/keeper"
"github.com/NibiruChain/nibiru/x/perp/types"
)

const defaultWeight = 100

// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(
appParams simtypes.AppParams,
cdc codec.JSONCodec,
ak types.AccountKeeper,
bk types.BankKeeper,
k keeper.Keeper) simulation.WeightedOperations {
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
defaultWeight,
SimulateMsgOpenPosition(ak, bk, k),
),
}
}

// SimulateMsgCreateBalancerPool generates a MsgCreatePool with random values.
func SimulateMsgOpenPosition(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
fundAccountWithTokens(ctx, simAccount.Address, bk)
spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)

quoteAmt, _ := simtypes.RandPositiveInt(r, spendableCoins.AmountOf(common.DenomNUSD))
leverage := simtypes.RandomDecAmount(r, sdk.NewDec(9)).Add(sdk.OneDec()) // between [1, 10]
openNotional := leverage.MulInt(quoteAmt)
feesAmt := openNotional.Mul(sdk.MustNewDecFromStr("0.002")).Ceil().TruncateInt()
spentCoins := sdk.NewCoins(sdk.NewCoin(common.DenomNUSD, quoteAmt.Add(feesAmt)))

msg := &types.MsgOpenPosition{
Sender: simAccount.Address.String(),
TokenPair: common.Pair_BTC_NUSD.String(),
Side: types.Side_BUY,
QuoteAssetAmount: quoteAmt,
Leverage: leverage,
BaseAssetAmountLimit: sdk.ZeroInt(),
}

opMsg, futureOps, err := simulation.GenAndDeliverTxWithRandFees(
simulation.OperationInput{
R: r,
App: app,
TxGen: simapp.MakeTestEncodingConfig().TxConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
CoinsSpentInMsg: spentCoins,
},
)
if err != nil {
fmt.Println(spendableCoins)
fmt.Println(quoteAmt)
}

return opMsg, futureOps, err
}
}

func fundAccountWithTokens(ctx sdk.Context, receiver sdk.AccAddress, bk types.BankKeeper) {
newCoins := sdk.NewCoins(
sdk.NewCoin(common.DenomNUSD, sdk.NewInt(1e6)),
)

if err := bk.MintCoins(ctx, types.ModuleName, newCoins); err != nil {
panic(err)
}

if err := bk.SendCoinsFromModuleToAccount(
ctx,
types.ModuleName,
receiver,
newCoins,
); err != nil {
panic(err)
}
}
2 changes: 1 addition & 1 deletion x/perp/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var (

MemStoreKey = "mem_perp"

// RouterKey is the message route for slashing.
// RouterKey is the message route for perp.
RouterKey = ModuleName

// QuerierRoute defines the module's query routing key.
Expand Down
7 changes: 7 additions & 0 deletions x/perp/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ func (m MsgAddMargin) GetSigners() []sdk.AccAddress {

// MsgOpenPosition

func (m MsgOpenPosition) Route() string { return RouterKey }
func (m MsgOpenPosition) Type() string { return "open_position_msg" }

func (msg *MsgOpenPosition) ValidateBasic() error {
if msg.Side != Side_SELL && msg.Side != Side_BUY {
return fmt.Errorf("invalid side")
Expand All @@ -117,6 +120,10 @@ func (msg *MsgOpenPosition) ValidateBasic() error {
return nil
}

func (m MsgOpenPosition) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m))
}

func (m *MsgOpenPosition) GetSigners() []sdk.AccAddress {
signer, err := sdk.AccAddressFromBech32(m.Sender)
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion x/vpool/keeper/prices.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,12 @@ func (k Keeper) calcTwap(
var cumulativePeriodMs int64 = 0
var prevTimestampMs int64 = ctx.BlockTime().UnixMilli()
var currentSnapshot types.ReserveSnapshot
var currentPrice sdk.Dec = sdk.ZeroDec()

for ; iter.Valid(); iter.Next() {
k.codec.MustUnmarshal(iter.Value(), &currentSnapshot)

currentPrice, err := getPriceWithSnapshot(
currentPrice, err = getPriceWithSnapshot(
currentSnapshot,
snapshotPriceOptions{
pair: pair,
Expand Down Expand Up @@ -269,6 +270,10 @@ func (k Keeper) calcTwap(
prevTimestampMs = currentSnapshot.TimestampMs
}

if cumulativePeriodMs <= 0 {
NibiruHeisenberg marked this conversation as resolved.
Show resolved Hide resolved
return currentPrice, nil
}

// definition of TWAP
return cumulativePrice.QuoInt64(cumulativePeriodMs), nil
}
Loading