package keeper_test import ( "testing" "time" sdkmath "cosmossdk.io/math" tmprototypes "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/cdp/keeper" "github.com/kava-labs/kava/x/cdp/types" "github.com/stretchr/testify/suite" ) type grpcQueryTestSuite struct { suite.Suite tApp app.TestApp ctx sdk.Context keeper keeper.Keeper queryServer types.QueryServer addrs []sdk.AccAddress now time.Time } func (suite *grpcQueryTestSuite) SetupTest() { suite.tApp = app.NewTestApp() suite.tApp.InitializeFromGenesisStates( NewPricefeedGenStateMulti(suite.tApp.AppCodec()), NewCDPGenStateMulti(suite.tApp.AppCodec()), ) suite.ctx = suite.tApp.NewContext(true, tmprototypes.Header{}). WithBlockTime(time.Now().UTC()) suite.keeper = suite.tApp.GetCDPKeeper() suite.queryServer = keeper.NewQueryServerImpl(suite.keeper) _, addrs := app.GeneratePrivKeyAddressPairs(5) suite.addrs = addrs suite.now = time.Now().UTC() } func (suite *grpcQueryTestSuite) addCdp() { ak := suite.tApp.GetAccountKeeper() pk := suite.tApp.GetPriceFeedKeeper() acc := ak.NewAccountWithAddress(suite.ctx, suite.addrs[0]) err := suite.tApp.FundAccount(suite.ctx, acc.GetAddress(), cs(c("xrp", 200000000), c("btc", 500000000))) suite.NoError(err) ak.SetAccount(suite.ctx, acc) err = pk.SetCurrentPrices(suite.ctx, "xrp:usd") suite.NoError(err) ok := suite.keeper.UpdatePricefeedStatus(suite.ctx, "xrp:usd") suite.True(ok) err = suite.keeper.AddCdp(suite.ctx, suite.addrs[0], c("xrp", 100000000), c("usdx", 10000000), "xrp-a") suite.NoError(err) id := suite.keeper.GetNextCdpID(suite.ctx) suite.Equal(uint64(2), id) tp := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx") suite.Equal(i(10000000), tp) } func (suite *grpcQueryTestSuite) TestGrpcQueryParams() { res, err := suite.queryServer.Params(sdk.WrapSDKContext(suite.ctx), &types.QueryParamsRequest{}) suite.Require().NoError(err) var expected types.GenesisState defaultCdpState := NewCDPGenStateMulti(suite.tApp.AppCodec()) suite.tApp.AppCodec().MustUnmarshalJSON(defaultCdpState[types.ModuleName], &expected) suite.Equal(expected.Params, res.Params, "params should equal test genesis state") } func (suite *grpcQueryTestSuite) TestGrpcQueryParams_Default() { suite.keeper.SetParams(suite.ctx, types.DefaultParams()) res, err := suite.queryServer.Params(sdk.WrapSDKContext(suite.ctx), &types.QueryParamsRequest{}) suite.Require().NoError(err) suite.Empty(res.Params.CollateralParams) } func (suite *grpcQueryTestSuite) TestGrpcQueryAccounts() { res, err := suite.queryServer.Accounts(sdk.WrapSDKContext(suite.ctx), &types.QueryAccountsRequest{}) suite.Require().NoError(err) ak := suite.tApp.GetAccountKeeper() acc := ak.GetModuleAccount(suite.ctx, types.ModuleName) liquidator := ak.GetModuleAccount(suite.ctx, types.LiquidatorMacc) suite.Len(res.Accounts, 2) suite.Equal(acc, &res.Accounts[0], "accounts should include module account") suite.Equal(liquidator, &res.Accounts[1], "accounts should include liquidator account") } func (suite *grpcQueryTestSuite) TestGrpcQueryTotalPrincipal() { suite.addCdp() res, err := suite.queryServer.TotalPrincipal(sdk.WrapSDKContext(suite.ctx), &types.QueryTotalPrincipalRequest{}) suite.Require().NoError(err) suite.Len(res.TotalPrincipal, 4, "total principal should include all collateral params") suite.Contains(res.TotalPrincipal, types.TotalPrincipal{ CollateralType: "xrp-a", Amount: sdk.NewCoin("usdx", sdkmath.NewInt(10000000)), }, "total principals should include added cdp") suite.Contains(res.TotalPrincipal, types.TotalPrincipal{ CollateralType: "busd-a", Amount: sdk.NewCoin("usdx", sdkmath.NewInt(0)), }, "total busd principal should be 0") } func (suite *grpcQueryTestSuite) TestGrpcQueryTotalCollateral() { suite.addCdp() res, err := suite.queryServer.TotalCollateral(sdk.WrapSDKContext(suite.ctx), &types.QueryTotalCollateralRequest{}) suite.Require().NoError(err) suite.Len(res.TotalCollateral, 4, "total collateral should include all collateral params") suite.Contains(res.TotalCollateral, types.TotalCollateral{ CollateralType: "xrp-a", Amount: sdk.NewCoin("xrp", sdkmath.NewInt(100000000)), }, "total collaterals should include added cdp") suite.Contains(res.TotalCollateral, types.TotalCollateral{ CollateralType: "busd-a", Amount: sdk.NewCoin("busd", sdkmath.NewInt(0)), }, "busd total collateral should be 0") } func (suite *grpcQueryTestSuite) TestGrpcQueryCdps() { suite.addCdp() res, err := suite.queryServer.Cdps(sdk.WrapSDKContext(suite.ctx), &types.QueryCdpsRequest{ CollateralType: "xrp-a", Pagination: &query.PageRequest{ Limit: 100, }, }) suite.Require().NoError(err) suite.Len(res.Cdps, 1) } func (suite *grpcQueryTestSuite) TestGrpcQueryCdps_InvalidCollateralType() { suite.addCdp() _, err := suite.queryServer.Cdps(sdk.WrapSDKContext(suite.ctx), &types.QueryCdpsRequest{ CollateralType: "kava-a", }) suite.Require().Error(err) suite.Require().Equal("rpc error: code = InvalidArgument desc = invalid collateral type", err.Error()) } func (suite *grpcQueryTestSuite) TestGrpcQueryCdp() { suite.addCdp() tests := []struct { giveName string giveRequest types.QueryCdpRequest wantAccepted bool wantErr string }{ { "valid", types.QueryCdpRequest{ CollateralType: "xrp-a", Owner: suite.addrs[0].String(), }, true, "", }, { "invalid collateral", types.QueryCdpRequest{ CollateralType: "kava-a", Owner: suite.addrs[0].String(), }, false, "kava-a: invalid collateral for input collateral type", }, { "missing owner", types.QueryCdpRequest{ CollateralType: "xrp-a", }, false, "rpc error: code = InvalidArgument desc = invalid address", }, { "invalid owner", types.QueryCdpRequest{ CollateralType: "xrp-a", Owner: "invalid addr", }, false, "rpc error: code = InvalidArgument desc = invalid address", }, } for _, tt := range tests { suite.Run(tt.giveName, func() { _, err := suite.queryServer.Cdp(sdk.WrapSDKContext(suite.ctx), &tt.giveRequest) if tt.wantAccepted { suite.Require().NoError(err) } else { suite.Require().Error(err) suite.Require().Equal(tt.wantErr, err.Error()) } }) } } func (suite *grpcQueryTestSuite) TestGrpcQueryDeposits() { suite.addCdp() tests := []struct { giveName string giveRequest *types.QueryDepositsRequest wantContainsDeposit *types.Deposit wantShouldErr bool wantErr string }{ { "valid", &types.QueryDepositsRequest{ CollateralType: "xrp-a", Owner: suite.addrs[0].String(), }, &types.Deposit{ CdpID: 1, Depositor: suite.addrs[0], Amount: sdk.NewCoin("xrp", sdkmath.NewInt(100000000)), }, false, "", }, { "invalid collateral type", &types.QueryDepositsRequest{ CollateralType: "kava-a", Owner: suite.addrs[0].String(), }, nil, true, "kava-a: invalid collateral for input collateral type", }, { "missing owner", &types.QueryDepositsRequest{ CollateralType: "xrp-a", }, nil, true, "rpc error: code = InvalidArgument desc = invalid address", }, } for _, tt := range tests { suite.Run(tt.giveName, func() { res, err := suite.queryServer.Deposits(sdk.WrapSDKContext(suite.ctx), tt.giveRequest) if tt.wantShouldErr { suite.Error(err) suite.Equal(tt.wantErr, err.Error()) } else { suite.NoError(err) suite.Contains(res.Deposits, *tt.wantContainsDeposit) } }) } } func TestGrpcQueryTestSuite(t *testing.T) { suite.Run(t, new(grpcQueryTestSuite)) }