-
Notifications
You must be signed in to change notification settings - Fork 17
/
StandardNFT.template.cdc
230 lines (175 loc) · 7.43 KB
/
StandardNFT.template.cdc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import NonFungibleToken from {{{ imports.NonFungibleToken }}}
import MetadataViews from {{{ imports.MetadataViews }}}
import FungibleToken from {{{ imports.FungibleToken }}}
import FreshmintMetadataViews from {{{ imports.FreshmintMetadataViews }}}
pub contract {{ contractName }}: NonFungibleToken {
pub let version: String
pub event ContractInitialized()
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
pub event Minted(id: UInt64)
pub event Burned(id: UInt64, metadata: Metadata)
pub let CollectionStoragePath: StoragePath
pub let CollectionPublicPath: PublicPath
pub let CollectionPrivatePath: PrivatePath
pub let AdminStoragePath: StoragePath
/// The total number of {{ contractName }} NFTs that have been minted.
///
pub var totalSupply: UInt64
{{> royalties-field contractName=contractName }}
{{> collection-metadata-field }}
pub struct Metadata {
/// The core metadata fields for a {{ contractName }} NFT.
///
{{#each fields}}
pub let {{ this.name }}: {{ this.asCadenceTypeString }}
{{/each}}
/// Optional attributes for a {{ contractName }} NFT.
///
pub let attributes: {String: String}
init(
{{#each fields}}
{{ this.name }}: {{ this.asCadenceTypeString }},
{{/each}}
attributes: {String: String}
) {
{{#each fields}}
self.{{ this.name }} = {{ this.name }}
{{/each}}
self.attributes = attributes
}
}
pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
pub let id: UInt64
pub let metadata: Metadata
init(metadata: Metadata) {
self.id = self.uuid
self.metadata = metadata
}
pub fun getViews(): [Type] {
return [
{{#each views}}
{{{ this.cadenceTypeString }}}{{#unless @last }},{{/unless}}
{{/each}}
]
}
pub fun resolveView(_ view: Type): AnyStruct? {
switch view {
{{#each views }}
{{> viewCase view=this metadata="self.metadata" }}
{{/each}}
}
return nil
}
{{#each views}}
{{#if this.cadenceResolverFunction }}
{{> (lookup . "id") view=this contractName=../contractName }}
{{/if}}
{{/each}}
destroy() {
{{ contractName }}.totalSupply = {{ contractName }}.totalSupply - (1 as UInt64)
// This contract includes metadata in the burn event so that off-chain systems
// can retroactively index NFTs that were burned in past sporks.
//
emit Burned(id: self.id, metadata: self.metadata)
}
}
/// This dictionary indexes NFTs by their mint ID.
///
/// It is populated at mint time and used to prevent duplicate mints.
/// The mint ID can be any unique string value,
/// for example the hash of the NFT metadata.
///
access(contract) var nftsByMintID: {String: UInt64}
pub fun getNFTByMintID(mintID: String): UInt64? {
return {{ contractName }}.nftsByMintID[mintID]
}
{{> collection contractName=contractName }}
/// The administrator resource used to mint and reveal NFTs.
///
pub resource Admin {
/// Mint a new NFT.
///
/// To mint an NFT, specify a value for each of its metadata fields.
///
pub fun mintNFT(
mintID: String,
{{#each fields}}
{{ this.name }}: {{ this.asCadenceTypeString }},
{{/each}}
attributes: {String: String}
): @{{ contractName }}.NFT {
// Prevent multiple NFTs from being minted with the same mint ID
assert(
{{ contractName }}.nftsByMintID[mintID] == nil,
message: "an NFT has already been minted with mintID=".concat(mintID)
)
let metadata = Metadata(
{{#each fields}}
{{ this.name }}: {{ this.name }},
{{/each}}
attributes: attributes
)
let nft <- create {{ contractName }}.NFT(metadata: metadata)
// Update the mint ID index
{{ contractName }}.nftsByMintID[mintID] = nft.id
emit Minted(id: nft.id)
{{ contractName }}.totalSupply = {{ contractName }}.totalSupply + (1 as UInt64)
return <- nft
}
}
/// Return a public path that is scoped to this contract.
///
pub fun getPublicPath(suffix: String): PublicPath {
return PublicPath(identifier: "{{ contractName }}_".concat(suffix))!
}
/// Return a private path that is scoped to this contract.
///
pub fun getPrivatePath(suffix: String): PrivatePath {
return PrivatePath(identifier: "{{ contractName }}_".concat(suffix))!
}
/// Return a storage path that is scoped to this contract.
///
pub fun getStoragePath(suffix: String): StoragePath {
return StoragePath(identifier: "{{ contractName }}_".concat(suffix))!
}
/// Return a collection name with an optional bucket suffix.
///
pub fun makeCollectionName(bucketName maybeBucketName: String?): String {
if let bucketName = maybeBucketName {
return "Collection_".concat(bucketName)
}
return "Collection"
}
/// Return a queue name with an optional bucket suffix.
///
pub fun makeQueueName(bucketName maybeBucketName: String?): String {
if let bucketName = maybeBucketName {
return "Queue_".concat(bucketName)
}
return "Queue"
}
priv fun initAdmin(admin: AuthAccount) {
// Create an empty collection and save it to storage
let collection <- {{ contractName }}.createEmptyCollection()
admin.save(<- collection, to: {{ contractName }}.CollectionStoragePath)
admin.link<&{{ contractName }}.Collection>({{ contractName }}.CollectionPrivatePath, target: {{ contractName }}.CollectionStoragePath)
admin.link<&{{ contractName }}.Collection{NonFungibleToken.CollectionPublic, {{ contractName }}.{{ contractName }}CollectionPublic, MetadataViews.ResolverCollection}>({{ contractName }}.CollectionPublicPath, target: {{ contractName }}.CollectionStoragePath)
// Create an admin resource and save it to storage
let adminResource <- create Admin()
admin.save(<- adminResource, to: self.AdminStoragePath)
}
init(collectionMetadata: MetadataViews.NFTCollectionDisplay, royalties: [MetadataViews.Royalty]{{#unless saveAdminResourceToContractAccount }}, admin: AuthAccount{{/unless}}) {
self.version = "{{ freshmintVersion }}"
self.CollectionPublicPath = {{ contractName }}.getPublicPath(suffix: "Collection")
self.CollectionStoragePath = {{ contractName }}.getStoragePath(suffix: "Collection")
self.CollectionPrivatePath = {{ contractName }}.getPrivatePath(suffix: "Collection")
self.AdminStoragePath = {{ contractName }}.getStoragePath(suffix: "Admin")
self.royalties = royalties
self.collectionMetadata = collectionMetadata
self.totalSupply = 0
self.nftsByMintID = {}
self.initAdmin(admin: {{#if saveAdminResourceToContractAccount }}self.account{{ else }}admin{{/if}})
emit ContractInitialized()
}
}