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

token.gno

2.36 Kb · 102 lines
  1package metadata
  2
  3import (
  4	"chain"
  5
  6	"gno.land/p/nt/grc721/v0"
  7)
  8
  9const Kind = "metadata"
 10
 11// NewMetadata attaches a metadata extension and registers it as a core Extension.
 12// Attach it before the first mint so every token is indexed.
 13func NewMetadata(coreLedger *grc721.PrivateLedger) (*Metadata, *Ledger) {
 14	if coreLedger == nil {
 15		panic("metadata: nil core ledger")
 16	}
 17
 18	st := &storage{}
 19	core := coreLedger.ReadToken()
 20	led := &Ledger{core: core, st: st}
 21	coreLedger.RegisterExtension(led)
 22
 23	return &Metadata{core: core, st: st}, led
 24}
 25
 26func (m *Metadata) ExtensionKind() string { return Kind }
 27
 28func (m *Metadata) TokenID() string { return m.core.ID() }
 29
 30func (m *Metadata) TokenURI(tid grc721.TokenID) (string, error) {
 31	v := m.st.uris.Get(tid.String())
 32	if v == nil {
 33		return "", ErrNoTokenURI
 34	}
 35
 36	return v.(string), nil
 37}
 38
 39func (m *Metadata) TokenMetadata(tid grc721.TokenID) (Data, error) {
 40	v := m.st.data.Get(tid.String())
 41	if v == nil {
 42		return Data{}, ErrNoMetadata
 43	}
 44
 45	return v.(Data), nil
 46}
 47
 48func (m *Metadata) HasTokenURI(tid grc721.TokenID) bool {
 49	return m.st.uris.Has(tid.String())
 50}
 51
 52func (m *Metadata) HasMetadata(tid grc721.TokenID) bool {
 53	return m.st.data.Has(tid.String())
 54}
 55
 56// SetTokenURI sets the EIP-721 tokenURI of tid; issuer-only so a holder cannot
 57// rewrite the URI after acquisition.
 58func (led *Ledger) SetTokenURI(tid grc721.TokenID, uri string) error {
 59	if _, err := led.core.OwnerOf(tid); err != nil {
 60		return ErrTokenNotMinted
 61	}
 62
 63	led.st.uris.Set(tid.String(), uri)
 64
 65	chain.Emit(
 66		TokenURIUpdateEvent,
 67		"token", led.core.ID(),
 68		"tokenId", tid.String(),
 69		"uri", uri,
 70	)
 71
 72	return nil
 73}
 74
 75// SetTokenMetadata sets the OpenSea on-chain metadata of tid; issuer-only.
 76func (led *Ledger) SetTokenMetadata(tid grc721.TokenID, data Data) error {
 77	if _, err := led.core.OwnerOf(tid); err != nil {
 78		return ErrTokenNotMinted
 79	}
 80
 81	led.st.data.Set(tid.String(), data)
 82
 83	chain.Emit(
 84		MetadataUpdateEvent,
 85		"token", led.core.ID(),
 86		"tokenId", tid.String(),
 87	)
 88
 89	return nil
 90}
 91
 92func (led *Ledger) ExtensionKind() string { return Kind }
 93
 94func (led *Ledger) OnMint(to address, tid grc721.TokenID)           {}
 95func (led *Ledger) OnTransfer(from, to address, tid grc721.TokenID) {}
 96
 97// OnBurn clears per-token state so it cannot resurface on re-mint.
 98func (led *Ledger) OnBurn(tid grc721.TokenID) {
 99	tidStr := tid.String()
100	led.st.uris.Remove(tidStr)
101	led.st.data.Remove(tidStr)
102}