github.com/Finschia/finschia-sdk@v0.49.1/x/feegrant/client/testutil/suite.go (about) 1 package testutil 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 ostcli "github.com/Finschia/ostracon/libs/cli" 10 "github.com/gogo/protobuf/proto" 11 "github.com/stretchr/testify/suite" 12 13 "github.com/Finschia/finschia-sdk/client" 14 "github.com/Finschia/finschia-sdk/client/flags" 15 "github.com/Finschia/finschia-sdk/crypto/hd" 16 "github.com/Finschia/finschia-sdk/crypto/keyring" 17 "github.com/Finschia/finschia-sdk/testutil" 18 clitestutil "github.com/Finschia/finschia-sdk/testutil/cli" 19 "github.com/Finschia/finschia-sdk/testutil/network" 20 sdk "github.com/Finschia/finschia-sdk/types" 21 "github.com/Finschia/finschia-sdk/x/feegrant" 22 "github.com/Finschia/finschia-sdk/x/feegrant/client/cli" 23 govtestutil "github.com/Finschia/finschia-sdk/x/gov/client/testutil" 24 govtypes "github.com/Finschia/finschia-sdk/x/gov/types" 25 ) 26 27 const ( 28 oneYear = 365 * 24 * 60 * 60 29 tenHours = 10 * 60 * 60 30 oneHour = 60 * 60 31 ) 32 33 type IntegrationTestSuite struct { 34 suite.Suite 35 36 cfg network.Config 37 network *network.Network 38 addedGranter sdk.AccAddress 39 addedGrantee sdk.AccAddress 40 addedGrant feegrant.Grant 41 } 42 43 func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { 44 return &IntegrationTestSuite{cfg: cfg} 45 } 46 47 func (s *IntegrationTestSuite) SetupSuite() { 48 s.T().Log("setting up integration test suite") 49 50 if testing.Short() { 51 s.T().Skip("skipping test in unit-tests mode.") 52 } 53 54 s.network = network.New(s.T(), s.cfg) 55 56 _, err := s.network.WaitForHeight(1) 57 s.Require().NoError(err) 58 59 val := s.network.Validators[0] 60 granter := val.Address 61 grantee := s.network.Validators[1].Address 62 63 s.createGrant(granter, grantee) 64 65 grant, err := feegrant.NewGrant(granter, grantee, &feegrant.BasicAllowance{ 66 SpendLimit: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), 67 }) 68 s.Require().NoError(err) 69 70 s.addedGrant = grant 71 s.addedGranter = granter 72 s.addedGrantee = grantee 73 } 74 75 // createGrant creates a new basic allowance fee grant from granter to grantee. 76 func (s *IntegrationTestSuite) createGrant(granter, grantee sdk.Address) { 77 val := s.network.Validators[0] 78 79 clientCtx := val.ClientCtx 80 commonFlags := []string{ 81 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 82 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 83 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 84 } 85 86 fee := sdk.NewCoin("stake", sdk.NewInt(100)) 87 88 args := append( 89 []string{ 90 granter.String(), 91 grantee.String(), 92 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, fee.String()), 93 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 94 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneYear)), 95 }, 96 commonFlags..., 97 ) 98 99 cmd := cli.NewCmdFeeGrant() 100 101 _, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) 102 s.Require().NoError(err) 103 _, err = s.network.WaitForHeight(1) 104 s.Require().NoError(err) 105 } 106 107 func (s *IntegrationTestSuite) TearDownSuite() { 108 s.T().Log("tearing down integration test suite") 109 s.network.Cleanup() 110 } 111 112 func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { 113 val := s.network.Validators[0] 114 granter := val.Address 115 grantee := s.addedGrantee 116 clientCtx := val.ClientCtx 117 118 testCases := []struct { 119 name string 120 args []string 121 expectErrMsg string 122 expectErr bool 123 respType *feegrant.Grant 124 resp *feegrant.Grant 125 }{ 126 { 127 "wrong granter", 128 []string{ 129 "wrong_granter", 130 grantee.String(), 131 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 132 }, 133 "decoding bech32 failed", 134 true, nil, nil, 135 }, 136 { 137 "wrong grantee", 138 []string{ 139 granter.String(), 140 "wrong_grantee", 141 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 142 }, 143 "decoding bech32 failed", 144 true, nil, nil, 145 }, 146 { 147 "non existed grant", 148 []string{ 149 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 150 grantee.String(), 151 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 152 }, 153 "fee-grant not found", 154 true, nil, nil, 155 }, 156 { 157 "valid req", 158 []string{ 159 granter.String(), 160 grantee.String(), 161 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 162 }, 163 "", 164 false, 165 &feegrant.Grant{}, 166 &s.addedGrant, 167 }, 168 } 169 170 for _, tc := range testCases { 171 s.Run(tc.name, func() { 172 cmd := cli.GetCmdQueryFeeGrant() 173 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 174 175 if tc.expectErr { 176 s.Require().Error(err) 177 s.Require().Contains(err.Error(), tc.expectErrMsg) 178 } else { 179 s.Require().NoError(err) 180 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) 181 s.Require().Equal(tc.respType.Grantee, tc.respType.Grantee) 182 s.Require().Equal(tc.respType.Granter, tc.respType.Granter) 183 grant, err := tc.respType.GetGrant() 184 s.Require().NoError(err) 185 grant1, err1 := tc.resp.GetGrant() 186 s.Require().NoError(err1) 187 s.Require().Equal( 188 grant.(*feegrant.BasicAllowance).SpendLimit, 189 grant1.(*feegrant.BasicAllowance).SpendLimit, 190 ) 191 } 192 }) 193 } 194 } 195 196 func (s *IntegrationTestSuite) TestCmdGetFeeGrantsByGrantee() { 197 val := s.network.Validators[0] 198 grantee := s.addedGrantee 199 clientCtx := val.ClientCtx 200 201 testCases := []struct { 202 name string 203 args []string 204 expectErr bool 205 resp *feegrant.QueryAllowancesResponse 206 expectLength int 207 }{ 208 { 209 "wrong grantee", 210 []string{ 211 "wrong_grantee", 212 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 213 }, 214 true, nil, 0, 215 }, 216 { 217 "non existent grantee", 218 []string{ 219 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 220 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 221 }, 222 false, &feegrant.QueryAllowancesResponse{}, 0, 223 }, 224 { 225 "valid req", 226 []string{ 227 grantee.String(), 228 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 229 }, 230 false, &feegrant.QueryAllowancesResponse{}, 1, 231 }, 232 } 233 234 for _, tc := range testCases { 235 s.Run(tc.name, func() { 236 cmd := cli.GetCmdQueryFeeGrantsByGrantee() 237 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 238 239 if tc.expectErr { 240 s.Require().Error(err) 241 } else { 242 s.Require().NoError(err) 243 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) 244 s.Require().Len(tc.resp.Allowances, tc.expectLength) 245 } 246 }) 247 } 248 } 249 250 func (s *IntegrationTestSuite) TestCmdGetFeeGrantsByGranter() { 251 val := s.network.Validators[0] 252 granter := s.addedGranter 253 clientCtx := val.ClientCtx 254 255 testCases := []struct { 256 name string 257 args []string 258 expectErr bool 259 resp *feegrant.QueryAllowancesByGranterResponse 260 expectLength int 261 }{ 262 { 263 "wrong grantee", 264 []string{ 265 "wrong_grantee", 266 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 267 }, 268 true, nil, 0, 269 }, 270 { 271 "non existent grantee", 272 []string{ 273 "link1nph3cfzk6trsmfxkeu943nvach5qw4vw99nwdh", 274 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 275 }, 276 false, &feegrant.QueryAllowancesByGranterResponse{}, 0, 277 }, 278 { 279 "valid req", 280 []string{ 281 granter.String(), 282 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 283 }, 284 false, &feegrant.QueryAllowancesByGranterResponse{}, 1, 285 }, 286 } 287 288 for _, tc := range testCases { 289 s.Run(tc.name, func() { 290 cmd := cli.GetCmdQueryFeeGrantsByGranter() 291 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 292 293 if tc.expectErr { 294 s.Require().Error(err) 295 } else { 296 s.Require().NoError(err) 297 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) 298 s.Require().Len(tc.resp.Allowances, tc.expectLength) 299 } 300 }) 301 } 302 } 303 304 func (s *IntegrationTestSuite) TestNewCmdFeeGrant() { 305 val := s.network.Validators[0] 306 granter := val.Address 307 alreadyExistedGrantee := s.addedGrantee 308 clientCtx := val.ClientCtx 309 310 fromAddr, fromName, _, err := client.GetFromFields(clientCtx.Keyring, granter.String(), clientCtx.GenerateOnly) 311 s.Require().Equal(fromAddr, granter) 312 s.Require().NoError(err) 313 314 commonFlags := []string{ 315 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 316 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 317 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 318 } 319 320 testCases := []struct { 321 name string 322 args []string 323 expectErr bool 324 expectedCode uint32 325 respType proto.Message 326 }{ 327 { 328 "wrong granter address", 329 append( 330 []string{ 331 "wrong_granter", 332 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 333 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 334 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 335 }, 336 commonFlags..., 337 ), 338 true, 0, nil, 339 }, 340 { 341 "wrong grantee address", 342 append( 343 []string{ 344 granter.String(), 345 "wrong_grantee", 346 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 347 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 348 }, 349 commonFlags..., 350 ), 351 true, 0, nil, 352 }, 353 { 354 "wrong granter key name", 355 append( 356 []string{ 357 "invalid_granter", 358 "link1rsx5wakg9kxfa05ueqjpkher9yddy3u4n47f9z", 359 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 360 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 361 }, 362 commonFlags..., 363 ), 364 true, 0, nil, 365 }, 366 { 367 "valid basic fee grant", 368 append( 369 []string{ 370 granter.String(), 371 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 372 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 373 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 374 }, 375 commonFlags..., 376 ), 377 false, 0, &sdk.TxResponse{}, 378 }, 379 { 380 "valid basic fee grant with granter key name", 381 append( 382 []string{ 383 fromName, 384 "link1rsx5wakg9kxfa05ueqjpkher9yddy3u4n47f9z", 385 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 386 fmt.Sprintf("--%s=%s", flags.FlagFrom, fromName), 387 }, 388 commonFlags..., 389 ), 390 false, 0, &sdk.TxResponse{}, 391 }, 392 { 393 "valid basic fee grant with amino", 394 append( 395 []string{ 396 granter.String(), 397 "link1yhxv9jv8kwtud80azf674l5yddv2pecfzgxmrw", 398 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 399 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 400 fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), 401 }, 402 commonFlags..., 403 ), 404 false, 0, &sdk.TxResponse{}, 405 }, 406 { 407 "valid basic fee grant without spend limit", 408 append( 409 []string{ 410 granter.String(), 411 "link1kgj5mx00euxeqjhu5uh0l4lwnt99aadvrzxl6t", 412 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 413 }, 414 commonFlags..., 415 ), 416 false, 0, &sdk.TxResponse{}, 417 }, 418 { 419 "valid basic fee grant without expiration", 420 append( 421 []string{ 422 granter.String(), 423 "link1y4hn2txq7eghuydjrmwvc6sqrr7z9aa3m3zjv2", 424 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 425 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 426 }, 427 commonFlags..., 428 ), 429 false, 0, &sdk.TxResponse{}, 430 }, 431 { 432 "valid basic fee grant without spend-limit and expiration", 433 append( 434 []string{ 435 granter.String(), 436 "link1mp668xdzzdulrc40wwasqqflmagxfyc29zgvav", 437 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 438 }, 439 commonFlags..., 440 ), 441 false, 0, &sdk.TxResponse{}, 442 }, 443 { 444 "try to add existed grant", 445 append( 446 []string{ 447 granter.String(), 448 alreadyExistedGrantee.String(), 449 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 450 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 451 }, 452 commonFlags..., 453 ), 454 false, 18, &sdk.TxResponse{}, 455 }, 456 { 457 "invalid number of args(periodic fee grant)", 458 append( 459 []string{ 460 granter.String(), 461 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 462 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 463 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 464 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 465 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)), 466 }, 467 commonFlags..., 468 ), 469 true, 0, nil, 470 }, 471 { 472 "period mentioned and period limit omitted, invalid periodic grant", 473 append( 474 []string{ 475 granter.String(), 476 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 477 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 478 fmt.Sprintf("--%s=%d", cli.FlagPeriod, tenHours), 479 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 480 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneHour)), 481 }, 482 commonFlags..., 483 ), 484 true, 0, nil, 485 }, 486 { 487 "period cannot be greater than the actual expiration(periodic fee grant)", 488 append( 489 []string{ 490 granter.String(), 491 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 492 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 493 fmt.Sprintf("--%s=%d", cli.FlagPeriod, tenHours), 494 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 495 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 496 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneHour)), 497 }, 498 commonFlags..., 499 ), 500 true, 0, nil, 501 }, 502 { 503 "valid periodic fee grant", 504 append( 505 []string{ 506 granter.String(), 507 "link1xr0fqfdcen5ayqtch9n5j6rxfvjuul37mev25v", 508 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 509 fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour), 510 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 511 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 512 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)), 513 }, 514 commonFlags..., 515 ), 516 false, 0, &sdk.TxResponse{}, 517 }, 518 { 519 "valid periodic fee grant without spend-limit", 520 append( 521 []string{ 522 granter.String(), 523 "link1xjqjff3zde5le2t0u26gutnq3kag76l4jsjaqq", 524 fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour), 525 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 526 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 527 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)), 528 }, 529 commonFlags..., 530 ), 531 false, 0, &sdk.TxResponse{}, 532 }, 533 { 534 "valid periodic fee grant without expiration", 535 append( 536 []string{ 537 granter.String(), 538 "link1j583lutp3vz6z43j62wgcjxzfuch0ucmxgepac", 539 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 540 fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour), 541 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 542 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 543 }, 544 commonFlags..., 545 ), 546 false, 0, &sdk.TxResponse{}, 547 }, 548 { 549 "valid periodic fee grant without spend-limit and expiration", 550 append( 551 []string{ 552 granter.String(), 553 "link1dzthj3umpcnapfydrkt2lcv5nxgjk9kkndrfz5", 554 fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour), 555 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 556 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 557 }, 558 commonFlags..., 559 ), 560 false, 0, &sdk.TxResponse{}, 561 }, 562 { 563 "invalid expiration", 564 append( 565 []string{ 566 granter.String(), 567 "link1xjqjff3zde5le2t0u26gutnq3kag76l4jsjaqq", 568 fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour), 569 fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"), 570 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 571 fmt.Sprintf("--%s=%s", cli.FlagExpiration, "invalid"), 572 }, 573 commonFlags..., 574 ), 575 true, 0, nil, 576 }, 577 } 578 579 for _, tc := range testCases { 580 s.Run(tc.name, func() { 581 cmd := cli.NewCmdFeeGrant() 582 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 583 584 if tc.expectErr { 585 s.Require().Error(err) 586 } else { 587 s.Require().NoError(err) 588 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) 589 590 txResp := tc.respType.(*sdk.TxResponse) 591 s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) 592 } 593 }) 594 } 595 } 596 597 func (s *IntegrationTestSuite) TestNewCmdRevokeFeegrant() { 598 val := s.network.Validators[0] 599 granter := s.addedGranter 600 grantee := s.addedGrantee 601 clientCtx := val.ClientCtx 602 603 commonFlags := []string{ 604 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 605 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 606 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 607 } 608 609 // Create new fee grant specifically to test amino. 610 aminoGrantee, err := sdk.AccAddressFromBech32("link1zp4lzwuwzvhq7xhe8xj688vv00dxv2zyue4xuj") 611 s.Require().NoError(err) 612 s.createGrant(granter, aminoGrantee) 613 614 testCases := []struct { 615 name string 616 args []string 617 expectErr bool 618 expectedCode uint32 619 respType proto.Message 620 }{ 621 { 622 "invalid grantee", 623 append( 624 []string{ 625 "wrong_granter", 626 grantee.String(), 627 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 628 }, 629 commonFlags..., 630 ), 631 true, 0, nil, 632 }, 633 { 634 "invalid grantee", 635 append( 636 []string{ 637 granter.String(), 638 "wrong_grantee", 639 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 640 }, 641 commonFlags..., 642 ), 643 true, 0, nil, 644 }, 645 { 646 "Non existed grant", 647 append( 648 []string{ 649 granter.String(), 650 "link1qwvn8n0cs9lq4q46qjummvfkqah3paxx37etxm", 651 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 652 }, 653 commonFlags..., 654 ), 655 false, 4, &sdk.TxResponse{}, 656 }, 657 { 658 "Valid revoke", 659 append( 660 []string{ 661 granter.String(), 662 grantee.String(), 663 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 664 }, 665 commonFlags..., 666 ), 667 false, 0, &sdk.TxResponse{}, 668 }, 669 { 670 "Valid revoke with amino", 671 append( 672 []string{ 673 granter.String(), 674 aminoGrantee.String(), 675 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 676 fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), 677 }, 678 commonFlags..., 679 ), 680 false, 0, &sdk.TxResponse{}, 681 }, 682 } 683 684 for _, tc := range testCases { 685 s.Run(tc.name, func() { 686 cmd := cli.NewCmdRevokeFeegrant() 687 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 688 689 if tc.expectErr { 690 s.Require().Error(err) 691 } else { 692 s.Require().NoError(err) 693 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) 694 695 txResp := tc.respType.(*sdk.TxResponse) 696 s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) 697 } 698 }) 699 } 700 } 701 702 func (s *IntegrationTestSuite) TestTxWithFeeGrant() { 703 val := s.network.Validators[0] 704 clientCtx := val.ClientCtx 705 granter := val.Address 706 707 // creating an account manually (This account won't be exist in state) 708 info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) 709 s.Require().NoError(err) 710 grantee := sdk.AccAddress(info.GetPubKey().Address()) 711 712 commonFlags := []string{ 713 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 714 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 715 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 716 } 717 718 fee := sdk.NewCoin("stake", sdk.NewInt(100)) 719 720 args := append( 721 []string{ 722 granter.String(), 723 grantee.String(), 724 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, fee.String()), 725 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 726 fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneYear)), 727 }, 728 commonFlags..., 729 ) 730 731 cmd := cli.NewCmdFeeGrant() 732 733 _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) 734 s.Require().NoError(err) 735 _, err = s.network.WaitForHeight(1) 736 s.Require().NoError(err) 737 738 // granted fee allowance for an account which is not in state and creating 739 // any tx with it by using --fee-account shouldn't fail 740 out, err := govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(), 741 "Text Proposal", "No desc", govtypes.ProposalTypeText, 742 fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()), 743 ) 744 745 s.Require().NoError(err) 746 var resp sdk.TxResponse 747 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) 748 s.Require().Equal(uint32(0), resp.Code) 749 } 750 751 func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { 752 val := s.network.Validators[0] 753 754 granter := val.Address 755 info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) 756 s.Require().NoError(err) 757 grantee := sdk.AccAddress(info.GetPubKey().Address()) 758 759 clientCtx := val.ClientCtx 760 761 commonFlags := []string{ 762 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 763 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 764 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 765 } 766 spendLimit := sdk.NewCoin("stake", sdk.NewInt(1000)) 767 768 allowMsgs := strings.Join([]string{sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{}), sdk.MsgTypeURL(&govtypes.MsgVoteWeighted{})}, ",") 769 770 testCases := []struct { 771 name string 772 args []string 773 expectErr bool 774 respType proto.Message 775 expectedCode uint32 776 }{ 777 { 778 "invalid granter address", 779 append( 780 []string{ 781 "not an address", 782 "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", 783 fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs), 784 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()), 785 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 786 }, 787 commonFlags..., 788 ), 789 true, &sdk.TxResponse{}, 0, 790 }, 791 { 792 "invalid grantee address", 793 append( 794 []string{ 795 granter.String(), 796 "not an address", 797 fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs), 798 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()), 799 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 800 }, 801 commonFlags..., 802 ), 803 true, &sdk.TxResponse{}, 0, 804 }, 805 { 806 "valid filter fee grant", 807 append( 808 []string{ 809 granter.String(), 810 grantee.String(), 811 fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs), 812 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()), 813 fmt.Sprintf("--%s=%s", flags.FlagFrom, granter), 814 }, 815 commonFlags..., 816 ), 817 false, &sdk.TxResponse{}, 0, 818 }, 819 } 820 821 for _, tc := range testCases { 822 s.Run(tc.name, func() { 823 cmd := cli.NewCmdFeeGrant() 824 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 825 826 if tc.expectErr { 827 s.Require().Error(err) 828 } else { 829 s.Require().NoError(err) 830 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) 831 832 txResp := tc.respType.(*sdk.TxResponse) 833 s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) 834 } 835 }) 836 } 837 838 args := []string{ 839 granter.String(), 840 grantee.String(), 841 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 842 } 843 844 // get filtered fee allowance and check info 845 cmd := cli.GetCmdQueryFeeGrant() 846 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) 847 s.Require().NoError(err) 848 849 resp := &feegrant.Grant{} 850 851 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp), out.String()) 852 s.Require().Equal(resp.Grantee, resp.Grantee) 853 s.Require().Equal(resp.Granter, resp.Granter) 854 855 grant, err := resp.GetGrant() 856 s.Require().NoError(err) 857 858 filteredFeeGrant, err := grant.(*feegrant.AllowedMsgAllowance).GetAllowance() 859 s.Require().NoError(err) 860 861 s.Require().Equal( 862 filteredFeeGrant.(*feegrant.BasicAllowance).SpendLimit.String(), 863 spendLimit.String(), 864 ) 865 866 // exec filtered fee allowance 867 cases := []struct { 868 name string 869 malleate func() (testutil.BufferWriter, error) 870 respType proto.Message 871 expectedCode uint32 872 }{ 873 { 874 "valid proposal tx", 875 func() (testutil.BufferWriter, error) { 876 return govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(), 877 "Text Proposal", "No desc", govtypes.ProposalTypeText, 878 fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()), 879 ) 880 }, 881 &sdk.TxResponse{}, 882 0, 883 }, 884 { 885 "valid weighted_vote tx", 886 func() (testutil.BufferWriter, error) { 887 return govtestutil.MsgVote(val.ClientCtx, grantee.String(), "0", "yes", 888 fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()), 889 ) 890 }, 891 &sdk.TxResponse{}, 892 2, 893 }, 894 { 895 "should fail with unauthorized msgs", 896 func() (testutil.BufferWriter, error) { 897 args := append( 898 []string{ 899 grantee.String(), 900 "link1j583lutp3vz6z43j62wgcjxzfuch0ucmxgepac", 901 fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"), 902 fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter), 903 }, 904 commonFlags..., 905 ) 906 cmd := cli.NewCmdFeeGrant() 907 return clitestutil.ExecTestCLICmd(clientCtx, cmd, args) 908 }, 909 &sdk.TxResponse{}, 910 7, 911 }, 912 } 913 914 for _, tc := range cases { 915 s.Run(tc.name, func() { 916 out, err := tc.malleate() 917 s.Require().NoError(err) 918 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) 919 txResp := tc.respType.(*sdk.TxResponse) 920 s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) 921 }) 922 } 923 } 924 925 func getFormattedExpiration(duration int64) string { 926 return time.Now().Add(time.Duration(duration) * time.Second).Format(time.RFC3339) 927 }