diff --git a/.github/release.yml b/.github/release.yml index fae91ba4..00da9328 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index f9bd9eac..1694b0db 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b9fe851..abb63d04 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,10 +39,12 @@ jobs: arch: arm64 steps: - - name: Check out repository code - uses: actions/checkout@v4 - - name: Get git diff - uses: technote-space/get-diff-action@v6.1.2 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: 1.22 + - uses: technote-space/get-diff-action@v4 + id: git_diff with: PATTERNS: | **/**.wasm @@ -82,23 +84,23 @@ jobs: go-version: 1.22 - uses: actions/checkout@v4 - name: Create a file with all the pkgs - run: go list ./... > pkgs.txt + run: go list ./... | grep -E -v 'tests/e2e' > pkgs.txt - name: Split pkgs into 4 files run: split -d -n l/4 pkgs.txt pkgs.txt.part. # cache multiple - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-00" path: ./pkgs.txt.part.00 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-01" path: ./pkgs.txt.part.01 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-02" path: ./pkgs.txt.part.02 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-03" path: ./pkgs.txt.part.03 @@ -121,7 +123,7 @@ jobs: **/**.go go.mod go.sum - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-${{ matrix.part }}" if: env.GIT_DIFF @@ -129,7 +131,7 @@ jobs: run: | cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 30m -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags='norace ledger test_ledger_mock' if: env.GIT_DIFF - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-${{ matrix.part }}-coverage" path: ./${{ matrix.part }}profile.out @@ -145,19 +147,19 @@ jobs: **/**.go go.mod go.sum - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-00-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-01-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-02-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-03-coverage" if: env.GIT_DIFF @@ -199,7 +201,7 @@ jobs: **/**.go go.mod go.sum - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: name: "${{ github.sha }}-${{ matrix.part }}" if: env.GIT_DIFF @@ -207,7 +209,7 @@ jobs: run: | xargs --arg-file=pkgs.txt.part.${{ matrix.part }} go test -mod=readonly -timeout 30m -race -tags='cgo ledger test_ledger_mock' if: env.GIT_DIFF - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: "${{ github.sha }}-${{ matrix.part }}-race-output" path: ./${{ matrix.part }}-race-output.txt diff --git a/tests/e2e/bet/cli_test.go b/tests/e2e/bet/cli_test.go new file mode 100644 index 00000000..72228e20 --- /dev/null +++ b/tests/e2e/bet/cli_test.go @@ -0,0 +1,16 @@ +package client_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + client "github.com/sge-network/sge/tests/e2e/bet" + "github.com/sge-network/sge/testutil/network" +) + +func TestE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, client.NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/bet/grpc.go b/tests/e2e/bet/grpc.go new file mode 100644 index 00000000..22ecb957 --- /dev/null +++ b/tests/e2e/bet/grpc.go @@ -0,0 +1,106 @@ +package client + +import ( + "fmt" + + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/cosmos-sdk/testutil" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/sge-network/sge/x/bet/types" +) + +func (s *E2ETestSuite) TestBetsGRPCHandler() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + testCases := []struct { + name string + url string + headers map[string]string + respType proto.Message + expected proto.Message + }{ + { + "test GRPC Bet by UID", + fmt.Sprintf("%s/sge/bet/%s/%s", baseURL, dummyBetCreator, dummyBetUID), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryBetResponse{}, + &types.QueryBetResponse{ + Bet: genesis.BetList[0], + Market: dummyMarket, + }, + }, + { + "test GRPC sorted Bet by creator", + fmt.Sprintf("%s/sge/bet/creator/%s/bets", baseURL, dummyBetCreator), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryBetsByCreatorResponse{}, + &types.QueryBetsByCreatorResponse{ + Bet: genesis.BetList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + { + "test GRPC Bet by UID", + fmt.Sprintf("%s/sge/bet/bets", baseURL), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryBetsResponse{}, + &types.QueryBetsResponse{ + Bet: genesis.BetList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + { + "test GRPC pending bets by market", + fmt.Sprintf("%s/sge/bet/bets/pending/%s", baseURL, dummyMarketUID), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryPendingBetsResponse{}, + &types.QueryPendingBetsResponse{ + Bet: genesis.BetList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + { + "test GRPC settled bets by market", + fmt.Sprintf("%s/sge/bet/bets/settled/%d", baseURL, 1), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QuerySettledBetsOfHeightResponse{}, + &types.QuerySettledBetsOfHeightResponse{ + Bet: genesis.BetList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) + s.Require().NoError(err) + + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + s.Require().Equal(tc.expected.String(), tc.respType.String()) + }) + } +} diff --git a/tests/e2e/bet/suite.go b/tests/e2e/bet/suite.go new file mode 100644 index 00000000..c6d5a203 --- /dev/null +++ b/tests/e2e/bet/suite.go @@ -0,0 +1,461 @@ +package client + +import ( + "fmt" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + e2esdk "github.com/sge-network/sge/tests/e2e/sdk" + "github.com/sge-network/sge/testutil/network" + "github.com/sge-network/sge/testutil/sample" + "github.com/sge-network/sge/testutil/simapp" + sgetypes "github.com/sge-network/sge/types" + "github.com/sge-network/sge/x/bet/client/cli" + "github.com/sge-network/sge/x/bet/types" + housecli "github.com/sge-network/sge/x/house/client/cli" + marketcli "github.com/sge-network/sge/x/market/client/cli" + markettypes "github.com/sge-network/sge/x/market/types" +) + +var ( + genesis types.GenesisState + + dummyMarket = markettypes.Market{} + dummyBetCreator = sample.AccAddress() + dummyBetUID = uuid.NewString() + dummyMarketUID = uuid.NewString() + + oddsUID1 = "9991c60f-2025-48ce-ae79-1dc110f16900" + oddsValue1 = sdkmath.LegacyNewDecWithPrec(14, 1) // 1.4 + oddsUID2 = "9991c60f-2025-48ce-ae79-1dc110f16901" + oddsValue2 = sdkmath.LegacyNewDecWithPrec(13, 1) // 1.3 + oddsUID3 = "9991c60f-2025-48ce-ae79-1dc110f16902" + maxLossMultiplier = sdkmath.LegacyNewDecWithPrec(10, 2) + + betFees = sdkmath.NewInt(10) + fees = int64(10) + marketUID = uuid.NewString() + marketStartDate = uint64(time.Now().Unix()) + marketEndDate = uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()) + depositAmount = sdkmath.NewInt(100000) + + wagerDate = time.Now().Add(time.Minute * time.Duration(180)).Unix() + wagerAmount = sdkmath.NewInt(100) + + acc1 = sdk.AccAddress{} + acc1Balance = sdkmath.ZeroInt() + + acc2 = sdk.AccAddress{} + acc2Balance = sdkmath.ZeroInt() +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + + genesisState := s.cfg.GenesisState + + var marketGenesis markettypes.GenesisState + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[markettypes.ModuleName], &marketGenesis)) + + dummyMarket = markettypes.Market{ + Creator: sample.AccAddress(), + UID: dummyMarketUID, + StartTS: uint64(time.Now().Unix()), + EndTS: uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()), + Odds: []*markettypes.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16904", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16905", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16906", + Meta: "Away", + }, + }, + WinnerOddsUIDs: []string{}, + Status: markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + Meta: "dummy market", + BookUID: dummyMarketUID, + } + marketGenesis.MarketList = []markettypes.Market{dummyMarket} + marketGenesisBz, err := s.cfg.Codec.MarshalJSON(&marketGenesis) + s.Require().NoError(err) + genesisState[markettypes.ModuleName] = marketGenesisBz + + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &genesis)) + + genesis.BetList = []types.Bet{ + { + Creator: dummyBetCreator, + UID: dummyBetUID, + OddsUID: marketGenesis.MarketList[0].OddsUIDS()[0], + OddsValue: "0.5", + Fee: sdkmath.NewInt(10), + Status: types.Bet_STATUS_SETTLED, + Result: types.Bet_RESULT_WON, + CreatedAt: wagerDate, + SettlementHeight: 1, + MaxLossMultiplier: sdkmath.LegacyNewDecWithPrec(10, 2), + Meta: types.MetaData{ + SelectedOddsType: types.OddsType_ODDS_TYPE_DECIMAL, + SelectedOddsValue: "0.5", + IsMainMarket: false, + }, + BetFulfillment: []*types.BetFulfillment{}, + MarketUID: dummyMarketUID, + Amount: wagerAmount, + }, + } + + genesis.Uid2IdList = []types.UID2ID{ + { + UID: dummyBetUID, + ID: 1, + }, + } + + genesis.PendingBetList = []types.PendingBet{ + { + UID: dummyBetUID, + Creator: dummyBetCreator, + }, + } + + genesis.SettledBetList = []types.SettledBet{ + { + UID: dummyBetUID, + BettorAddress: dummyBetCreator, + }, + } + + genesis.Stats = types.BetStats{ + Count: 1, + } + + genesis.Params = types.Params{ + BatchSettlementCount: uint32(1000), + MaxBetByUidQueryCount: uint32(1000), + Constraints: types.Constraints{ + MinAmount: sdkmath.NewInt(100), + Fee: betFees, + }, + } + + genesisBz, err := s.cfg.Codec.MarshalJSON(&genesis) + s.Require().NoError(err) + genesisState[types.ModuleName] = genesisBz + s.cfg.GenesisState = genesisState + + s.network = network.New(s.T(), s.cfg) + + s.Require().NoError(s.network.WaitForNextBlock()) +} + +func (s *E2ETestSuite) TestWagerTxCmd() { + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []markettypes.Odds{ + { + UID: oddsUID1, + Meta: "Home", + }, + { + UID: oddsUID2, + Meta: "Draw", + }, + { + UID: oddsUID3, + Meta: "Away", + }, + }, + "status": markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }) + require.Nil(s.T(), err) + + args := []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdAdd(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + } + s.Require().NoError(s.network.WaitForNextBlock()) + + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }) + require.Nil(s.T(), err) + + bz, err := clitestutil.ExecTestCLICmd(clientCtx, housecli.CmdDeposit(), []string{ + marketUID, + depositAmount.String(), + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }) + s.Require().NoError(err) + + var respType sdk.TxResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(uint32(0), txResp.Code) + } + + acc1initialBalance := 1000 + acc1 = e2esdk.CreateAccount(val, "acc1") + e2esdk.SendToken(val, acc1, acc1initialBalance) + s.Require().NoError(s.network.WaitForNextBlock()) + acc1Balance = e2esdk.GetSGEBalance(clientCtx, acc1.String()) + + acc2initialBalance := 1000 + acc2 = e2esdk.CreateAccount(val, "acc2") + e2esdk.SendToken(val, acc2, acc2initialBalance) + s.Require().NoError(s.network.WaitForNextBlock()) + acc2Balance = e2esdk.GetSGEBalance(clientCtx, acc2.String()) + + testCases := []struct { + name string + uid string + marketUID string + amount sdkmath.Int + ticketClaims jwt.MapClaims + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "valid transaction for acc1", + uuid.NewString(), + marketUID, + wagerAmount, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: acc1.String(), + }, + "selected_odds": types.BetOdds{ + UID: oddsUID1, + MarketUID: marketUID, + Value: oddsValue1.String(), + MaxLossMultiplier: maxLossMultiplier, + }, + "all_odds": []types.BetOddsCompact{ + {UID: oddsUID1, MaxLossMultiplier: maxLossMultiplier}, + {UID: oddsUID2, MaxLossMultiplier: maxLossMultiplier}, + {UID: oddsUID3, MaxLossMultiplier: maxLossMultiplier}, + }, + "meta": types.MetaData{ + SelectedOddsType: types.OddsType_ODDS_TYPE_DECIMAL, + SelectedOddsValue: oddsValue1.String(), + IsMainMarket: false, + }, + "context": "sample context", + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc1"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + { + "valid transaction for acc2", + uuid.NewString(), + marketUID, + wagerAmount, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: acc2.String(), + }, + "selected_odds": types.BetOdds{ + UID: oddsUID2, + MarketUID: marketUID, + Value: oddsValue2.String(), + MaxLossMultiplier: maxLossMultiplier, + }, + "all_odds": []types.BetOddsCompact{ + {UID: oddsUID1, MaxLossMultiplier: maxLossMultiplier}, + {UID: oddsUID2, MaxLossMultiplier: maxLossMultiplier}, + {UID: oddsUID3, MaxLossMultiplier: maxLossMultiplier}, + }, + "meta": types.MetaData{ + SelectedOddsType: types.OddsType_ODDS_TYPE_DECIMAL, + SelectedOddsValue: oddsValue2.String(), + IsMainMarket: false, + }, + "context": "sample context", + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc2"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.uid, + tc.amount.String(), + ticket, + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdWager(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + } + }) + } + + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "resolution_ts": uint64(time.Now().Unix()), + "winner_odds_uids": []string{oddsUID1}, + "status": markettypes.MarketStatus_MARKET_STATUS_RESULT_DECLARED, + }) + require.Nil(s.T(), err) + + bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdResolve(), []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }) + s.Require().NoError(err) + + var respType sdk.TxResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + + s.Require().NoError(s.network.WaitForNextBlock()) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(uint32(0), txResp.Code) + s.T().Logf("==== success deposit create test case finished") + } + + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdListBet(), []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}) + s.Require().NoError(err) + respType := types.QueryBetsResponse{} + err = clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType) + s.Require().NoError(err) + + s.Require().Equal(3, len(respType.Bet)) + + for _, b := range respType.Bet { + s.Require().Equal(types.Bet_STATUS_SETTLED, b.Status) + } + + payout1 := oddsValue1.Mul(wagerAmount.Sub(betFees).ToLegacyDec()).TruncateInt().Sub(wagerAmount) + expectedAcc1Balance := acc1Balance.Add(payout1).Sub(sdkmath.NewInt(fees)) + acc1Balance = e2esdk.GetSGEBalance(clientCtx, acc1.String()) + s.Require().Equal(expectedAcc1Balance, acc1Balance) + + expectedAcc2Balance := acc2Balance.Sub(wagerAmount).Sub(sdkmath.NewInt(fees)) + acc2Balance = e2esdk.GetSGEBalance(clientCtx, acc2.String()) + s.Require().Equal(expectedAcc2Balance, acc2Balance) +} diff --git a/tests/e2e/house/cli_test.go b/tests/e2e/house/cli_test.go new file mode 100644 index 00000000..6e37be14 --- /dev/null +++ b/tests/e2e/house/cli_test.go @@ -0,0 +1,16 @@ +package client_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + client "github.com/sge-network/sge/tests/e2e/house" + "github.com/sge-network/sge/testutil/network" +) + +func TestE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, client.NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/house/grpc.go b/tests/e2e/house/grpc.go new file mode 100644 index 00000000..192c8705 --- /dev/null +++ b/tests/e2e/house/grpc.go @@ -0,0 +1,105 @@ +package client + +import ( + "fmt" + + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/cosmos-sdk/testutil" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/sge-network/sge/x/house/types" +) + +func (s *E2ETestSuite) TestDepositsGRPCHandler() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + testCases := []struct { + name string + url string + headers map[string]string + respType proto.Message + expected proto.Message + }{ + { + "test GRPC all deposits", + fmt.Sprintf("%s/sge/house/deposits", baseURL), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryDepositsResponse{}, + &types.QueryDepositsResponse{ + Deposits: genesis.DepositList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + { + "test GRPC deposits of certain creator", + fmt.Sprintf("%s/sge/house/deposits/%s", baseURL, dummyDepositor), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryDepositsByAccountResponse{}, + &types.QueryDepositsByAccountResponse{ + Deposits: genesis.DepositList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) + s.Require().NoError(err) + + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + s.Require().Equal(tc.expected.String(), tc.respType.String()) + }) + } +} + +func (s *E2ETestSuite) TestGRPCHandler() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + testCases := []struct { + name string + url string + headers map[string]string + respType proto.Message + expected proto.Message + }{ + { + "test GRPC all withdraws", + fmt.Sprintf("%s/sge/house/withdrawals/%s", baseURL, dummyDepositor), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryWithdrawalsByAccountResponse{}, + &types.QueryWithdrawalsByAccountResponse{ + Withdrawals: genesis.WithdrawalList, + Pagination: &query.PageResponse{ + Total: 1, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) + s.Require().NoError(err) + + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + s.Require().Equal(tc.expected.String(), tc.respType.String()) + }) + } +} diff --git a/tests/e2e/house/suite.go b/tests/e2e/house/suite.go new file mode 100644 index 00000000..7276221c --- /dev/null +++ b/tests/e2e/house/suite.go @@ -0,0 +1,1046 @@ +package client + +import ( + "fmt" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "github.com/spf13/cast" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrtypes "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/gogoproto/proto" + + e2esdk "github.com/sge-network/sge/tests/e2e/sdk" + "github.com/sge-network/sge/testutil/network" + "github.com/sge-network/sge/testutil/sample" + "github.com/sge-network/sge/testutil/simapp" + sgetypes "github.com/sge-network/sge/types" + "github.com/sge-network/sge/x/house/client/cli" + "github.com/sge-network/sge/x/house/types" + marketcli "github.com/sge-network/sge/x/market/client/cli" + markettypes "github.com/sge-network/sge/x/market/types" +) + +var ( + genesis types.GenesisState + dummyDepositor = sample.AccAddress() + + fees = int64(10) + marketUID = uuid.NewString() + marketStartDate = uint64(time.Now().Unix()) + marketEndDate = uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()) + depositAmount = sdkmath.NewInt(100) + + valBalance = sdkmath.NewInt(400000000) + + acc1 = sdk.AccAddress{} + acc1Balance = sdkmath.ZeroInt() + + acc2 = sdk.AccAddress{} + acc2Balance = sdkmath.ZeroInt() +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + + genesisState := s.cfg.GenesisState + + var marketGenesis markettypes.GenesisState + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[markettypes.ModuleName], &marketGenesis)) + + dummyMarketUID := uuid.NewString() + marketGenesis.MarketList = []markettypes.Market{ + { + Creator: sample.AccAddress(), + UID: dummyMarketUID, + StartTS: uint64(time.Now().Unix()), + EndTS: uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()), + Odds: []*markettypes.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16900", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16901", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16901", + Meta: "Away", + }, + }, + WinnerOddsUIDs: []string{}, + Status: markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + Meta: "dummy market", + BookUID: dummyMarketUID, + }, + } + marketGenesisBz, err := s.cfg.Codec.MarshalJSON(&marketGenesis) + s.Require().NoError(err) + genesisState[markettypes.ModuleName] = marketGenesisBz + + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &genesis)) + + genesis.DepositList = []types.Deposit{ + { + Creator: sample.AccAddress(), + DepositorAddress: dummyDepositor, + MarketUID: marketUID, + ParticipationIndex: 0, + Amount: sdkmath.NewInt(10000), + WithdrawalCount: 0, + TotalWithdrawalAmount: sdkmath.ZeroInt(), + }, + } + + genesis.WithdrawalList = []types.Withdrawal{ + { + ID: 1, + Creator: sample.AccAddress(), + Address: dummyDepositor, + MarketUID: marketUID, + ParticipationIndex: 0, + Amount: sdkmath.NewInt(10000), + Mode: types.WithdrawalMode_WITHDRAWAL_MODE_FULL, + }, + } + + genesis.Params = types.Params{ + MinDeposit: sdkmath.NewInt(100), + HouseParticipationFee: sdk.NewDecWithPrec(0, 2), + MaxWithdrawalCount: 2, + } + + genesisBz, err := s.cfg.Codec.MarshalJSON(&genesis) + s.Require().NoError(err) + genesisState[types.ModuleName] = genesisBz + s.cfg.GenesisState = genesisState + + s.network = network.New(s.T(), s.cfg) + + s.Require().NoError(s.network.WaitForNextBlock()) +} + +func (s *E2ETestSuite) TestDepositTxCmd() { + s.T().Log("==== new house deposit command test started") + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []markettypes.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16990", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16991", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16992", + Meta: "Away", + }, + }, + "status": markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }) + require.Nil(s.T(), err) + + args := []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdAdd(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + } + s.Require().NoError(s.network.WaitForNextBlock()) + + expectedValBalance := valBalance.Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + + acc1initialBalance := 1000 + acc1 = e2esdk.CreateAccount(val, "acc1") + e2esdk.SendToken(val, acc1, acc1initialBalance) + s.Require().NoError(s.network.WaitForNextBlock()) + + expectedValBalance = valBalance.Sub(sdkmath.NewInt(int64(acc1initialBalance))).Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + + testCases := []struct { + name string + marketUID string + amount sdkmath.Int + ticketClaims jwt.MapClaims + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "valid transaction for val", + marketUID, + depositAmount, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + { + "invalid transaction for acc1", + marketUID, + sdkmath.NewInt(100000000), + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: acc1.String(), + }, + "depositor_address": acc1.String(), + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc1"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + true, + sdkerrtypes.ErrInsufficientFunds.ABCICode(), + "", + &sdk.TxResponse{}, + }, + { + "valid transaction for acc1", + marketUID, + depositAmount, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: acc1.String(), + }, + "depositor_address": acc1.String(), + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc1"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.marketUID, + tc.amount.String(), + ticket, + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdDeposit(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + s.T().Logf("==== success deposit create test case finished: %s", tc.name) + } + }) + } + + depositFeeAmount := sdk.NewDecFromInt(depositAmount).Mul(genesis.Params.HouseParticipationFee).TruncateInt() + + expectedValBalance = valBalance.Sub(depositAmount).Sub(depositFeeAmount).Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + s.T().Logf("==== bank val balance checked after deposit to the market: %s", valBalance) + + acc1Balance = e2esdk.GetSGEBalance(clientCtx, acc1.String()) + expectedBalance := sdkmath.NewInt(int64(acc1initialBalance)).Sub(depositAmount).Sub(depositFeeAmount).Sub(sdkmath.NewInt(fees)) + s.Require().Equal(expectedBalance, acc1Balance) + s.T().Logf("==== bank acc1 balance checked after deposit to the market: %s", acc1Balance) + + depositsBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDeposits(), []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposits := types.QueryDepositsResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositsBz.Bytes(), &deposits) + require.NoError(s.T(), err) + + require.Equal(s.T(), 3, len(deposits.Deposits)) + + depositBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDepositsByAccount(), []string{ + acc1.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposit := types.QueryDepositsByAccountResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositBz.Bytes(), &deposit) + require.NoError(s.T(), err) + + require.Equal(s.T(), []types.Deposit{ + { + Creator: acc1.String(), + DepositorAddress: acc1.String(), + MarketUID: marketUID, + ParticipationIndex: 2, + Amount: depositAmount, + WithdrawalCount: 0, + TotalWithdrawalAmount: sdkmath.ZeroInt(), + }, + }, deposit.Deposits) + require.Equal(s.T(), acc1.String(), deposit.Deposits[0].DepositorAddress) + s.T().Log("==== state modifications checked after deposit to the market") + + s.T().Log("==== new deposit test passed successfully") +} + +func (s *E2ETestSuite) TestDepositWithAuthzTxCmd() { + s.T().Log("==== new house deposit with authorization command test started") + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []markettypes.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16990", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16991", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16992", + Meta: "Away", + }, + }, + "status": markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }) + require.Nil(s.T(), err) + + args := []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdAdd(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + } + s.Require().NoError(s.network.WaitForNextBlock()) + + expectedValBalance := valBalance.Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + + e2esdk.SetGenericAuthorization(val, acc1, sdk.MsgTypeURL(&types.MsgDeposit{})) + s.Require().NoError(s.network.WaitForNextBlock()) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + + testCases := []struct { + name string + marketUID string + amount sdkmath.Int + ticketClaims jwt.MapClaims + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "valid transaction for acc1", + marketUID, + depositAmount, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc1"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.marketUID, + tc.amount.String(), + ticket, + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdDeposit(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + s.T().Logf("==== success deposit create test case finished: %s", tc.name) + } + }) + } + + depositFeeAmount := sdk.NewDecFromInt(depositAmount).Mul(genesis.Params.HouseParticipationFee).TruncateInt() + + expectedValBalance = valBalance.Sub(depositAmount).Sub(depositFeeAmount) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + s.T().Logf("==== bank val balance checked after deposit to the market: %s", valBalance) + + expectedAcc1Balance := acc1Balance.Sub(sdkmath.NewInt(fees)) + acc1Balance = e2esdk.GetSGEBalance(clientCtx, acc1.String()) + s.Require().Equal(expectedAcc1Balance, acc1Balance) + s.T().Logf("==== bank acc1 balance checked after deposit to the market: %s", acc1Balance) + + depositsBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDeposits(), []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposits := types.QueryDepositsResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositsBz.Bytes(), &deposits) + require.NoError(s.T(), err) + + require.Equal(s.T(), 4, len(deposits.Deposits)) + + depositBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDepositsByAccount(), []string{ + val.Address.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposit := types.QueryDepositsByAccountResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositBz.Bytes(), &deposit) + require.NoError(s.T(), err) + + require.Equal(s.T(), []types.Deposit{ + { + Creator: val.Address.String(), + DepositorAddress: val.Address.String(), + MarketUID: marketUID, + ParticipationIndex: 1, + Amount: depositAmount, + WithdrawalCount: 0, + TotalWithdrawalAmount: sdkmath.ZeroInt(), + }, + { + Creator: acc1.String(), + DepositorAddress: val.Address.String(), + MarketUID: marketUID, + ParticipationIndex: 3, + Amount: depositAmount, + WithdrawalCount: 0, + TotalWithdrawalAmount: sdkmath.ZeroInt(), + }, + }, deposit.Deposits) + require.Equal(s.T(), val.Address.String(), deposit.Deposits[0].DepositorAddress) + s.T().Log("==== state modifications checked after deposit to the market") + + s.T().Log("==== new deposit with authorization test passed successfully") +} + +func (s *E2ETestSuite) TestWithdrawTxCmd() { + s.T().Log("==== new house deposit command test started") + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []markettypes.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16990", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16991", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16992", + Meta: "Away", + }, + }, + "status": markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }) + require.Nil(s.T(), err) + + args := []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdAdd(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + } + s.Require().NoError(s.network.WaitForNextBlock()) + + expectedValBalance := valBalance.Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }) + require.Nil(s.T(), err) + + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdDeposit(), []string{ + marketUID, + depositAmount.String(), + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }) + s.Require().NoError(err) + + var respType sdk.TxResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(uint32(0), txResp.Code) + s.T().Logf("==== success deposit create test case finished") + } + + depositFeeAmount := sdk.NewDecFromInt(depositAmount).Mul(genesis.Params.HouseParticipationFee).TruncateInt() + + expectedValBalance = valBalance.Sub(depositAmount).Sub(depositFeeAmount).Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + s.T().Logf("==== bank val balance checked after deposit to the market: %s", valBalance) + + depositsBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDeposits(), []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposits := types.QueryDepositsResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositsBz.Bytes(), &deposits) + require.NoError(s.T(), err) + + require.Equal(s.T(), 5, len(deposits.Deposits)) + + depositBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDepositsByAccount(), []string{ + acc1.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposit := types.QueryDepositsByAccountResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositBz.Bytes(), &deposit) + require.NoError(s.T(), err) + + require.Equal(s.T(), []types.Deposit{ + { + Creator: acc1.String(), + DepositorAddress: acc1.String(), + MarketUID: marketUID, + ParticipationIndex: 2, + Amount: depositAmount, + WithdrawalCount: 0, + TotalWithdrawalAmount: sdkmath.ZeroInt(), + }, + }, deposit.Deposits) + require.Equal(s.T(), acc1.String(), deposit.Deposits[0].DepositorAddress) + s.T().Log("==== state modifications checked after deposit to the market") + + firstWithdrawAmount := depositAmount.Sub(sdkmath.NewInt(10)) + testCases := []struct { + name string + marketUID string + participationIndex uint64 + ticketClaims jwt.MapClaims + mode types.WithdrawalMode + amount sdkmath.Int + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "invalid transaction with large amount for val", + marketUID, + 4, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + }, + types.WithdrawalMode_WITHDRAWAL_MODE_PARTIAL, + sdkmath.NewInt(10000000000), + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + true, + 0, + "withdrawal is more than unused amount", + &sdk.TxResponse{}, + }, + { + "valid transaction for val", + marketUID, + 4, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + }, + types.WithdrawalMode_WITHDRAWAL_MODE_PARTIAL, + firstWithdrawAmount, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + { + "second valid transaction for val with the rest of the amount", + marketUID, + 4, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + }, + types.WithdrawalMode_WITHDRAWAL_MODE_FULL, + sdkmath.Int{}, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.marketUID, + cast.ToString(tc.participationIndex), + ticket, + cast.ToString(int32(tc.mode)), + tc.amount.String(), + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdWithdraw(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + s.T().Logf("==== success deposit create test case finished: %s", tc.name) + } + }) + } + + s.T().Log("==== new deposit test passed successfully") +} + +func (s *E2ETestSuite) TestWithdrawWithAuthzTxCmd() { + s.T().Log("==== new house deposit command test started") + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + // { + // ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + // "exp": time.Now().Add(time.Minute * 5).Unix(), + // "iat": time.Now().Unix(), + // "uid": marketUID, + // "start_ts": marketStartDate, + // "end_ts": marketEndDate, + // "odds": []markettypes.Odds{ + // { + // UID: "9991c60f-2025-48ce-ae79-1dc110f16990", + // Meta: "Home", + // }, + // { + // UID: "9991c60f-2025-48ce-ae79-1dc110f16991", + // Meta: "Draw", + // }, + // { + // UID: "9991c60f-2025-48ce-ae79-1dc110f16992", + // Meta: "Away", + // }, + // }, + // "status": markettypes.MarketStatus_MARKET_STATUS_ACTIVE, + // "meta": "sample 3way market", + // }) + // require.Nil(s.T(), err) + + // args := []string{ + // ticket, + // fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + // fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + // fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + // fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + // } + // bz, err := clitestutil.ExecTestCLICmd(clientCtx, marketcli.CmdAdd(), args) + // s.Require().NoError(err) + // respType := sdk.TxResponse{} + // s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + // s.Require().Equal(uint32(0), respType.Code) + // } + // s.Require().NoError(s.network.WaitForNextBlock()) + + acc2initialBalance := 1000 + acc2 = e2esdk.CreateAccount(val, "acc2") + e2esdk.SendToken(val, acc2, acc2initialBalance) + s.Require().NoError(s.network.WaitForNextBlock()) + acc2Balance = e2esdk.GetSGEBalance(clientCtx, acc2.String()) + + e2esdk.SetGenericAuthorization(val, acc2, sdk.MsgTypeURL(&types.MsgWithdraw{})) + s.Require().NoError(s.network.WaitForNextBlock()) + + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }) + require.Nil(s.T(), err) + + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdDeposit(), []string{ + marketUID, + depositAmount.String(), + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }) + s.Require().NoError(err) + + var respType sdk.TxResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(uint32(0), txResp.Code) + s.T().Logf("==== success deposit create test case finished") + } + + depositFeeAmount := sdk.NewDecFromInt(depositAmount).Mul(genesis.Params.HouseParticipationFee).TruncateInt() + + expectedValBalance := valBalance.Sub(depositAmount).Sub(depositFeeAmount).Sub(sdkmath.NewInt(fees)) + valBalance = e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedValBalance, valBalance) + s.T().Logf("==== bank val balance checked after deposit to the market: %s", valBalance) + + depositsBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDeposits(), []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposits := types.QueryDepositsResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositsBz.Bytes(), &deposits) + require.NoError(s.T(), err) + + require.Equal(s.T(), 6, len(deposits.Deposits)) + + depositBz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.GetCmdQueryDepositsByAccount(), []string{ + val.Address.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }) + require.NoError(s.T(), err) + deposit := types.QueryDepositsByAccountResponse{} + err = clientCtx.Codec.UnmarshalJSON(depositBz.Bytes(), &deposit) + require.NoError(s.T(), err) + + require.Equal(s.T(), val.Address.String(), deposit.Deposits[0].DepositorAddress) + s.T().Log("==== state modifications checked after deposit to the market") + + firstWithdrawAmount := depositAmount.Sub(sdkmath.NewInt(10)) + testCases := []struct { + name string + marketUID string + participationIndex uint64 + ticketClaims jwt.MapClaims + mode types.WithdrawalMode + amount sdkmath.Int + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "valid transaction for acc2", + marketUID, + 5, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "kyc_data": sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + "depositor_address": val.Address.String(), + }, + types.WithdrawalMode_WITHDRAWAL_MODE_PARTIAL, + firstWithdrawAmount, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, "acc2"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.marketUID, + cast.ToString(tc.participationIndex), + ticket, + cast.ToString(int32(tc.mode)), + tc.amount.String(), + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdWithdraw(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + s.T().Logf("==== success deposit create test case finished: %s", tc.name) + } + }) + } + + expectedAcc2Balance := acc2Balance.Sub(sdkmath.NewInt(fees)) + acc2Balance = e2esdk.GetSGEBalance(clientCtx, acc2.String()) + s.Require().Equal(expectedAcc2Balance, acc2Balance) + + s.T().Log("==== new deposit test passed successfully") +} diff --git a/tests/e2e/market/cli_test.go b/tests/e2e/market/cli_test.go new file mode 100644 index 00000000..18c7022a --- /dev/null +++ b/tests/e2e/market/cli_test.go @@ -0,0 +1,16 @@ +package client_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + client "github.com/sge-network/sge/tests/e2e/market" + "github.com/sge-network/sge/testutil/network" +) + +func TestE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, client.NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/market/grpc.go b/tests/e2e/market/grpc.go new file mode 100644 index 00000000..2eb83ee5 --- /dev/null +++ b/tests/e2e/market/grpc.go @@ -0,0 +1,48 @@ +package client + +import ( + "fmt" + + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/cosmos-sdk/testutil" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + + "github.com/sge-network/sge/x/market/types" +) + +func (s *E2ETestSuite) TestMarketsGRPCHandler() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + testCases := []struct { + name string + url string + headers map[string]string + respType proto.Message + expected proto.Message + }{ + { + "test GRPC Market by UID", + fmt.Sprintf("%s/sge/market/%s", baseURL, dummyMarketUID), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + &types.QueryMarketResponse{}, + &types.QueryMarketResponse{ + Market: dummyMarket, + }, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) + s.Require().NoError(err) + + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + s.Require().Equal(tc.expected.String(), tc.respType.String()) + }) + } +} diff --git a/tests/e2e/market/suite.go b/tests/e2e/market/suite.go new file mode 100644 index 00000000..711f92d0 --- /dev/null +++ b/tests/e2e/market/suite.go @@ -0,0 +1,214 @@ +package client + +import ( + "fmt" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + e2esdk "github.com/sge-network/sge/tests/e2e/sdk" + "github.com/sge-network/sge/testutil/network" + "github.com/sge-network/sge/testutil/sample" + "github.com/sge-network/sge/testutil/simapp" + "github.com/sge-network/sge/x/market/client/cli" + "github.com/sge-network/sge/x/market/types" +) + +var ( + genesis types.GenesisState + + dummyMarket = types.Market{} + dummyMarketUID = uuid.NewString() + + oddsUID1 = "9991c60f-2025-48ce-ae79-1dc110f16900" + oddsUID2 = "9991c60f-2025-48ce-ae79-1dc110f16901" + oddsUID3 = "9991c60f-2025-48ce-ae79-1dc110f16902" + + fees = int64(10) + marketUID = uuid.NewString() + marketStartDate = uint64(time.Now().Unix()) + marketEndDate = uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()) +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + + genesisState := s.cfg.GenesisState + + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &genesis)) + + dummyMarket = types.Market{ + Creator: sample.AccAddress(), + UID: dummyMarketUID, + StartTS: uint64(time.Now().Unix()), + EndTS: uint64(time.Now().Add(time.Minute * time.Duration(120)).Unix()), + Odds: []*types.Odds{ + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16904", + Meta: "Home", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16905", + Meta: "Draw", + }, + { + UID: "9991c60f-2025-48ce-ae79-1dc110f16906", + Meta: "Away", + }, + }, + WinnerOddsUIDs: []string{}, + Status: types.MarketStatus_MARKET_STATUS_ACTIVE, + Meta: "dummy market", + BookUID: dummyMarketUID, + } + genesis.MarketList = []types.Market{dummyMarket} + + genesis.Stats = types.MarketStats{ + // ResolvedUnsettled: []string{dummyMarketUID}, + } + + // genesis.Params = types.Params{} + + genesisBz, err := s.cfg.Codec.MarshalJSON(&genesis) + s.Require().NoError(err) + genesisState[types.ModuleName] = genesisBz + s.cfg.GenesisState = genesisState + + s.network = network.New(s.T(), s.cfg) + + s.Require().NoError(s.network.WaitForNextBlock()) +} + +func (s *E2ETestSuite) TestMarketAddTxCmd() { + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + + valBalance := e2esdk.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(sdkmath.NewInt(400000000), valBalance) + + testCases := []struct { + name string + ticketClaims jwt.MapClaims + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "invalid transaction for val", + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []types.Odds{}, + "status": types.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + true, + 0, + "", + &sdk.TxResponse{}, + }, + { + "valid transaction for val", + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": marketUID, + "start_ts": marketStartDate, + "end_ts": marketEndDate, + "odds": []types.Odds{ + { + UID: oddsUID1, + Meta: "Home", + }, + { + UID: oddsUID2, + Meta: "Draw", + }, + { + UID: oddsUID3, + Meta: "Away", + }, + }, + "status": types.MarketStatus_MARKET_STATUS_ACTIVE, + "meta": "sample 3way market", + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagGas, flags.GasFlagAuto), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.15"), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(fees))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ticket}, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdAdd(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + respType, ok := tc.respType.(*sdk.TxResponse) + s.Require().True(ok) + s.Require().Equal(tc.expectedCode, respType.Code) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + } + }) + } +} diff --git a/tests/e2e/reward/cli_test.go b/tests/e2e/reward/cli_test.go new file mode 100644 index 00000000..06d65961 --- /dev/null +++ b/tests/e2e/reward/cli_test.go @@ -0,0 +1,16 @@ +package client_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + client "github.com/sge-network/sge/tests/e2e/reward" + "github.com/sge-network/sge/testutil/network" +) + +func TestE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, client.NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/reward/grpc.go b/tests/e2e/reward/grpc.go new file mode 100644 index 00000000..da13c8ef --- /dev/null +++ b/tests/e2e/reward/grpc.go @@ -0,0 +1 @@ +package client diff --git a/tests/e2e/reward/suite.go b/tests/e2e/reward/suite.go new file mode 100644 index 00000000..31057b0c --- /dev/null +++ b/tests/e2e/reward/suite.go @@ -0,0 +1,281 @@ +package client + +import ( + "fmt" + "time" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + sdkcli "github.com/sge-network/sge/tests/e2e/sdk" + "github.com/sge-network/sge/testutil/network" + "github.com/sge-network/sge/testutil/simapp" + sgetypes "github.com/sge-network/sge/types" + "github.com/sge-network/sge/x/reward/client/cli" + "github.com/sge-network/sge/x/reward/types" + subaccountcli "github.com/sge-network/sge/x/subaccount/client/cli" + subaccounttypes "github.com/sge-network/sge/x/subaccount/types" +) + +var ( + genesis types.GenesisState + fees = int64(10) + promoterUID = uuid.NewString() + campaignStartDate = uint64(time.Now().Unix()) + campaignEndDate = time.Now().Add(time.Minute * time.Duration(120)).Unix() + campaignFunds = sdkmath.NewInt(100000000) +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + + genesisState := s.cfg.GenesisState + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &genesis)) + + genesisBz, err := s.cfg.Codec.MarshalJSON(&genesis) + s.Require().NoError(err) + genesisState[types.ModuleName] = genesisBz + s.cfg.GenesisState = genesisState + + s.network = network.New(s.T(), s.cfg) + s.Require().NoError(s.network.WaitForNextBlock()) +} + +func (s *E2ETestSuite) TestNewCampaignTxCmd() { + s.T().Log("==== new campaign create command test started") + val := s.network.Validators[0] + + clientCtx := val.ClientCtx + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "uid": promoterUID, + "conf": types.PromoterConf{ + CategoryCap: []types.CategoryCap{{ + Category: types.RewardCategory_REWARD_CATEGORY_SIGNUP, + CapPerAcc: 1, + }}, + }, + }) + require.Nil(s.T(), err) + + args := []string{ + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(10))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdCreatePromoter(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + s.Require().Equal(uint32(0), respType.Code) + } + + valBalance := sdkcli.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(sdkmath.NewInt(400000000), valBalance) + + campaignUID := uuid.NewString() + testCases := []struct { + name string + uid string + totalFunds sdkmath.Int + ticketClaims jwt.MapClaims + args []string + expectErr bool + expectedCode uint32 + expectedErrMsg string + respType proto.Message + }{ + { + "not enough balance to charge pool", + campaignUID, + sdkmath.NewInt(4000000000), + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "promoter": val.Address, + "start_ts": campaignStartDate, + "end_ts": campaignEndDate, + "category": types.RewardCategory_REWARD_CATEGORY_SIGNUP, + "reward_type": types.RewardType_REWARD_TYPE_SIGNUP, + "reward_amount_type": types.RewardAmountType_REWARD_AMOUNT_TYPE_FIXED, + "reward_amount": types.RewardAmount{ + SubaccountAmount: sdkmath.NewInt(100), + UnlockPeriod: uint64(1000), + }, + "is_active": true, + "meta": "sample signup campaign", + "cap_count": 1, + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(10))).String()), + }, + false, + types.ErrInFundingCampaignPool.ABCICode(), + "", + &sdk.TxResponse{}, + }, + { + "valid transaction", + campaignUID, + campaignFunds, + jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "promoter": val.Address, + "start_ts": campaignStartDate, + "end_ts": campaignEndDate, + "category": types.RewardCategory_REWARD_CATEGORY_SIGNUP, + "reward_type": types.RewardType_REWARD_TYPE_SIGNUP, + "reward_amount_type": types.RewardAmountType_REWARD_AMOUNT_TYPE_FIXED, + "reward_amount": types.RewardAmount{ + SubaccountAmount: sdkmath.NewInt(100), + UnlockPeriod: uint64(1000), + }, + "is_active": true, + "meta": "sample signup campaign", + "cap_count": 1, + }, + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(10))).String()), + }, + false, + 0, + "", + &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Require().NoError(s.network.WaitForNextBlock()) + s.Run(tc.name, func() { + clientCtx := val.ClientCtx + + ticket, err := simapp.CreateJwtTicket(tc.ticketClaims) + require.Nil(s.T(), err) + + tc.args = append([]string{ + tc.uid, + tc.totalFunds.String(), + ticket, + }, tc.args...) + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdCreateCampaign(), tc.args) + + if tc.expectErr { + s.Require().Error(err) + s.T().Logf("error captured: %s", tc.name) + } else { + s.Require().NoError(err) + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, tc.respType.(*sdk.TxResponse).TxHash) + s.Require().NoError(err) + s.Require().Equal(tc.expectedCode, txResp.Code) + if tc.expectedErrMsg != "" { + s.Require().Contains(txResp.RawLog, tc.expectedErrMsg) + } + s.T().Logf("==== success campaign create test case finished: %s", tc.name) + } + }) + } + + s.Require().NoError(s.network.WaitForNextBlock()) + expectedBalance := valBalance.Sub(campaignFunds).Sub(sdk.NewInt(fees * 3)) + valBalance = sdkcli.GetSGEBalance(clientCtx, val.Address.String()) + s.Require().Equal(expectedBalance, valBalance) + s.T().Logf("==== bank balance checked after creating the campaign: %s", valBalance) + + { + ticket, err := simapp.CreateJwtTicket(jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 5).Unix(), + "iat": time.Now().Unix(), + "common": types.RewardPayloadCommon{ + Receiver: val.Address.String(), + SourceUID: "", + Meta: "signup reward campaign", + KycData: &sgetypes.KycDataPayload{ + Ignore: false, + Approved: true, + ID: val.Address.String(), + }, + }, + }) + require.Nil(s.T(), err) + + rewardUID := uuid.NewString() + args := []string{ + rewardUID, + campaignUID, + ticket, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdkmath.NewInt(10))).String()), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, cli.CmdGrantReward(), args) + s.Require().NoError(err) + respType := sdk.TxResponse{} + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType), bz.String()) + + txResp, err := clitestutil.GetTxResponse(s.network, clientCtx, respType.TxHash) + s.Require().NoError(err) + s.Require().Equal(uint32(0), txResp.Code) + s.T().Logf("==== success reward grant test case finished: %s", rewardUID) + } + + valBalance = sdkcli.GetSGEBalance(clientCtx, val.Address.String()) + expectedBalance = expectedBalance.Sub(sdkmath.NewInt(10)) + s.Require().Equal(expectedBalance, valBalance) + s.T().Logf("==== bank balance checked after creating the campaign: %s", valBalance) + + args := []string{ + val.Address.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, subaccountcli.QuerySubaccount(), args) + if err != nil { + panic(err) + } + respType := subaccounttypes.QuerySubaccountResponse{} + err = clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType) + if err != nil { + panic(err) + } + + subaccountBalance := sdkcli.GetSGEBalance(clientCtx, respType.Address) + s.Require().Equal(sdkmath.NewInt(100), subaccountBalance) + s.T().Logf("==== bank balance checked after creating the campaign: %s", subaccountBalance) + + s.T().Log("==== new campaign create command test passed successfully") +} diff --git a/tests/e2e/sdk/account.go b/tests/e2e/sdk/account.go new file mode 100644 index 00000000..00083d0e --- /dev/null +++ b/tests/e2e/sdk/account.go @@ -0,0 +1,23 @@ +package sdk + +import ( + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func CreateAccount(val *sdknetwork.Validator, uid string) sdk.AccAddress { + // Create new account in the keyring. + k, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + if err != nil { + panic(err) + } + + addr, err := k.GetAddress() + if err != nil { + panic(err) + } + + return addr +} diff --git a/tests/e2e/sdk/auth.go b/tests/e2e/sdk/auth.go new file mode 100644 index 00000000..a0873195 --- /dev/null +++ b/tests/e2e/sdk/auth.go @@ -0,0 +1,40 @@ +package sdk + +import ( + "fmt" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz/client/cli" + authzclitestutil "github.com/cosmos/cosmos-sdk/x/authz/client/testutil" + "github.com/sge-network/sge/app/params" +) + +func SetGenericAuthorization(val *sdknetwork.Validator, grantee sdk.AccAddress, typeMsg string) { + twoHours := time.Now().Add(time.Minute * 120).Unix() + + // Send some funds to the new account. + out, err := authzclitestutil.CreateGrant( + val.ClientCtx, + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsg), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(params.DefaultBondDenom, fees)).String()), + }, + ) + if err != nil { + panic(err) + } + + if !strings.Contains(out.String(), `"code":0`) { + panic(fmt.Sprintf("failed to send tokens: %s", out.String())) + } +} diff --git a/tests/e2e/sdk/balance.go b/tests/e2e/sdk/balance.go new file mode 100644 index 00000000..170f57a5 --- /dev/null +++ b/tests/e2e/sdk/balance.go @@ -0,0 +1,54 @@ +package sdk + +import ( + "fmt" + "strings" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli" + "github.com/sge-network/sge/app/params" +) + +func GetSGEBalance(clientCtx client.Context, address string) sdkmath.Int { + args := []string{ + address, + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=usge", bankcli.FlagDenom), + } + bz, err := clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args) + if err != nil { + panic(err) + } + respType := sdk.Coin{} + err = clientCtx.Codec.UnmarshalJSON(bz.Bytes(), &respType) + if err != nil { + panic(err) + } + + return respType.Amount +} + +func SendToken(val *sdknetwork.Validator, acc sdk.AccAddress, amount int) { + // Send some funds to the new account. + out, err := clitestutil.MsgSendExec( + val.ClientCtx, + val.Address, + acc, + sdk.NewCoins(sdk.NewCoin(params.DefaultBondDenom, sdkmath.NewInt(int64(amount)))), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(params.DefaultBondDenom, fees)).String()), + ) + if err != nil { + panic(err) + } + + if !strings.Contains(out.String(), `"code":0`) { + panic(fmt.Sprintf("failed to send tokens: %s", out.String())) + } +} diff --git a/tests/e2e/sdk/consts.go b/tests/e2e/sdk/consts.go new file mode 100644 index 00000000..494cb602 --- /dev/null +++ b/tests/e2e/sdk/consts.go @@ -0,0 +1,5 @@ +package sdk + +import sdkmath "cosmossdk.io/math" + +var fees = sdkmath.NewInt(10) diff --git a/testutil/network/network.go b/testutil/network/network.go index 25d8893f..95a61f03 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -16,10 +16,14 @@ import ( simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/sge-network/sge/app" + "github.com/sge-network/sge/app/params" + "github.com/sge-network/sge/testutil/simapp" + ovmtypes "github.com/sge-network/sge/x/ovm/types" ) type ( @@ -41,6 +45,39 @@ func New(t *testing.T, configs ...network.Config) *network.Network { } else { cfg = configs[0] } + // baseDir := t.TempDir() + + // nodeDirName := fmt.Sprintf("node%d", 0) + // node0Dir := filepath.Join(baseDir, nodeDirName, "simcli") + + // buf := bufio.NewReader(os.Stdin) + // kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, node0Dir, buf, cfg.Codec, cfg.KeyringOptions...) + // if err != nil { + // panic(err) + // } + + // keyringAlgos, _ := kb.SupportedAlgorithms() + // algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos) + // if err != nil { + // panic(err) + // } + + // addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo) + // if err != nil { + // panic(err) + // } + + // info := map[string]string{"secret": secret} + // infoBz, err := json.Marshal(info) + // if err != nil { + // panic(err) + // } + + // // save private key seed words + // err = simapp.WriteKeyringFile(fmt.Sprintf("%v.json", "key_seed"), node0Dir, infoBz) + // if err != nil { + // panic(err) + // } net, err := network.New(t, t.TempDir(), cfg) if err != nil { @@ -58,6 +95,93 @@ func DefaultConfig() network.Config { encoding = app.MakeEncodingConfig() chainID = "chain-" + tmrand.NewRand().Str(6) ) + + // simapp.GenerateSimappUsers() + + // Initialize test app by genesis account + // genAccs := simapp.GenerateSimappGenesisAccounts() + + // Create testapp instance + // balances := simapp.GenerateSimappUserBalances() + + defGen := app.ModuleBasics.DefaultGenesis(encoding.Marshaler) + { + // modify the staking denom in the genesis + stakingGenState := defGen[stakingtypes.ModuleName] + var newStakingGenState stakingtypes.GenesisState + + if err := encoding.Marshaler.UnmarshalJSON(stakingGenState, &newStakingGenState); err != nil { + panic(err) + } + + // change to default bond denom + newStakingGenState.Params.BondDenom = params.DefaultBondDenom + + var err error + defGen[stakingtypes.ModuleName], err = encoding.Marshaler.MarshalJSON(&newStakingGenState) + if err != nil { + panic(err) + } + } + // { + // authGenState := defGen[authtypes.ModuleName] + // var newAuthGenState authtypes.GenesisState + + // if err := encoding.Marshaler.UnmarshalJSON(authGenState, &newAuthGenState); err != nil { + // panic(err) + // } + + // for _, v := range genAccs { + // anyVal, err := codectypes.NewAnyWithValue(v) + // if err != nil { + // panic(err) + // } + // newAuthGenState.Accounts = append(newAuthGenState.Accounts, anyVal) + // } + + // var err error + // defGen[authtypes.ModuleName], err = encoding.Marshaler.MarshalJSON(&newAuthGenState) + // if err != nil { + // panic(err) + // } + // } + // { + // bankGenState := defGen[banktypes.ModuleName] + // var newBankGenState banktypes.GenesisState + + // if err := encoding.Marshaler.UnmarshalJSON(bankGenState, &newBankGenState); err != nil { + // panic(err) + // } + + // newBankGenState.Balances = append(newBankGenState.Balances, balances...) + + // // totalSupply := sdk.NewCoins() + // // for _, b := range balances { + // // totalSupply = totalSupply.Add(b.Coins...) + // // } + // // newBankGenState.Supply = totalSupply + + // var err error + // defGen[banktypes.ModuleName], err = encoding.Marshaler.MarshalJSON(&newBankGenState) + // if err != nil { + // panic(err) + // } + + // // stateBytes, err := json.MarshalIndent(genesisState, "", " ") + // // if err != nil { + // // panic(err) + // // } + // } + + { + ovmGenesisState := &ovmtypes.GenesisState{ + KeyVault: ovmtypes.KeyVault{ + PublicKeys: simapp.GenerateOvmPublicKeys(ovmtypes.MinPubKeysCount), + }, + } + defGen[ovmtypes.ModuleName] = encoding.Marshaler.MustMarshalJSON(ovmGenesisState) + } + return network.Config{ Codec: encoding.Marshaler, TxConfig: encoding.TxConfig, @@ -81,12 +205,12 @@ func DefaultConfig() network.Config { baseapp.SetChainID(chainID), ) }, - GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler), + GenesisState: defGen, TimeoutCommit: 2 * time.Second, ChainID: chainID, NumValidators: 1, - BondDenom: sdk.DefaultBondDenom, - MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), + BondDenom: params.DefaultBondDenom, + MinGasPrices: fmt.Sprintf("0.000006%s", params.DefaultBondDenom), AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), diff --git a/testutil/simapp/test_helpers.go b/testutil/simapp/test_helpers.go index c2a6fd8e..18e23d10 100644 --- a/testutil/simapp/test_helpers.go +++ b/testutil/simapp/test_helpers.go @@ -7,6 +7,8 @@ import ( "encoding/hex" "fmt" "math" + "os" + "path/filepath" "github.com/golang-jwt/jwt" "github.com/spf13/cast" @@ -111,3 +113,19 @@ func RandomString(length int) string { str := base64.RawURLEncoding.EncodeToString(buff) return str[:length] // strip 1 extra character we get from odd length results } + +func WriteKeyringFile(name string, dir string, contents []byte) error { + file := filepath.Join(dir, name) + + //#nosec + if err := os.MkdirAll(dir, 0o755); err != nil { + return fmt.Errorf("could not create directory %q: %w", dir, err) + } + + //#nosec + if err := os.WriteFile(file, contents, 0o644); err != nil { + return err + } + + return nil +} diff --git a/x/mint/client/cli/query_minter_test.go b/x/mint/client/cli/query_minter_test.go index 2da04737..841da800 100644 --- a/x/mint/client/cli/query_minter_test.go +++ b/x/mint/client/cli/query_minter_test.go @@ -131,7 +131,7 @@ func TestQueryPhaseProvision(t *testing.T) { } else { require.NoError(t, err) phaseProvision := strings.Replace(string(res.Bytes()), "\n", "", 1) - require.Equal(t, "0.000000000000000000", phaseProvision) + require.Equal(t, "57446808.510638297750000000", phaseProvision) } }) }