github.com/Finschia/finschia-sdk@v0.48.1/x/collection/keeper/msg_server.go (about) 1 package keeper 2 3 import ( 4 "context" 5 6 "github.com/gogo/protobuf/proto" 7 8 sdk "github.com/Finschia/finschia-sdk/types" 9 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 10 "github.com/Finschia/finschia-sdk/x/collection" 11 ) 12 13 type msgServer struct { 14 keeper Keeper 15 } 16 17 // NewMsgServer returns an implementation of the collection MsgServer interface 18 // for the provided Keeper. 19 func NewMsgServer(keeper Keeper) collection.MsgServer { 20 return &msgServer{ 21 keeper: keeper, 22 } 23 } 24 25 var _ collection.MsgServer = (*msgServer)(nil) 26 27 func (s msgServer) SendFT(c context.Context, req *collection.MsgSendFT) (*collection.MsgSendFTResponse, error) { 28 ctx := sdk.UnwrapSDKContext(c) 29 30 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 31 return nil, err 32 } 33 34 fromAddr := sdk.MustAccAddressFromBech32(req.From) 35 toAddr := sdk.MustAccAddressFromBech32(req.To) 36 37 if err := s.keeper.SendCoins(ctx, req.ContractId, fromAddr, toAddr, req.Amount); err != nil { 38 return nil, err 39 } 40 41 event := collection.EventSent{ 42 ContractId: req.ContractId, 43 Operator: req.From, 44 From: req.From, 45 To: req.To, 46 Amount: req.Amount, 47 } 48 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 49 panic(err) 50 } 51 52 return &collection.MsgSendFTResponse{}, nil 53 } 54 55 func (s msgServer) OperatorSendFT(c context.Context, req *collection.MsgOperatorSendFT) (*collection.MsgOperatorSendFTResponse, error) { 56 ctx := sdk.UnwrapSDKContext(c) 57 58 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 59 return nil, err 60 } 61 62 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 63 fromAddr := sdk.MustAccAddressFromBech32(req.From) 64 65 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 66 return nil, collection.ErrCollectionNotApproved.Wrap(err.Error()) 67 } 68 69 toAddr := sdk.MustAccAddressFromBech32(req.To) 70 71 if err := s.keeper.SendCoins(ctx, req.ContractId, fromAddr, toAddr, req.Amount); err != nil { 72 return nil, err 73 } 74 75 event := collection.EventSent{ 76 ContractId: req.ContractId, 77 Operator: req.Operator, 78 From: req.From, 79 To: req.To, 80 Amount: req.Amount, 81 } 82 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 83 panic(err) 84 } 85 86 return &collection.MsgOperatorSendFTResponse{}, nil 87 } 88 89 func (s msgServer) SendNFT(c context.Context, req *collection.MsgSendNFT) (*collection.MsgSendNFTResponse, error) { 90 ctx := sdk.UnwrapSDKContext(c) 91 92 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 93 return nil, err 94 } 95 96 fromAddr := sdk.MustAccAddressFromBech32(req.From) 97 98 amount := make([]collection.Coin, len(req.TokenIds)) 99 for i, id := range req.TokenIds { 100 amount[i] = collection.Coin{TokenId: id, Amount: sdk.OneInt()} 101 102 // legacy 103 if err := s.keeper.hasNFT(ctx, req.ContractId, id); err != nil { 104 return nil, err 105 } 106 if _, err := s.keeper.GetParent(ctx, req.ContractId, id); err == nil { 107 return nil, collection.ErrTokenCannotTransferChildToken.Wrap(id) 108 } 109 if !s.keeper.getOwner(ctx, req.ContractId, id).Equals(fromAddr) { 110 return nil, collection.ErrTokenNotOwnedBy.Wrapf("%s does not have %s", fromAddr, id) 111 } 112 } 113 114 toAddr := sdk.MustAccAddressFromBech32(req.To) 115 116 if err := s.keeper.SendCoins(ctx, req.ContractId, fromAddr, toAddr, amount); err != nil { 117 panic(err) 118 } 119 120 event := collection.EventSent{ 121 ContractId: req.ContractId, 122 Operator: req.From, 123 From: req.From, 124 To: req.To, 125 Amount: amount, 126 } 127 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 128 panic(err) 129 } 130 131 return &collection.MsgSendNFTResponse{}, nil 132 } 133 134 func (s msgServer) OperatorSendNFT(c context.Context, req *collection.MsgOperatorSendNFT) (*collection.MsgOperatorSendNFTResponse, error) { 135 ctx := sdk.UnwrapSDKContext(c) 136 137 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 138 return nil, err 139 } 140 141 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 142 fromAddr := sdk.MustAccAddressFromBech32(req.From) 143 144 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 145 return nil, collection.ErrCollectionNotApproved.Wrap(err.Error()) 146 } 147 148 amount := make([]collection.Coin, len(req.TokenIds)) 149 for i, id := range req.TokenIds { 150 amount[i] = collection.Coin{TokenId: id, Amount: sdk.OneInt()} 151 152 // legacy 153 if err := s.keeper.hasNFT(ctx, req.ContractId, id); err != nil { 154 return nil, err 155 } 156 if _, err := s.keeper.GetParent(ctx, req.ContractId, id); err == nil { 157 return nil, collection.ErrTokenCannotTransferChildToken.Wrap(id) 158 } 159 if !s.keeper.getOwner(ctx, req.ContractId, id).Equals(fromAddr) { 160 return nil, collection.ErrTokenNotOwnedBy.Wrapf("%s does not have %s", fromAddr, id) 161 } 162 } 163 164 toAddr := sdk.MustAccAddressFromBech32(req.To) 165 166 if err := s.keeper.SendCoins(ctx, req.ContractId, fromAddr, toAddr, amount); err != nil { 167 panic(err) 168 } 169 170 event := collection.EventSent{ 171 ContractId: req.ContractId, 172 Operator: req.Operator, 173 From: req.From, 174 To: req.To, 175 Amount: amount, 176 } 177 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 178 panic(err) 179 } 180 181 return &collection.MsgOperatorSendNFTResponse{}, nil 182 } 183 184 func (s msgServer) AuthorizeOperator(c context.Context, req *collection.MsgAuthorizeOperator) (*collection.MsgAuthorizeOperatorResponse, error) { 185 ctx := sdk.UnwrapSDKContext(c) 186 187 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 188 return nil, err 189 } 190 191 holderAddr := sdk.MustAccAddressFromBech32(req.Holder) 192 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 193 194 if err := s.keeper.AuthorizeOperator(ctx, req.ContractId, holderAddr, operatorAddr); err != nil { 195 return nil, err 196 } 197 198 event := collection.EventAuthorizedOperator{ 199 ContractId: req.ContractId, 200 Holder: req.Holder, 201 Operator: req.Operator, 202 } 203 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 204 panic(err) 205 } 206 207 return &collection.MsgAuthorizeOperatorResponse{}, nil 208 } 209 210 func (s msgServer) RevokeOperator(c context.Context, req *collection.MsgRevokeOperator) (*collection.MsgRevokeOperatorResponse, error) { 211 ctx := sdk.UnwrapSDKContext(c) 212 213 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 214 return nil, err 215 } 216 217 holderAddr := sdk.MustAccAddressFromBech32(req.Holder) 218 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 219 220 if err := s.keeper.RevokeOperator(ctx, req.ContractId, holderAddr, operatorAddr); err != nil { 221 return nil, err 222 } 223 224 event := collection.EventRevokedOperator{ 225 ContractId: req.ContractId, 226 Holder: req.Holder, 227 Operator: req.Operator, 228 } 229 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 230 panic(err) 231 } 232 233 return &collection.MsgRevokeOperatorResponse{}, nil 234 } 235 236 func (s msgServer) CreateContract(c context.Context, req *collection.MsgCreateContract) (*collection.MsgCreateContractResponse, error) { 237 ctx := sdk.UnwrapSDKContext(c) 238 239 contract := collection.Contract{ 240 Name: req.Name, 241 Uri: req.Uri, 242 Meta: req.Meta, 243 } 244 ownerAddr := sdk.MustAccAddressFromBech32(req.Owner) 245 246 id := s.keeper.CreateContract(ctx, ownerAddr, contract) 247 248 return &collection.MsgCreateContractResponse{ContractId: id}, nil 249 } 250 251 func (s msgServer) IssueFT(c context.Context, req *collection.MsgIssueFT) (*collection.MsgIssueFTResponse, error) { 252 ctx := sdk.UnwrapSDKContext(c) 253 254 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 255 return nil, err 256 } 257 258 ownerAddr := sdk.MustAccAddressFromBech32(req.Owner) 259 260 if _, err := s.keeper.GetGrant(ctx, req.ContractId, ownerAddr, collection.PermissionIssue); err != nil { 261 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 262 } 263 264 class := &collection.FTClass{ 265 Name: req.Name, 266 Meta: req.Meta, 267 Decimals: req.Decimals, 268 Mintable: req.Mintable, 269 } 270 id, err := s.keeper.CreateTokenClass(ctx, req.ContractId, class) 271 if err != nil { 272 return nil, err 273 } 274 275 event := collection.EventCreatedFTClass{ 276 ContractId: req.ContractId, 277 Operator: req.Owner, 278 TokenId: collection.NewFTID(*id), 279 Name: class.Name, 280 Meta: class.Meta, 281 Decimals: class.Decimals, 282 Mintable: class.Mintable, 283 } 284 285 toAddr := sdk.MustAccAddressFromBech32(req.To) 286 287 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 288 panic(err) 289 } 290 291 // supply tokens 292 if req.Amount.IsPositive() { 293 s.keeper.mintFT(ctx, req.ContractId, toAddr, *id, req.Amount) 294 295 event := collection.EventMintedFT{ 296 ContractId: req.ContractId, 297 Operator: req.Owner, 298 To: req.To, 299 Amount: collection.NewCoins(collection.NewFTCoin(*id, req.Amount)), 300 } 301 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 302 panic(err) 303 } 304 } 305 306 return &collection.MsgIssueFTResponse{TokenId: *id}, nil 307 } 308 309 func (s msgServer) IssueNFT(c context.Context, req *collection.MsgIssueNFT) (*collection.MsgIssueNFTResponse, error) { 310 ctx := sdk.UnwrapSDKContext(c) 311 312 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 313 return nil, err 314 } 315 316 ownerAddr := sdk.MustAccAddressFromBech32(req.Owner) 317 318 if _, err := s.keeper.GetGrant(ctx, req.ContractId, ownerAddr, collection.PermissionIssue); err != nil { 319 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 320 } 321 322 class := &collection.NFTClass{ 323 Name: req.Name, 324 Meta: req.Meta, 325 } 326 id, err := s.keeper.CreateTokenClass(ctx, req.ContractId, class) 327 if err != nil { 328 return nil, err 329 } 330 331 event := collection.EventCreatedNFTClass{ 332 ContractId: req.ContractId, 333 Operator: req.Owner, 334 TokenType: *id, 335 Name: class.Name, 336 Meta: class.Meta, 337 } 338 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 339 panic(err) 340 } 341 342 for _, permission := range []collection.Permission{ 343 collection.PermissionMint, 344 collection.PermissionBurn, 345 } { 346 s.keeper.Grant(ctx, req.ContractId, []byte{}, ownerAddr, permission) 347 } 348 349 return &collection.MsgIssueNFTResponse{TokenType: *id}, nil 350 } 351 352 func (s msgServer) MintFT(c context.Context, req *collection.MsgMintFT) (*collection.MsgMintFTResponse, error) { 353 ctx := sdk.UnwrapSDKContext(c) 354 355 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 356 return nil, err 357 } 358 359 fromAddr := sdk.MustAccAddressFromBech32(req.From) 360 361 if _, err := s.keeper.GetGrant(ctx, req.ContractId, fromAddr, collection.PermissionMint); err != nil { 362 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 363 } 364 365 toAddr := sdk.MustAccAddressFromBech32(req.To) 366 367 if err := s.keeper.MintFT(ctx, req.ContractId, toAddr, req.Amount); err != nil { 368 return nil, err 369 } 370 371 event := collection.EventMintedFT{ 372 ContractId: req.ContractId, 373 Operator: req.From, 374 To: req.To, 375 Amount: req.Amount, 376 } 377 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 378 panic(err) 379 } 380 381 return &collection.MsgMintFTResponse{}, nil 382 } 383 384 func (s msgServer) MintNFT(c context.Context, req *collection.MsgMintNFT) (*collection.MsgMintNFTResponse, error) { 385 ctx := sdk.UnwrapSDKContext(c) 386 387 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 388 return nil, err 389 } 390 391 fromAddr := sdk.MustAccAddressFromBech32(req.From) 392 393 if _, err := s.keeper.GetGrant(ctx, req.ContractId, fromAddr, collection.PermissionMint); err != nil { 394 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 395 } 396 397 toAddr := sdk.MustAccAddressFromBech32(req.To) 398 399 tokens, err := s.keeper.MintNFT(ctx, req.ContractId, toAddr, req.Params) 400 if err != nil { 401 return nil, err 402 } 403 404 event := collection.EventMintedNFT{ 405 ContractId: req.ContractId, 406 Operator: req.From, 407 To: req.To, 408 Tokens: tokens, 409 } 410 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 411 panic(err) 412 } 413 414 tokenIDs := make([]string, 0, len(tokens)) 415 for _, token := range tokens { 416 tokenIDs = append(tokenIDs, token.TokenId) 417 } 418 return &collection.MsgMintNFTResponse{TokenIds: tokenIDs}, nil 419 } 420 421 func (s msgServer) BurnFT(c context.Context, req *collection.MsgBurnFT) (*collection.MsgBurnFTResponse, error) { 422 ctx := sdk.UnwrapSDKContext(c) 423 424 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 425 return nil, err 426 } 427 428 fromAddr := sdk.MustAccAddressFromBech32(req.From) 429 430 if _, err := s.keeper.GetGrant(ctx, req.ContractId, fromAddr, collection.PermissionBurn); err != nil { 431 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 432 } 433 434 burnt, err := s.keeper.BurnCoins(ctx, req.ContractId, fromAddr, req.Amount) 435 if err != nil { 436 return nil, err 437 } 438 439 event := collection.EventBurned{ 440 ContractId: req.ContractId, 441 Operator: req.From, 442 From: req.From, 443 Amount: burnt, 444 } 445 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 446 panic(err) 447 } 448 449 return &collection.MsgBurnFTResponse{}, nil 450 } 451 452 func (s msgServer) OperatorBurnFT(c context.Context, req *collection.MsgOperatorBurnFT) (*collection.MsgOperatorBurnFTResponse, error) { 453 ctx := sdk.UnwrapSDKContext(c) 454 455 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 456 return nil, err 457 } 458 459 fromAddr := sdk.MustAccAddressFromBech32(req.From) 460 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 461 462 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 463 return nil, collection.ErrCollectionNotApproved.Wrap(err.Error()) 464 } 465 466 if _, err := s.keeper.GetGrant(ctx, req.ContractId, operatorAddr, collection.PermissionBurn); err != nil { 467 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 468 } 469 470 burnt, err := s.keeper.BurnCoins(ctx, req.ContractId, fromAddr, req.Amount) 471 if err != nil { 472 return nil, err 473 } 474 475 event := collection.EventBurned{ 476 ContractId: req.ContractId, 477 Operator: req.Operator, 478 From: req.From, 479 Amount: burnt, 480 } 481 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 482 panic(err) 483 } 484 485 return &collection.MsgOperatorBurnFTResponse{}, nil 486 } 487 488 func (s msgServer) BurnNFT(c context.Context, req *collection.MsgBurnNFT) (*collection.MsgBurnNFTResponse, error) { 489 ctx := sdk.UnwrapSDKContext(c) 490 491 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 492 return nil, err 493 } 494 495 fromAddr := sdk.MustAccAddressFromBech32(req.From) 496 497 if _, err := s.keeper.GetGrant(ctx, req.ContractId, fromAddr, collection.PermissionBurn); err != nil { 498 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 499 } 500 501 coins := make([]collection.Coin, 0, len(req.TokenIds)) 502 for _, id := range req.TokenIds { 503 coins = append(coins, collection.NewCoin(id, sdk.OneInt())) 504 505 // legacy 506 if err := s.keeper.hasNFT(ctx, req.ContractId, id); err != nil { 507 return nil, err 508 } 509 if _, err := s.keeper.GetParent(ctx, req.ContractId, id); err == nil { 510 return nil, collection.ErrBurnNonRootNFT.Wrap(id) 511 } 512 if !s.keeper.getOwner(ctx, req.ContractId, id).Equals(fromAddr) { 513 return nil, collection.ErrTokenNotOwnedBy.Wrapf("%s does not have %s", fromAddr, id) 514 } 515 } 516 517 burnt, err := s.keeper.BurnCoins(ctx, req.ContractId, fromAddr, coins) 518 if err != nil { 519 panic(err) 520 } 521 522 // emit events against all burnt tokens. 523 event := collection.EventBurned{ 524 ContractId: req.ContractId, 525 Operator: req.From, 526 From: req.From, 527 Amount: burnt, 528 } 529 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 530 panic(err) 531 } 532 533 return &collection.MsgBurnNFTResponse{}, nil 534 } 535 536 func (s msgServer) OperatorBurnNFT(c context.Context, req *collection.MsgOperatorBurnNFT) (*collection.MsgOperatorBurnNFTResponse, error) { 537 ctx := sdk.UnwrapSDKContext(c) 538 539 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 540 return nil, err 541 } 542 543 fromAddr := sdk.MustAccAddressFromBech32(req.From) 544 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 545 546 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 547 return nil, collection.ErrCollectionNotApproved.Wrap(err.Error()) 548 } 549 550 if _, err := s.keeper.GetGrant(ctx, req.ContractId, operatorAddr, collection.PermissionBurn); err != nil { 551 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 552 } 553 554 coins := make([]collection.Coin, 0, len(req.TokenIds)) 555 for _, id := range req.TokenIds { 556 coins = append(coins, collection.NewCoin(id, sdk.OneInt())) 557 558 // legacy 559 if err := s.keeper.hasNFT(ctx, req.ContractId, id); err != nil { 560 return nil, err 561 } 562 if _, err := s.keeper.GetParent(ctx, req.ContractId, id); err == nil { 563 return nil, collection.ErrBurnNonRootNFT.Wrap(id) 564 } 565 if !s.keeper.getOwner(ctx, req.ContractId, id).Equals(fromAddr) { 566 return nil, collection.ErrTokenNotOwnedBy.Wrapf("%s does not have %s", fromAddr, id) 567 } 568 } 569 570 burnt, err := s.keeper.BurnCoins(ctx, req.ContractId, fromAddr, coins) 571 if err != nil { 572 panic(err) 573 } 574 575 // emit events against all burnt tokens. 576 event := collection.EventBurned{ 577 ContractId: req.ContractId, 578 Operator: req.Operator, 579 From: req.From, 580 Amount: burnt, 581 } 582 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 583 panic(err) 584 } 585 586 return &collection.MsgOperatorBurnNFTResponse{}, nil 587 } 588 589 func (s msgServer) Modify(c context.Context, req *collection.MsgModify) (*collection.MsgModifyResponse, error) { 590 ctx := sdk.UnwrapSDKContext(c) 591 592 collection.UpdateMsgModify(req) 593 594 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 595 return nil, err 596 } 597 598 operator := sdk.MustAccAddressFromBech32(req.Owner) 599 600 if _, err := s.keeper.GetGrant(ctx, req.ContractId, operator, collection.PermissionModify); err != nil { 601 return nil, collection.ErrTokenNoPermission.Wrap(err.Error()) 602 } 603 604 // copied from daphne 605 modify := func(tokenType, tokenIndex string) error { 606 changes := make([]collection.Attribute, len(req.Changes)) 607 for i, change := range req.Changes { 608 changes[i] = collection.Attribute{ 609 Key: change.Key, 610 Value: change.Value, 611 } 612 } 613 614 classID := tokenType 615 tokenID := classID + tokenIndex 616 if tokenType != "" { 617 if tokenIndex != "" { 618 if collection.ValidateNFTID(tokenID) == nil { 619 event := collection.EventModifiedNFT{ 620 ContractId: req.ContractId, 621 Operator: operator.String(), 622 TokenId: tokenID, 623 Changes: changes, 624 } 625 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 626 panic(err) 627 } 628 629 return s.keeper.ModifyNFT(ctx, req.ContractId, tokenID, operator, changes) 630 } 631 632 event := collection.EventModifiedTokenClass{ 633 ContractId: req.ContractId, 634 Operator: operator.String(), 635 TokenType: classID, 636 Changes: changes, 637 TypeName: proto.MessageName(&collection.FTClass{}), 638 } 639 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 640 panic(err) 641 } 642 643 return s.keeper.ModifyTokenClass(ctx, req.ContractId, classID, operator, changes) 644 } 645 646 event := collection.EventModifiedTokenClass{ 647 ContractId: req.ContractId, 648 Operator: operator.String(), 649 TokenType: classID, 650 Changes: changes, 651 TypeName: proto.MessageName(&collection.NFTClass{}), 652 } 653 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 654 panic(err) 655 } 656 657 return s.keeper.ModifyTokenClass(ctx, req.ContractId, classID, operator, changes) 658 } 659 if req.TokenIndex == "" { 660 event := collection.EventModifiedContract{ 661 ContractId: req.ContractId, 662 Operator: operator.String(), 663 Changes: changes, 664 } 665 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 666 panic(err) 667 } 668 669 return s.keeper.ModifyContract(ctx, req.ContractId, operator, changes) 670 } 671 672 panic(sdkerrors.ErrInvalidRequest.Wrap("token index without type")) 673 } 674 675 if err := modify(req.TokenType, req.TokenIndex); err != nil { 676 return nil, err 677 } 678 679 return &collection.MsgModifyResponse{}, nil 680 } 681 682 func (s msgServer) GrantPermission(c context.Context, req *collection.MsgGrantPermission) (*collection.MsgGrantPermissionResponse, error) { 683 ctx := sdk.UnwrapSDKContext(c) 684 685 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 686 return nil, err 687 } 688 689 granter := sdk.MustAccAddressFromBech32(req.From) 690 grantee := sdk.MustAccAddressFromBech32(req.To) 691 permission := collection.Permission(collection.LegacyPermissionFromString(req.Permission)) 692 693 if _, err := s.keeper.GetGrant(ctx, req.ContractId, granter, permission); err != nil { 694 return nil, collection.ErrTokenNoPermission.Wrapf("%s is not authorized for %s", granter, permission) 695 } 696 697 // it emits typed event inside s.keeper.Grant() 698 s.keeper.Grant(ctx, req.ContractId, granter, grantee, permission) 699 700 return &collection.MsgGrantPermissionResponse{}, nil 701 } 702 703 func (s msgServer) RevokePermission(c context.Context, req *collection.MsgRevokePermission) (*collection.MsgRevokePermissionResponse, error) { 704 ctx := sdk.UnwrapSDKContext(c) 705 706 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 707 return nil, err 708 } 709 710 grantee := sdk.MustAccAddressFromBech32(req.From) 711 permission := collection.Permission(collection.LegacyPermissionFromString(req.Permission)) 712 713 if _, err := s.keeper.GetGrant(ctx, req.ContractId, grantee, permission); err != nil { 714 return nil, collection.ErrTokenNoPermission.Wrapf("%s is not authorized for %s", grantee, permission) 715 } 716 717 // it emits typed event inside s.keeper.Abandon() 718 s.keeper.Abandon(ctx, req.ContractId, grantee, permission) 719 720 return &collection.MsgRevokePermissionResponse{}, nil 721 } 722 723 func (s msgServer) Attach(c context.Context, req *collection.MsgAttach) (*collection.MsgAttachResponse, error) { 724 ctx := sdk.UnwrapSDKContext(c) 725 726 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 727 return nil, err 728 } 729 730 event := collection.EventAttached{ 731 ContractId: req.ContractId, 732 Operator: req.From, 733 Holder: req.From, 734 Subject: req.TokenId, 735 Target: req.ToTokenId, 736 } 737 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 738 panic(err) 739 } 740 741 fromAddr := sdk.MustAccAddressFromBech32(req.From) 742 743 if err := s.keeper.Attach(ctx, req.ContractId, fromAddr, req.TokenId, req.ToTokenId); err != nil { 744 return nil, err 745 } 746 747 return &collection.MsgAttachResponse{}, nil 748 } 749 750 func (s msgServer) Detach(c context.Context, req *collection.MsgDetach) (*collection.MsgDetachResponse, error) { 751 ctx := sdk.UnwrapSDKContext(c) 752 753 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 754 return nil, err 755 } 756 757 // legacy 758 if err := s.keeper.hasNFT(ctx, req.ContractId, req.TokenId); err != nil { 759 return nil, err 760 } 761 762 // for the additional field of the event 763 parent, err := s.keeper.GetParent(ctx, req.ContractId, req.TokenId) 764 if err != nil { 765 return nil, collection.ErrTokenNotAChild.Wrap(err.Error()) 766 } 767 event := collection.EventDetached{ 768 ContractId: req.ContractId, 769 Operator: req.From, 770 Holder: req.From, 771 Subject: req.TokenId, 772 PreviousParent: *parent, 773 } 774 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 775 panic(err) 776 } 777 778 fromAddr := sdk.MustAccAddressFromBech32(req.From) 779 780 if err := s.keeper.Detach(ctx, req.ContractId, fromAddr, req.TokenId); err != nil { 781 return nil, err 782 } 783 784 return &collection.MsgDetachResponse{}, nil 785 } 786 787 func (s msgServer) OperatorAttach(c context.Context, req *collection.MsgOperatorAttach) (*collection.MsgOperatorAttachResponse, error) { 788 ctx := sdk.UnwrapSDKContext(c) 789 790 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 791 return nil, err 792 } 793 794 fromAddr := sdk.MustAccAddressFromBech32(req.From) 795 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 796 797 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 798 return nil, collection.ErrCollectionNotApproved.Wrap(err.Error()) 799 } 800 801 event := collection.EventAttached{ 802 ContractId: req.ContractId, 803 Operator: req.Operator, 804 Holder: req.From, 805 Subject: req.TokenId, 806 Target: req.ToTokenId, 807 } 808 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 809 panic(err) 810 } 811 812 if err := s.keeper.Attach(ctx, req.ContractId, fromAddr, req.TokenId, req.ToTokenId); err != nil { 813 return nil, err 814 } 815 816 return &collection.MsgOperatorAttachResponse{}, nil 817 } 818 819 func (s msgServer) OperatorDetach(c context.Context, req *collection.MsgOperatorDetach) (*collection.MsgOperatorDetachResponse, error) { 820 ctx := sdk.UnwrapSDKContext(c) 821 822 if err := ValidateLegacyContract(s.keeper, ctx, req.ContractId); err != nil { 823 return nil, err 824 } 825 826 fromAddr := sdk.MustAccAddressFromBech32(req.From) 827 operatorAddr := sdk.MustAccAddressFromBech32(req.Operator) 828 829 if _, err := s.keeper.GetAuthorization(ctx, req.ContractId, fromAddr, operatorAddr); err != nil { 830 return nil, err 831 } 832 833 // legacy 834 if err := s.keeper.hasNFT(ctx, req.ContractId, req.TokenId); err != nil { 835 return nil, err 836 } 837 838 // for the additional field of the event 839 parent, err := s.keeper.GetParent(ctx, req.ContractId, req.TokenId) 840 if err != nil { 841 return nil, collection.ErrTokenNotAChild.Wrap(err.Error()) 842 } 843 event := collection.EventDetached{ 844 ContractId: req.ContractId, 845 Operator: req.Operator, 846 Holder: req.From, 847 Subject: req.TokenId, 848 PreviousParent: *parent, 849 } 850 if err := ctx.EventManager().EmitTypedEvent(&event); err != nil { 851 panic(err) 852 } 853 854 if err := s.keeper.Detach(ctx, req.ContractId, fromAddr, req.TokenId); err != nil { 855 return nil, err 856 } 857 858 return &collection.MsgOperatorDetachResponse{}, nil 859 }