Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

extensions.gno

3.61 Kb · 131 lines
  1package guardians
  2
  3import (
  4	"gno.land/p/nt/grc721/enumerable/v0"
  5	"gno.land/p/nt/grc721/metadata/v0"
  6	"gno.land/p/nt/grc721/royalty/v0"
  7	"gno.land/p/nt/grc721/v0"
  8)
  9
 10const (
 11	defaultRoyaltyBps = int64(400)  // 4% creator royalty on marketplace sales.
 12	royaltyMaxBps     = int64(1000) // Permanent collection cap: 10%.
 13)
 14
 15// Replace this value through SetVeiledURI before the first public mint.
 16// The explicit placeholder prevents an unfinished CID from looking production-ready.
 17var veiledURI = "ipfs://REPLACE_WITH_VEILED_METADATA_CID/metadata.json"
 18
 19var (
 20	metadataView     *metadata.Metadata
 21	metadataLedger   *metadata.Ledger
 22	enumerableView   *enumerable.Enumerable
 23	enumerableLedger *enumerable.Ledger
 24	royaltyView      *royalty.Royalty
 25	royaltyLedger    *royalty.Ledger
 26)
 27
 28// attachExtensions must run before the first mint so the enumerable index and
 29// metadata hooks observe every token from genesis.
 30func attachExtensions(coreLedger *grc721.PrivateLedger) {
 31	metadataView, metadataLedger = metadata.NewMetadata(coreLedger)
 32	enumerableView, enumerableLedger = enumerable.NewEnumerable(coreLedger)
 33	royaltyView, royaltyLedger = royalty.NewRoyalty(coreLedger, royaltyMaxBps)
 34
 35	if err := royaltyLedger.SetDefaultRoyalty(address("g1lp547ww848djw0ammpqswegg7tc6xczqqtx07n"), defaultRoyaltyBps); err != nil {
 36		panic(err)
 37	}
 38}
 39
 40// Metadata / veil facade.
 41
 42func VeiledURI() string { return veiledURI }
 43
 44func TokenURI(tokenID string) string {
 45	uri, err := metadataView.TokenURI(grc721.TokenID(tokenID))
 46	if err != nil {
 47		panic(err)
 48	}
 49	return uri
 50}
 51
 52// SetVeiledURI allows the final placeholder CID to be configured once before
 53// minting begins. Existing token URIs are never silently rewritten.
 54func SetVeiledURI(cur realm, uri string) {
 55	assertAdmin(cur.Previous().Address())
 56	supply := token.TotalSupply()
 57	if !canConfigureVeiledURI(uri, supply) {
 58		if supply != 0 {
 59			panic("guardians: veiled uri is locked after the first mint")
 60		}
 61		panic("guardians: veiled uri cannot be empty")
 62	}
 63	veiledURI = uri
 64}
 65
 66func validVeiledURI(uri string) bool { return uri != "" }
 67
 68func canConfigureVeiledURI(uri string, supply int64) bool {
 69	return supply == 0 && validVeiledURI(uri)
 70}
 71
 72func setInitialTokenURI(tokenID grc721.TokenID) {
 73	if err := metadataLedger.SetTokenURI(tokenID, veiledURI); err != nil {
 74		panic(err)
 75	}
 76}
 77
 78// Enumerable facade.
 79
 80func EnumerableSupply() int64 { return enumerableView.TotalSupply() }
 81
 82func TokenByIndex(index int64) string {
 83	tokenID, err := enumerableView.TokenByIndex(index)
 84	if err != nil {
 85		panic(err)
 86	}
 87	return tokenID.String()
 88}
 89
 90func TokenOfOwnerByIndex(owner address, index int64) string {
 91	tokenID, err := enumerableView.TokenOfOwnerByIndex(owner, index)
 92	if err != nil {
 93		panic(err)
 94	}
 95	return tokenID.String()
 96}
 97
 98// Royalty facade. This is EIP-2981-style royalty information. Actual payment
 99// enforcement belongs in the project marketplace settlement realm.
100
101func RoyaltyMaxBps() int64 { return royaltyView.MaxBps() }
102
103func DefaultRoyalty() (address, int64) {
104	info, ok := royaltyView.DefaultRoyalty()
105	if !ok {
106		return address(""), 0
107	}
108	return info.Receiver, info.Bps
109}
110
111func RoyaltyInfo(tokenID string, salePrice int64) (address, int64) {
112	receiver, amount, err := royaltyView.RoyaltyInfo(grc721.TokenID(tokenID), salePrice)
113	if err != nil {
114		panic(err)
115	}
116	return receiver, amount
117}
118
119func SetDefaultRoyalty(cur realm, receiver address, bps int64) {
120	assertAdmin(cur.Previous().Address())
121	if !validRoyaltyBps(bps) {
122		panic("guardians: royalty bps out of range")
123	}
124	if err := royaltyLedger.SetDefaultRoyalty(receiver, bps); err != nil {
125		panic(err)
126	}
127}
128
129func validRoyaltyBps(bps int64) bool {
130	return bps >= 0 && bps <= royaltyMaxBps
131}