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.

guardians.gno

4.20 Kb · 165 lines
  1package guardians
  2
  3import (
  4	"gno.land/p/nt/grc721/v0"
  5	"gno.land/p/nt/ufmt/v0"
  6)
  7
  8const (
  9	collectionName   = "Guardians"
 10	collectionSymbol = "GUARDIANS"
 11	maxSupply        = int64(3333)
 12	maxPublicMintBatch = 20
 13	maxMintBatch     = maxPublicMintBatch + 1 // One free claim plus 20 paid NFTs.
 14)
 15
 16// localAdmin is the standard prefunded gnodev account. It is intentionally
 17// limited to local development and must be replaced by the deployment owner
 18// before Pearl or Mainnet deployment.
 19const localAdmin address = "g1nmqhha0ua730vejxqhrelldm4pga5j5ptle5ea"
 20
 21var (
 22	token        *grc721.Token
 23	ledger       *grc721.PrivateLedger
 24	callerTeller grc721.Teller
 25)
 26
 27func init(cur realm) {
 28	token, ledger = grc721.NewToken(collectionName, collectionSymbol, 0, cur)
 29	callerTeller = ledger.CallerTeller()
 30	attachExtensions(ledger)
 31}
 32
 33// Collection getters.
 34
 35func Status() string { return "REVEAL_ENGINE_READY" }
 36
 37func Name() string { return token.GetName() }
 38
 39func Symbol() string { return token.GetSymbol() }
 40
 41func CollectionID() string { return token.ID() }
 42
 43func TotalSupply() int64 { return token.TotalSupply() }
 44
 45func MaxSupply() int64 { return maxSupply }
 46
 47func Admin() address { return localAdmin }
 48
 49// GRC-721 read facade.
 50
 51func BalanceOf(owner address) int64 {
 52	balance, err := token.BalanceOf(owner)
 53	if err != nil {
 54		panic(err)
 55	}
 56	return balance
 57}
 58
 59func OwnerOf(tokenID string) address {
 60	owner, err := token.OwnerOf(grc721.TokenID(tokenID))
 61	if err != nil {
 62		panic(err)
 63	}
 64	return owner
 65}
 66
 67func GetApproved(tokenID string) address {
 68	approved, err := token.GetApproved(grc721.TokenID(tokenID))
 69	if err != nil {
 70		panic(err)
 71	}
 72	return approved
 73}
 74
 75func IsApprovedForAll(owner, operator address) bool {
 76	return token.IsApprovedForAll(owner, operator)
 77}
 78
 79// GRC-721 write facade. CallerTeller derives the acting account from the
 80// current cross-realm frame and keeps the PrivateLedger inside this realm.
 81
 82func Approve(cur realm, to address, tokenID string) {
 83	if err := callerTeller.Approve(0, cur, to, grc721.TokenID(tokenID)); err != nil {
 84		panic(err)
 85	}
 86}
 87
 88func SetApprovalForAll(cur realm, operator address, approved bool) {
 89	if err := callerTeller.SetApprovalForAll(0, cur, operator, approved); err != nil {
 90		panic(err)
 91	}
 92}
 93
 94func TransferFrom(cur realm, from, to address, tokenID string) {
 95	if cur.Previous().Address() != from {
 96		panic("guardians: operator transfers require marketplace settlement")
 97	}
 98	if err := callerTeller.TransferFrom(0, cur, from, to, grc721.TokenID(tokenID)); err != nil {
 99		panic(err)
100	}
101}
102
103// AdminMint is for reserve/local-development minting and is permanently locked
104// after the first sale activation to prevent post-sale rare-token allocation.
105func AdminMint(cur realm, to address, quantity int) {
106	assertAdmin(cur.Previous().Address())
107	assertMintingAllowed()
108	if !salePaused || allowlistRootLocked {
109		panic("guardians: admin mint is locked after sale activation")
110	}
111	mintTokens(to, quantity)
112}
113
114func mintTokens(to address, quantity int) {
115	mintAllocatedTokens(to, 0, quantity)
116}
117
118func mintAllocatedTokens(to address, freeQuantity, paidQuantity int) {
119	quantity := freeQuantity + paidQuantity
120	assertMintingAllowed()
121	assertMintQuantity(quantity)
122	assertReserveCapacity(freeQuantity, paidQuantity)
123	for i := 0; i < quantity; i++ {
124		nextID := token.TotalSupply() + 1
125		tokenID := grc721.TokenID(ufmt.Sprintf("%d", nextID))
126		if err := ledger.Mint(to, tokenID); err != nil {
127			panic(err)
128		}
129		setInitialTokenURI(tokenID)
130	}
131	allowlistMintedSupply += int64(freeQuantity)
132}
133
134func Render(path string) string {
135	if path != "" {
136		return "404\n"
137	}
138
139	out := token.RenderHome()
140	out += ufmt.Sprintf("* **Maximum supply**: %d\n", maxSupply)
141	out += ufmt.Sprintf("* **Sale phase**: %s\n", SalePhase())
142	out += ufmt.Sprintf("* **Sale paused**: %t\n", SalePaused())
143	out += ufmt.Sprintf("* **Status**: %s\n", Status())
144	return out
145}
146
147func assertAdmin(caller address) {
148	if !isAdmin(caller) {
149		panic("guardians: restricted access")
150	}
151}
152
153func isAdmin(caller address) bool {
154	return caller == localAdmin
155}
156
157func assertMintQuantity(quantity int) {
158	if !validMintQuantity(quantity) {
159		panic(ufmt.Sprintf("guardians: quantity must be between 1 and %d", maxMintBatch))
160	}
161}
162
163func validMintQuantity(quantity int) bool {
164	return quantity >= 1 && quantity <= maxMintBatch
165}