Skip to content

Commit

Permalink
Fix open position CLI and add cli tests. (#485)
Browse files Browse the repository at this point in the history
* add basic test bootstrap

* add query

* Hook up vpool query cmd

* add some changes in order to work

* add metadata types

* make open position work

* generate proto!

* golangci proto

* fix tests

* add cli tests for open position

* fix linter

* redo protoc

* remove test genesis

* add query position

* add query for the position

* fix linter for cli query

Co-authored-by: Walter White <heisenberg@matrixsystems.co>
Co-authored-by: Mat-Cosmos <97468149+matthiasmatt@users.noreply.github.com>
  • Loading branch information
3 people authored May 25, 2022
1 parent c9a13f8 commit fd9b661
Show file tree
Hide file tree
Showing 27 changed files with 544 additions and 163 deletions.
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ var (
perp.AppModuleBasic{},
lockup.AppModuleBasic{},
incentivization.AppModuleBasic{},
vpool.AppModuleBasic{},
)

// module account permissions
Expand Down
2 changes: 2 additions & 0 deletions cmd/nibid/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
perpcmd "github.com/NibiruChain/nibiru/x/perp/client/cli"
pricefeedcmd "github.com/NibiruChain/nibiru/x/pricefeed/client/cli"
sccmd "github.com/NibiruChain/nibiru/x/stablecoin/client/cli"
vpoolcmd "github.com/NibiruChain/nibiru/x/vpool/client/cli"

// Cosmos-SDK
"github.com/cosmos/cosmos-sdk/baseapp"
Expand Down Expand Up @@ -221,6 +222,7 @@ func queryCommand() *cobra.Command {
pricefeedcmd.GetQueryCmd(),
sccmd.GetQueryCmd(),
perpcmd.GetQueryCmd(),
vpoolcmd.GetQueryCmd(),
)

// Adds all query commands to the 'rootQueryCmd'
Expand Down
1 change: 1 addition & 0 deletions proto/perp/v1/state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ message GenesisState {
(gogoproto.moretags) = "yaml:\"module_account_balance\"",
(gogoproto.nullable) = false
];
repeated PairMetadata pair_metadata = 3;
}

// Position identifies and records information on a user's position on one of
Expand Down
2 changes: 1 addition & 1 deletion x/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type AssetPair struct {
Token1 string
}

// name is the name of the pool that corresponds to the two assets on this pair.
// Name is the name of the pool that corresponds to the two assets on this pair.
func (pair AssetPair) Name() string {
return PoolNameFromDenoms([]string{pair.Token0, pair.Token1})
}
Expand Down
2 changes: 1 addition & 1 deletion x/dex/client/testutil/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ func (s *IntegrationTestSuite) FundAccount(recipient sdk.Address, tokens sdk.Coi
/*extraArgs*/
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
testutil.DefaultFeeString(s.cfg),
testutil.DefaultFeeString(s.cfg.BondDenom),
)
s.Require().NoError(err)
}
Expand Down
12 changes: 9 additions & 3 deletions x/perp/client/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,19 @@ func CmdQueryPosition() *cobra.Command {

queryClient := types.NewQueryClient(clientCtx)

trader := args[0]
trader, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return fmt.Errorf("invalid trader address: %w", err)
}

tokenPair, err := common.NewTokenPairFromStr(args[1])
if err != nil {
return err
}

res, err := queryClient.TraderPosition(
context.Background(), &types.QueryTraderPositionRequest{
Trader: sdk.AccAddress(trader),
Trader: trader,
TokenPair: tokenPair.String(),
},
)
Expand Down Expand Up @@ -143,7 +147,8 @@ func OpenPositionCmd() *cobra.Command {
return err
}

txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)

var side types.Side
switch args[0] {
Expand Down Expand Up @@ -193,6 +198,7 @@ func OpenPositionCmd() *cobra.Command {
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

Expand Down
151 changes: 151 additions & 0 deletions x/perp/client/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package cli_test

import (
"fmt"
"strings"
"testing"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"

"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/perp/client/cli"
perptypes "github.com/NibiruChain/nibiru/x/perp/types"
utils "github.com/NibiruChain/nibiru/x/testutil"
testutilcli "github.com/NibiruChain/nibiru/x/testutil/cli"
vpooltypes "github.com/NibiruChain/nibiru/x/vpool/types"
)

type IntegrationTestSuite struct {
suite.Suite

cfg testutilcli.Config
network *testutilcli.Network
}

func (s *IntegrationTestSuite) SetupSuite() {
/* Make test skip if -short is not used:
All tests: `go test ./...`
Unit tests only: `go test ./... -short`
Integration tests only: `go test ./... -run Integration`
https://stackoverflow.com/a/41407042/13305627 */
if testing.Short() {
s.T().Skip("skipping integration test suite")
}

s.T().Log("setting up integration test suite")

s.cfg = utils.DefaultConfig()

genesisState := app.ModuleBasics.DefaultGenesis(s.cfg.Codec)

vpoolGenesis := vpooltypes.DefaultGenesis()
vpoolGenesis.Vpools = []*vpooltypes.Pool{
{
Pair: "ubtc:unibi",
BaseAssetReserve: sdk.MustNewDecFromStr("10000000"),
QuoteAssetReserve: sdk.MustNewDecFromStr("60000000000"),
TradeLimitRatio: sdk.MustNewDecFromStr("0.8"),
FluctuationLimitRatio: sdk.MustNewDecFromStr("0.2"),
MaxOracleSpreadRatio: sdk.MustNewDecFromStr("0.2"),
},
}
genesisState[vpooltypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(vpoolGenesis)

perpGenesis := perptypes.DefaultGenesis()
perpGenesis.PairMetadata = []*perptypes.PairMetadata{
{
Pair: "ubtc:unibi",
CumulativePremiumFractions: []sdk.Dec{
sdk.ZeroDec(),
},
},
}

genesisState[perptypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(perpGenesis)
s.cfg.GenesisState = genesisState

app.SetPrefixes(app.AccountAddressPrefix)

s.network = testutilcli.New(s.T(), s.cfg)

_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
}

func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}

func (s *IntegrationTestSuite) TestOpenPositionCmd() {
val := s.network.Validators[0]
pair := fmt.Sprintf("%s%s%s", "ubtc", common.PairSeparator, "unibi")

info, _, err := val.ClientCtx.Keyring.
NewMnemonic("user1", keyring.English, sdk.FullFundraiserPath, "", hd.Secp256k1)
s.Require().NoError(err)

user := sdk.AccAddress(info.GetPubKey().Address())

_, err = utils.FillWalletFromValidator(user,
sdk.NewCoins(
sdk.NewInt64Coin(s.cfg.BondDenom, 20_000),
sdk.NewInt64Coin(common.GovDenom, 100_000_000),
sdk.NewInt64Coin(common.CollDenom, 100_000_000),
),
val,
s.cfg.BondDenom,
)
s.Require().NoError(err)

// Check vpool balances
reserveAssets, err := testutilcli.QueryVpoolReserveAssets(val.ClientCtx, common.TokenPair(pair))
s.Require().NoError(err)
s.Require().Equal(sdk.MustNewDecFromStr("10000000"), reserveAssets.BaseAssetReserve)
s.Require().Equal(sdk.MustNewDecFromStr("60000000000"), reserveAssets.QuoteAssetReserve)

args := []string{
"--from",
user.String(),
"buy",
fmt.Sprintf("%s%s%s", "ubtc", common.PairSeparator, "unibi"),
"1", // Leverage
"1000000", // 1 BTC
"1",
}
commonArgs := []string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()),
}

_, err = testutilcli.QueryTraderPosition(val.ClientCtx, common.TokenPair(pair), user)
s.Require().True(strings.Contains(err.Error(), "no position found"))

_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, cli.OpenPositionCmd(), append(args, commonArgs...))
s.Require().NoError(err)

// Check vpool after opening position
reserveAssets, err = testutilcli.QueryVpoolReserveAssets(val.ClientCtx, "ubtc:unibi")
s.Require().NoError(err)
s.Require().Equal(sdk.MustNewDecFromStr("9999833.336111064815586407"), reserveAssets.BaseAssetReserve)
s.Require().Equal(sdk.MustNewDecFromStr("60001000000"), reserveAssets.QuoteAssetReserve)

// Check position
queryResp, err := testutilcli.QueryTraderPosition(val.ClientCtx, common.TokenPair(pair), user)
s.Require().NoError(err)
s.Require().Equal(user, queryResp.Position.TraderAddress)
s.Require().Equal(pair, queryResp.Position.Pair)
s.Require().Equal(sdk.MustNewDecFromStr("1000000"), queryResp.Position.Margin)
s.Require().Equal(sdk.MustNewDecFromStr("1000000"), queryResp.Position.OpenNotional)
}

func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
42 changes: 42 additions & 0 deletions x/perp/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package perp

import (
sdk "github.com/cosmos/cosmos-sdk/types"

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

// InitGenesis initializes the capability module's state from a provided genesis
// state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
if genState.ModuleAccountBalance.Amount.GT(sdk.ZeroInt()) {
if err := k.BankKeeper.MintCoins(
ctx, types.ModuleName, sdk.NewCoins(genState.ModuleAccountBalance),
); err != nil {
panic(err)
}
}

k.SetParams(ctx, genState.Params)

for _, pm := range genState.PairMetadata {
k.PairMetadata().Set(ctx, pm)
}

// See https://github.com/cosmos/cosmos-sdk/issues/5569 on why we do this.
k.AccountKeeper.GetModuleAccount(ctx, types.FeePoolModuleAccount)
k.AccountKeeper.GetModuleAccount(ctx, types.VaultModuleAccount)
}

// ExportGenesis returns the capability module's exported genesis.
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
genesis := types.DefaultGenesis()

genesis.Params = k.GetParams(ctx)
genesis.ModuleAccountBalance = k.GetModuleAccountBalance(ctx, common.GovDenom)
genesis.PairMetadata = k.PairMetadata().GetAll(ctx)

return genesis
}
47 changes: 47 additions & 0 deletions x/perp/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package perp_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

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

func TestGenesis(t *testing.T) {
genesisState := types.GenesisState{
Params: types.DefaultParams(),
ModuleAccountBalance: sdk.NewCoin(common.GovDenom, sdk.ZeroInt()),
PairMetadata: []*types.PairMetadata{
{
Pair: "ubtc:unibi",
CumulativePremiumFractions: []sdk.Dec{
sdk.MustNewDecFromStr("2.0"),
},
},
{
Pair: "ueth:unibi",
CumulativePremiumFractions: nil,
},
},
}

nibiruApp, ctx := testutil.NewNibiruApp(true)
perp.InitGenesis(ctx, nibiruApp.PerpKeeper, genesisState)

exportedGenesisState := perp.ExportGenesis(ctx, nibiruApp.PerpKeeper)
require.NotNil(t, exportedGenesisState)

require.Equal(t, genesisState.GetParams(), exportedGenesisState.GetParams())
require.Equal(t, genesisState.ModuleAccountBalance, exportedGenesisState.ModuleAccountBalance)

require.Len(t, exportedGenesisState.PairMetadata, 2)

for _, pm := range exportedGenesisState.PairMetadata {
require.Contains(t, genesisState.PairMetadata, pm)
}
}
4 changes: 2 additions & 2 deletions x/perp/keeper/calc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestCalcRemainMarginWithFundingPayment(t *testing.T) {
Pair: "osmo:nusd",
}, marginDelta)
require.Error(t, err)
require.ErrorContains(t, err, types.ErrPairNotFound.Error())
require.ErrorContains(t, err, types.ErrPairMetadataNotFound.Error())
},
},
{
Expand All @@ -42,7 +42,7 @@ func TestCalcRemainMarginWithFundingPayment(t *testing.T) {
_, err := nibiruApp.PerpKeeper.CalcRemainMarginWithFundingPayment(
ctx, types.Position{Pair: the3pool}, marginDelta)
require.Error(t, err)
require.ErrorContains(t, err, types.ErrPairNotFound.Error())
require.ErrorContains(t, err, types.ErrPairMetadataNotFound.Error())
},
},
{
Expand Down
1 change: 0 additions & 1 deletion x/perp/keeper/clearing_house.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ func (k Keeper) OpenPosition(
leverage sdk.Dec,
baseAssetAmountLimit sdk.Dec,
) (err error) {
// require vpool
err = k.requireVpool(ctx, pair)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion x/perp/keeper/margin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestOpenPosition_Setup(t *testing.T) {
ctx, pair, side, alice, quote, leverage, baseLimit)

require.Error(t, err)
require.ErrorContains(t, err, types.ErrPairNotFound.Error())
require.ErrorContains(t, err, types.ErrPairMetadataNotFound.Error())
},
},
{
Expand Down
4 changes: 3 additions & 1 deletion x/perp/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

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

type msgServer struct {
Expand Down Expand Up @@ -46,7 +48,7 @@ func (k msgServer) OpenPosition(goCtx context.Context, req *types.MsgOpenPositio
req.BaseAssetAmountLimit.ToDec(),
)
if err != nil {
return nil, err
return nil, sdkerrors.Wrap(vpooltypes.ErrOpeningPosition, err.Error())
}

return &types.MsgOpenPositionResponse{}, nil
Expand Down
Loading

0 comments on commit fd9b661

Please sign in to comment.