github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/grc/grc721/grc721_metadata.gno (about) 1 package grc721 2 3 import ( 4 "std" 5 6 "gno.land/p/demo/avl" 7 ) 8 9 // metadataNFT represents an NFT with metadata extensions. 10 type metadataNFT struct { 11 *basicNFT // Embedded basicNFT struct for basic NFT functionality 12 extensions *avl.Tree // AVL tree for storing metadata extensions 13 } 14 15 // Ensure that metadataNFT implements the IGRC721MetadataOnchain interface. 16 var _ IGRC721MetadataOnchain = (*metadataNFT)(nil) 17 18 // NewNFTWithMetadata creates a new basic NFT with metadata extensions. 19 func NewNFTWithMetadata(name string, symbol string) *metadataNFT { 20 // Create a new basic NFT 21 nft := NewBasicNFT(name, symbol) 22 23 // Return a metadataNFT with basicNFT embedded and an empty AVL tree for extensions 24 return &metadataNFT{ 25 basicNFT: nft, 26 extensions: avl.NewTree(), 27 } 28 } 29 30 // SetTokenMetadata sets metadata for a given token ID. 31 func (s *metadataNFT) SetTokenMetadata(tid TokenID, metadata Metadata) error { 32 // Check if the caller is the owner of the token 33 owner, err := s.basicNFT.OwnerOf(tid) 34 if err != nil { 35 return err 36 } 37 caller := std.PrevRealm().Addr() 38 if caller != owner { 39 return ErrCallerIsNotOwner 40 } 41 42 // Set the metadata for the token ID in the extensions AVL tree 43 s.extensions.Set(string(tid), metadata) 44 return nil 45 } 46 47 // TokenMetadata retrieves metadata for a given token ID. 48 func (s *metadataNFT) TokenMetadata(tid TokenID) (Metadata, error) { 49 // Retrieve metadata from the extensions AVL tree 50 metadata, found := s.extensions.Get(string(tid)) 51 if !found { 52 return Metadata{}, ErrInvalidTokenId 53 } 54 55 return metadata.(Metadata), nil 56 } 57 58 // mint mints a new token and assigns it to the specified address. 59 func (s *metadataNFT) mint(to std.Address, tid TokenID) error { 60 // Check if the address is valid 61 if err := isValidAddress(to); err != nil { 62 return err 63 } 64 65 // Check if the token ID already exists 66 if s.basicNFT.exists(tid) { 67 return ErrTokenIdAlreadyExists 68 } 69 70 s.basicNFT.beforeTokenTransfer(zeroAddress, to, tid, 1) 71 72 // Check if the token ID was minted by beforeTokenTransfer 73 if s.basicNFT.exists(tid) { 74 return ErrTokenIdAlreadyExists 75 } 76 77 // Increment balance of the recipient address 78 toBalance, err := s.basicNFT.BalanceOf(to) 79 if err != nil { 80 return err 81 } 82 toBalance += 1 83 s.basicNFT.balances.Set(to.String(), toBalance) 84 85 // Set owner of the token ID to the recipient address 86 s.basicNFT.owners.Set(string(tid), to) 87 88 // Emit transfer event 89 event := TransferEvent{zeroAddress, to, tid} 90 emit(&event) 91 92 s.basicNFT.afterTokenTransfer(zeroAddress, to, tid, 1) 93 94 return nil 95 }