diff --git a/app/test_helpers.go b/app/test_helpers.go index 3676eafaab..30e1b81ac9 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -35,6 +35,8 @@ import ( "github.com/umee-network/umee/v6/app/params" "github.com/umee-network/umee/v6/x/leverage/fixtures" leveragetypes "github.com/umee-network/umee/v6/x/leverage/types" + "github.com/umee-network/umee/v6/x/metoken" + "github.com/umee-network/umee/v6/x/metoken/mocks" oracletypes "github.com/umee-network/umee/v6/x/oracle/types" ) @@ -301,6 +303,20 @@ func IntegrationTestNetworkConfig() network.Config { } appGenState[govtypes.ModuleName] = bz + var metokenGenState metoken.GenesisState + if err := cdc.UnmarshalJSON(appGenState[metoken.ModuleName], &metokenGenState); err != nil { + panic(err) + } + + metokenGenState.Registry = []metoken.Index{mocks.BondIndex()} + metokenGenState.Balances = []metoken.IndexBalances{mocks.BondBalance()} + + bz, err = cdc.MarshalJSON(&metokenGenState) + if err != nil { + panic(err) + } + appGenState[metoken.ModuleName] = bz + cfg.Codec = encCfg.Codec cfg.TxConfig = encCfg.TxConfig cfg.LegacyAmino = encCfg.Amino diff --git a/x/metoken/client/tests/cli_test.go b/x/metoken/client/tests/cli_test.go new file mode 100644 index 0000000000..bfda01fef4 --- /dev/null +++ b/x/metoken/client/tests/cli_test.go @@ -0,0 +1,29 @@ +package tests + +import ( + "testing" + + umeeapp "github.com/umee-network/umee/v6/app" +) + +func TestIntegrationSuite(t *testing.T) { + t.Parallel() + cfg := umeeapp.IntegrationTestNetworkConfig() + cfg.NumValidators = 2 + cfg.Mnemonics = []string{ + "empower ridge mystery shrimp predict alarm swear brick across funny vendor essay antique vote place lava proof gaze crush head east arch twin lady", + "clean target advice dirt onion correct original vibrant actor upon waste eternal color barely shrimp aspect fall material wait repeat bench demise length seven", + } + + // init the integration test and start the network + s := NewIntegrationTestSuite(cfg, t) + s.SetupSuite() + defer s.TearDownSuite() + + // test cli queries + s.TestInvalidQueries() + s.TestValidQueries() + + //test cli transactions + s.TestTransactions() +} diff --git a/x/metoken/client/tests/suite.go b/x/metoken/client/tests/suite.go new file mode 100644 index 0000000000..77a2b882a5 --- /dev/null +++ b/x/metoken/client/tests/suite.go @@ -0,0 +1,19 @@ +package tests + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/testutil/network" + + itestsuite "github.com/umee-network/umee/v6/tests/cli" +) + +type IntegrationTests struct { + *itestsuite.E2ESuite +} + +func NewIntegrationTestSuite(cfg network.Config, t *testing.T) *IntegrationTests { + return &IntegrationTests{ + &itestsuite.E2ESuite{Cfg: cfg, T: t}, + } +} diff --git a/x/metoken/client/tests/tests.go b/x/metoken/client/tests/tests.go new file mode 100644 index 0000000000..81b579a477 --- /dev/null +++ b/x/metoken/client/tests/tests.go @@ -0,0 +1,207 @@ +package tests + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + itestsuite "github.com/umee-network/umee/v6/tests/cli" + "github.com/umee-network/umee/v6/x/metoken" + "github.com/umee-network/umee/v6/x/metoken/client/cli" + mfixtures "github.com/umee-network/umee/v6/x/metoken/mocks" +) + +func (s *IntegrationTests) TestInvalidQueries() { + invalidQueries := []itestsuite.TestQuery{ + { + + Name: "query swap fee - invalid asset for swap", + Command: cli.GetCmdSwapFee(), + Args: []string{ + "{abcd}{100000000}", + "xyz", + }, + Response: nil, + ExpectedResponse: nil, + ErrMsg: "invalid decimal coin expression", + }, + { + Name: "query swap fee - index not found", + Command: cli.GetCmdSwapFee(), + Args: []string{ + "1000abcd", + "xyz", + }, + Response: nil, + ExpectedResponse: nil, + ErrMsg: "index xyz not found", + }, + { + Name: "query redeem fee - invalid meToken for redemption", + Command: cli.GetCmdRedeemFee(), + Args: []string{ + "{abcd}{100000000}", + "xyz", + }, + Response: nil, + ExpectedResponse: nil, + ErrMsg: "invalid decimal coin expression", + }, + { + Name: "query redeem fee - index not found", + Command: cli.GetCmdRedeemFee(), + Args: []string{ + "1000xyz", + "abcd", + }, + Response: nil, + ExpectedResponse: nil, + ErrMsg: "index xyz not found", + }, + } + + // These queries do not require any setup because they contain invalid arguments + s.RunTestQueries(invalidQueries...) +} + +func (s *IntegrationTests) TestValidQueries() { + queries := []itestsuite.TestQuery{ + { + Name: "query params", + Command: cli.GetCmdQueryParams(), + Args: []string{}, + Response: &metoken.QueryParamsResponse{}, + ExpectedResponse: &metoken.QueryParamsResponse{ + Params: metoken.DefaultParams(), + }, + ErrMsg: "", + }, + { + Name: "query indexes", + Command: cli.GetCmdIndexes(), + Args: []string{}, + Response: &metoken.QueryIndexesResponse{}, + ExpectedResponse: &metoken.QueryIndexesResponse{ + Registry: []metoken.Index{mfixtures.BondIndex()}, + }, + ErrMsg: "", + }, + { + Name: "query balances", + Command: cli.GetCmdIndexBalances(), + Args: []string{}, + Response: &metoken.QueryIndexBalancesResponse{}, + ExpectedResponse: &metoken.QueryIndexBalancesResponse{ + IndexBalances: []metoken.IndexBalances{mfixtures.BondBalance()}, + Prices: []metoken.IndexPrices{ + { + Denom: mfixtures.MeBondDenom, + Price: sdk.MustNewDecFromStr("34.21"), + Exponent: 6, + Assets: []metoken.AssetPrice{ + { + BaseDenom: mfixtures.BondDenom, + SymbolDenom: "UMEE", + Price: sdk.MustNewDecFromStr("34.21"), + Exponent: 6, + SwapRate: sdk.OneDec(), + RedeemRate: sdk.OneDec(), + }, + }, + }, + }, + }, + ErrMsg: "", + }, + { + Name: "query swap fee for 1876 uumee", + Command: cli.GetCmdSwapFee(), + Args: []string{ + "1876000000uumee", + mfixtures.MeBondDenom, + }, + Response: &metoken.QuerySwapFeeResponse{}, + ExpectedResponse: &metoken.QuerySwapFeeResponse{ + // swap_fee = 0.01 * 1876_000000 = 18760000 + Asset: sdk.NewCoin( + "uumee", + sdkmath.NewInt(18_760000), + ), + }, + ErrMsg: "", + }, + { + Name: "query redeem fee for 100 meUSD to uumee", + Command: cli.GetCmdRedeemFee(), + Args: []string{ + "100000000me/uumee", + "uumee", + }, + Response: &metoken.QueryRedeemFeeResponse{}, + ExpectedResponse: &metoken.QueryRedeemFeeResponse{ + // with all balances in 0 + // current_allocation = 0 + // redeem_delta_allocation = target_allocation - current_allocation + // redeem_delta_allocation = 1.0 - 0 = 1.0 + // fee = redeem_delta_allocation * balanced_fee + balanced_fee + // fee = 1.0 * 0.2 + 0.2 = 0.4 + // exchange_rate = 1 + // asset_to_redeem = exchange_rate * metoken_amount + // asset_to_redeem = 1 * 100_000000 = 100_000000 + // total_fee = asset_to_redeem * fee + // total_fee = 100_000000 * 0.4 = 40_000000 + + Asset: sdk.NewCoin( + "uumee", + sdkmath.NewInt(40_000000), + ), + }, + ErrMsg: "", + }, + } + + // These queries do not require any setup + s.RunTestQueries(queries...) +} + +func (s *IntegrationTests) TestTransactions() { + txs := []itestsuite.TestTransaction{ + { + Name: "swap index not found", + Command: cli.GetCmdSwap(), + Args: []string{ + "300000000" + mfixtures.BondDenom, + "me/Test", + }, + ExpectedErr: sdkerrors.ErrNotFound, + }, + { + Name: "swap 300uumee", + Command: cli.GetCmdSwap(), + Args: []string{ + "300000000" + mfixtures.BondDenom, + mfixtures.MeBondDenom, + }, + ExpectedErr: nil, + }, + { + Name: "swap index not found", + Command: cli.GetCmdRedeem(), + Args: []string{ + "300000000" + "me/Test", + mfixtures.BondDenom, + }, + ExpectedErr: sdkerrors.ErrNotFound, + }, + { + Name: "redeem 100me/uumee", + Command: cli.GetCmdRedeem(), + Args: []string{ + "100000000" + mfixtures.MeBondDenom, + mfixtures.BondDenom, + }, + ExpectedErr: nil, + }, + } + + s.RunTestTransactions(txs...) +} diff --git a/x/metoken/mocks/metoken.go b/x/metoken/mocks/metoken.go index b1076e70f7..ef43573282 100644 --- a/x/metoken/mocks/metoken.go +++ b/x/metoken/mocks/metoken.go @@ -3,6 +3,7 @@ package mocks import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/umee-network/umee/v6/util/coin" ltypes "github.com/umee-network/umee/v6/x/leverage/types" "github.com/umee-network/umee/v6/x/metoken" @@ -25,6 +26,8 @@ const ( MeUSDDenom = "me/USD" MeNonStableDenom = "me/NonStable" TestDenom1 = "testDenom1" + BondDenom = "uumee" + MeBondDenom = "me/" + BondDenom ) var ( @@ -64,6 +67,36 @@ func NonStableIndex(denom string) metoken.Index { ) } +func BondIndex() metoken.Index { + return metoken.Index{ + Denom: MeBondDenom, + MaxSupply: sdk.NewInt(1000000_00000), + Exponent: 6, + Fee: ValidFee(), + AcceptedAssets: []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset( + BondDenom, sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("1.0"), + ), + }, + } +} + +func BondBalance() metoken.IndexBalances { + return metoken.IndexBalances{ + MetokenSupply: coin.Zero(MeBondDenom), + AssetBalances: []metoken.AssetBalance{ + { + Denom: BondDenom, + Leveraged: sdkmath.ZeroInt(), + Reserved: sdkmath.ZeroInt(), + Fees: sdkmath.ZeroInt(), + Interest: sdkmath.ZeroInt(), + }, + }, + } +} + func acceptedAsset(denom, targetAllocation string) metoken.AcceptedAsset { return metoken.NewAcceptedAsset(denom, sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr(targetAllocation)) }