github.com/Finschia/finschia-sdk@v0.49.1/x/auth/client/testutil/suite.go (about)

     1  package testutil
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	ostcli "github.com/Finschia/ostracon/libs/cli"
    14  	"github.com/stretchr/testify/require"
    15  	"github.com/stretchr/testify/suite"
    16  
    17  	"github.com/Finschia/finschia-sdk/client"
    18  	"github.com/Finschia/finschia-sdk/client/flags"
    19  	"github.com/Finschia/finschia-sdk/crypto/hd"
    20  	"github.com/Finschia/finschia-sdk/crypto/keyring"
    21  	kmultisig "github.com/Finschia/finschia-sdk/crypto/keys/multisig"
    22  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    23  	"github.com/Finschia/finschia-sdk/simapp"
    24  	"github.com/Finschia/finschia-sdk/testutil"
    25  	clitestutil "github.com/Finschia/finschia-sdk/testutil/cli"
    26  	"github.com/Finschia/finschia-sdk/testutil/network"
    27  	"github.com/Finschia/finschia-sdk/testutil/testdata"
    28  	sdk "github.com/Finschia/finschia-sdk/types"
    29  	"github.com/Finschia/finschia-sdk/types/tx"
    30  	"github.com/Finschia/finschia-sdk/types/tx/signing"
    31  	authcli "github.com/Finschia/finschia-sdk/x/auth/client/cli"
    32  	authtypes "github.com/Finschia/finschia-sdk/x/auth/types"
    33  	bankcli "github.com/Finschia/finschia-sdk/x/bank/client/testutil"
    34  	banktypes "github.com/Finschia/finschia-sdk/x/bank/types"
    35  	"github.com/Finschia/finschia-sdk/x/genutil/client/cli"
    36  )
    37  
    38  type IntegrationTestSuite struct {
    39  	suite.Suite
    40  
    41  	cfg     network.Config
    42  	network *network.Network
    43  }
    44  
    45  func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
    46  	return &IntegrationTestSuite{cfg: cfg}
    47  }
    48  
    49  func (s *IntegrationTestSuite) SetupSuite() {
    50  	s.T().Log("setting up integration test suite")
    51  
    52  	s.network = network.New(s.T(), s.cfg)
    53  
    54  	kb := s.network.Validators[0].ClientCtx.Keyring
    55  	_, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    56  	s.Require().NoError(err)
    57  
    58  	account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    59  	s.Require().NoError(err)
    60  
    61  	account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    62  	s.Require().NoError(err)
    63  
    64  	// Create a dummy account for testing purpose
    65  	_, _, err = kb.NewMnemonic("dummyAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    66  	s.Require().NoError(err)
    67  
    68  	multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()})
    69  	_, err = kb.SaveMultisig("multi", multi)
    70  	s.Require().NoError(err)
    71  
    72  	_, err = s.network.WaitForHeight(1)
    73  	s.Require().NoError(err)
    74  }
    75  
    76  func (s *IntegrationTestSuite) TearDownSuite() {
    77  	s.T().Log("tearing down integration test suite")
    78  	s.network.Cleanup()
    79  }
    80  
    81  func (s *IntegrationTestSuite) TestCLIValidateSignatures() {
    82  	val := s.network.Validators[0]
    83  	sendTokens := sdk.NewCoins(
    84  		sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
    85  		sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)))
    86  
    87  	res, err := s.createBankMsg(val, val.Address, sendTokens,
    88  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
    89  	s.Require().NoError(err)
    90  
    91  	// write  unsigned tx to file
    92  	unsignedTx := testutil.WriteToNewTempFile(s.T(), res.String())
    93  	res, err = TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name())
    94  	s.Require().NoError(err)
    95  	signedTx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(res.Bytes())
    96  	s.Require().NoError(err)
    97  
    98  	signedTxFile := testutil.WriteToNewTempFile(s.T(), res.String())
    99  	txBuilder, err := val.ClientCtx.TxConfig.WrapTxBuilder(signedTx)
   100  	s.Require().NoError(err)
   101  	_, err = TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name())
   102  	s.Require().NoError(err)
   103  
   104  	txBuilder.SetMemo("MODIFIED TX")
   105  	bz, err := val.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
   106  	s.Require().NoError(err)
   107  
   108  	modifiedTxFile := testutil.WriteToNewTempFile(s.T(), string(bz))
   109  
   110  	_, err = TxValidateSignaturesExec(val.ClientCtx, modifiedTxFile.Name())
   111  	s.Require().EqualError(err, "signatures validation failed")
   112  }
   113  
   114  func (s *IntegrationTestSuite) TestCLISignBatch() {
   115  	val := s.network.Validators[0]
   116  	sendTokens := sdk.NewCoins(
   117  		sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
   118  		sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
   119  	)
   120  
   121  	generatedStd, err := s.createBankMsg(val, val.Address,
   122  		sendTokens, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
   123  	s.Require().NoError(err)
   124  
   125  	outputFile := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3))
   126  	val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
   127  
   128  	// sign-batch file - offline is set but account-number and sequence are not
   129  	_, err = TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--offline")
   130  	s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set")
   131  
   132  	// sign-batch file
   133  	res, err := TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
   134  	s.Require().NoError(err)
   135  	s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
   136  
   137  	// sign-batch file signature only
   138  	res, err = TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
   139  	s.Require().NoError(err)
   140  	s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
   141  
   142  	// Sign batch malformed tx file.
   143  	malformedFile := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf("%smalformed", generatedStd))
   144  	_, err = TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
   145  	s.Require().Error(err)
   146  
   147  	// Sign batch malformed tx file signature only.
   148  	_, err = TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
   149  	s.Require().Error(err)
   150  
   151  	// make a txn to increase the sequence of sender
   152  	_, seq, err := val.ClientCtx.AccountRetriever.GetAccountNumberSequence(val.ClientCtx, val.Address)
   153  	s.Require().NoError(err)
   154  
   155  	account1, err := val.ClientCtx.Keyring.Key("newAccount1")
   156  	s.Require().NoError(err)
   157  
   158  	addr := account1.GetAddress()
   159  	s.Require().NoError(err)
   160  
   161  	// Send coins from validator to multisig.
   162  	_, err = s.createBankMsg(
   163  		val,
   164  		addr,
   165  		sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 1000)),
   166  	)
   167  	s.Require().NoError(err)
   168  	s.Require().NoError(s.network.WaitForNextBlock())
   169  
   170  	// fetch the sequence after a tx, should be incremented.
   171  	_, seq1, err := val.ClientCtx.AccountRetriever.GetAccountNumberSequence(val.ClientCtx, val.Address)
   172  	s.Require().NoError(err)
   173  	s.Require().Equal(seq+1, seq1)
   174  
   175  	// signing sign-batch should start from the last sequence.
   176  	signed, err := TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
   177  	s.Require().NoError(err)
   178  	signedTxs := strings.Split(strings.Trim(signed.String(), "\n"), "\n")
   179  	s.Require().GreaterOrEqual(len(signedTxs), 1)
   180  
   181  	sigs, err := s.cfg.TxConfig.UnmarshalSignatureJSON([]byte(signedTxs[0]))
   182  	s.Require().NoError(err)
   183  	s.Require().Equal(sigs[0].Sequence, seq1)
   184  }
   185  
   186  func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
   187  	require := s.Require()
   188  	val1 := s.network.Validators[0]
   189  	txCfg := val1.ClientCtx.TxConfig
   190  	sendTokens := sdk.NewCoins(
   191  		sdk.NewCoin(fmt.Sprintf("%stoken", val1.Moniker), sdk.NewInt(10)),
   192  		sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
   193  	)
   194  	txBz, err := s.createBankMsg(val1, val1.Address,
   195  		sendTokens, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
   196  	require.NoError(err)
   197  	fileUnsigned := testutil.WriteToNewTempFile(s.T(), txBz.String())
   198  	chainFlag := fmt.Sprintf("--%s=%s", flags.FlagChainID, val1.ClientCtx.ChainID)
   199  	sigOnlyFlag := "--signature-only"
   200  	signModeAminoFlag := "--sign-mode=amino-json"
   201  
   202  	// SIC! validators have same key names and same addresses as those registered in the keyring,
   203  	//      BUT the keys are different!
   204  	valInfo, err := val1.ClientCtx.Keyring.Key(val1.Moniker)
   205  	require.NoError(err)
   206  
   207  	// query account info
   208  	queryResJSON, err := QueryAccountExec(val1.ClientCtx, val1.Address)
   209  	require.NoError(err)
   210  	var account authtypes.AccountI
   211  	require.NoError(val1.ClientCtx.Codec.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account))
   212  
   213  	/****  test signature-only  ****/
   214  	res, err := TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag,
   215  		sigOnlyFlag, signModeAminoFlag)
   216  	require.NoError(err)
   217  	checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey())
   218  	sigs, err := txCfg.UnmarshalSignatureJSON(res.Bytes())
   219  	require.NoError(err)
   220  	require.Equal(1, len(sigs))
   221  	require.Equal(account.GetSequence(), sigs[0].Sequence)
   222  
   223  	/****  test full output  ****/
   224  	res, err = TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, signModeAminoFlag)
   225  	require.NoError(err)
   226  
   227  	// txCfg.UnmarshalSignatureJSON can't unmarshal a fragment of the signature, so we create this structure.
   228  	type txFragment struct {
   229  		Signatures []json.RawMessage
   230  	}
   231  	var txOut txFragment
   232  	err = json.Unmarshal(res.Bytes(), &txOut)
   233  	require.NoError(err)
   234  	require.Len(txOut.Signatures, 1)
   235  
   236  	/****  test file output  ****/
   237  	filenameSigned := filepath.Join(s.T().TempDir(), "test_sign_out.json")
   238  	fileFlag := fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, filenameSigned)
   239  	_, err = TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, fileFlag, signModeAminoFlag)
   240  	require.NoError(err)
   241  	fContent, err := os.ReadFile(filenameSigned)
   242  	require.NoError(err)
   243  	require.Equal(res.String(), string(fContent))
   244  
   245  	/****  try to append to the previously signed transaction  ****/
   246  	res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
   247  		sigOnlyFlag, signModeAminoFlag)
   248  	require.NoError(err)
   249  	checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey(), valInfo.GetPubKey())
   250  
   251  	/****  try to overwrite the previously signed transaction  ****/
   252  
   253  	// We can't sign with other address, because the bank send message supports only one signer for a simple
   254  	// account. Changing the file is too much hacking, because TxDecoder returns sdk.Tx, which doesn't
   255  	// provide functionality to check / manage `auth_info`.
   256  	// Cases with different keys are are covered in unit tests of `tx.Sign`.
   257  	res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
   258  		sigOnlyFlag, "--overwrite", signModeAminoFlag)
   259  	require.NoError(err)
   260  	checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey())
   261  
   262  	/****  test flagAmino  ****/
   263  	res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
   264  		"--amino=true", signModeAminoFlag)
   265  	require.NoError(err)
   266  
   267  	var txAmino authcli.BroadcastReq
   268  	err = val1.ClientCtx.LegacyAmino.UnmarshalJSON(res.Bytes(), &txAmino)
   269  	require.NoError(err)
   270  	require.Len(txAmino.Tx.Signatures, 2)
   271  	require.Equal(txAmino.Tx.Signatures[0].PubKey, valInfo.GetPubKey())
   272  	require.Equal(txAmino.Tx.Signatures[1].PubKey, valInfo.GetPubKey())
   273  }
   274  
   275  func checkSignatures(require *require.Assertions, txCfg client.TxConfig, output []byte, pks ...cryptotypes.PubKey) {
   276  	sigs, err := txCfg.UnmarshalSignatureJSON(output)
   277  	require.NoError(err, string(output))
   278  	require.Len(sigs, len(pks))
   279  	for i := range pks {
   280  		require.True(sigs[i].PubKey.Equals(pks[i]), "Pub key doesn't match. Got: %s, expected: %s, idx: %d", sigs[i].PubKey, pks[i], i)
   281  		require.NotEmpty(sigs[i].Data)
   282  	}
   283  }
   284  
   285  func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() {
   286  	val := s.network.Validators[0]
   287  
   288  	account2, err := val.ClientCtx.Keyring.Key("newAccount2")
   289  	s.Require().NoError(err)
   290  
   291  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
   292  
   293  	// Send coins.
   294  	out, err := s.createBankMsg(
   295  		val, account2.GetAddress(),
   296  		sdk.NewCoins(sendTokens),
   297  	)
   298  	s.Require().NoError(err)
   299  
   300  	var txRes sdk.TxResponse
   301  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
   302  	s.Require().NoError(s.network.WaitForNextBlock())
   303  
   304  	testCases := []struct {
   305  		name           string
   306  		args           []string
   307  		expectErr      bool
   308  		rawLogContains string
   309  	}{
   310  		{
   311  			"not enough args",
   312  			[]string{},
   313  			true, "",
   314  		},
   315  		{
   316  			"with invalid hash",
   317  			[]string{"somethinginvalid", fmt.Sprintf("--%s=json", ostcli.OutputFlag)},
   318  			true, "",
   319  		},
   320  		{
   321  			"with valid and not existing hash",
   322  			[]string{"C7E7D3A86A17AB3A321172239F3B61357937AF0F25D9FA4D2F4DCCAD9B0D7747", fmt.Sprintf("--%s=json", ostcli.OutputFlag)},
   323  			true, "",
   324  		},
   325  		{
   326  			"happy case",
   327  			[]string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)},
   328  			false,
   329  			sdk.MsgTypeURL(&banktypes.MsgSend{}),
   330  		},
   331  	}
   332  
   333  	for _, tc := range testCases {
   334  		s.Run(tc.name, func() {
   335  			cmd := authcli.QueryTxCmd()
   336  			clientCtx := val.ClientCtx
   337  
   338  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   339  
   340  			if tc.expectErr {
   341  				s.Require().Error(err)
   342  				s.Require().NotEqual("internal", err.Error())
   343  			} else {
   344  				var result sdk.TxResponse
   345  				s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result))
   346  				s.Require().NotNil(result.Height)
   347  				s.Require().Contains(result.RawLog, tc.rawLogContains)
   348  			}
   349  		})
   350  	}
   351  }
   352  
   353  func (s *IntegrationTestSuite) TestCLIQueryTxCmdByEvents() {
   354  	val := s.network.Validators[0]
   355  
   356  	account2, err := val.ClientCtx.Keyring.Key("newAccount2")
   357  	s.Require().NoError(err)
   358  
   359  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
   360  
   361  	// Send coins.
   362  	out, err := s.createBankMsg(
   363  		val, account2.GetAddress(),
   364  		sdk.NewCoins(sendTokens),
   365  	)
   366  	s.Require().NoError(err)
   367  	var txRes sdk.TxResponse
   368  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
   369  	s.Require().NoError(s.network.WaitForNextBlock())
   370  
   371  	// Query the tx by hash to get the inner tx.
   372  	out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.QueryTxCmd(), []string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)})
   373  	s.Require().NoError(err)
   374  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
   375  	protoTx := txRes.GetTx().(*tx.Tx)
   376  
   377  	testCases := []struct {
   378  		name         string
   379  		args         []string
   380  		expectErr    bool
   381  		expectErrStr string
   382  	}{
   383  		{
   384  			"invalid --type",
   385  			[]string{
   386  				fmt.Sprintf("--type=%s", "foo"),
   387  				"bar",
   388  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   389  			},
   390  			true, "unknown --type value foo",
   391  		},
   392  		{
   393  			"--type=acc_seq with no addr+seq",
   394  			[]string{
   395  				"--type=acc_seq",
   396  				"",
   397  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   398  			},
   399  			true, "`acc_seq` type takes an argument '<addr>/<seq>'",
   400  		},
   401  		{
   402  			"non-existing addr+seq combo",
   403  			[]string{
   404  				"--type=acc_seq",
   405  				"foobar",
   406  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   407  			},
   408  			true, "found no txs matching given address and sequence combination",
   409  		},
   410  		{
   411  			"addr+seq happy case",
   412  			[]string{
   413  				"--type=acc_seq",
   414  				fmt.Sprintf("%s/%d", val.Address, protoTx.AuthInfo.SignerInfos[0].Sequence),
   415  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   416  			},
   417  			false, "",
   418  		},
   419  		{
   420  			"--type=signature with no signature",
   421  			[]string{
   422  				"--type=signature",
   423  				"",
   424  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   425  			},
   426  			true, "argument should be comma-separated signatures",
   427  		},
   428  		{
   429  			"non-existing signatures",
   430  			[]string{
   431  				"--type=signature",
   432  				"foo",
   433  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   434  			},
   435  			true, "found no txs matching given signatures",
   436  		},
   437  		{
   438  			"with --signatures happy case",
   439  			[]string{
   440  				"--type=signature",
   441  				base64.StdEncoding.EncodeToString(protoTx.Signatures[0]),
   442  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   443  			},
   444  			false, "",
   445  		},
   446  	}
   447  
   448  	for _, tc := range testCases {
   449  		s.Run(tc.name, func() {
   450  			cmd := authcli.QueryTxCmd()
   451  			clientCtx := val.ClientCtx
   452  
   453  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   454  			if tc.expectErr {
   455  				s.Require().Error(err)
   456  				s.Require().Contains(err.Error(), tc.expectErrStr)
   457  			} else {
   458  				var result sdk.TxResponse
   459  				s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result))
   460  				s.Require().NotNil(result.Height)
   461  			}
   462  		})
   463  	}
   464  }
   465  
   466  func (s *IntegrationTestSuite) TestCLIQueryTxsCmdByEvents() {
   467  	val := s.network.Validators[0]
   468  
   469  	account2, err := val.ClientCtx.Keyring.Key("newAccount2")
   470  	s.Require().NoError(err)
   471  
   472  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
   473  
   474  	// Send coins.
   475  	out, err := s.createBankMsg(
   476  		val, account2.GetAddress(),
   477  		sdk.NewCoins(sendTokens),
   478  	)
   479  	s.Require().NoError(err)
   480  	var txRes sdk.TxResponse
   481  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
   482  	s.Require().NoError(s.network.WaitForNextBlock())
   483  
   484  	// Query the tx by hash to get the inner tx.
   485  	out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.QueryTxCmd(), []string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)})
   486  	s.Require().NoError(err)
   487  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
   488  
   489  	testCases := []struct {
   490  		name        string
   491  		args        []string
   492  		expectErr   bool
   493  		expectEmpty bool
   494  	}{
   495  		{
   496  			"fee event happy case",
   497  			[]string{
   498  				fmt.Sprintf("--events=tx.fee=%s",
   499  					sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   500  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   501  			},
   502  			false,
   503  			false,
   504  		},
   505  		{
   506  			"no matching fee event",
   507  			[]string{
   508  				fmt.Sprintf("--events=tx.fee=%s",
   509  					sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(0))).String()),
   510  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   511  			},
   512  			false,
   513  			true,
   514  		},
   515  		{
   516  			"wrong number of arguments",
   517  			[]string{
   518  				"extra",
   519  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
   520  			},
   521  			true,
   522  			true,
   523  		},
   524  	}
   525  
   526  	for _, tc := range testCases {
   527  		s.Run(tc.name, func() {
   528  			cmd := authcli.QueryTxsByEventsCmd()
   529  			clientCtx := val.ClientCtx
   530  
   531  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   532  			if tc.expectErr {
   533  				s.Require().Error(err)
   534  				return
   535  			}
   536  			s.Require().NoError(err)
   537  
   538  			var result sdk.SearchTxsResult
   539  			s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result))
   540  
   541  			if tc.expectEmpty {
   542  				s.Require().Equal(0, len(result.Txs))
   543  			} else {
   544  				s.Require().NotEqual(0, len(result.Txs))
   545  				s.Require().NotNil(result.Txs[0])
   546  			}
   547  		})
   548  	}
   549  }
   550  
   551  func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
   552  	val1 := s.network.Validators[0]
   553  
   554  	account, err := val1.ClientCtx.Keyring.Key("newAccount")
   555  	s.Require().NoError(err)
   556  
   557  	sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction))
   558  
   559  	normalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
   560  		sdk.NewCoins(sendTokens), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
   561  	s.Require().NoError(err)
   562  
   563  	txCfg := val1.ClientCtx.TxConfig
   564  
   565  	normalGeneratedStdTx, err := txCfg.TxJSONDecoder()(normalGeneratedTx.Bytes())
   566  	s.Require().NoError(err)
   567  	txBuilder, err := txCfg.WrapTxBuilder(normalGeneratedStdTx)
   568  	s.Require().NoError(err)
   569  	s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(flags.DefaultGasLimit))
   570  	s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
   571  	sigs, err := txBuilder.GetTx().GetSignaturesV2()
   572  	s.Require().NoError(err)
   573  	s.Require().Equal(0, len(sigs))
   574  
   575  	// Test generate sendTx with --gas=$amount
   576  	limitedGasGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
   577  		sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", 100),
   578  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   579  	)
   580  	s.Require().NoError(err)
   581  
   582  	limitedGasStdTx, err := txCfg.TxJSONDecoder()(limitedGasGeneratedTx.Bytes())
   583  	s.Require().NoError(err)
   584  	txBuilder, err = txCfg.WrapTxBuilder(limitedGasStdTx)
   585  	s.Require().NoError(err)
   586  	s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(100))
   587  	s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
   588  	sigs, err = txBuilder.GetTx().GetSignaturesV2()
   589  	s.Require().NoError(err)
   590  	s.Require().Equal(0, len(sigs))
   591  
   592  	resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
   593  	s.Require().NoError(err)
   594  
   595  	var balRes banktypes.QueryAllBalancesResponse
   596  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   597  	s.Require().NoError(err)
   598  	startTokens := balRes.Balances.AmountOf(s.cfg.BondDenom)
   599  
   600  	// Test generate sendTx, estimate gas
   601  	finalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
   602  		sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
   603  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
   604  	s.Require().NoError(err)
   605  
   606  	finalStdTx, err := txCfg.TxJSONDecoder()(finalGeneratedTx.Bytes())
   607  	s.Require().NoError(err)
   608  	txBuilder, err = txCfg.WrapTxBuilder(finalStdTx)
   609  	s.Require().NoError(err)
   610  	s.Require().Equal(uint64(flags.DefaultGasLimit), txBuilder.GetTx().GetGas())
   611  	s.Require().Equal(len(finalStdTx.GetMsgs()), 1)
   612  
   613  	// Write the output to disk
   614  	unsignedTxFile := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String())
   615  
   616  	// Test validate-signatures
   617  	res, err := TxValidateSignaturesExec(val1.ClientCtx, unsignedTxFile.Name())
   618  	s.Require().EqualError(err, "signatures validation failed")
   619  	s.Require().True(strings.Contains(res.String(), fmt.Sprintf("Signers:\n  0: %v\n\nSignatures:\n\n", val1.Address.String())))
   620  
   621  	// Test sign
   622  
   623  	// Does not work in offline mode
   624  	_, err = TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline")
   625  	s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set")
   626  
   627  	// But works offline if we set account number and sequence
   628  	val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
   629  	_, err = TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1")
   630  	s.Require().NoError(err)
   631  
   632  	// Sign transaction
   633  	signedTx, err := TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name())
   634  	s.Require().NoError(err)
   635  	signedFinalTx, err := txCfg.TxJSONDecoder()(signedTx.Bytes())
   636  	s.Require().NoError(err)
   637  	txBuilder, err = val1.ClientCtx.TxConfig.WrapTxBuilder(signedFinalTx)
   638  	s.Require().NoError(err)
   639  	s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
   640  	sigs, err = txBuilder.GetTx().GetSignaturesV2()
   641  	s.Require().NoError(err)
   642  	s.Require().Equal(1, len(sigs))
   643  	s.Require().Equal(val1.Address.String(), txBuilder.GetTx().GetSigners()[0].String())
   644  
   645  	// Write the output to disk
   646  	signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String())
   647  
   648  	// validate Signature
   649  	res, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
   650  	s.Require().NoError(err)
   651  	s.Require().True(strings.Contains(res.String(), "[OK]"))
   652  
   653  	// Ensure foo has right amount of funds
   654  	resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
   655  	s.Require().NoError(err)
   656  
   657  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   658  	s.Require().NoError(err)
   659  	s.Require().Equal(startTokens, balRes.Balances.AmountOf(s.cfg.BondDenom))
   660  
   661  	// Test broadcast
   662  
   663  	// Does not work in offline mode
   664  	_, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name(), "--offline")
   665  	s.Require().EqualError(err, "cannot broadcast tx during offline mode")
   666  
   667  	s.Require().NoError(s.network.WaitForNextBlock())
   668  
   669  	// Broadcast correct transaction.
   670  	val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
   671  	_, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
   672  	s.Require().NoError(err)
   673  
   674  	s.Require().NoError(s.network.WaitForNextBlock())
   675  
   676  	// Ensure destiny account state
   677  	resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, account.GetAddress())
   678  	s.Require().NoError(err)
   679  
   680  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   681  	s.Require().NoError(err)
   682  	s.Require().Equal(sendTokens.Amount, balRes.Balances.AmountOf(s.cfg.BondDenom))
   683  
   684  	// Ensure origin account state
   685  	resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
   686  	s.Require().NoError(err)
   687  
   688  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   689  	s.Require().NoError(err)
   690  }
   691  
   692  func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
   693  	val1 := s.network.Validators[0]
   694  
   695  	// Fetch account and a multisig info
   696  	account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
   697  	s.Require().NoError(err)
   698  
   699  	multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
   700  	s.Require().NoError(err)
   701  
   702  	// Send coins from validator to multisig.
   703  	_, err = s.createBankMsg(
   704  		val1,
   705  		multisigInfo.GetAddress(),
   706  		sdk.NewCoins(
   707  			sdk.NewInt64Coin(s.cfg.BondDenom, 10),
   708  		),
   709  	)
   710  	s.Require().NoError(err)
   711  
   712  	s.Require().NoError(s.network.WaitForNextBlock())
   713  
   714  	// Generate multisig transaction.
   715  	multiGeneratedTx, err := bankcli.MsgSendExec(
   716  		val1.ClientCtx,
   717  		multisigInfo.GetAddress(),
   718  		val1.Address,
   719  		sdk.NewCoins(
   720  			sdk.NewInt64Coin(s.cfg.BondDenom, 5),
   721  		),
   722  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   723  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   724  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   725  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   726  	)
   727  	s.Require().NoError(err)
   728  
   729  	// Save tx to file
   730  	multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
   731  
   732  	// Multisign, sign with one signature
   733  	val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
   734  	account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   735  	s.Require().NoError(err)
   736  
   737  	sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
   738  
   739  	multiSigWith1Signature, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name())
   740  	s.Require().NoError(err)
   741  
   742  	// Save tx to file
   743  	multiSigWith1SignatureFile := testutil.WriteToNewTempFile(s.T(), multiSigWith1Signature.String())
   744  
   745  	_, err = TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name())
   746  	s.Require().Error(err)
   747  }
   748  
   749  func (s *IntegrationTestSuite) TestCLIEncode() {
   750  	val1 := s.network.Validators[0]
   751  
   752  	sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction))
   753  
   754  	normalGeneratedTx, err := s.createBankMsg(
   755  		val1, val1.Address,
   756  		sdk.NewCoins(sendTokens),
   757  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   758  		fmt.Sprintf("--%s=deadbeef", flags.FlagNote),
   759  	)
   760  	s.Require().NoError(err)
   761  	savedTxFile := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
   762  
   763  	// Encode
   764  	encodeExec, err := TxEncodeExec(val1.ClientCtx, savedTxFile.Name())
   765  	s.Require().NoError(err)
   766  	trimmedBase64 := strings.Trim(encodeExec.String(), "\"\n")
   767  
   768  	// Check that the transaction decodes as expected
   769  	decodedTx, err := TxDecodeExec(val1.ClientCtx, trimmedBase64)
   770  	s.Require().NoError(err)
   771  
   772  	txCfg := val1.ClientCtx.TxConfig
   773  	theTx, err := txCfg.TxJSONDecoder()(decodedTx.Bytes())
   774  	s.Require().NoError(err)
   775  	txBuilder, err := val1.ClientCtx.TxConfig.WrapTxBuilder(theTx)
   776  	s.Require().NoError(err)
   777  	s.Require().Equal("deadbeef", txBuilder.GetTx().GetMemo())
   778  }
   779  
   780  func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
   781  	val1 := s.network.Validators[0]
   782  
   783  	// Generate 2 accounts and a multisig.
   784  	account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
   785  	s.Require().NoError(err)
   786  
   787  	account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
   788  	s.Require().NoError(err)
   789  
   790  	multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
   791  	s.Require().NoError(err)
   792  
   793  	// Generate dummy account which is not a part of multisig.
   794  	dummyAcc, err := val1.ClientCtx.Keyring.Key("dummyAccount")
   795  	s.Require().NoError(err)
   796  
   797  	resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
   798  	s.Require().NoError(err)
   799  
   800  	var balRes banktypes.QueryAllBalancesResponse
   801  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   802  	s.Require().NoError(err)
   803  	intialCoins := balRes.Balances
   804  
   805  	// Send coins from validator to multisig.
   806  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
   807  	_, err = s.createBankMsg(
   808  		val1,
   809  		multisigInfo.GetAddress(),
   810  		sdk.NewCoins(sendTokens),
   811  	)
   812  	s.Require().NoError(err)
   813  
   814  	s.Require().NoError(s.network.WaitForNextBlock())
   815  
   816  	resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
   817  	s.Require().NoError(err)
   818  
   819  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   820  	s.Require().NoError(err)
   821  	diff, _ := balRes.Balances.SafeSub(intialCoins)
   822  	s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom))
   823  
   824  	// Generate multisig transaction.
   825  	multiGeneratedTx, err := bankcli.MsgSendExec(
   826  		val1.ClientCtx,
   827  		multisigInfo.GetAddress(),
   828  		val1.Address,
   829  		sdk.NewCoins(
   830  			sdk.NewInt64Coin(s.cfg.BondDenom, 5),
   831  		),
   832  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   833  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   834  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   835  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   836  	)
   837  	s.Require().NoError(err)
   838  
   839  	// Save tx to file
   840  	multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
   841  
   842  	// Sign with account1
   843  	val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
   844  	account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   845  	s.Require().NoError(err)
   846  
   847  	sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
   848  
   849  	// Sign with account2
   850  	account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   851  	s.Require().NoError(err)
   852  
   853  	sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
   854  
   855  	// Sign with dummy account
   856  	dummyAddr := dummyAcc.GetAddress()
   857  	_, err = TxSignExec(val1.ClientCtx, dummyAddr, multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   858  	s.Require().Error(err)
   859  	s.Require().Contains(err.Error(), "signing key is not a part of multisig key")
   860  
   861  	multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
   862  	s.Require().NoError(err)
   863  
   864  	// Write the output to disk
   865  	signedTxFile := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String())
   866  
   867  	_, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
   868  	s.Require().NoError(err)
   869  
   870  	val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
   871  	_, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
   872  	s.Require().NoError(err)
   873  
   874  	s.Require().NoError(s.network.WaitForNextBlock())
   875  }
   876  
   877  func (s *IntegrationTestSuite) TestSignWithMultisig() {
   878  	val1 := s.network.Validators[0]
   879  
   880  	// Generate a account for signing.
   881  	account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
   882  	s.Require().NoError(err)
   883  
   884  	addr1 := account1.GetAddress()
   885  	s.Require().NoError(err)
   886  
   887  	// Create an address that is not in the keyring, will be used to simulate `--multisig`
   888  	multisig := "link1hd6fsrvnz6qkp87s3u86ludegq97agxsccwqll"
   889  	multisigAddr, err := sdk.AccAddressFromBech32(multisig)
   890  	s.Require().NoError(err)
   891  
   892  	// Generate a transaction for testing --multisig with an address not in the keyring.
   893  	multisigTx, err := bankcli.MsgSendExec(
   894  		val1.ClientCtx,
   895  		val1.Address,
   896  		val1.Address,
   897  		sdk.NewCoins(
   898  			sdk.NewInt64Coin(s.cfg.BondDenom, 5),
   899  		),
   900  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   901  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   902  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   903  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   904  	)
   905  	s.Require().NoError(err)
   906  
   907  	// Save multi tx to file
   908  	multiGeneratedTx2File := testutil.WriteToNewTempFile(s.T(), multisigTx.String())
   909  
   910  	// Sign using multisig. We're signing a tx on behalf of the multisig address,
   911  	// even though the tx signer is NOT the multisig address. This is fine though,
   912  	// as the main point of this test is to test the `--multisig` flag with an address
   913  	// that is not in the keyring.
   914  	_, err = TxSignExec(val1.ClientCtx, addr1, multiGeneratedTx2File.Name(), "--multisig", multisigAddr.String())
   915  	s.Require().Contains(err.Error(), "error getting account from keybase")
   916  }
   917  
   918  func (s *IntegrationTestSuite) TestCLIMultisign() {
   919  	val1 := s.network.Validators[0]
   920  
   921  	// Generate 2 accounts and a multisig.
   922  	account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
   923  	s.Require().NoError(err)
   924  
   925  	account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
   926  	s.Require().NoError(err)
   927  
   928  	multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
   929  	s.Require().NoError(err)
   930  
   931  	// Send coins from validator to multisig.
   932  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
   933  	_, err = s.createBankMsg(
   934  		val1, multisigInfo.GetAddress(),
   935  		sdk.NewCoins(sendTokens),
   936  	)
   937  	s.Require().NoError(err)
   938  	s.Require().NoError(s.network.WaitForNextBlock())
   939  
   940  	resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
   941  	s.Require().NoError(err)
   942  
   943  	var balRes banktypes.QueryAllBalancesResponse
   944  	err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
   945  	s.Require().NoError(err)
   946  	s.Require().Equal(sendTokens.Amount, balRes.Balances.AmountOf(s.cfg.BondDenom))
   947  
   948  	// Generate multisig transaction.
   949  	multiGeneratedTx, err := bankcli.MsgSendExec(
   950  		val1.ClientCtx,
   951  		multisigInfo.GetAddress(),
   952  		val1.Address,
   953  		sdk.NewCoins(
   954  			sdk.NewInt64Coin(s.cfg.BondDenom, 5),
   955  		),
   956  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   957  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   958  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   959  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   960  	)
   961  	s.Require().NoError(err)
   962  
   963  	// Save tx to file
   964  	multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
   965  
   966  	// Sign with account1
   967  	val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
   968  	account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   969  	s.Require().NoError(err)
   970  
   971  	sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
   972  
   973  	// Sign with account2
   974  	account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
   975  	s.Require().NoError(err)
   976  
   977  	sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
   978  
   979  	// Does not work in offline mode.
   980  	_, err = TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name())
   981  	s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature for address %s", account1.GetAddress()))
   982  
   983  	val1.ClientCtx.Offline = false
   984  	multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
   985  	s.Require().NoError(err)
   986  
   987  	// Write the output to disk
   988  	signedTxFile := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String())
   989  
   990  	_, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
   991  	s.Require().NoError(err)
   992  
   993  	val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
   994  	_, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
   995  	s.Require().NoError(err)
   996  
   997  	s.Require().NoError(s.network.WaitForNextBlock())
   998  }
   999  
  1000  func (s *IntegrationTestSuite) TestSignBatchMultisig() {
  1001  	val := s.network.Validators[0]
  1002  
  1003  	// Fetch 2 accounts and a multisig.
  1004  	account1, err := val.ClientCtx.Keyring.Key("newAccount1")
  1005  	s.Require().NoError(err)
  1006  	account2, err := val.ClientCtx.Keyring.Key("newAccount2")
  1007  	s.Require().NoError(err)
  1008  	multisigInfo, err := val.ClientCtx.Keyring.Key("multi")
  1009  	s.Require().NoError(err)
  1010  
  1011  	// Send coins from validator to multisig.
  1012  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
  1013  	_, err = s.createBankMsg(
  1014  		val,
  1015  		multisigInfo.GetAddress(),
  1016  		sdk.NewCoins(sendTokens),
  1017  	)
  1018  	s.Require().NoError(err)
  1019  	s.Require().NoError(s.network.WaitForNextBlock())
  1020  
  1021  	generatedStd, err := bankcli.MsgSendExec(
  1022  		val.ClientCtx,
  1023  		multisigInfo.GetAddress(),
  1024  		val.Address,
  1025  		sdk.NewCoins(
  1026  			sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
  1027  		),
  1028  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1029  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1030  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1031  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
  1032  	)
  1033  	s.Require().NoError(err)
  1034  
  1035  	// Write the output to disk
  1036  	filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 1))
  1037  	val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
  1038  
  1039  	// sign-batch file
  1040  	res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
  1041  	s.Require().NoError(err)
  1042  	s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1043  	// write sigs to file
  1044  	file1 := testutil.WriteToNewTempFile(s.T(), res.String())
  1045  
  1046  	// sign-batch file with account2
  1047  	res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
  1048  	s.Require().NoError(err)
  1049  	s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1050  	// write sigs to file2
  1051  	file2 := testutil.WriteToNewTempFile(s.T(), res.String())
  1052  
  1053  	// sign-batch file with multisig key name
  1054  	res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName())
  1055  	s.Require().NoError(err)
  1056  	s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1057  	// write sigs to file3
  1058  	file3 := testutil.WriteToNewTempFile(s.T(), res.String())
  1059  
  1060  	_, err = TxMultiSignExec(val.ClientCtx, multisigInfo.GetName(), filename.Name(), file1.Name(), file2.Name(), file3.Name())
  1061  	s.Require().NoError(err)
  1062  }
  1063  
  1064  func (s *IntegrationTestSuite) TestMultisignBatch() {
  1065  	val := s.network.Validators[0]
  1066  
  1067  	// Fetch 2 accounts and a multisig.
  1068  	account1, err := val.ClientCtx.Keyring.Key("newAccount1")
  1069  	s.Require().NoError(err)
  1070  	account2, err := val.ClientCtx.Keyring.Key("newAccount2")
  1071  	s.Require().NoError(err)
  1072  	multisigInfo, err := val.ClientCtx.Keyring.Key("multi")
  1073  	s.Require().NoError(err)
  1074  
  1075  	// Send coins from validator to multisig.
  1076  	sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 1000)
  1077  	_, err = s.createBankMsg(
  1078  		val,
  1079  		multisigInfo.GetAddress(),
  1080  		sdk.NewCoins(sendTokens),
  1081  	)
  1082  	s.Require().NoError(err)
  1083  	s.Require().NoError(s.network.WaitForNextBlock())
  1084  
  1085  	generatedStd, err := bankcli.MsgSendExec(
  1086  		val.ClientCtx,
  1087  		multisigInfo.GetAddress(),
  1088  		val.Address,
  1089  		sdk.NewCoins(
  1090  			sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
  1091  		),
  1092  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1093  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1094  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1095  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
  1096  	)
  1097  	s.Require().NoError(err)
  1098  
  1099  	// Write the output to disk
  1100  	filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3))
  1101  	val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
  1102  
  1103  	queryResJSON, err := QueryAccountExec(val.ClientCtx, multisigInfo.GetAddress())
  1104  	s.Require().NoError(err)
  1105  	var account authtypes.AccountI
  1106  	s.Require().NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account))
  1107  
  1108  	// sign-batch file
  1109  	res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
  1110  	s.Require().NoError(err)
  1111  	s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1112  	// write sigs to file
  1113  	file1 := testutil.WriteToNewTempFile(s.T(), res.String())
  1114  
  1115  	// sign-batch file with account2
  1116  	res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
  1117  	s.Require().NoError(err)
  1118  	s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1119  
  1120  	// multisign the file
  1121  	file2 := testutil.WriteToNewTempFile(s.T(), res.String())
  1122  
  1123  	// sign-batch file with multisig key name
  1124  	res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
  1125  	s.Require().NoError(err)
  1126  	s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
  1127  	// write sigs to file
  1128  	file3 := testutil.WriteToNewTempFile(s.T(), res.String())
  1129  
  1130  	res, err = TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigInfo.GetName(), file1.Name(), file2.Name(), file3.Name())
  1131  	s.Require().NoError(err)
  1132  	signedTxs := strings.Split(strings.Trim(res.String(), "\n"), "\n")
  1133  
  1134  	// Broadcast transactions.
  1135  	for _, signedTx := range signedTxs {
  1136  		signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx)
  1137  		val.ClientCtx.BroadcastMode = flags.BroadcastBlock
  1138  		_, err = TxBroadcastExec(val.ClientCtx, signedTxFile.Name())
  1139  		s.Require().NoError(err)
  1140  		s.Require().NoError(s.network.WaitForNextBlock())
  1141  	}
  1142  }
  1143  
  1144  func (s *IntegrationTestSuite) TestGetAccountCmd() {
  1145  	val := s.network.Validators[0]
  1146  	_, _, addr1 := testdata.KeyTestPubAddr()
  1147  
  1148  	testCases := []struct {
  1149  		name      string
  1150  		address   sdk.AccAddress
  1151  		expectErr bool
  1152  	}{
  1153  		{
  1154  			"invalid address",
  1155  			addr1,
  1156  			true,
  1157  		},
  1158  		{
  1159  			"valid address",
  1160  			val.Address,
  1161  			false,
  1162  		},
  1163  	}
  1164  
  1165  	for _, tc := range testCases {
  1166  		s.Run(tc.name, func() {
  1167  			clientCtx := val.ClientCtx
  1168  
  1169  			out, err := QueryAccountExec(clientCtx, tc.address)
  1170  			if tc.expectErr {
  1171  				s.Require().Error(err)
  1172  				s.Require().NotEqual("internal", err.Error())
  1173  			} else {
  1174  				var acc authtypes.AccountI
  1175  				s.Require().NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &acc))
  1176  				s.Require().Equal(val.Address, acc.GetAddress())
  1177  			}
  1178  		})
  1179  	}
  1180  }
  1181  
  1182  func (s *IntegrationTestSuite) TestGetAccountsCmd() {
  1183  	val := s.network.Validators[0]
  1184  
  1185  	commonArgs := []string{
  1186  		fmt.Sprintf("--%s=json", ostcli.OutputFlag),
  1187  	}
  1188  
  1189  	testCases := map[string]struct {
  1190  		args  []string
  1191  		valid bool
  1192  	}{
  1193  		"valid request": {
  1194  			valid: true,
  1195  		},
  1196  		"wrong number of args": {
  1197  			args: []string{
  1198  				"extra",
  1199  			},
  1200  		},
  1201  	}
  1202  
  1203  	for name, tc := range testCases {
  1204  		s.Run(name, func() {
  1205  			cmd := authcli.GetAccountsCmd()
  1206  			clientCtx := val.ClientCtx
  1207  
  1208  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, append(tc.args, commonArgs...))
  1209  			if !tc.valid {
  1210  				s.Require().Error(err)
  1211  				return
  1212  			}
  1213  			s.Require().NoError(err)
  1214  
  1215  			var res authtypes.QueryAccountsResponse
  1216  			s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
  1217  			s.Require().NotEmpty(res.Accounts)
  1218  		})
  1219  	}
  1220  }
  1221  
  1222  func (s *IntegrationTestSuite) TestQueryModuleAccountByNameCmd() {
  1223  	val := s.network.Validators[0]
  1224  
  1225  	testCases := []struct {
  1226  		name       string
  1227  		moduleName string
  1228  		expectErr  bool
  1229  	}{
  1230  		{
  1231  			"invalid module name",
  1232  			"gover",
  1233  			true,
  1234  		},
  1235  		{
  1236  			"valid module name",
  1237  			"mint",
  1238  			false,
  1239  		},
  1240  	}
  1241  
  1242  	for _, tc := range testCases {
  1243  		s.Run(tc.name, func() {
  1244  			clientCtx := val.ClientCtx
  1245  
  1246  			out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountByNameCmd(), []string{
  1247  				tc.moduleName,
  1248  				fmt.Sprintf("--%s=json", ostcli.OutputFlag),
  1249  			})
  1250  			if tc.expectErr {
  1251  				s.Require().Error(err)
  1252  				s.Require().NotEqual("internal", err.Error())
  1253  			} else {
  1254  				var res authtypes.QueryModuleAccountByNameResponse
  1255  				s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
  1256  
  1257  				var account authtypes.AccountI
  1258  				err := val.ClientCtx.InterfaceRegistry.UnpackAny(res.Account, &account)
  1259  				s.Require().NoError(err)
  1260  
  1261  				moduleAccount, ok := account.(authtypes.ModuleAccountI)
  1262  				s.Require().True(ok)
  1263  				s.Require().Equal(tc.moduleName, moduleAccount.GetName())
  1264  			}
  1265  		})
  1266  	}
  1267  }
  1268  
  1269  func TestGetBroadcastCommandOfflineFlag(t *testing.T) {
  1270  	clientCtx := client.Context{}.WithOffline(true)
  1271  	_ = clientCtx.WithTxConfig(simapp.MakeTestEncodingConfig().TxConfig)
  1272  
  1273  	cmd := authcli.GetBroadcastCommand()
  1274  	_ = testutil.ApplyMockIODiscardOutErr(cmd)
  1275  	cmd.SetArgs([]string{fmt.Sprintf("--%s=true", flags.FlagOffline), ""})
  1276  
  1277  	require.EqualError(t, cmd.Execute(), "cannot broadcast tx during offline mode")
  1278  }
  1279  
  1280  func TestGetBroadcastCommandWithoutOfflineFlag(t *testing.T) {
  1281  	clientCtx := client.Context{}
  1282  	txCfg := simapp.MakeTestEncodingConfig().TxConfig
  1283  	clientCtx = clientCtx.WithTxConfig(txCfg)
  1284  
  1285  	ctx := context.Background()
  1286  	ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
  1287  
  1288  	cmd := authcli.GetBroadcastCommand()
  1289  	_, out := testutil.ApplyMockIO(cmd)
  1290  
  1291  	// Create new file with tx
  1292  	builder := txCfg.NewTxBuilder()
  1293  	builder.SetGasLimit(200000)
  1294  	from, err := sdk.AccAddressFromBech32("link1xpesesq0zddk2ersedyezgtywr0q92a34ddfku")
  1295  	require.NoError(t, err)
  1296  	to, err := sdk.AccAddressFromBech32("link1xpesesq0zddk2ersedyezgtywr0q92a34ddfku")
  1297  	require.NoError(t, err)
  1298  	err = builder.SetMsgs(banktypes.NewMsgSend(from, to, sdk.Coins{sdk.NewInt64Coin("stake", 10000)}))
  1299  	require.NoError(t, err)
  1300  	txContents, err := txCfg.TxJSONEncoder()(builder.GetTx())
  1301  	require.NoError(t, err)
  1302  	txFile := testutil.WriteToNewTempFile(t, string(txContents))
  1303  
  1304  	cmd.SetArgs([]string{txFile.Name()})
  1305  	err = cmd.ExecuteContext(ctx)
  1306  	require.Error(t, err)
  1307  	require.Contains(t, err.Error(), "connect: connection refused")
  1308  	require.Contains(t, out.String(), "connect: connection refused")
  1309  }
  1310  
  1311  func (s *IntegrationTestSuite) TestQueryParamsCmd() {
  1312  	val := s.network.Validators[0]
  1313  
  1314  	testCases := []struct {
  1315  		name      string
  1316  		args      []string
  1317  		expectErr bool
  1318  	}{
  1319  		{
  1320  			"happy case",
  1321  			[]string{fmt.Sprintf("--%s=json", ostcli.OutputFlag)},
  1322  			false,
  1323  		},
  1324  		{
  1325  			"with specific height",
  1326  			[]string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", ostcli.OutputFlag)},
  1327  			false,
  1328  		},
  1329  	}
  1330  
  1331  	for _, tc := range testCases {
  1332  		s.Run(tc.name, func() {
  1333  			cmd := authcli.QueryParamsCmd()
  1334  			clientCtx := val.ClientCtx
  1335  
  1336  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
  1337  			if tc.expectErr {
  1338  				s.Require().Error(err)
  1339  				s.Require().NotEqual("internal", err.Error())
  1340  			} else {
  1341  				var authParams authtypes.Params
  1342  				s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &authParams))
  1343  				s.Require().NotNil(authParams.MaxMemoCharacters)
  1344  			}
  1345  		})
  1346  	}
  1347  }
  1348  
  1349  // TestTxWithoutPublicKey makes sure sending a proto tx message without the
  1350  // public key doesn't cause any error in the RPC layer (broadcast).
  1351  // See https://github.com/cosmos/cosmos-sdk/issues/7585 for more details.
  1352  func (s *IntegrationTestSuite) TestTxWithoutPublicKey() {
  1353  	val1 := s.network.Validators[0]
  1354  	txCfg := val1.ClientCtx.TxConfig
  1355  
  1356  	// Create a txBuilder with an unsigned tx.
  1357  	txBuilder := txCfg.NewTxBuilder()
  1358  	msg := banktypes.NewMsgSend(val1.Address, val1.Address, sdk.NewCoins(
  1359  		sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
  1360  	))
  1361  	err := txBuilder.SetMsgs(msg)
  1362  	s.Require().NoError(err)
  1363  	txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(150))))
  1364  	txBuilder.SetGasLimit(testdata.NewTestGasLimit())
  1365  	// Set empty signature to set signer infos.
  1366  	sigV2 := signing.SignatureV2{
  1367  		PubKey: val1.PubKey,
  1368  		Data: &signing.SingleSignatureData{
  1369  			SignMode:  txCfg.SignModeHandler().DefaultMode(),
  1370  			Signature: nil,
  1371  		},
  1372  	}
  1373  	err = txBuilder.SetSignatures(sigV2)
  1374  	s.Require().NoError(err)
  1375  
  1376  	// Create a file with the unsigned tx.
  1377  	txJSON, err := txCfg.TxJSONEncoder()(txBuilder.GetTx())
  1378  	s.Require().NoError(err)
  1379  	unsignedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON))
  1380  
  1381  	// Sign the file with the unsignedTx.
  1382  	signedTx, err := TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), fmt.Sprintf("--%s=true", cli.FlagOverwrite))
  1383  	s.Require().NoError(err)
  1384  
  1385  	// Remove the signerInfo's `public_key` field manually from the signedTx.
  1386  	// Note: this method is only used for test purposes! In general, one should
  1387  	// use txBuilder and TxEncoder/TxDecoder to manipulate txs.
  1388  	var tx tx.Tx
  1389  	err = val1.ClientCtx.Codec.UnmarshalJSON(signedTx.Bytes(), &tx)
  1390  	s.Require().NoError(err)
  1391  	tx.AuthInfo.SignerInfos[0].PublicKey = nil
  1392  	// Re-encode the tx again, to another file.
  1393  	txJSON, err = val1.ClientCtx.Codec.MarshalJSON(&tx)
  1394  	s.Require().NoError(err)
  1395  	signedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON))
  1396  	s.Require().True(strings.Contains(string(txJSON), "\"public_key\":null"))
  1397  
  1398  	// Broadcast tx, test that it shouldn't panic.
  1399  	val1.ClientCtx.BroadcastMode = flags.BroadcastSync
  1400  	out, err := TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
  1401  	s.Require().NoError(err)
  1402  	var res sdk.TxResponse
  1403  	s.Require().NoError(val1.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
  1404  	s.Require().NotEqual(0, res.Code)
  1405  }
  1406  
  1407  func (s *IntegrationTestSuite) TestSignWithMultiSignersAminoJSON() {
  1408  	// test case:
  1409  	// Create a transaction with 2 messages which has to be signed with 2 different keys
  1410  	// Sign and append the signatures using the CLI with Amino signing mode.
  1411  	// Finally send the transaction to the blockchain. It should work.
  1412  
  1413  	require := s.Require()
  1414  	val0, val1 := s.network.Validators[0], s.network.Validators[1]
  1415  	val0Coin := sdk.NewCoin(fmt.Sprintf("%stoken", val0.Moniker), sdk.NewInt(10))
  1416  	val1Coin := sdk.NewCoin(fmt.Sprintf("%stoken", val1.Moniker), sdk.NewInt(10))
  1417  	_, _, addr1 := testdata.KeyTestPubAddr()
  1418  
  1419  	// Creating a tx with 2 msgs from 2 signers: val0 and val1.
  1420  	// The validators need to sign with SIGN_MODE_LEGACY_AMINO_JSON,
  1421  	// because DIRECT doesn't support multi signers via the CLI.
  1422  	// Since we use amino, we don't need to pre-populate signer_infos.
  1423  	txBuilder := val0.ClientCtx.TxConfig.NewTxBuilder()
  1424  	err := txBuilder.SetMsgs(
  1425  		banktypes.NewMsgSend(val0.Address, addr1, sdk.NewCoins(val0Coin)),
  1426  		banktypes.NewMsgSend(val1.Address, addr1, sdk.NewCoins(val1Coin)),
  1427  	)
  1428  	require.NoError(err)
  1429  	txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))))
  1430  	txBuilder.SetGasLimit(testdata.NewTestGasLimit()) // min required is 101892
  1431  	require.Equal([]sdk.AccAddress{val0.Address, val1.Address}, txBuilder.GetTx().GetSigners())
  1432  
  1433  	// Write the unsigned tx into a file.
  1434  	txJSON, err := val0.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
  1435  	require.NoError(err)
  1436  	unsignedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON))
  1437  
  1438  	// Let val0 sign first the file with the unsignedTx.
  1439  	signedByVal0, err := TxSignExec(val0.ClientCtx, val0.Address, unsignedTxFile.Name(), "--overwrite", "--sign-mode=amino-json")
  1440  	require.NoError(err)
  1441  	signedByVal0File := testutil.WriteToNewTempFile(s.T(), signedByVal0.String())
  1442  
  1443  	// Then let val1 sign the file with signedByVal0.
  1444  	val1AccNum, val1Seq, err := val0.ClientCtx.AccountRetriever.GetAccountNumberSequence(val0.ClientCtx, val1.Address)
  1445  	require.NoError(err)
  1446  	signedTx, err := TxSignExec(
  1447  		val1.ClientCtx, val1.Address, signedByVal0File.Name(),
  1448  		"--offline", fmt.Sprintf("--account-number=%d", val1AccNum), fmt.Sprintf("--sequence=%d", val1Seq), "--sign-mode=amino-json",
  1449  	)
  1450  	require.NoError(err)
  1451  	signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String())
  1452  
  1453  	// Now let's try to send this tx.
  1454  	res, err := TxBroadcastExec(
  1455  		val0.ClientCtx,
  1456  		signedTxFile.Name(),
  1457  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1458  	)
  1459  
  1460  	require.NoError(err)
  1461  	var txRes sdk.TxResponse
  1462  	require.NoError(val0.ClientCtx.Codec.UnmarshalJSON(res.Bytes(), &txRes))
  1463  	require.Equal(uint32(0), txRes.Code)
  1464  
  1465  	// Make sure the addr1's balance got funded.
  1466  	queryResJSON, err := bankcli.QueryBalancesExec(val0.ClientCtx, addr1)
  1467  	require.NoError(err)
  1468  	var queryRes banktypes.QueryAllBalancesResponse
  1469  	err = val0.ClientCtx.Codec.UnmarshalJSON(queryResJSON.Bytes(), &queryRes)
  1470  	require.NoError(err)
  1471  	require.Equal(sdk.NewCoins(val0Coin, val1Coin), queryRes.Balances)
  1472  }
  1473  
  1474  func (s *IntegrationTestSuite) createBankMsg(val *network.Validator, toAddr sdk.AccAddress, amount sdk.Coins, extraFlags ...string) (testutil.BufferWriter, error) {
  1475  	flags := []string{
  1476  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1477  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1478  		fmt.Sprintf("--%s=%s", flags.FlagFees,
  1479  			sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1480  	}
  1481  
  1482  	flags = append(flags, extraFlags...)
  1483  	return bankcli.MsgSendExec(val.ClientCtx, val.Address, toAddr, amount, flags...)
  1484  }