diff --git a/examples/gno.land/p/demo/grc/grc721/basic_nft.gno b/examples/gno.land/p/demo/grc/grc721/basic_nft.gno index 0505aaa1c26..d2e7ca506fa 100644 --- a/examples/gno.land/p/demo/grc/grc721/basic_nft.gno +++ b/examples/gno.land/p/demo/grc/grc721/basic_nft.gno @@ -395,3 +395,10 @@ func (s *basicNFT) RenderHome() (str string) { return } + +// Then add the Getter method to your NFT types +func (n *basicNFT) Getter() NFTGetter { + return func() IGRC721 { + return n + } +} diff --git a/examples/gno.land/p/demo/grc/grc721/igrc721.gno b/examples/gno.land/p/demo/grc/grc721/igrc721.gno index 6c26c953d51..508da6744d9 100644 --- a/examples/gno.land/p/demo/grc/grc721/igrc721.gno +++ b/examples/gno.land/p/demo/grc/grc721/igrc721.gno @@ -26,3 +26,6 @@ const ( ApprovalEvent = "Approval" ApprovalForAllEvent = "ApprovalForAll" ) + +type NFTGetter func() IGRC721 + diff --git a/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno b/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno index 6ab2812e520..231ddd28847 100644 --- a/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno +++ b/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno @@ -3,51 +3,51 @@ package tokenhub import ( "std" - "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/ufmt" ) - var ( - tokenA *grc20.Token - tokenB *grc20.Token - tokenC *grc20.Token - tokenD *grc20.Token - tokenE *grc20.Token + // Initialize basic NFTs using the public constructor + nftA = grc721.NewBasicNFT("Collection A", "NFTA") + nftB = grc721.NewBasicNFT("Collection B", "NFTB") + nftC = grc721.NewBasicNFT("Collection C", "NFTC") ) - func init() { - tokenA = grc20.NewToken("Token A", "TKNA", 6) - tokenB = grc20.NewToken("Token B", "TKNB", 6) - tokenC = grc20.NewToken("Token C", "TKNC", 6) - tokenD = grc20.NewToken("Token D", "TKND", 6) - tokenE = grc20.NewToken("Token E", "TKNE", 6) - - Send5OfEach("g1ej0qca5ptsw9kfr64ey8jvfy9eacga6mpj2z0y") - RegisterToken(tokenA) - RegisterToken(tokenB) - RegisterToken(tokenC) - RegisterToken(tokenD) - RegisterToken(tokenE) + + // Test address to receive NFTs + testAddr := std.Address("g1ej0qca5ptsw9kfr64ey8jvfy9eacga6mpj2z0y") + + // Mint test NFTs + MintTestNFTs(testAddr) + + // Register all NFT collections using the Getter method + RegisterNFT(func() grc721.IGRC721 { return nftA }) + RegisterNFT(func() grc721.IGRC721 { return nftB }) + RegisterNFT(func() grc721.IGRC721 { return nftC }) } -func Send5OfEach(to std.Address) error { +func MintTestNFTs(to std.Address) error { if !to.IsValid() { - return grc20.ErrInvalidAddress + return grc721.ErrInvalidAddress } - if err := adminA.Mint(to, 5); err != nil { - return err - } - if err := adminB.Mint(to, 5); err != nil { - return err - } - if err := adminC.Mint(to, 5); err != nil { - return err - } - if err := adminD.Mint(to, 5); err != nil { - return err - } - if err := adminE.Mint(to, 5); err != nil { - return err + // Mint NFTs for each collection + for i := 1; i <= 2; i++ { + // Create TokenID for each NFT + tokenIDA := grc721.TokenID(ufmt.Sprintf("NFTA_%d", i)) + if err := nftA.Mint(to, tokenIDA); err != nil { + return err + } + + tokenIDB := grc721.TokenID(ufmt.Sprintf("NFTB_%d", i)) + if err := nftB.Mint(to, tokenIDB); err != nil { + return err + } + + tokenIDC := grc721.TokenID(ufmt.Sprintf("NFTC_%d", i)) + if err := nftC.Mint(to, tokenIDC); err != nil { + return err + } } return nil diff --git a/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno b/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno index c5264378600..a7664a2cfab 100644 --- a/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno +++ b/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno @@ -3,28 +3,34 @@ package tokenhub import ( "std" "errors" - "strings" + "strings" "gno.land/p/demo/avl" - "gno.land/p/demo/grc/grc20" - "gno.land/p/moul/md" - "gno.land/p/demo/ufmt" + "gno.land/p/demo/grc/grc721" + "gno.land/p/moul/md" + "gno.land/p/demo/ufmt" ) var ( - registeredTokens = avl.NewTree() // symbol -> *grc20.Token + registeredNFTs = avl.NewTree() // symbol -> NFTGetter - ErrTokenAlreadyRegistered = errors.New("token already registered") - ErrTokenNotFound = errors.New("token not found") + ErrNFTAlreadyRegistered = errors.New("NFT already registered") + ErrNFTNotFound = errors.New("NFT not found") ) -func RegisterToken(token *grc20.Token) error { - symbol := token.GetSymbol() +func RegisterNFT(nftGetter grc721.NFTGetter) error { + nft := nftGetter() + metadata, ok := nft.(grc721.IGRC721CollectionMetadata) + if !ok { + return errors.New("NFT must implement IGRC721CollectionMetadata") + } + + symbol := metadata.Symbol() - if registeredTokens.Has(symbol) { - return ErrTokenAlreadyRegistered + if registeredNFTs.Has(symbol) { + return ErrNFTAlreadyRegistered } - registeredTokens.Set(symbol, token) + registeredNFTs.Set(symbol, nftGetter) return nil } @@ -32,14 +38,15 @@ func getBalances(addr std.Address) string { balances := avl.NewTree() var sb strings.Builder - registeredTokens.Iterate("", "", func(key string, value interface{}) bool { - token := value.(*grc20.Token) - balance := token.BalanceOf(addr) + registeredNFTs.Iterate("", "", func(key string, value interface{}) bool { + nftGetter := value.(grc721.NFTGetter) + nft := nftGetter() + balance, _ := nft.BalanceOf(addr) balances.Set(key, balance) return false }) - sb.WriteString("Balances: ") + sb.WriteString("NFT Balances: ") balances.Iterate("", "", func(key string, value interface{}) bool { balance := value.(uint64) sb.WriteString(ufmt.Sprintf("%s: %d ", key, balance)) @@ -56,25 +63,29 @@ func GetMyBalances() string { func Render(path string) string { var sb strings.Builder - sb.WriteString(md.H1("TokenHub")) - sb.WriteString(md.Paragraph("A central registry for GRC20 tokens on gno.land")) + sb.WriteString(md.H1("NFT Hub")) + sb.WriteString(md.Paragraph("A central registry for GRC721 NFTs on gno.land")) - sb.WriteString(md.H2("Registered Tokens")) + sb.WriteString(md.H2("Registered NFTs")) - var tokenItems []string - registeredTokens.Iterate("", "", func(key string, value interface{}) bool { - token := value.(*grc20.Token) - tokenItems = append(tokenItems, ufmt.Sprintf("%s (%s) - %d decimals", - token.GetName(), - token.GetSymbol(), - token.GetDecimals())) + var nftItems []string + registeredNFTs.Iterate("", "", func(key string, value interface{}) bool { + nftGetter := value.(grc721.NFTGetter) + nft := nftGetter() + metadata, ok := nft.(grc721.IGRC721CollectionMetadata) + if !ok { + return false + } + nftItems = append(nftItems, ufmt.Sprintf("%s (%s)", + metadata.Name(), + metadata.Symbol())) return false }) - if len(tokenItems) > 0 { - sb.WriteString(md.BulletList(tokenItems)) + if len(nftItems) > 0 { + sb.WriteString(md.BulletList(nftItems)) } else { - sb.WriteString(md.Italic("No tokens registered yet")) + sb.WriteString(md.Italic("No NFTs registered yet")) sb.WriteString("\n") }