github.com/Finschia/finschia-sdk@v0.49.1/x/token/keeper/msg_server_test.go (about) 1 package keeper_test 2 3 import ( 4 abci "github.com/tendermint/tendermint/abci/types" 5 6 "github.com/Finschia/finschia-sdk/testutil" 7 sdk "github.com/Finschia/finschia-sdk/types" 8 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 9 "github.com/Finschia/finschia-sdk/x/token" 10 "github.com/Finschia/finschia-sdk/x/token/class" 11 ) 12 13 func (s *KeeperTestSuite) TestMsgSend() { 14 testCases := map[string]struct { 15 contractID string 16 amount sdk.Int 17 err error 18 events sdk.Events 19 }{ 20 "valid request": { 21 contractID: s.contractID, 22 amount: s.balance, 23 events: sdk.Events{ 24 sdk.Event{ 25 Type: "lbm.token.v1.EventSent", 26 Attributes: []abci.EventAttribute{ 27 {Key: []byte("amount"), Value: testutil.W(s.balance), Index: false}, 28 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 29 {Key: []byte("from"), Value: testutil.W(s.vendor), Index: false}, 30 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 31 {Key: []byte("to"), Value: testutil.W(s.customer), Index: false}, 32 }, 33 }, 34 }, 35 }, 36 "contract not found": { 37 contractID: "fee1dead", 38 amount: sdk.OneInt(), 39 err: class.ErrContractNotExist, 40 }, 41 "insufficient funds": { 42 contractID: s.contractID, 43 amount: s.balance.Add(sdk.OneInt()), 44 err: token.ErrInsufficientBalance, 45 }, 46 } 47 48 for name, tc := range testCases { 49 s.Run(name, func() { 50 ctx, _ := s.ctx.CacheContext() 51 52 req := &token.MsgSend{ 53 ContractId: tc.contractID, 54 From: s.vendor.String(), 55 To: s.customer.String(), 56 Amount: tc.amount, 57 } 58 res, err := s.msgServer.Send(sdk.WrapSDKContext(ctx), req) 59 s.Require().ErrorIs(err, tc.err) 60 if tc.err != nil { 61 return 62 } 63 64 s.Require().NotNil(res) 65 s.Require().Equal(tc.events, ctx.EventManager().Events()) 66 }) 67 } 68 } 69 70 func (s *KeeperTestSuite) TestMsgOperatorSend() { 71 testCases := map[string]struct { 72 contractID string 73 operator sdk.AccAddress 74 from sdk.AccAddress 75 amount sdk.Int 76 err error 77 events sdk.Events 78 }{ 79 "valid request": { 80 contractID: s.contractID, 81 operator: s.operator, 82 from: s.customer, 83 amount: s.balance, 84 events: sdk.Events{ 85 sdk.Event{ 86 Type: "lbm.token.v1.EventSent", 87 Attributes: []abci.EventAttribute{ 88 {Key: []byte("amount"), Value: testutil.W(s.balance), Index: false}, 89 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 90 {Key: []byte("from"), Value: testutil.W(s.customer), Index: false}, 91 {Key: []byte("operator"), Value: testutil.W(s.operator), Index: false}, 92 {Key: []byte("to"), Value: testutil.W(s.vendor), Index: false}, 93 }, 94 }, 95 }, 96 }, 97 "contract not found": { 98 contractID: "fee1dead", 99 operator: s.operator, 100 from: s.customer, 101 amount: s.balance, 102 err: class.ErrContractNotExist, 103 }, 104 "not approved": { 105 contractID: s.contractID, 106 operator: s.vendor, 107 from: s.customer, 108 amount: s.balance, 109 err: token.ErrTokenNotApproved, 110 }, 111 "insufficient funds": { 112 contractID: s.contractID, 113 operator: s.operator, 114 from: s.customer, 115 amount: s.balance.Add(sdk.OneInt()), 116 err: token.ErrInsufficientBalance, 117 }, 118 } 119 120 for name, tc := range testCases { 121 s.Run(name, func() { 122 ctx, _ := s.ctx.CacheContext() 123 124 req := &token.MsgOperatorSend{ 125 ContractId: tc.contractID, 126 Operator: tc.operator.String(), 127 From: tc.from.String(), 128 To: s.vendor.String(), 129 Amount: tc.amount, 130 } 131 res, err := s.msgServer.OperatorSend(sdk.WrapSDKContext(ctx), req) 132 s.Require().ErrorIs(err, tc.err) 133 if tc.err != nil { 134 return 135 } 136 137 s.Require().NotNil(res) 138 s.Require().Equal(tc.events, ctx.EventManager().Events()) 139 }) 140 } 141 } 142 143 func (s *KeeperTestSuite) TestMsgRevokeOperator() { 144 testCases := map[string]struct { 145 contractID string 146 holder sdk.AccAddress 147 operator sdk.AccAddress 148 err error 149 events sdk.Events 150 }{ 151 "valid request": { 152 contractID: s.contractID, 153 holder: s.customer, 154 operator: s.operator, 155 events: sdk.Events{ 156 sdk.Event{ 157 Type: "lbm.token.v1.EventRevokedOperator", 158 Attributes: []abci.EventAttribute{ 159 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 160 {Key: []byte("holder"), Value: testutil.W(s.customer), Index: false}, 161 {Key: []byte("operator"), Value: testutil.W(s.operator), Index: false}, 162 }, 163 }, 164 }, 165 }, 166 "contract not found": { 167 contractID: "fee1dead", 168 holder: s.customer, 169 operator: s.operator, 170 err: class.ErrContractNotExist, 171 }, 172 "no authorization": { 173 contractID: s.contractID, 174 holder: s.customer, 175 operator: s.vendor, 176 err: token.ErrTokenNotApproved, 177 }, 178 } 179 180 for name, tc := range testCases { 181 s.Run(name, func() { 182 ctx, _ := s.ctx.CacheContext() 183 184 req := &token.MsgRevokeOperator{ 185 ContractId: tc.contractID, 186 Holder: tc.holder.String(), 187 Operator: tc.operator.String(), 188 } 189 res, err := s.msgServer.RevokeOperator(sdk.WrapSDKContext(ctx), req) 190 s.Require().ErrorIs(err, tc.err) 191 if tc.err != nil { 192 return 193 } 194 195 s.Require().NotNil(res) 196 s.Require().Equal(tc.events, ctx.EventManager().Events()) 197 }) 198 } 199 } 200 201 func (s *KeeperTestSuite) TestMsgAuthorizeOperator() { 202 testCases := map[string]struct { 203 contractID string 204 holder sdk.AccAddress 205 operator sdk.AccAddress 206 err error 207 events sdk.Events 208 }{ 209 "valid request": { 210 contractID: s.contractID, 211 holder: s.customer, 212 operator: s.vendor, 213 events: sdk.Events{ 214 sdk.Event{ 215 Type: "lbm.token.v1.EventAuthorizedOperator", 216 Attributes: []abci.EventAttribute{ 217 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 218 {Key: []byte("holder"), Value: testutil.W(s.customer), Index: false}, 219 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 220 }, 221 }, 222 }, 223 }, 224 "contract not found": { 225 contractID: "fee1dead", 226 holder: s.customer, 227 operator: s.vendor, 228 err: class.ErrContractNotExist, 229 }, 230 "already approved": { 231 contractID: s.contractID, 232 holder: s.customer, 233 operator: s.operator, 234 err: token.ErrTokenAlreadyApproved, 235 }, 236 } 237 238 for name, tc := range testCases { 239 s.Run(name, func() { 240 ctx, _ := s.ctx.CacheContext() 241 242 req := &token.MsgAuthorizeOperator{ 243 ContractId: tc.contractID, 244 Holder: tc.holder.String(), 245 Operator: tc.operator.String(), 246 } 247 res, err := s.msgServer.AuthorizeOperator(sdk.WrapSDKContext(ctx), req) 248 s.Require().ErrorIs(err, tc.err) 249 if tc.err != nil { 250 return 251 } 252 253 s.Require().NotNil(res) 254 s.Require().Equal(tc.events, ctx.EventManager().Events()) 255 }) 256 } 257 } 258 259 func (s *KeeperTestSuite) TestMsgIssue() { 260 testCases := map[string]struct { 261 mintable bool 262 amount sdk.Int 263 err error 264 events sdk.Events 265 }{ 266 "mintable true": { 267 mintable: true, 268 amount: sdk.NewInt(10), 269 events: sdk.Events{ 270 sdk.Event{ 271 Type: "lbm.token.v1.EventIssued", 272 Attributes: []abci.EventAttribute{ 273 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 274 {Key: []uint8("creator"), Value: testutil.W(s.vendor), Index: false}, 275 {Key: []uint8("decimals"), Value: []byte("0"), Index: false}, 276 {Key: []uint8("meta"), Value: testutil.W(""), Index: false}, 277 {Key: []uint8("mintable"), Value: []byte("true"), Index: false}, 278 {Key: []uint8("name"), Value: testutil.W("test"), Index: false}, 279 {Key: []uint8("symbol"), Value: testutil.W("TT"), Index: false}, 280 {Key: []uint8("uri"), Value: testutil.W(""), Index: false}, 281 }, 282 }, 283 sdk.Event{ 284 Type: "lbm.token.v1.EventGranted", 285 Attributes: []abci.EventAttribute{ 286 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 287 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 288 {Key: []uint8("granter"), Value: testutil.W(""), Index: false}, 289 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MODIFY"), Index: false}, 290 }, 291 }, 292 sdk.Event{ 293 Type: "lbm.token.v1.EventGranted", 294 Attributes: []abci.EventAttribute{ 295 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 296 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 297 {Key: []uint8("granter"), Value: testutil.W(""), Index: false}, 298 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MINT"), Index: false}, 299 }, 300 }, 301 sdk.Event{ 302 Type: "lbm.token.v1.EventGranted", 303 Attributes: []abci.EventAttribute{ 304 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 305 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 306 {Key: []uint8("granter"), Value: testutil.W(""), Index: false}, 307 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_BURN"), Index: false}, 308 }, 309 }, 310 sdk.Event{ 311 Type: "lbm.token.v1.EventMinted", 312 Attributes: []abci.EventAttribute{ 313 {Key: []uint8("amount"), Value: testutil.W("10"), Index: false}, 314 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 315 {Key: []uint8("operator"), Value: testutil.W(s.vendor), Index: false}, 316 {Key: []uint8("to"), Value: testutil.W(s.vendor), Index: false}, 317 }, 318 }, 319 }, 320 }, 321 "mintable false": { 322 mintable: false, 323 amount: sdk.NewInt(10), 324 events: sdk.Events{ 325 sdk.Event{ 326 Type: "lbm.token.v1.EventIssued", 327 Attributes: []abci.EventAttribute{ 328 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 329 {Key: []uint8("creator"), Value: testutil.W(s.vendor), Index: false}, 330 {Key: []uint8("decimals"), Value: []byte("0"), Index: false}, 331 {Key: []uint8("meta"), Value: testutil.W(""), Index: false}, 332 {Key: []uint8("mintable"), Value: []byte("false"), Index: false}, 333 {Key: []uint8("name"), Value: testutil.W("test"), Index: false}, 334 {Key: []uint8("symbol"), Value: testutil.W("TT"), Index: false}, 335 {Key: []uint8("uri"), Value: testutil.W(""), Index: false}, 336 }, 337 }, 338 sdk.Event{ 339 Type: "lbm.token.v1.EventGranted", 340 Attributes: []abci.EventAttribute{ 341 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 342 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 343 {Key: []uint8("granter"), Value: testutil.W(""), Index: false}, 344 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MODIFY"), Index: false}, 345 }, 346 }, 347 sdk.Event{ 348 Type: "lbm.token.v1.EventMinted", 349 Attributes: []abci.EventAttribute{ 350 {Key: []uint8("amount"), Value: testutil.W(sdk.NewInt(10)), Index: false}, 351 {Key: []uint8("contract_id"), Value: testutil.W("ca8bfd79"), Index: false}, 352 {Key: []uint8("operator"), Value: testutil.W(s.vendor), Index: false}, 353 {Key: []uint8("to"), Value: testutil.W(s.vendor), Index: false}, 354 }, 355 }, 356 }, 357 }, 358 } 359 360 // define a function to check MsgIssue result 361 checkerIssueResult := func(ctx sdk.Context, contractId string, expectedMintable bool, expectedAmount sdk.Int) { 362 // check contract 363 contract, err := s.queryServer.Contract(sdk.WrapSDKContext(ctx), &token.QueryContractRequest{ContractId: contractId}) 364 s.Require().NoError(err) 365 s.Require().Equal(expectedMintable, contract.Contract.Mintable) 366 367 // check supply 368 supply, err := s.queryServer.Supply(sdk.WrapSDKContext(ctx), &token.QuerySupplyRequest{ContractId: contractId}) 369 s.Require().NoError(err) 370 s.Require().Equal(expectedAmount, supply.Amount) 371 372 // check mint 373 mint, err := s.queryServer.Minted(sdk.WrapSDKContext(ctx), &token.QueryMintedRequest{ContractId: contractId}) 374 s.Require().NoError(err) 375 s.Require().Equal(expectedAmount, mint.Amount) 376 377 // check burnt 378 burn, err := s.queryServer.Burnt(sdk.WrapSDKContext(ctx), &token.QueryBurntRequest{ContractId: contractId}) 379 s.Require().NoError(err) 380 s.Require().Equal(sdk.ZeroInt(), burn.Amount) 381 382 // check owner balance 383 balance, err := s.queryServer.Balance(sdk.WrapSDKContext(ctx), &token.QueryBalanceRequest{ 384 ContractId: contractId, 385 Address: s.vendor.String(), 386 }) 387 s.Require().NoError(err) 388 s.Require().Equal(expectedAmount, balance.Amount) 389 } 390 391 for name, tc := range testCases { 392 s.Run(name, func() { 393 ctx, _ := s.ctx.CacheContext() 394 395 req := &token.MsgIssue{ 396 Owner: s.vendor.String(), 397 To: s.vendor.String(), 398 Mintable: tc.mintable, 399 Name: "test", 400 Symbol: "TT", 401 Amount: tc.amount, 402 } 403 res, err := s.msgServer.Issue(sdk.WrapSDKContext(ctx), req) 404 s.Require().ErrorIs(err, tc.err) 405 if tc.err != nil { 406 return 407 } 408 409 s.Require().NotNil(res) 410 s.Require().Equal(tc.events, ctx.EventManager().Events()) 411 412 // check result status 413 checkerIssueResult(ctx, res.ContractId, tc.mintable, tc.amount) 414 415 // Second request for the same request 416 res2, err := s.msgServer.Issue(sdk.WrapSDKContext(ctx), req) 417 s.Require().ErrorIs(err, tc.err) 418 if tc.err != nil { 419 return 420 } 421 // check result status 422 checkerIssueResult(ctx, res2.ContractId, tc.mintable, tc.amount) 423 s.Require().NotEqual(res.ContractId, res2.ContractId) 424 }) 425 } 426 } 427 428 func (s *KeeperTestSuite) TestMsgGrantPermission() { 429 testCases := map[string]struct { 430 contractID string 431 granter sdk.AccAddress 432 grantee sdk.AccAddress 433 permission string 434 err error 435 events sdk.Events 436 }{ 437 "contract not found": { 438 contractID: "fee1dead", 439 granter: s.vendor, 440 grantee: s.operator, 441 permission: token.LegacyPermissionModify.String(), 442 err: class.ErrContractNotExist, 443 }, 444 "contract has no permission - MINT": { 445 contractID: s.unmintableContractId, 446 granter: s.vendor, 447 grantee: s.operator, 448 permission: token.LegacyPermissionMint.String(), 449 err: token.ErrTokenNoPermission, 450 }, 451 "contract has no permission - BURN": { 452 contractID: s.unmintableContractId, 453 granter: s.vendor, 454 grantee: s.operator, 455 permission: token.LegacyPermissionBurn.String(), 456 err: token.ErrTokenNoPermission, 457 }, 458 "granter has no permission - MINT": { 459 contractID: s.contractID, 460 granter: s.customer, 461 grantee: s.stranger, 462 permission: token.LegacyPermissionMint.String(), 463 err: token.ErrTokenNoPermission, 464 }, 465 "granter has no permission - BURN": { 466 contractID: s.contractID, 467 granter: s.customer, 468 grantee: s.stranger, 469 permission: token.LegacyPermissionBurn.String(), 470 err: token.ErrTokenNoPermission, 471 }, 472 "granter has no permission - MODIFY": { 473 contractID: s.contractID, 474 granter: s.customer, 475 grantee: s.stranger, 476 permission: token.LegacyPermissionModify.String(), 477 err: token.ErrTokenNoPermission, 478 }, 479 "valid request - MINT": { 480 contractID: s.contractID, 481 granter: s.vendor, 482 grantee: s.operator, 483 permission: token.LegacyPermissionMint.String(), 484 events: sdk.Events{ 485 sdk.Event{ 486 Type: "lbm.token.v1.EventGranted", 487 Attributes: []abci.EventAttribute{ 488 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 489 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 490 {Key: []uint8("granter"), Value: testutil.W(s.vendor), Index: false}, 491 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MINT"), Index: false}, 492 }, 493 }, 494 }, 495 }, 496 "valid request - BURN": { 497 contractID: s.contractID, 498 granter: s.vendor, 499 grantee: s.operator, 500 permission: token.LegacyPermissionBurn.String(), 501 events: sdk.Events{ 502 sdk.Event{ 503 Type: "lbm.token.v1.EventGranted", 504 Attributes: []abci.EventAttribute{ 505 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 506 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 507 {Key: []uint8("granter"), Value: testutil.W(s.vendor), Index: false}, 508 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_BURN"), Index: false}, 509 }, 510 }, 511 }, 512 }, 513 "valid request - MODIFY": { 514 contractID: s.contractID, 515 granter: s.vendor, 516 grantee: s.operator, 517 permission: token.LegacyPermissionModify.String(), 518 events: sdk.Events{ 519 sdk.Event{ 520 Type: "lbm.token.v1.EventGranted", 521 Attributes: []abci.EventAttribute{ 522 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 523 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 524 {Key: []uint8("granter"), Value: testutil.W(s.vendor), Index: false}, 525 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MODIFY"), Index: false}, 526 }, 527 }, 528 }, 529 }, 530 } 531 532 for name, tc := range testCases { 533 s.Run(name, func() { 534 ctx, _ := s.ctx.CacheContext() 535 536 req := &token.MsgGrantPermission{ 537 ContractId: tc.contractID, 538 From: tc.granter.String(), 539 To: tc.grantee.String(), 540 Permission: tc.permission, 541 } 542 res, err := s.msgServer.GrantPermission(sdk.WrapSDKContext(ctx), req) 543 s.Require().ErrorIs(err, tc.err) 544 if tc.err != nil { 545 return 546 } 547 548 s.Require().NotNil(res) 549 s.Require().Equal(tc.events, ctx.EventManager().Events()) 550 551 // check to grant permission 552 per, err := s.queryServer.GranteeGrants(sdk.WrapSDKContext(ctx), &token.QueryGranteeGrantsRequest{ 553 ContractId: tc.contractID, 554 Grantee: tc.grantee.String(), 555 Pagination: nil, 556 }) 557 s.Require().NoError(err) 558 s.Require().NotNil(per) 559 expectPermission := token.Grant{ 560 Grantee: tc.grantee.String(), 561 Permission: token.Permission(token.LegacyPermissionFromString(tc.permission)), 562 } 563 s.Require().Contains(per.Grants, expectPermission) 564 }) 565 } 566 } 567 568 func (s *KeeperTestSuite) TestMsgRevokePermission() { 569 testCases := map[string]struct { 570 contractID string 571 from sdk.AccAddress 572 permission string 573 err error 574 events sdk.Events 575 }{ 576 "contract not found": { 577 contractID: "fee1dead", 578 from: s.operator, 579 permission: token.LegacyPermissionMint.String(), 580 err: class.ErrContractNotExist, 581 }, 582 "contract has no permission - MINT": { 583 contractID: s.unmintableContractId, 584 from: s.operator, 585 permission: token.LegacyPermissionMint.String(), 586 err: token.ErrTokenNoPermission, 587 }, 588 "contract has no permission - BURN": { 589 contractID: s.unmintableContractId, 590 from: s.operator, 591 permission: token.LegacyPermissionBurn.String(), 592 err: token.ErrTokenNoPermission, 593 }, 594 "grantee has no permission - MINT": { 595 contractID: s.contractID, 596 from: s.customer, 597 permission: token.LegacyPermissionMint.String(), 598 err: token.ErrTokenNoPermission, 599 }, 600 "grantee has no permission - BURN": { 601 contractID: s.contractID, 602 from: s.customer, 603 permission: token.LegacyPermissionBurn.String(), 604 err: token.ErrTokenNoPermission, 605 }, 606 "grantee has no permission - MODIFY": { 607 contractID: s.contractID, 608 from: s.customer, 609 permission: token.LegacyPermissionModify.String(), 610 err: token.ErrTokenNoPermission, 611 }, 612 "valid request - revoke MINT": { 613 contractID: s.contractID, 614 from: s.operator, 615 permission: token.LegacyPermissionMint.String(), 616 events: sdk.Events{ 617 sdk.Event{ 618 Type: "lbm.token.v1.EventRenounced", 619 Attributes: []abci.EventAttribute{ 620 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 621 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 622 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MINT"), Index: false}, 623 }, 624 }, 625 }, 626 }, 627 "valid request - revoke BURN": { 628 contractID: s.contractID, 629 from: s.operator, 630 permission: token.LegacyPermissionBurn.String(), 631 events: sdk.Events{ 632 sdk.Event{ 633 Type: "lbm.token.v1.EventRenounced", 634 Attributes: []abci.EventAttribute{ 635 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 636 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 637 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_BURN"), Index: false}, 638 }, 639 }, 640 }, 641 }, 642 "valid request - revoke MODIFY": { 643 contractID: s.contractID, 644 from: s.vendor, 645 permission: token.LegacyPermissionModify.String(), 646 events: sdk.Events{ 647 sdk.Event{ 648 Type: "lbm.token.v1.EventRenounced", 649 Attributes: []abci.EventAttribute{ 650 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 651 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 652 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MODIFY"), Index: false}, 653 }, 654 }, 655 }, 656 }, 657 } 658 659 for name, tc := range testCases { 660 s.Run(name, func() { 661 ctx, _ := s.ctx.CacheContext() 662 663 req := &token.MsgRevokePermission{ 664 ContractId: tc.contractID, 665 From: tc.from.String(), 666 Permission: tc.permission, 667 } 668 res, err := s.msgServer.RevokePermission(sdk.WrapSDKContext(ctx), req) 669 s.Require().ErrorIs(err, tc.err) 670 if tc.err != nil { 671 return 672 } 673 674 s.Require().NotNil(res) 675 s.Require().Equal(tc.events, ctx.EventManager().Events()) 676 677 // check to remove permission 678 per, err := s.queryServer.GranteeGrants(sdk.WrapSDKContext(ctx), &token.QueryGranteeGrantsRequest{ 679 ContractId: tc.contractID, 680 Grantee: tc.from.String(), 681 Pagination: nil, 682 }) 683 s.Require().NoError(err) 684 s.Require().NotNil(per) 685 expectPermission := token.Grant{ 686 Grantee: tc.from.String(), 687 Permission: token.Permission(token.LegacyPermissionFromString(tc.permission)), 688 } 689 s.Require().NotContains(per.Grants, expectPermission) 690 }) 691 } 692 } 693 694 func (s *KeeperTestSuite) TestMsgMint() { 695 testCases := map[string]struct { 696 isNegativeCase bool 697 req *token.MsgMint 698 expectedEvents sdk.Events 699 expectedError *sdkerrors.Error 700 }{ 701 "mint(contractID, from, to, 10)": { 702 req: &token.MsgMint{ 703 ContractId: s.contractID, 704 From: s.vendor.String(), 705 To: s.customer.String(), 706 Amount: sdk.NewInt(10), 707 }, 708 expectedEvents: sdk.Events{ 709 sdk.Event{ 710 Type: "lbm.token.v1.EventMinted", 711 Attributes: []abci.EventAttribute{ 712 {Key: []byte("amount"), Value: testutil.W(sdk.NewInt(10)), Index: false}, 713 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 714 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 715 {Key: []byte("to"), Value: testutil.W(s.customer), Index: false}, 716 }, 717 }, 718 }, 719 }, 720 "mint(contractID, from, from, 10)": { 721 req: &token.MsgMint{ 722 ContractId: s.contractID, 723 From: s.vendor.String(), 724 To: s.customer.String(), 725 Amount: sdk.NewInt(10), 726 }, 727 expectedEvents: sdk.Events{ 728 sdk.Event{ 729 Type: "lbm.token.v1.EventMinted", 730 Attributes: []abci.EventAttribute{ 731 {Key: []byte("amount"), Value: testutil.W(sdk.NewInt(10)), Index: false}, 732 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 733 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 734 {Key: []byte("to"), Value: testutil.W(s.customer), Index: false}, 735 }, 736 }, 737 }, 738 }, 739 "mint(contractID, vendor, customer, 1) -> error": { 740 isNegativeCase: true, 741 req: &token.MsgMint{ 742 ContractId: s.unmintableContractId, 743 From: s.vendor.String(), 744 To: s.customer.String(), 745 Amount: sdk.OneInt(), 746 }, 747 expectedError: token.ErrTokenNoPermission, 748 }, 749 "mint(nonExistingContractId, from, to, 1) -> error": { 750 isNegativeCase: true, 751 req: &token.MsgMint{ 752 ContractId: "fee1dead", 753 From: s.vendor.String(), 754 To: s.customer.String(), 755 Amount: sdk.OneInt(), 756 }, 757 expectedError: class.ErrContractNotExist, 758 }, 759 "mint(contractID, from, unauthorized account, 1) -> error": { 760 isNegativeCase: true, 761 req: &token.MsgMint{ 762 ContractId: s.contractID, 763 From: s.stranger.String(), 764 To: s.vendor.String(), 765 Amount: sdk.OneInt(), 766 }, 767 expectedError: token.ErrTokenNoPermission, 768 }, 769 } 770 771 for name, tc := range testCases { 772 s.Run(name, func() { 773 // Arrange 774 s.Require().NoError(tc.req.ValidateBasic()) 775 from, err := sdk.AccAddressFromBech32(tc.req.From) 776 s.Require().NoError(err) 777 to, err := sdk.AccAddressFromBech32(tc.req.To) 778 s.Require().NoError(err) 779 ctx, _ := s.ctx.CacheContext() 780 prevFrom := s.keeper.GetBalance(ctx, tc.req.ContractId, from) 781 prevTo := s.keeper.GetBalance(ctx, tc.req.ContractId, to) 782 prevMint := s.keeper.GetMinted(ctx, tc.req.ContractId) 783 prevSupplyAmount := s.keeper.GetSupply(ctx, tc.req.ContractId) 784 785 // Act 786 res, err := s.msgServer.Mint(sdk.WrapSDKContext(ctx), tc.req) 787 if tc.isNegativeCase { 788 s.Require().Nil(res) 789 s.Require().ErrorIs(err, tc.expectedError) 790 s.Require().Equal(0, len(ctx.EventManager().Events())) 791 return 792 } 793 s.Require().NoError(err) 794 s.Require().NotNil(res) 795 796 // Assert 797 events := ctx.EventManager().Events() 798 s.Require().Equal(tc.expectedEvents, events) 799 mintAmount := tc.req.Amount 800 curMinted := s.keeper.GetMinted(ctx, tc.req.ContractId) 801 curSupply := s.keeper.GetSupply(ctx, tc.req.ContractId) 802 curToAmount := s.keeper.GetBalance(ctx, s.contractID, to) 803 s.Require().Equal(prevMint.Add(mintAmount), curMinted) 804 s.Require().Equal(prevSupplyAmount.Add(mintAmount), curSupply) 805 s.Require().Equal(prevTo.Add(mintAmount), curToAmount) 806 if !from.Equals(to) { 807 curFrom := s.keeper.GetBalance(ctx, s.contractID, from) 808 s.Require().Equal(prevFrom, curFrom) 809 } 810 }) 811 } 812 } 813 814 func (s *KeeperTestSuite) TestMsgBurn() { 815 testCases := map[string]struct { 816 isNegativeCase bool 817 req *token.MsgBurn 818 expectedEvents sdk.Events 819 expectedError *sdkerrors.Error 820 }{ 821 "burn(contractID, from, amount)": { 822 req: &token.MsgBurn{ 823 ContractId: s.contractID, 824 From: s.vendor.String(), 825 Amount: sdk.OneInt(), 826 }, 827 expectedEvents: sdk.Events{ 828 sdk.Event{ 829 Type: "lbm.token.v1.EventBurned", 830 Attributes: []abci.EventAttribute{ 831 {Key: []byte("amount"), Value: testutil.W(sdk.OneInt()), Index: false}, 832 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 833 {Key: []byte("from"), Value: testutil.W(s.vendor), Index: false}, 834 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 835 }, 836 }, 837 }, 838 }, 839 "burn(nonExistingContractId, from, 1) -> error": { 840 isNegativeCase: true, 841 req: &token.MsgBurn{ 842 ContractId: "fee1dead", 843 From: s.vendor.String(), 844 Amount: sdk.OneInt(), 845 }, 846 expectedError: class.ErrContractNotExist, 847 }, 848 "burn(contractID, from, unauthorized account, 1) -> error": { 849 isNegativeCase: true, 850 req: &token.MsgBurn{ 851 ContractId: s.contractID, 852 From: s.stranger.String(), 853 Amount: sdk.OneInt(), 854 }, 855 expectedError: token.ErrTokenNoPermission, 856 }, 857 } 858 859 for name, tc := range testCases { 860 s.Run(name, func() { 861 // Arrange 862 from, err := sdk.AccAddressFromBech32(tc.req.From) 863 s.Require().NoError(err) 864 ctx, _ := s.ctx.CacheContext() 865 prevFrom := s.keeper.GetBalance(ctx, tc.req.ContractId, from) 866 prevBurnt := s.keeper.GetBurnt(ctx, tc.req.ContractId) 867 prevSupplyAmount := s.keeper.GetSupply(ctx, tc.req.ContractId) 868 s.Require().NoError(tc.req.ValidateBasic()) 869 870 // Act 871 res, err := s.msgServer.Burn(sdk.WrapSDKContext(ctx), tc.req) 872 if tc.isNegativeCase { 873 s.Require().Nil(res) 874 s.Require().ErrorIs(err, tc.expectedError) 875 s.Require().Equal(0, len(ctx.EventManager().Events())) 876 return 877 } 878 s.Require().NoError(err) 879 s.Require().NotNil(res) 880 881 // Assert 882 events := ctx.EventManager().Events() 883 s.Require().Equal(tc.expectedEvents, events) 884 885 curBurnt := s.keeper.GetBurnt(ctx, tc.req.ContractId) 886 curSupply := s.keeper.GetSupply(ctx, tc.req.ContractId) 887 curFromAmount := s.keeper.GetBalance(ctx, s.contractID, from) 888 burnAmount := tc.req.Amount 889 s.Require().Equal(prevBurnt.Add(burnAmount), curBurnt) 890 s.Require().Equal(prevSupplyAmount.Sub(burnAmount), curSupply) 891 s.Require().Equal(prevFrom.Sub(burnAmount), curFromAmount) 892 }) 893 } 894 } 895 896 func (s *KeeperTestSuite) TestMsgOperatorBurn() { 897 testCases := map[string]struct { 898 isNegativeCase bool 899 req *token.MsgOperatorBurn 900 expectedEvent sdk.Event 901 expectedError *sdkerrors.Error 902 }{ 903 "operatorBurn(contractID, operator, from, 1)": { 904 req: &token.MsgOperatorBurn{ 905 ContractId: s.contractID, 906 Operator: s.operator.String(), 907 From: s.customer.String(), 908 Amount: sdk.OneInt(), 909 }, 910 expectedEvent: sdk.Event{ 911 Type: "lbm.token.v1.EventBurned", 912 Attributes: []abci.EventAttribute{ 913 {Key: []byte("amount"), Value: testutil.W(sdk.OneInt()), Index: false}, 914 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 915 {Key: []byte("from"), Value: testutil.W(s.customer), Index: false}, 916 {Key: []byte("operator"), Value: testutil.W(s.operator), Index: false}, 917 }, 918 }, 919 }, 920 "operatorBurn(nonExistingContractId, operator, from, 1) -> error": { 921 isNegativeCase: true, 922 req: &token.MsgOperatorBurn{ 923 ContractId: "fee1dead", 924 Operator: s.operator.String(), 925 From: s.customer.String(), 926 Amount: sdk.OneInt(), 927 }, 928 expectedError: class.ErrContractNotExist, 929 }, 930 "operatorBurn(contractID, operator, unauthorized account, 1) -> error": { 931 isNegativeCase: true, 932 req: &token.MsgOperatorBurn{ 933 ContractId: s.contractID, 934 Operator: s.operator.String(), 935 From: s.stranger.String(), 936 Amount: sdk.OneInt(), 937 }, 938 expectedError: token.ErrTokenNotApproved, 939 }, 940 } 941 942 for name, tc := range testCases { 943 s.Run(name, func() { 944 // Arrange 945 operator, err := sdk.AccAddressFromBech32(tc.req.Operator) 946 s.Require().NoError(err) 947 from, err := sdk.AccAddressFromBech32(tc.req.From) 948 s.Require().NoError(err) 949 prevOperator := s.keeper.GetBalance(s.ctx, tc.req.ContractId, operator) 950 prevFrom := s.keeper.GetBalance(s.ctx, tc.req.ContractId, from) 951 prevBurnt := s.keeper.GetBurnt(s.ctx, tc.req.ContractId) 952 prevSupplyAmount := s.keeper.GetSupply(s.ctx, tc.req.ContractId) 953 s.Require().NoError(tc.req.ValidateBasic()) 954 prevEvtCnt := len(s.ctx.EventManager().Events()) 955 956 // Act 957 res, err := s.msgServer.OperatorBurn(sdk.WrapSDKContext(s.ctx), tc.req) 958 if tc.isNegativeCase { 959 s.Require().Nil(res) 960 s.Require().ErrorIs(err, tc.expectedError) 961 s.Require().Equal(prevEvtCnt, len(s.ctx.EventManager().Events())) 962 return 963 } 964 s.Require().NoError(err) 965 s.Require().NotNil(res) 966 967 // Assert 968 events := s.ctx.EventManager().Events() 969 s.Require().Equal(events[len(events)-1], tc.expectedEvent) 970 s.Require().Greater(len(s.ctx.EventManager().Events()), prevEvtCnt) 971 972 curBurnt := s.keeper.GetBurnt(s.ctx, tc.req.ContractId) 973 curSupply := s.keeper.GetSupply(s.ctx, tc.req.ContractId) 974 curFromAmount := s.keeper.GetBalance(s.ctx, s.contractID, from) 975 burnAmount := tc.req.Amount 976 s.Require().Equal(prevBurnt.Add(burnAmount), curBurnt) 977 s.Require().Equal(prevSupplyAmount.Sub(burnAmount), curSupply) 978 s.Require().Equal(prevFrom.Sub(burnAmount), curFromAmount) 979 if !from.Equals(operator) { 980 curOperator := s.keeper.GetBalance(s.ctx, s.contractID, operator) 981 s.Require().Equal(prevOperator, curOperator) 982 } 983 }) 984 } 985 } 986 987 func (s *KeeperTestSuite) TestMsgModify() { 988 testCases := map[string]struct { 989 isNegativeCase bool 990 req *token.MsgModify 991 expectedEvents sdk.Events 992 expectedError *sdkerrors.Error 993 }{ 994 "modify(contractID, owner, changes:uri,name)": { 995 req: &token.MsgModify{ 996 ContractId: s.contractID, 997 Owner: s.vendor.String(), 998 Changes: []token.Attribute{ 999 {Key: token.AttributeKeyURI.String(), Value: "uri"}, 1000 {Key: token.AttributeKeyName.String(), Value: "NA<ENDSLSDN"}, 1001 }, 1002 }, 1003 expectedEvents: []sdk.Event{ 1004 { 1005 Type: "lbm.token.v1.EventModified", 1006 Attributes: []abci.EventAttribute{ 1007 {Key: []byte("changes"), Value: testutil.MustJSONMarshal([]token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}, {Key: token.AttributeKeyName.String(), Value: "NA<ENDSLSDN"}}), Index: false}, 1008 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 1009 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 1010 }, 1011 }, 1012 }, 1013 }, 1014 "modify(contractID, owner, changes:uri)": { 1015 req: &token.MsgModify{ 1016 ContractId: s.contractID, 1017 Owner: s.vendor.String(), 1018 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri222"}}, 1019 }, 1020 expectedEvents: []sdk.Event{ 1021 { 1022 Type: "lbm.token.v1.EventModified", 1023 Attributes: []abci.EventAttribute{ 1024 {Key: []byte("changes"), Value: testutil.MustJSONMarshal([]token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri222"}}), Index: false}, 1025 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 1026 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 1027 }, 1028 }, 1029 }, 1030 }, 1031 "modify(nonExistingContractId, from, 1) -> error": { 1032 isNegativeCase: true, 1033 req: &token.MsgModify{ 1034 ContractId: "fee1dead", 1035 Owner: s.vendor.String(), 1036 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}}, 1037 }, 1038 expectedError: class.ErrContractNotExist, 1039 }, 1040 "modify(contractID, from, unauthorized account, 1) -> error": { 1041 isNegativeCase: true, 1042 req: &token.MsgModify{ 1043 ContractId: s.contractID, 1044 Owner: s.stranger.String(), 1045 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}}, 1046 }, 1047 expectedError: token.ErrTokenNoPermission, 1048 }, 1049 } 1050 1051 for name, tc := range testCases { 1052 s.Run(name, func() { 1053 // Arrange 1054 s.Require().NoError(tc.req.ValidateBasic()) 1055 ctx, _ := s.ctx.CacheContext() 1056 1057 // Act 1058 res, err := s.msgServer.Modify(sdk.WrapSDKContext(ctx), tc.req) 1059 if tc.isNegativeCase { 1060 s.Require().Nil(res) 1061 s.Require().ErrorIs(err, tc.expectedError) 1062 s.Require().Equal(0, len(ctx.EventManager().Events())) 1063 return 1064 } 1065 s.Require().NotNil(res) 1066 s.Require().NoError(err) 1067 1068 // Assert 1069 events := ctx.EventManager().Events() 1070 s.Require().Equal(tc.expectedEvents, events) 1071 }) 1072 } 1073 }