github.com/Finschia/finschia-sdk@v0.48.1/x/authz/client/testutil/tx.go (about)

     1  package testutil
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/gogo/protobuf/proto"
     8  	"github.com/stretchr/testify/suite"
     9  
    10  	"github.com/Finschia/finschia-sdk/client/flags"
    11  	"github.com/Finschia/finschia-sdk/crypto/hd"
    12  	"github.com/Finschia/finschia-sdk/crypto/keyring"
    13  	"github.com/Finschia/finschia-sdk/testutil"
    14  	clitestutil "github.com/Finschia/finschia-sdk/testutil/cli"
    15  	"github.com/Finschia/finschia-sdk/testutil/network"
    16  	sdk "github.com/Finschia/finschia-sdk/types"
    17  	"github.com/Finschia/finschia-sdk/x/authz/client/cli"
    18  	banktestutil "github.com/Finschia/finschia-sdk/x/bank/client/testutil"
    19  	bank "github.com/Finschia/finschia-sdk/x/bank/types"
    20  	govcli "github.com/Finschia/finschia-sdk/x/gov/client/cli"
    21  	govtestutil "github.com/Finschia/finschia-sdk/x/gov/client/testutil"
    22  	govtypes "github.com/Finschia/finschia-sdk/x/gov/types"
    23  	stakingcli "github.com/Finschia/finschia-sdk/x/staking/client/cli"
    24  )
    25  
    26  type IntegrationTestSuite struct {
    27  	suite.Suite
    28  
    29  	cfg     network.Config
    30  	network *network.Network
    31  	grantee []sdk.AccAddress
    32  }
    33  
    34  func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
    35  	return &IntegrationTestSuite{cfg: cfg}
    36  }
    37  
    38  func (s *IntegrationTestSuite) SetupSuite() {
    39  	s.T().Log("setting up integration test suite")
    40  
    41  	s.network = network.New(s.T(), s.cfg)
    42  
    43  	val := s.network.Validators[0]
    44  	s.grantee = make([]sdk.AccAddress, 2)
    45  
    46  	// Create new account in the keyring.
    47  	s.grantee[0] = s.createAccount("grantee1")
    48  	// Send some funds to the new account.
    49  	s.msgSendExec(s.grantee[0])
    50  
    51  	_, err := s.network.WaitForHeight(1)
    52  	s.Require().NoError(err)
    53  
    54  	// create a proposal with deposit
    55  	_, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(),
    56  		"Text Proposal 1", "Where is the title!?", govtypes.ProposalTypeText,
    57  		fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String()))
    58  	s.Require().NoError(err)
    59  
    60  	// Create new account in the keyring.
    61  	s.grantee[1] = s.createAccount("grantee2")
    62  	// Send some funds to the new account.
    63  	s.msgSendExec(s.grantee[1])
    64  
    65  	// grant send authorization to grantee2
    66  	out, err := ExecGrant(val, []string{
    67  		s.grantee[1].String(),
    68  		"send",
    69  		fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
    70  		fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
    71  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
    72  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
    73  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()),
    74  		fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
    75  	})
    76  	s.Require().NoError(err)
    77  	s.Require().Contains(out.String(), `"code":0`)
    78  
    79  	_, err = s.network.WaitForHeight(1)
    80  	s.Require().NoError(err)
    81  }
    82  
    83  func (s *IntegrationTestSuite) createAccount(uid string) sdk.AccAddress {
    84  	val := s.network.Validators[0]
    85  	// Create new account in the keyring.
    86  	info, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    87  	s.Require().NoError(err)
    88  	return sdk.AccAddress(info.GetPubKey().Address())
    89  }
    90  
    91  func (s *IntegrationTestSuite) msgSendExec(grantee sdk.AccAddress) {
    92  	val := s.network.Validators[0]
    93  	// Send some funds to the new account.
    94  	out, err := banktestutil.MsgSendExec(
    95  		val.ClientCtx,
    96  		val.Address,
    97  		grantee,
    98  		sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
    99  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   100  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   101  	)
   102  	s.Require().NoError(err)
   103  	s.Require().Contains(out.String(), `"code":0`)
   104  }
   105  
   106  func (s *IntegrationTestSuite) TearDownSuite() {
   107  	s.T().Log("tearing down integration test suite")
   108  	s.network.Cleanup()
   109  }
   110  
   111  var (
   112  	typeMsgSend           = bank.SendAuthorization{}.MsgTypeURL()
   113  	typeMsgVote           = sdk.MsgTypeURL(&govtypes.MsgVote{})
   114  	typeMsgSubmitProposal = sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{})
   115  )
   116  
   117  func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
   118  	val := s.network.Validators[0]
   119  	grantee := s.grantee[0]
   120  
   121  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   122  	pastHour := time.Now().Add(time.Minute * time.Duration(-60)).Unix()
   123  
   124  	testCases := []struct {
   125  		name         string
   126  		args         []string
   127  		expectedCode uint32
   128  		expectErr    bool
   129  	}{
   130  		{
   131  			"Invalid granter Address",
   132  			[]string{
   133  				"grantee_addr",
   134  				"send",
   135  				fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   136  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
   137  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   138  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   139  			},
   140  			0,
   141  			true,
   142  		},
   143  		{
   144  			"Invalid grantee Address",
   145  			[]string{
   146  				"grantee_addr",
   147  				"send",
   148  				fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   149  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   150  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   151  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   152  			},
   153  			0,
   154  			true,
   155  		},
   156  		{
   157  			"Invalid expiration time",
   158  			[]string{
   159  				grantee.String(),
   160  				"send",
   161  				fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   162  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   163  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   164  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour),
   165  			},
   166  			0xd,
   167  			false, // TODO: enable in v0.45
   168  		},
   169  		{
   170  			"fail with error invalid msg-type",
   171  			[]string{
   172  				grantee.String(),
   173  				"generic",
   174  				fmt.Sprintf("--%s=invalid-msg-type", cli.FlagMsgType),
   175  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   176  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   177  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   178  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   179  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   180  			},
   181  			0x1d,
   182  			false,
   183  		},
   184  		{
   185  			"failed with error both validators not allowed",
   186  			[]string{
   187  				grantee.String(),
   188  				"delegate",
   189  				fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   190  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   191  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   192  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   193  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   194  				fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   195  				fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
   196  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   197  			},
   198  			0,
   199  			true,
   200  		},
   201  		{
   202  			"valid tx delegate authorization allowed validators",
   203  			[]string{
   204  				grantee.String(),
   205  				"delegate",
   206  				fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   207  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   208  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   209  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   210  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   211  				fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   212  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   213  			},
   214  			0,
   215  			false,
   216  		},
   217  		{
   218  			"valid tx delegate authorization deny validators",
   219  			[]string{
   220  				grantee.String(),
   221  				"delegate",
   222  				fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   223  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   224  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   225  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   226  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   227  				fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
   228  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   229  			},
   230  			0,
   231  			false,
   232  		},
   233  		{
   234  			"valid tx undelegate authorization",
   235  			[]string{
   236  				grantee.String(),
   237  				"unbond",
   238  				fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   239  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   240  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   241  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   242  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   243  				fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   244  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   245  			},
   246  			0,
   247  			false,
   248  		},
   249  		{
   250  			"valid tx redelegate authorization",
   251  			[]string{
   252  				grantee.String(),
   253  				"redelegate",
   254  				fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   255  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   256  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   257  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   258  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   259  				fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   260  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   261  			},
   262  			0,
   263  			false,
   264  		},
   265  		{
   266  			"Valid tx send authorization",
   267  			[]string{
   268  				grantee.String(),
   269  				"send",
   270  				fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   271  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   272  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   273  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   274  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   275  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   276  			},
   277  			0,
   278  			false,
   279  		},
   280  		{
   281  			"Valid tx generic authorization",
   282  			[]string{
   283  				grantee.String(),
   284  				"generic",
   285  				fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   286  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   287  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   288  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   289  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   290  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   291  			},
   292  			0,
   293  			false,
   294  		},
   295  		{
   296  			"Valid tx with amino",
   297  			[]string{
   298  				grantee.String(),
   299  				"generic",
   300  				fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   301  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   302  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   303  				fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   304  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   305  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   306  				fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   307  			},
   308  			0,
   309  			false,
   310  		},
   311  	}
   312  
   313  	for _, tc := range testCases {
   314  		tc := tc
   315  		s.Run(tc.name, func() {
   316  			clientCtx := val.ClientCtx
   317  			out, err := ExecGrant(
   318  				val,
   319  				tc.args,
   320  			)
   321  			if tc.expectErr {
   322  				s.Require().Error(err)
   323  			} else {
   324  				var txResp sdk.TxResponse
   325  				s.Require().NoError(err)
   326  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
   327  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   328  			}
   329  		})
   330  	}
   331  }
   332  
   333  func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) {
   334  	cmd := stakingcli.NewDelegateCmd()
   335  	clientCtx := val.ClientCtx
   336  	return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
   337  }
   338  
   339  func (s *IntegrationTestSuite) TestCmdRevokeAuthorizations() {
   340  	val := s.network.Validators[0]
   341  
   342  	grantee := s.grantee[0]
   343  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   344  
   345  	// send-authorization
   346  	_, err := ExecGrant(
   347  		val,
   348  		[]string{
   349  			grantee.String(),
   350  			"send",
   351  			fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   352  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   353  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   354  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   355  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   356  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   357  		},
   358  	)
   359  	s.Require().NoError(err)
   360  
   361  	// generic-authorization
   362  	_, err = ExecGrant(
   363  		val,
   364  		[]string{
   365  			grantee.String(),
   366  			"generic",
   367  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   368  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   369  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   370  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   371  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   372  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   373  		},
   374  	)
   375  	s.Require().NoError(err)
   376  
   377  	// generic-authorization used for amino testing
   378  	_, err = ExecGrant(
   379  		val,
   380  		[]string{
   381  			grantee.String(),
   382  			"generic",
   383  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgSubmitProposal),
   384  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   385  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   386  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   387  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   388  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   389  			fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   390  		},
   391  	)
   392  	s.Require().NoError(err)
   393  
   394  	testCases := []struct {
   395  		name         string
   396  		args         []string
   397  		respType     proto.Message
   398  		expectedCode uint32
   399  		expectErr    bool
   400  	}{
   401  		{
   402  			"invalid grantee address",
   403  			[]string{
   404  				"invalid grantee",
   405  				typeMsgSend,
   406  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   407  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   408  			},
   409  			nil,
   410  			0,
   411  			true,
   412  		},
   413  		{
   414  			"invalid granter address",
   415  			[]string{
   416  				grantee.String(),
   417  				typeMsgSend,
   418  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
   419  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   420  			},
   421  			nil,
   422  			0,
   423  			true,
   424  		},
   425  		{
   426  			"Valid tx send authorization",
   427  			[]string{
   428  				grantee.String(),
   429  				typeMsgSend,
   430  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   431  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   432  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   433  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   434  			},
   435  			&sdk.TxResponse{}, 0,
   436  			false,
   437  		},
   438  		{
   439  			"Valid tx generic authorization",
   440  			[]string{
   441  				grantee.String(),
   442  				typeMsgVote,
   443  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   444  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   445  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   446  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   447  			},
   448  			&sdk.TxResponse{}, 0,
   449  			false,
   450  		},
   451  		{
   452  			"Valid tx with amino",
   453  			[]string{
   454  				grantee.String(),
   455  				typeMsgSubmitProposal,
   456  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   457  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   458  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   459  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   460  				fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   461  			},
   462  			&sdk.TxResponse{}, 0,
   463  			false,
   464  		},
   465  	}
   466  	for _, tc := range testCases {
   467  		tc := tc
   468  		s.Run(tc.name, func() {
   469  			cmd := cli.NewCmdRevokeAuthorization()
   470  			clientCtx := val.ClientCtx
   471  
   472  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   473  			if tc.expectErr {
   474  				s.Require().Error(err)
   475  			} else {
   476  				s.Require().NoError(err)
   477  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
   478  
   479  				txResp := tc.respType.(*sdk.TxResponse)
   480  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   481  			}
   482  		})
   483  	}
   484  }
   485  
   486  func (s *IntegrationTestSuite) TestExecAuthorizationWithExpiration() {
   487  	val := s.network.Validators[0]
   488  	grantee := s.grantee[0]
   489  	tenSeconds := time.Now().Add(time.Second * time.Duration(10)).Unix()
   490  
   491  	_, err := ExecGrant(
   492  		val,
   493  		[]string{
   494  			grantee.String(),
   495  			"generic",
   496  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   497  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   498  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   499  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   500  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, tenSeconds),
   501  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   502  		},
   503  	)
   504  	s.Require().NoError(err)
   505  	// msg vote
   506  	voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
   507  	execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
   508  
   509  	// waiting for authorization to expires
   510  	time.Sleep(12 * time.Second)
   511  
   512  	cmd := cli.NewCmdExecAuthorization()
   513  	clientCtx := val.ClientCtx
   514  
   515  	res, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{
   516  		execMsg.Name(),
   517  		fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   518  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   519  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   520  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   521  	})
   522  	s.Require().NoError(err)
   523  	s.Require().Contains(res.String(), "authorization not found")
   524  }
   525  
   526  func (s *IntegrationTestSuite) TestNewExecGenericAuthorized() {
   527  	val := s.network.Validators[0]
   528  	grantee := s.grantee[0]
   529  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   530  
   531  	_, err := ExecGrant(
   532  		val,
   533  		[]string{
   534  			grantee.String(),
   535  			"generic",
   536  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   537  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   538  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   539  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   540  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   541  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   542  		},
   543  	)
   544  	s.Require().NoError(err)
   545  
   546  	// msg vote
   547  	voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
   548  	execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
   549  
   550  	testCases := []struct {
   551  		name         string
   552  		args         []string
   553  		respType     proto.Message
   554  		expectedCode uint32
   555  		expectErr    bool
   556  	}{
   557  		{
   558  			"fail invalid grantee",
   559  			[]string{
   560  				execMsg.Name(),
   561  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"),
   562  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   563  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   564  			},
   565  			nil,
   566  			0,
   567  			true,
   568  		},
   569  		{
   570  			"fail invalid json path",
   571  			[]string{
   572  				"/invalid/file.txt",
   573  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   574  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   575  			},
   576  			nil,
   577  			0,
   578  			true,
   579  		},
   580  		{
   581  			"valid txn",
   582  			[]string{
   583  				execMsg.Name(),
   584  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   585  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   586  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   587  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   588  			},
   589  			&sdk.TxResponse{},
   590  			0,
   591  			false,
   592  		},
   593  		{
   594  			"valid tx with amino",
   595  			[]string{
   596  				execMsg.Name(),
   597  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   598  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   599  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   600  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   601  				fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   602  			},
   603  			&sdk.TxResponse{}, 0,
   604  			false,
   605  		},
   606  	}
   607  
   608  	for _, tc := range testCases {
   609  		tc := tc
   610  		s.Run(tc.name, func() {
   611  			cmd := cli.NewCmdExecAuthorization()
   612  			clientCtx := val.ClientCtx
   613  
   614  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   615  			if tc.expectErr {
   616  				s.Require().Error(err)
   617  			} else {
   618  				s.Require().NoError(err)
   619  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
   620  				txResp := tc.respType.(*sdk.TxResponse)
   621  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   622  			}
   623  		})
   624  	}
   625  }
   626  
   627  func (s *IntegrationTestSuite) TestNewExecGrantAuthorized() {
   628  	val := s.network.Validators[0]
   629  	grantee := s.grantee[0]
   630  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   631  
   632  	_, err := ExecGrant(
   633  		val,
   634  		[]string{
   635  			grantee.String(),
   636  			"send",
   637  			fmt.Sprintf("--%s=12%stoken", cli.FlagSpendLimit, val.Moniker),
   638  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   639  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   640  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   641  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   642  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   643  		},
   644  	)
   645  	s.Require().NoError(err)
   646  	tokens := sdk.NewCoins(
   647  		sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(12)),
   648  	)
   649  	normalGeneratedTx, err := banktestutil.MsgSendExec(
   650  		val.ClientCtx,
   651  		val.Address,
   652  		grantee,
   653  		tokens,
   654  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   655  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   656  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   657  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   658  	)
   659  	s.Require().NoError(err)
   660  	execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
   661  	testCases := []struct {
   662  		name         string
   663  		args         []string
   664  		expectedCode uint32
   665  		expectErr    bool
   666  	}{
   667  		{
   668  			"valid txn",
   669  			[]string{
   670  				execMsg.Name(),
   671  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   672  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   673  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   674  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   675  			},
   676  			0,
   677  			false,
   678  		},
   679  		{
   680  			"error over spent",
   681  			[]string{
   682  				execMsg.Name(),
   683  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   684  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   685  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   686  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   687  			},
   688  			4,
   689  			false,
   690  		},
   691  	}
   692  
   693  	for _, tc := range testCases {
   694  		tc := tc
   695  		s.Run(tc.name, func() {
   696  			cmd := cli.NewCmdExecAuthorization()
   697  			clientCtx := val.ClientCtx
   698  
   699  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   700  			if tc.expectErr {
   701  				s.Require().Error(err)
   702  			} else {
   703  				var response sdk.TxResponse
   704  				s.Require().NoError(err)
   705  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   706  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   707  			}
   708  		})
   709  	}
   710  }
   711  
   712  func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
   713  	val := s.network.Validators[0]
   714  	grantee := s.grantee[0]
   715  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   716  
   717  	_, err := ExecGrant(
   718  		val,
   719  		[]string{
   720  			grantee.String(),
   721  			"delegate",
   722  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   723  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   724  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   725  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   726  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   727  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   728  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   729  		},
   730  	)
   731  	s.Require().NoError(err)
   732  
   733  	tokens := sdk.NewCoins(
   734  		sdk.NewCoin("stake", sdk.NewInt(50)),
   735  	)
   736  
   737  	delegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
   738  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   739  	execMsg := testutil.WriteToNewTempFile(s.T(), delegateTx)
   740  
   741  	testCases := []struct {
   742  		name         string
   743  		args         []string
   744  		expectedCode uint32
   745  		expectErr    bool
   746  		errMsg       string
   747  	}{
   748  		{
   749  			"valid txn: (delegate half tokens)",
   750  			[]string{
   751  				execMsg.Name(),
   752  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   753  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   754  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   755  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   756  			},
   757  			0,
   758  			false,
   759  			"",
   760  		},
   761  		{
   762  			"valid txn: (delegate remaining half tokens)",
   763  			[]string{
   764  				execMsg.Name(),
   765  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   766  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   767  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   768  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   769  			},
   770  			0,
   771  			false,
   772  			"",
   773  		},
   774  		{
   775  			"failed with error no authorization found",
   776  			[]string{
   777  				execMsg.Name(),
   778  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   779  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   780  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   781  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   782  			},
   783  			4,
   784  			false,
   785  			"authorization not found",
   786  		},
   787  	}
   788  
   789  	for _, tc := range testCases {
   790  		tc := tc
   791  		s.Run(tc.name, func() {
   792  			cmd := cli.NewCmdExecAuthorization()
   793  			clientCtx := val.ClientCtx
   794  
   795  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   796  			if tc.expectErr {
   797  				s.Require().Error(err)
   798  				s.Require().Contains(err.Error(), tc.errMsg)
   799  			} else {
   800  				var response sdk.TxResponse
   801  				s.Require().NoError(err)
   802  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   803  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   804  			}
   805  		})
   806  	}
   807  
   808  	// test delegate no spend-limit
   809  	_, err = ExecGrant(
   810  		val,
   811  		[]string{
   812  			grantee.String(),
   813  			"delegate",
   814  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   815  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   816  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   817  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   818  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   819  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   820  		},
   821  	)
   822  	s.Require().NoError(err)
   823  	tokens = sdk.NewCoins(
   824  		sdk.NewCoin("stake", sdk.NewInt(50)),
   825  	)
   826  
   827  	delegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
   828  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   829  	execMsg = testutil.WriteToNewTempFile(s.T(), delegateTx)
   830  
   831  	testCases = []struct {
   832  		name         string
   833  		args         []string
   834  		expectedCode uint32
   835  		expectErr    bool
   836  		errMsg       string
   837  	}{
   838  		{
   839  			"valid txn",
   840  			[]string{
   841  				execMsg.Name(),
   842  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   843  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   844  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   845  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   846  			},
   847  			0,
   848  			false,
   849  			"",
   850  		},
   851  		{
   852  			"valid txn",
   853  			[]string{
   854  				execMsg.Name(),
   855  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   856  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   857  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   858  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   859  			},
   860  			0,
   861  			false,
   862  			"",
   863  		},
   864  	}
   865  
   866  	for _, tc := range testCases {
   867  		tc := tc
   868  		s.Run(tc.name, func() {
   869  			cmd := cli.NewCmdExecAuthorization()
   870  			clientCtx := val.ClientCtx
   871  
   872  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   873  			if tc.expectErr {
   874  				s.Require().Error(err)
   875  				s.Require().Contains(err.Error(), tc.errMsg)
   876  			} else {
   877  				var response sdk.TxResponse
   878  				s.Require().NoError(err)
   879  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   880  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   881  			}
   882  		})
   883  	}
   884  
   885  	// test delegating to denied validator
   886  	_, err = ExecGrant(
   887  		val,
   888  		[]string{
   889  			grantee.String(),
   890  			"delegate",
   891  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   892  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   893  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   894  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   895  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   896  			fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
   897  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   898  		},
   899  	)
   900  	s.Require().NoError(err)
   901  
   902  	args := []string{
   903  		execMsg.Name(),
   904  		fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   905  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   906  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   907  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   908  	}
   909  	cmd := cli.NewCmdExecAuthorization()
   910  	out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
   911  	s.Require().NoError(err)
   912  	s.Contains(out.String(), fmt.Sprintf("cannot delegate/undelegate to %s validator", val.ValAddress.String()))
   913  }
   914  
   915  func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
   916  	val := s.network.Validators[0]
   917  	grantee := s.grantee[0]
   918  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   919  
   920  	// granting undelegate msg authorization
   921  	_, err := ExecGrant(
   922  		val,
   923  		[]string{
   924  			grantee.String(),
   925  			"unbond",
   926  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   927  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   928  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   929  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   930  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   931  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   932  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   933  		},
   934  	)
   935  	s.Require().NoError(err)
   936  
   937  	// delegating stakes to validator
   938  	_, err = execDelegate(
   939  		val,
   940  		[]string{
   941  			val.ValAddress.String(),
   942  			"100stake",
   943  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   944  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   945  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   946  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   947  		},
   948  	)
   949  	s.Require().NoError(err)
   950  
   951  	tokens := sdk.NewCoins(
   952  		sdk.NewCoin("stake", sdk.NewInt(50)),
   953  	)
   954  
   955  	undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
   956  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   957  	execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx)
   958  
   959  	testCases := []struct {
   960  		name         string
   961  		args         []string
   962  		expectedCode uint32
   963  		expectErr    bool
   964  		errMsg       string
   965  	}{
   966  		{
   967  			"valid txn: (undelegate half tokens)",
   968  			[]string{
   969  				execMsg.Name(),
   970  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   971  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   972  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   973  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   974  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   975  			},
   976  			0,
   977  			false,
   978  			"",
   979  		},
   980  		{
   981  			"valid txn: (undelegate remaining half tokens)",
   982  			[]string{
   983  				execMsg.Name(),
   984  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   985  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   986  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   987  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   988  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   989  			},
   990  			0,
   991  			false,
   992  			"",
   993  		},
   994  		{
   995  			"failed with error no authorization found",
   996  			[]string{
   997  				execMsg.Name(),
   998  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   999  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
  1000  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1001  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1002  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1003  			},
  1004  			4,
  1005  			false,
  1006  			"authorization not found",
  1007  		},
  1008  	}
  1009  
  1010  	for _, tc := range testCases {
  1011  		tc := tc
  1012  		s.Run(tc.name, func() {
  1013  			cmd := cli.NewCmdExecAuthorization()
  1014  			clientCtx := val.ClientCtx
  1015  
  1016  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
  1017  			if tc.expectErr {
  1018  				s.Require().Error(err)
  1019  				s.Require().Contains(err.Error(), tc.errMsg)
  1020  			} else {
  1021  				var response sdk.TxResponse
  1022  				s.Require().NoError(err)
  1023  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
  1024  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
  1025  			}
  1026  		})
  1027  	}
  1028  
  1029  	// grant undelegate authorization without limit
  1030  	_, err = ExecGrant(
  1031  		val,
  1032  		[]string{
  1033  			grantee.String(),
  1034  			"unbond",
  1035  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1036  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
  1037  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1038  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
  1039  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
  1040  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1041  		},
  1042  	)
  1043  	s.Require().NoError(err)
  1044  	tokens = sdk.NewCoins(
  1045  		sdk.NewCoin("stake", sdk.NewInt(50)),
  1046  	)
  1047  
  1048  	undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
  1049  		tokens.GetDenomByIndex(0), tokens[0].Amount)
  1050  	execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx)
  1051  
  1052  	testCases = []struct {
  1053  		name         string
  1054  		args         []string
  1055  		expectedCode uint32
  1056  		expectErr    bool
  1057  		errMsg       string
  1058  	}{
  1059  		{
  1060  			"valid txn",
  1061  			[]string{
  1062  				execMsg.Name(),
  1063  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
  1064  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
  1065  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1066  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1067  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1068  			},
  1069  			0,
  1070  			false,
  1071  			"",
  1072  		},
  1073  		{
  1074  			"valid txn",
  1075  			[]string{
  1076  				execMsg.Name(),
  1077  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
  1078  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
  1079  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1080  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1081  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1082  			},
  1083  			0,
  1084  			false,
  1085  			"",
  1086  		},
  1087  	}
  1088  
  1089  	for _, tc := range testCases {
  1090  		tc := tc
  1091  		s.Run(tc.name, func() {
  1092  			cmd := cli.NewCmdExecAuthorization()
  1093  			clientCtx := val.ClientCtx
  1094  
  1095  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
  1096  			if tc.expectErr {
  1097  				s.Require().Error(err)
  1098  				s.Require().Contains(err.Error(), tc.errMsg)
  1099  			} else {
  1100  				var response sdk.TxResponse
  1101  				s.Require().NoError(err)
  1102  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
  1103  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
  1104  			}
  1105  		})
  1106  	}
  1107  }