github.com/Finschia/finschia-sdk@v0.48.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 "valid request - revoke BURN": { 627 contractID: s.contractID, 628 from: s.operator, 629 permission: token.LegacyPermissionBurn.String(), 630 events: sdk.Events{ 631 sdk.Event{ 632 Type: "lbm.token.v1.EventRenounced", 633 Attributes: []abci.EventAttribute{ 634 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 635 {Key: []uint8("grantee"), Value: testutil.W(s.operator), Index: false}, 636 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_BURN"), Index: false}, 637 }, 638 }}, 639 }, 640 "valid request - revoke MODIFY": { 641 contractID: s.contractID, 642 from: s.vendor, 643 permission: token.LegacyPermissionModify.String(), 644 events: sdk.Events{ 645 sdk.Event{ 646 Type: "lbm.token.v1.EventRenounced", 647 Attributes: []abci.EventAttribute{ 648 {Key: []uint8("contract_id"), Value: testutil.W("9be17165"), Index: false}, 649 {Key: []uint8("grantee"), Value: testutil.W(s.vendor), Index: false}, 650 {Key: []uint8("permission"), Value: testutil.W("PERMISSION_MODIFY"), Index: false}, 651 }, 652 }}, 653 }, 654 } 655 656 for name, tc := range testCases { 657 s.Run(name, func() { 658 ctx, _ := s.ctx.CacheContext() 659 660 req := &token.MsgRevokePermission{ 661 ContractId: tc.contractID, 662 From: tc.from.String(), 663 Permission: tc.permission, 664 } 665 res, err := s.msgServer.RevokePermission(sdk.WrapSDKContext(ctx), req) 666 s.Require().ErrorIs(err, tc.err) 667 if tc.err != nil { 668 return 669 } 670 671 s.Require().NotNil(res) 672 s.Require().Equal(tc.events, ctx.EventManager().Events()) 673 674 // check to remove permission 675 per, err := s.queryServer.GranteeGrants(sdk.WrapSDKContext(ctx), &token.QueryGranteeGrantsRequest{ 676 ContractId: tc.contractID, 677 Grantee: tc.from.String(), 678 Pagination: nil, 679 }) 680 s.Require().NoError(err) 681 s.Require().NotNil(per) 682 expectPermission := token.Grant{ 683 Grantee: tc.from.String(), 684 Permission: token.Permission(token.LegacyPermissionFromString(tc.permission)), 685 } 686 s.Require().NotContains(per.Grants, expectPermission) 687 }) 688 } 689 } 690 691 func (s *KeeperTestSuite) TestMsgMint() { 692 testCases := map[string]struct { 693 isNegativeCase bool 694 req *token.MsgMint 695 expectedEvents sdk.Events 696 expectedError *sdkerrors.Error 697 }{ 698 "mint(contractID, from, to, 10)": { 699 req: &token.MsgMint{ 700 ContractId: s.contractID, 701 From: s.vendor.String(), 702 To: s.customer.String(), 703 Amount: sdk.NewInt(10), 704 }, 705 expectedEvents: sdk.Events{ 706 sdk.Event{ 707 Type: "lbm.token.v1.EventMinted", 708 Attributes: []abci.EventAttribute{ 709 {Key: []byte("amount"), Value: testutil.W(sdk.NewInt(10)), Index: false}, 710 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 711 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 712 {Key: []byte("to"), Value: testutil.W(s.customer), Index: false}, 713 }, 714 }, 715 }, 716 }, 717 "mint(contractID, from, from, 10)": { 718 req: &token.MsgMint{ 719 ContractId: s.contractID, 720 From: s.vendor.String(), 721 To: s.customer.String(), 722 Amount: sdk.NewInt(10), 723 }, 724 expectedEvents: sdk.Events{ 725 sdk.Event{ 726 Type: "lbm.token.v1.EventMinted", 727 Attributes: []abci.EventAttribute{ 728 {Key: []byte("amount"), Value: testutil.W(sdk.NewInt(10)), Index: false}, 729 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 730 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 731 {Key: []byte("to"), Value: testutil.W(s.customer), Index: false}, 732 }, 733 }, 734 }, 735 }, 736 "mint(contractID, vendor, customer, 1) -> error": { 737 isNegativeCase: true, 738 req: &token.MsgMint{ 739 ContractId: s.unmintableContractId, 740 From: s.vendor.String(), 741 To: s.customer.String(), 742 Amount: sdk.OneInt(), 743 }, 744 expectedError: token.ErrTokenNoPermission, 745 }, 746 "mint(nonExistingContractId, from, to, 1) -> error": { 747 isNegativeCase: true, 748 req: &token.MsgMint{ 749 ContractId: "fee1dead", 750 From: s.vendor.String(), 751 To: s.customer.String(), 752 Amount: sdk.OneInt(), 753 }, 754 expectedError: class.ErrContractNotExist, 755 }, 756 "mint(contractID, from, unauthorized account, 1) -> error": { 757 isNegativeCase: true, 758 req: &token.MsgMint{ 759 ContractId: s.contractID, 760 From: s.stranger.String(), 761 To: s.vendor.String(), 762 Amount: sdk.OneInt(), 763 }, 764 expectedError: token.ErrTokenNoPermission, 765 }, 766 } 767 768 for name, tc := range testCases { 769 s.Run(name, func() { 770 // Arrange 771 s.Require().NoError(tc.req.ValidateBasic()) 772 from, err := sdk.AccAddressFromBech32(tc.req.From) 773 s.Require().NoError(err) 774 to, err := sdk.AccAddressFromBech32(tc.req.To) 775 s.Require().NoError(err) 776 ctx, _ := s.ctx.CacheContext() 777 prevFrom := s.keeper.GetBalance(ctx, tc.req.ContractId, from) 778 prevTo := s.keeper.GetBalance(ctx, tc.req.ContractId, to) 779 prevMint := s.keeper.GetMinted(ctx, tc.req.ContractId) 780 prevSupplyAmount := s.keeper.GetSupply(ctx, tc.req.ContractId) 781 782 // Act 783 res, err := s.msgServer.Mint(sdk.WrapSDKContext(ctx), tc.req) 784 if tc.isNegativeCase { 785 s.Require().Nil(res) 786 s.Require().ErrorIs(err, tc.expectedError) 787 s.Require().Equal(0, len(ctx.EventManager().Events())) 788 return 789 } 790 s.Require().NoError(err) 791 s.Require().NotNil(res) 792 793 // Assert 794 events := ctx.EventManager().Events() 795 s.Require().Equal(tc.expectedEvents, events) 796 mintAmount := tc.req.Amount 797 curMinted := s.keeper.GetMinted(ctx, tc.req.ContractId) 798 curSupply := s.keeper.GetSupply(ctx, tc.req.ContractId) 799 curToAmount := s.keeper.GetBalance(ctx, s.contractID, to) 800 s.Require().Equal(prevMint.Add(mintAmount), curMinted) 801 s.Require().Equal(prevSupplyAmount.Add(mintAmount), curSupply) 802 s.Require().Equal(prevTo.Add(mintAmount), curToAmount) 803 if !from.Equals(to) { 804 curFrom := s.keeper.GetBalance(ctx, s.contractID, from) 805 s.Require().Equal(prevFrom, curFrom) 806 } 807 }) 808 } 809 } 810 811 func (s *KeeperTestSuite) TestMsgBurn() { 812 testCases := map[string]struct { 813 isNegativeCase bool 814 req *token.MsgBurn 815 expectedEvents sdk.Events 816 expectedError *sdkerrors.Error 817 }{ 818 "burn(contractID, from, amount)": { 819 req: &token.MsgBurn{ 820 ContractId: s.contractID, 821 From: s.vendor.String(), 822 Amount: sdk.OneInt(), 823 }, 824 expectedEvents: sdk.Events{ 825 sdk.Event{ 826 Type: "lbm.token.v1.EventBurned", 827 Attributes: []abci.EventAttribute{ 828 {Key: []byte("amount"), Value: testutil.W(sdk.OneInt()), Index: false}, 829 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 830 {Key: []byte("from"), Value: testutil.W(s.vendor), Index: false}, 831 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 832 }, 833 }, 834 }, 835 }, 836 "burn(nonExistingContractId, from, 1) -> error": { 837 isNegativeCase: true, 838 req: &token.MsgBurn{ 839 ContractId: "fee1dead", 840 From: s.vendor.String(), 841 Amount: sdk.OneInt(), 842 }, 843 expectedError: class.ErrContractNotExist, 844 }, 845 "burn(contractID, from, unauthorized account, 1) -> error": { 846 isNegativeCase: true, 847 req: &token.MsgBurn{ 848 ContractId: s.contractID, 849 From: s.stranger.String(), 850 Amount: sdk.OneInt(), 851 }, 852 expectedError: token.ErrTokenNoPermission, 853 }, 854 } 855 856 for name, tc := range testCases { 857 s.Run(name, func() { 858 // Arrange 859 from, err := sdk.AccAddressFromBech32(tc.req.From) 860 s.Require().NoError(err) 861 ctx, _ := s.ctx.CacheContext() 862 prevFrom := s.keeper.GetBalance(ctx, tc.req.ContractId, from) 863 prevBurnt := s.keeper.GetBurnt(ctx, tc.req.ContractId) 864 prevSupplyAmount := s.keeper.GetSupply(ctx, tc.req.ContractId) 865 s.Require().NoError(tc.req.ValidateBasic()) 866 867 // Act 868 res, err := s.msgServer.Burn(sdk.WrapSDKContext(ctx), tc.req) 869 if tc.isNegativeCase { 870 s.Require().Nil(res) 871 s.Require().ErrorIs(err, tc.expectedError) 872 s.Require().Equal(0, len(ctx.EventManager().Events())) 873 return 874 } 875 s.Require().NoError(err) 876 s.Require().NotNil(res) 877 878 // Assert 879 events := ctx.EventManager().Events() 880 s.Require().Equal(tc.expectedEvents, events) 881 882 curBurnt := s.keeper.GetBurnt(ctx, tc.req.ContractId) 883 curSupply := s.keeper.GetSupply(ctx, tc.req.ContractId) 884 curFromAmount := s.keeper.GetBalance(ctx, s.contractID, from) 885 burnAmount := tc.req.Amount 886 s.Require().Equal(prevBurnt.Add(burnAmount), curBurnt) 887 s.Require().Equal(prevSupplyAmount.Sub(burnAmount), curSupply) 888 s.Require().Equal(prevFrom.Sub(burnAmount), curFromAmount) 889 }) 890 } 891 } 892 893 func (s *KeeperTestSuite) TestMsgOperatorBurn() { 894 testCases := map[string]struct { 895 isNegativeCase bool 896 req *token.MsgOperatorBurn 897 expectedEvent sdk.Event 898 expectedError *sdkerrors.Error 899 }{ 900 "operatorBurn(contractID, operator, from, 1)": { 901 req: &token.MsgOperatorBurn{ 902 ContractId: s.contractID, 903 Operator: s.operator.String(), 904 From: s.customer.String(), 905 Amount: sdk.OneInt(), 906 }, 907 expectedEvent: sdk.Event{ 908 Type: "lbm.token.v1.EventBurned", 909 Attributes: []abci.EventAttribute{ 910 {Key: []byte("amount"), Value: testutil.W(sdk.OneInt()), Index: false}, 911 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 912 {Key: []byte("from"), Value: testutil.W(s.customer), Index: false}, 913 {Key: []byte("operator"), Value: testutil.W(s.operator), Index: false}, 914 }, 915 }, 916 }, 917 "operatorBurn(nonExistingContractId, operator, from, 1) -> error": { 918 isNegativeCase: true, 919 req: &token.MsgOperatorBurn{ 920 ContractId: "fee1dead", 921 Operator: s.operator.String(), 922 From: s.customer.String(), 923 Amount: sdk.OneInt(), 924 }, 925 expectedError: class.ErrContractNotExist, 926 }, 927 "operatorBurn(contractID, operator, unauthorized account, 1) -> error": { 928 isNegativeCase: true, 929 req: &token.MsgOperatorBurn{ 930 ContractId: s.contractID, 931 Operator: s.operator.String(), 932 From: s.stranger.String(), 933 Amount: sdk.OneInt(), 934 }, 935 expectedError: token.ErrTokenNotApproved, 936 }, 937 } 938 939 for name, tc := range testCases { 940 s.Run(name, func() { 941 // Arrange 942 operator, err := sdk.AccAddressFromBech32(tc.req.Operator) 943 s.Require().NoError(err) 944 from, err := sdk.AccAddressFromBech32(tc.req.From) 945 s.Require().NoError(err) 946 prevOperator := s.keeper.GetBalance(s.ctx, tc.req.ContractId, operator) 947 prevFrom := s.keeper.GetBalance(s.ctx, tc.req.ContractId, from) 948 prevBurnt := s.keeper.GetBurnt(s.ctx, tc.req.ContractId) 949 prevSupplyAmount := s.keeper.GetSupply(s.ctx, tc.req.ContractId) 950 s.Require().NoError(tc.req.ValidateBasic()) 951 prevEvtCnt := len(s.ctx.EventManager().Events()) 952 953 // Act 954 res, err := s.msgServer.OperatorBurn(sdk.WrapSDKContext(s.ctx), tc.req) 955 if tc.isNegativeCase { 956 s.Require().Nil(res) 957 s.Require().ErrorIs(err, tc.expectedError) 958 s.Require().Equal(prevEvtCnt, len(s.ctx.EventManager().Events())) 959 return 960 } 961 s.Require().NoError(err) 962 s.Require().NotNil(res) 963 964 // Assert 965 events := s.ctx.EventManager().Events() 966 s.Require().Equal(events[len(events)-1], tc.expectedEvent) 967 s.Require().Greater(len(s.ctx.EventManager().Events()), prevEvtCnt) 968 969 curBurnt := s.keeper.GetBurnt(s.ctx, tc.req.ContractId) 970 curSupply := s.keeper.GetSupply(s.ctx, tc.req.ContractId) 971 curFromAmount := s.keeper.GetBalance(s.ctx, s.contractID, from) 972 burnAmount := tc.req.Amount 973 s.Require().Equal(prevBurnt.Add(burnAmount), curBurnt) 974 s.Require().Equal(prevSupplyAmount.Sub(burnAmount), curSupply) 975 s.Require().Equal(prevFrom.Sub(burnAmount), curFromAmount) 976 if !from.Equals(operator) { 977 curOperator := s.keeper.GetBalance(s.ctx, s.contractID, operator) 978 s.Require().Equal(prevOperator, curOperator) 979 } 980 }) 981 } 982 } 983 984 func (s *KeeperTestSuite) TestMsgModify() { 985 testCases := map[string]struct { 986 isNegativeCase bool 987 req *token.MsgModify 988 expectedEvents sdk.Events 989 expectedError *sdkerrors.Error 990 }{ 991 "modify(contractID, owner, changes:uri,name)": { 992 req: &token.MsgModify{ 993 ContractId: s.contractID, 994 Owner: s.vendor.String(), 995 Changes: []token.Attribute{ 996 {Key: token.AttributeKeyURI.String(), Value: "uri"}, 997 {Key: token.AttributeKeyName.String(), Value: "NA<ENDSLSDN"}, 998 }, 999 }, 1000 expectedEvents: []sdk.Event{ 1001 { 1002 Type: "lbm.token.v1.EventModified", 1003 Attributes: []abci.EventAttribute{ 1004 {Key: []byte("changes"), Value: testutil.MustJSONMarshal([]token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}, {Key: token.AttributeKeyName.String(), Value: "NA<ENDSLSDN"}}), Index: false}, 1005 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 1006 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 1007 }, 1008 }, 1009 }, 1010 }, 1011 "modify(contractID, owner, changes:uri)": { 1012 req: &token.MsgModify{ 1013 ContractId: s.contractID, 1014 Owner: s.vendor.String(), 1015 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri222"}}, 1016 }, 1017 expectedEvents: []sdk.Event{{ 1018 Type: "lbm.token.v1.EventModified", 1019 Attributes: []abci.EventAttribute{ 1020 {Key: []byte("changes"), Value: testutil.MustJSONMarshal([]token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri222"}}), Index: false}, 1021 {Key: []byte("contract_id"), Value: testutil.W(s.contractID), Index: false}, 1022 {Key: []byte("operator"), Value: testutil.W(s.vendor), Index: false}, 1023 }}, 1024 }, 1025 }, 1026 "modify(nonExistingContractId, from, 1) -> error": { 1027 isNegativeCase: true, 1028 req: &token.MsgModify{ 1029 ContractId: "fee1dead", 1030 Owner: s.vendor.String(), 1031 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}}, 1032 }, 1033 expectedError: class.ErrContractNotExist, 1034 }, 1035 "modify(contractID, from, unauthorized account, 1) -> error": { 1036 isNegativeCase: true, 1037 req: &token.MsgModify{ 1038 ContractId: s.contractID, 1039 Owner: s.stranger.String(), 1040 Changes: []token.Attribute{{Key: token.AttributeKeyURI.String(), Value: "uri"}}, 1041 }, 1042 expectedError: token.ErrTokenNoPermission, 1043 }, 1044 } 1045 1046 for name, tc := range testCases { 1047 s.Run(name, func() { 1048 // Arrange 1049 s.Require().NoError(tc.req.ValidateBasic()) 1050 ctx, _ := s.ctx.CacheContext() 1051 1052 // Act 1053 res, err := s.msgServer.Modify(sdk.WrapSDKContext(ctx), tc.req) 1054 if tc.isNegativeCase { 1055 s.Require().Nil(res) 1056 s.Require().ErrorIs(err, tc.expectedError) 1057 s.Require().Equal(0, len(ctx.EventManager().Events())) 1058 return 1059 } 1060 s.Require().NotNil(res) 1061 s.Require().NoError(err) 1062 1063 // Assert 1064 events := ctx.EventManager().Events() 1065 s.Require().Equal(tc.expectedEvents, events) 1066 }) 1067 } 1068 }