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