Smart Contract

Templates

A.e81193c424cfd3fb.Templates

Deployed

2d ago
Feb 26, 2026, 01:49:14 PM UTC

Dependents

0 imports
1// SPDX-License-Identifier: MIT
2import MetadataViews from 0x1d7e57aa55817448
3import FungibleToken from 0xf233dcee88fe0abe
4
5// This contracts stores all the defined interfaces and structs.
6// Interfaces can span on both Doodles and Wearables therefore it is better to have them in a central contract
7access(all) contract Templates {
8
9	access(contract) let counters : {String : UInt64}
10	access(contract) let features : {String : Bool}
11
12	access(all) fun getCounter(_ name:String) :UInt64{
13		return Templates.counters[name] ?? 0
14	}
15
16	access(all) event CountersReset()
17
18	access(account) fun createEditionInfoManually(name: String, counter:String, edition:UInt64?) : EditionInfo {
19		let oldMax=Templates.counters[counter] ?? 0
20		if let e = edition {
21			// If edition is passed in, check if the edition is larger than the existing max.
22			// If so, set it as max, otherwise just mint with edition
23			if e > oldMax {
24				Templates.counters[counter] = e
25			}
26			return EditionInfo(counter: counter, name:name, number:e)
27		}
28		// If edition is NOT passed in, increment by 1 and set new max as edition
29		let max=oldMax+1
30		Templates.counters[counter] = max
31		return EditionInfo(counter: counter, name:name, number:max)
32	}
33
34	access(all) struct interface Editionable {
35
36		access(all) fun getCounterSuffix() : String
37		// e.g. set , position
38		access(all) fun getClassifier() : String
39		// e.g. character, wearable
40		access(all) fun getContract() : String
41
42		access(all) fun getCounter() : String {
43			return self.getContract().concat("_").concat(self.getClassifier()).concat("_").concat(self.getCounterSuffix())
44		}
45
46		access(account) fun createEditionInfo(_ edition: UInt64?) : EditionInfo {
47			return Templates.createEditionInfoManually(name:self.getClassifier(), counter:self.getCounter(), edition:edition)
48		}
49
50		access(all) fun getCurrentCount() : UInt64 {
51			return Templates.counters[self.getCounter()] ?? 0
52		}
53
54	}
55
56	access(all) struct interface Retirable{
57
58		access(all) var active:Bool
59
60		access(all) fun getCounterSuffix() : String
61		access(all) fun getClassifier() : String
62		access(all) fun getContract() : String
63
64		access(account) fun enable(_ bool : Bool) {
65			if (!self.active) {
66				panic(self.getContract().concat("-").concat(self.getClassifier()).concat(" is already retired : ").concat(self.getCounterSuffix()))
67			}
68			self.active = bool
69		}
70	}
71
72	access(all) struct interface RoyaltyHolder {
73		access(all) let royalties: [Templates.Royalty]
74
75		access(all) fun getRoyalties() : [MetadataViews.Royalty] {
76			let royalty : [MetadataViews.Royalty] = []
77			for r in self.royalties {
78				royalty.append(r.getRoyalty())
79			}
80			return royalty
81		}
82	}
83
84	access(all) struct EditionInfo {
85		access(all) let counter :String
86		access(all) let name : String
87		access(all) let number:UInt64
88
89		init(counter: String, name:String, number:UInt64) {
90			self.counter=counter
91			self.name=name
92			self.number=number
93		}
94
95		access(all) fun getSupply() : UInt64 {
96			return Templates.counters[self.counter] ?? 0
97		}
98
99		access(all) fun getAsMetadataEdition(_ active:Bool) : MetadataViews.Edition {
100			var max : UInt64?=nil
101			if !active  {
102				max=Templates.counters[self.counter]
103			}
104			return MetadataViews.Edition(name:self.name, number:self.number, max:max)
105		}
106
107		access(all) fun getMaxEdition() : UInt64 {
108			return Templates.counters[self.counter]!
109		}
110
111	}
112
113	access(all) struct Royalty {
114		access(all) let name : String
115		access(all) let address: Address
116		access(all) let cut: UFix64
117		access(all) let description: String
118		access(all) let publicPath: String
119
120		init(name : String , address: Address , cut: UFix64 , description: String , publicPath: String) {
121			self.name = name
122			self.address = address
123			self.cut = cut
124			self.description = description
125			self.publicPath = publicPath
126		}
127
128		access(all) fun getPublicPath() : PublicPath {
129			return PublicPath(identifier: self.publicPath)!
130		}
131
132		access(all) fun getRoyalty() : MetadataViews.Royalty {
133			let cap = getAccount(self.address).capabilities.get<&{FungibleToken.Receiver}>(self.getPublicPath())
134			return MetadataViews.Royalty(receiver: cap!, cut: self.cut, description: self.name)
135		}
136
137	}
138
139	access(all) fun featureEnabled(_ action: String) : Bool {
140		return self.features[action] ?? false
141	}
142
143	access(all) fun assertFeatureEnabled(_ action: String) {
144		if !Templates.featureEnabled(action) {
145			panic("Action cannot be taken, feature is not enabled : ".concat(action))
146		}
147	}
148
149	access(account) fun resetCounters() {
150		// The counter is in let, therefore we have to do this.
151		for key in self.counters.keys {
152			self.counters.remove(key: key)
153		}
154		emit CountersReset()
155	}
156
157	access(account) fun setFeature(action: String, enabled: Bool) {
158		self.features[action] = enabled
159	}
160
161	init() {
162		self.counters = {}
163		self.features = {}
164	}
165
166}