github.com/Finschia/finschia-sdk@v0.49.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  		s.Run(tc.name, func() {
   315  			clientCtx := val.ClientCtx
   316  			out, err := ExecGrant(
   317  				val,
   318  				tc.args,
   319  			)
   320  			if tc.expectErr {
   321  				s.Require().Error(err)
   322  			} else {
   323  				var txResp sdk.TxResponse
   324  				s.Require().NoError(err)
   325  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
   326  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   327  			}
   328  		})
   329  	}
   330  }
   331  
   332  func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) {
   333  	cmd := stakingcli.NewDelegateCmd()
   334  	clientCtx := val.ClientCtx
   335  	return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
   336  }
   337  
   338  func (s *IntegrationTestSuite) TestCmdRevokeAuthorizations() {
   339  	val := s.network.Validators[0]
   340  
   341  	grantee := s.grantee[0]
   342  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   343  
   344  	// send-authorization
   345  	_, err := ExecGrant(
   346  		val,
   347  		[]string{
   348  			grantee.String(),
   349  			"send",
   350  			fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
   351  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   352  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   353  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   354  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   355  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   356  		},
   357  	)
   358  	s.Require().NoError(err)
   359  
   360  	// generic-authorization
   361  	_, err = ExecGrant(
   362  		val,
   363  		[]string{
   364  			grantee.String(),
   365  			"generic",
   366  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   367  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   368  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   369  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   370  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   371  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   372  		},
   373  	)
   374  	s.Require().NoError(err)
   375  
   376  	// generic-authorization used for amino testing
   377  	_, err = ExecGrant(
   378  		val,
   379  		[]string{
   380  			grantee.String(),
   381  			"generic",
   382  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgSubmitProposal),
   383  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   384  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
   385  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   386  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   387  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   388  			fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   389  		},
   390  	)
   391  	s.Require().NoError(err)
   392  
   393  	testCases := []struct {
   394  		name         string
   395  		args         []string
   396  		respType     proto.Message
   397  		expectedCode uint32
   398  		expectErr    bool
   399  	}{
   400  		{
   401  			"invalid grantee address",
   402  			[]string{
   403  				"invalid grantee",
   404  				typeMsgSend,
   405  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   406  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   407  			},
   408  			nil,
   409  			0,
   410  			true,
   411  		},
   412  		{
   413  			"invalid granter address",
   414  			[]string{
   415  				grantee.String(),
   416  				typeMsgSend,
   417  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
   418  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   419  			},
   420  			nil,
   421  			0,
   422  			true,
   423  		},
   424  		{
   425  			"Valid tx send authorization",
   426  			[]string{
   427  				grantee.String(),
   428  				typeMsgSend,
   429  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   430  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   431  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   432  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   433  			},
   434  			&sdk.TxResponse{}, 0,
   435  			false,
   436  		},
   437  		{
   438  			"Valid tx generic authorization",
   439  			[]string{
   440  				grantee.String(),
   441  				typeMsgVote,
   442  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   443  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   444  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   445  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   446  			},
   447  			&sdk.TxResponse{}, 0,
   448  			false,
   449  		},
   450  		{
   451  			"Valid tx with amino",
   452  			[]string{
   453  				grantee.String(),
   454  				typeMsgSubmitProposal,
   455  				fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   456  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   457  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   458  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   459  				fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   460  			},
   461  			&sdk.TxResponse{}, 0,
   462  			false,
   463  		},
   464  	}
   465  	for _, tc := range testCases {
   466  		s.Run(tc.name, func() {
   467  			cmd := cli.NewCmdRevokeAuthorization()
   468  			clientCtx := val.ClientCtx
   469  
   470  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   471  			if tc.expectErr {
   472  				s.Require().Error(err)
   473  			} else {
   474  				s.Require().NoError(err)
   475  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
   476  
   477  				txResp := tc.respType.(*sdk.TxResponse)
   478  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   479  			}
   480  		})
   481  	}
   482  }
   483  
   484  func (s *IntegrationTestSuite) TestExecAuthorizationWithExpiration() {
   485  	val := s.network.Validators[0]
   486  	grantee := s.grantee[0]
   487  	tenSeconds := time.Now().Add(time.Second * time.Duration(10)).Unix()
   488  
   489  	_, err := ExecGrant(
   490  		val,
   491  		[]string{
   492  			grantee.String(),
   493  			"generic",
   494  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   495  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   496  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   497  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   498  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, tenSeconds),
   499  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   500  		},
   501  	)
   502  	s.Require().NoError(err)
   503  	// msg vote
   504  	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())
   505  	execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
   506  
   507  	// waiting for authorization to expires
   508  	time.Sleep(12 * time.Second)
   509  
   510  	cmd := cli.NewCmdExecAuthorization()
   511  	clientCtx := val.ClientCtx
   512  
   513  	res, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{
   514  		execMsg.Name(),
   515  		fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   516  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   517  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   518  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   519  	})
   520  	s.Require().NoError(err)
   521  	s.Require().Contains(res.String(), "authorization not found")
   522  }
   523  
   524  func (s *IntegrationTestSuite) TestNewExecGenericAuthorized() {
   525  	val := s.network.Validators[0]
   526  	grantee := s.grantee[0]
   527  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   528  
   529  	_, err := ExecGrant(
   530  		val,
   531  		[]string{
   532  			grantee.String(),
   533  			"generic",
   534  			fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
   535  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   536  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   537  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   538  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   539  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   540  		},
   541  	)
   542  	s.Require().NoError(err)
   543  
   544  	// msg vote
   545  	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())
   546  	execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
   547  
   548  	testCases := []struct {
   549  		name         string
   550  		args         []string
   551  		respType     proto.Message
   552  		expectedCode uint32
   553  		expectErr    bool
   554  	}{
   555  		{
   556  			"fail invalid grantee",
   557  			[]string{
   558  				execMsg.Name(),
   559  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"),
   560  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   561  				fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   562  			},
   563  			nil,
   564  			0,
   565  			true,
   566  		},
   567  		{
   568  			"fail invalid json path",
   569  			[]string{
   570  				"/invalid/file.txt",
   571  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   572  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   573  			},
   574  			nil,
   575  			0,
   576  			true,
   577  		},
   578  		{
   579  			"valid txn",
   580  			[]string{
   581  				execMsg.Name(),
   582  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   583  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   584  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   585  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   586  			},
   587  			&sdk.TxResponse{},
   588  			0,
   589  			false,
   590  		},
   591  		{
   592  			"valid tx with amino",
   593  			[]string{
   594  				execMsg.Name(),
   595  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   596  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   597  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   598  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   599  				fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
   600  			},
   601  			&sdk.TxResponse{}, 0,
   602  			false,
   603  		},
   604  	}
   605  
   606  	for _, tc := range testCases {
   607  		s.Run(tc.name, func() {
   608  			cmd := cli.NewCmdExecAuthorization()
   609  			clientCtx := val.ClientCtx
   610  
   611  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   612  			if tc.expectErr {
   613  				s.Require().Error(err)
   614  			} else {
   615  				s.Require().NoError(err)
   616  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
   617  				txResp := tc.respType.(*sdk.TxResponse)
   618  				s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
   619  			}
   620  		})
   621  	}
   622  }
   623  
   624  func (s *IntegrationTestSuite) TestNewExecGrantAuthorized() {
   625  	val := s.network.Validators[0]
   626  	grantee := s.grantee[0]
   627  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   628  
   629  	_, err := ExecGrant(
   630  		val,
   631  		[]string{
   632  			grantee.String(),
   633  			"send",
   634  			fmt.Sprintf("--%s=12%stoken", cli.FlagSpendLimit, val.Moniker),
   635  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   636  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   637  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   638  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   639  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   640  		},
   641  	)
   642  	s.Require().NoError(err)
   643  	tokens := sdk.NewCoins(
   644  		sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(12)),
   645  	)
   646  	normalGeneratedTx, err := banktestutil.MsgSendExec(
   647  		val.ClientCtx,
   648  		val.Address,
   649  		grantee,
   650  		tokens,
   651  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   652  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   653  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   654  		fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
   655  	)
   656  	s.Require().NoError(err)
   657  	execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
   658  	testCases := []struct {
   659  		name         string
   660  		args         []string
   661  		expectedCode uint32
   662  		expectErr    bool
   663  	}{
   664  		{
   665  			"valid txn",
   666  			[]string{
   667  				execMsg.Name(),
   668  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   669  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   670  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   671  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   672  			},
   673  			0,
   674  			false,
   675  		},
   676  		{
   677  			"error over spent",
   678  			[]string{
   679  				execMsg.Name(),
   680  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   681  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   682  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   683  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   684  			},
   685  			4,
   686  			false,
   687  		},
   688  	}
   689  
   690  	for _, tc := range testCases {
   691  		s.Run(tc.name, func() {
   692  			cmd := cli.NewCmdExecAuthorization()
   693  			clientCtx := val.ClientCtx
   694  
   695  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   696  			if tc.expectErr {
   697  				s.Require().Error(err)
   698  			} else {
   699  				var response sdk.TxResponse
   700  				s.Require().NoError(err)
   701  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   702  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   703  			}
   704  		})
   705  	}
   706  }
   707  
   708  func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
   709  	val := s.network.Validators[0]
   710  	grantee := s.grantee[0]
   711  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   712  
   713  	_, err := ExecGrant(
   714  		val,
   715  		[]string{
   716  			grantee.String(),
   717  			"delegate",
   718  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   719  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   720  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   721  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   722  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   723  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   724  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   725  		},
   726  	)
   727  	s.Require().NoError(err)
   728  
   729  	tokens := sdk.NewCoins(
   730  		sdk.NewCoin("stake", sdk.NewInt(50)),
   731  	)
   732  
   733  	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(),
   734  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   735  	execMsg := testutil.WriteToNewTempFile(s.T(), delegateTx)
   736  
   737  	testCases := []struct {
   738  		name         string
   739  		args         []string
   740  		expectedCode uint32
   741  		expectErr    bool
   742  		errMsg       string
   743  	}{
   744  		{
   745  			"valid txn: (delegate half tokens)",
   746  			[]string{
   747  				execMsg.Name(),
   748  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   749  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   750  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   751  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   752  			},
   753  			0,
   754  			false,
   755  			"",
   756  		},
   757  		{
   758  			"valid txn: (delegate remaining half tokens)",
   759  			[]string{
   760  				execMsg.Name(),
   761  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   762  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   763  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   764  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   765  			},
   766  			0,
   767  			false,
   768  			"",
   769  		},
   770  		{
   771  			"failed with error no authorization found",
   772  			[]string{
   773  				execMsg.Name(),
   774  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   775  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   776  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   777  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   778  			},
   779  			4,
   780  			false,
   781  			"authorization not found",
   782  		},
   783  	}
   784  
   785  	for _, tc := range testCases {
   786  		s.Run(tc.name, func() {
   787  			cmd := cli.NewCmdExecAuthorization()
   788  			clientCtx := val.ClientCtx
   789  
   790  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   791  			if tc.expectErr {
   792  				s.Require().Error(err)
   793  				s.Require().Contains(err.Error(), tc.errMsg)
   794  			} else {
   795  				var response sdk.TxResponse
   796  				s.Require().NoError(err)
   797  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   798  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   799  			}
   800  		})
   801  	}
   802  
   803  	// test delegate no spend-limit
   804  	_, err = ExecGrant(
   805  		val,
   806  		[]string{
   807  			grantee.String(),
   808  			"delegate",
   809  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   810  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   811  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   812  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   813  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   814  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   815  		},
   816  	)
   817  	s.Require().NoError(err)
   818  	tokens = sdk.NewCoins(
   819  		sdk.NewCoin("stake", sdk.NewInt(50)),
   820  	)
   821  
   822  	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(),
   823  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   824  	execMsg = testutil.WriteToNewTempFile(s.T(), delegateTx)
   825  
   826  	testCases = []struct {
   827  		name         string
   828  		args         []string
   829  		expectedCode uint32
   830  		expectErr    bool
   831  		errMsg       string
   832  	}{
   833  		{
   834  			"valid txn",
   835  			[]string{
   836  				execMsg.Name(),
   837  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   838  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   839  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   840  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   841  			},
   842  			0,
   843  			false,
   844  			"",
   845  		},
   846  		{
   847  			"valid txn",
   848  			[]string{
   849  				execMsg.Name(),
   850  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   851  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   852  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   853  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   854  			},
   855  			0,
   856  			false,
   857  			"",
   858  		},
   859  	}
   860  
   861  	for _, tc := range testCases {
   862  		s.Run(tc.name, func() {
   863  			cmd := cli.NewCmdExecAuthorization()
   864  			clientCtx := val.ClientCtx
   865  
   866  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
   867  			if tc.expectErr {
   868  				s.Require().Error(err)
   869  				s.Require().Contains(err.Error(), tc.errMsg)
   870  			} else {
   871  				var response sdk.TxResponse
   872  				s.Require().NoError(err)
   873  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
   874  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
   875  			}
   876  		})
   877  	}
   878  
   879  	// test delegating to denied validator
   880  	_, err = ExecGrant(
   881  		val,
   882  		[]string{
   883  			grantee.String(),
   884  			"delegate",
   885  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   886  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   887  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   888  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   889  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   890  			fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
   891  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   892  		},
   893  	)
   894  	s.Require().NoError(err)
   895  
   896  	args := []string{
   897  		execMsg.Name(),
   898  		fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   899  		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   900  		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   901  		fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   902  	}
   903  	cmd := cli.NewCmdExecAuthorization()
   904  	out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
   905  	s.Require().NoError(err)
   906  	s.Contains(out.String(), fmt.Sprintf("cannot delegate/undelegate to %s validator", val.ValAddress.String()))
   907  }
   908  
   909  func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
   910  	val := s.network.Validators[0]
   911  	grantee := s.grantee[0]
   912  	twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
   913  
   914  	// granting undelegate msg authorization
   915  	_, err := ExecGrant(
   916  		val,
   917  		[]string{
   918  			grantee.String(),
   919  			"unbond",
   920  			fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
   921  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   922  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   923  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   924  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
   925  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
   926  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   927  		},
   928  	)
   929  	s.Require().NoError(err)
   930  
   931  	// delegating stakes to validator
   932  	_, err = execDelegate(
   933  		val,
   934  		[]string{
   935  			val.ValAddress.String(),
   936  			"100stake",
   937  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   938  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
   939  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   940  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   941  		},
   942  	)
   943  	s.Require().NoError(err)
   944  
   945  	tokens := sdk.NewCoins(
   946  		sdk.NewCoin("stake", sdk.NewInt(50)),
   947  	)
   948  
   949  	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(),
   950  		tokens.GetDenomByIndex(0), tokens[0].Amount)
   951  	execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx)
   952  
   953  	testCases := []struct {
   954  		name         string
   955  		args         []string
   956  		expectedCode uint32
   957  		expectErr    bool
   958  		errMsg       string
   959  	}{
   960  		{
   961  			"valid txn: (undelegate half tokens)",
   962  			[]string{
   963  				execMsg.Name(),
   964  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   965  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   966  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   967  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   968  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   969  			},
   970  			0,
   971  			false,
   972  			"",
   973  		},
   974  		{
   975  			"valid txn: (undelegate remaining half tokens)",
   976  			[]string{
   977  				execMsg.Name(),
   978  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   979  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   980  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   981  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   982  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   983  			},
   984  			0,
   985  			false,
   986  			"",
   987  		},
   988  		{
   989  			"failed with error no authorization found",
   990  			[]string{
   991  				execMsg.Name(),
   992  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
   993  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
   994  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
   995  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
   996  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   997  			},
   998  			4,
   999  			false,
  1000  			"authorization not found",
  1001  		},
  1002  	}
  1003  
  1004  	for _, tc := range testCases {
  1005  		s.Run(tc.name, func() {
  1006  			cmd := cli.NewCmdExecAuthorization()
  1007  			clientCtx := val.ClientCtx
  1008  
  1009  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
  1010  			if tc.expectErr {
  1011  				s.Require().Error(err)
  1012  				s.Require().Contains(err.Error(), tc.errMsg)
  1013  			} else {
  1014  				var response sdk.TxResponse
  1015  				s.Require().NoError(err)
  1016  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
  1017  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
  1018  			}
  1019  		})
  1020  	}
  1021  
  1022  	// grant undelegate authorization without limit
  1023  	_, err = ExecGrant(
  1024  		val,
  1025  		[]string{
  1026  			grantee.String(),
  1027  			"unbond",
  1028  			fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1029  			fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
  1030  			fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1031  			fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
  1032  			fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
  1033  			fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1034  		},
  1035  	)
  1036  	s.Require().NoError(err)
  1037  	tokens = sdk.NewCoins(
  1038  		sdk.NewCoin("stake", sdk.NewInt(50)),
  1039  	)
  1040  
  1041  	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(),
  1042  		tokens.GetDenomByIndex(0), tokens[0].Amount)
  1043  	execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx)
  1044  
  1045  	testCases = []struct {
  1046  		name         string
  1047  		args         []string
  1048  		expectedCode uint32
  1049  		expectErr    bool
  1050  		errMsg       string
  1051  	}{
  1052  		{
  1053  			"valid txn",
  1054  			[]string{
  1055  				execMsg.Name(),
  1056  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
  1057  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
  1058  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1059  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1060  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1061  			},
  1062  			0,
  1063  			false,
  1064  			"",
  1065  		},
  1066  		{
  1067  			"valid txn",
  1068  			[]string{
  1069  				execMsg.Name(),
  1070  				fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
  1071  				fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
  1072  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
  1073  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
  1074  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
  1075  			},
  1076  			0,
  1077  			false,
  1078  			"",
  1079  		},
  1080  	}
  1081  
  1082  	for _, tc := range testCases {
  1083  		s.Run(tc.name, func() {
  1084  			cmd := cli.NewCmdExecAuthorization()
  1085  			clientCtx := val.ClientCtx
  1086  
  1087  			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
  1088  			if tc.expectErr {
  1089  				s.Require().Error(err)
  1090  				s.Require().Contains(err.Error(), tc.errMsg)
  1091  			} else {
  1092  				var response sdk.TxResponse
  1093  				s.Require().NoError(err)
  1094  				s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
  1095  				s.Require().Equal(tc.expectedCode, response.Code, out.String())
  1096  			}
  1097  		})
  1098  	}
  1099  }