Search Apps Documentation Source Content File Folder Download Copy Actions Download

registry.gno

5.63 Kb · 212 lines
  1package nftregistry2
  2
  3import (
  4	"chain/runtime"
  5
  6	"gno.land/p/nt/avl"
  7	"gno.land/p/demo/tokens/grc721"
  8)
  9
 10// CollectionInfo - Extended metadata stored in the registry
 11type CollectionInfo struct {
 12	Address         address           // Realm address of the NFT collection
 13	Name            string            // Collection name (from IGRC721CollectionMetadata)
 14	Symbol          string            // Collection symbol (from IGRC721CollectionMetadata)
 15	Creator         address           // Address that registered the collection
 16	RegisteredAt    int64             // Block height at registration
 17	Verified        bool              // Admin verification status
 18	Category        string            // Optional: "art", "gaming", "pfp", "utility", etc.
 19	Description     string            // Human-readable description
 20	ExternalURL     string            // Collection website/homepage
 21	NFTGetter       grc721.NFTGetter  // Function to get the NFT instance
 22	SupportsMetadata bool             // Does collection implement IGRC721MetadataOnchain?
 23}
 24
 25var (
 26	// Main registry: address → CollectionInfo
 27	collections avl.Tree // key: string(address), value: *CollectionInfo
 28
 29	// Admin addresses that can verify collections
 30	admins avl.Tree // key: string(address), value: bool
 31
 32	// Category index for faster filtering
 33	categoriesIndex avl.Tree // key: category, value: []address
 34
 35	// Owner of the registry
 36	owner address
 37
 38	// Registration fee (in ugnot)
 39	registrationFee int64 = 1000000 // 1 GNOT default
 40
 41	// Stats
 42	totalCollections int
 43	verifiedCount    int
 44)
 45
 46func init() {
 47	owner = runtime.PreviousRealm().Address()
 48	admins.Set(owner.String(), true)
 49}
 50
 51// RegisterCollection - Register a new NFT collection
 52// The collection realm must call this function itself
 53func RegisterCollection(
 54	name string,            // ← Ajouté
 55	symbol string,          // ← Ajouté
 56	category string,
 57	description string,
 58	externalURL string,
 59	getter grc721.NFTGetter,
 60) {
 61	caller := runtime.PreviousRealm().Address()
 62
 63	// Check if collection already registered
 64	if collections.Has(caller.String()) {
 65		panic("Collection already registered")
 66	}
 67
 68	if getter == nil {
 69		panic("NFT getter function is required")
 70	}
 71
 72	// Validate inputs
 73	if name == "" || symbol == "" {
 74		panic("Name and symbol cannot be empty")
 75	}
 76
 77	// Note: We trust the caller to provide correct name/symbol
 78	// since they match their own NFT collection
 79
 80	// Check if getter works
 81	nftInstance := getter()
 82	if nftInstance == nil {
 83		panic("NFT getter returned nil")
 84	}
 85
 86	// Check if implements IGRC721MetadataOnchain for rich metadata
 87	var supportsMetadata bool
 88	if _, ok := nftInstance.(grc721.IGRC721MetadataOnchain); ok {
 89		supportsMetadata = true
 90	}
 91
 92	// Create collection info
 93	info := &CollectionInfo{
 94		Address:          caller,
 95		Name:             name,
 96		Symbol:           symbol,
 97		Creator:          caller,
 98		RegisteredAt:     runtime.ChainHeight(),
 99		Verified:         false,
100		Category:         category,
101		Description:      description,
102		ExternalURL:      externalURL,
103		NFTGetter:        getter,
104		SupportsMetadata: supportsMetadata,
105	}
106
107	collections.Set(caller.String(), info)
108	totalCollections++
109}
110
111// IsRegistered - Check if a collection is registered
112func IsRegistered(collectionAddr address) bool {
113	return collections.Has(collectionAddr.String())
114}
115
116// GetCollection - Get collection info by address
117func GetCollection(collectionAddr address) *CollectionInfo {
118	val, exists := collections.Get(collectionAddr.String())
119	if !exists {
120		return nil
121	}
122	return val.(*CollectionInfo)
123}
124
125// GetNFTGetter - Get the NFT getter function for a collection
126// This is the main function marketplaces will use
127func GetNFTGetter(collectionAddr address) (grc721.NFTGetter, bool) {
128	info := GetCollection(collectionAddr)
129	if info == nil {
130		return nil, false
131	}
132	return info.NFTGetter, true
133}
134
135// GetTokenMetadata - Get metadata for a specific token (if collection supports it)
136func GetTokenMetadata(collectionAddr address, tokenId grc721.TokenID) (grc721.Metadata, error) {
137	info := GetCollection(collectionAddr)
138	if info == nil {
139		panic("Collection not registered")
140	}
141
142	if !info.SupportsMetadata {
143		panic("Collection does not support onchain metadata")
144	}
145
146	nftInstance := info.NFTGetter()
147	metadataCollection := nftInstance.(grc721.IGRC721MetadataOnchain)
148
149	return metadataCollection.TokenMetadata(tokenId)
150}
151
152// VerifyCollection - Admin function to verify a collection
153func VerifyCollection(collectionAddr address) {
154	caller := runtime.PreviousRealm().Address()
155
156	if !isAdmin(caller) {
157		panic("Only admins can verify collections")
158	}
159
160	info := GetCollection(collectionAddr)
161	if info == nil {
162		panic("Collection not found")
163	}
164
165	if !info.Verified {
166		info.Verified = true
167		verifiedCount++
168		collections.Set(collectionAddr.String(), info)
169	}
170}
171
172// UnverifyCollection - Admin function to remove verification
173func UnverifyCollection(collectionAddr address) {
174	caller := runtime.PreviousRealm().Address()
175
176	if !isAdmin(caller) {
177		panic("Only admins can unverify collections")
178	}
179
180	info := GetCollection(collectionAddr)
181	if info == nil {
182		panic("Collection not found")
183	}
184
185	if info.Verified {
186		info.Verified = false
187		verifiedCount--
188		collections.Set(collectionAddr.String(), info)
189	}
190}
191
192// UpdateCollectionInfo - Collection creator can update mutable metadata
193func UpdateCollectionInfo(category, description, externalURL string) {
194	caller := runtime.PreviousRealm().Address()
195
196	info := GetCollection(caller)
197	if info == nil {
198		panic("Collection not registered")
199	}
200
201	info.Category = category
202	info.Description = description
203	info.ExternalURL = externalURL
204	collections.Set(caller.String(), info)
205}
206
207// Helper functions
208
209func isAdmin(addr address) bool {
210	_, exists := admins.Get(addr.String())
211	return exists
212}