@flowtyio/flow-contracts 0.0.11 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/add.js +44 -4
- package/contracts/FlowStorageFees.cdc +193 -0
- package/contracts/FlowToken.cdc +274 -0
- package/contracts/FungibleTokenMetadataViews.cdc +183 -0
- package/contracts/TokenForwarding.cdc +82 -0
- package/contracts/dapper/DapperUtilityCoin.cdc +199 -0
- package/contracts/dapper/FlowUtilityToken.cdc +199 -0
- package/contracts/dapper/TopShot.cdc +1686 -0
- package/contracts/dapper/TopShotLocking.cdc +165 -0
- package/contracts/dapper/offers/DapperOffersV2.cdc +238 -0
- package/contracts/dapper/offers/OffersV2.cdc +344 -0
- package/contracts/dapper/offers/Resolver.cdc +70 -0
- package/contracts/lost-and-found/FeeEstimator.cdc +62 -0
- package/contracts/lost-and-found/LostAndFound.cdc +758 -0
- package/contracts/lost-and-found/LostAndFoundHelper.cdc +42 -0
- package/contracts/nft-catalog/NFTCatalog.cdc +422 -0
- package/contracts/nft-catalog/NFTCatalogAdmin.cdc +175 -0
- package/flow.json +152 -2
- package/index.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "LostAndFound"
|
|
2
|
+
|
|
3
|
+
pub contract LostAndFoundHelper {
|
|
4
|
+
|
|
5
|
+
pub struct Ticket {
|
|
6
|
+
|
|
7
|
+
// An optional message to attach to this item.
|
|
8
|
+
pub let memo: String?
|
|
9
|
+
// The address that it allowed to withdraw the item fromt this ticket
|
|
10
|
+
pub let redeemer: Address
|
|
11
|
+
//The type of the resource (non-optional) so that bins can represent the true type of an item
|
|
12
|
+
pub let type: Type
|
|
13
|
+
pub let typeIdentifier: String
|
|
14
|
+
// State maintained by LostAndFound
|
|
15
|
+
pub let redeemed: Bool
|
|
16
|
+
pub let name : String?
|
|
17
|
+
pub let description : String?
|
|
18
|
+
pub let thumbnail : String?
|
|
19
|
+
pub let ticketID : UInt64?
|
|
20
|
+
|
|
21
|
+
init(_ ticket: &LostAndFound.Ticket, id: UInt64?) {
|
|
22
|
+
self.memo = ticket.memo
|
|
23
|
+
self.redeemer = ticket.redeemer
|
|
24
|
+
self.type = ticket.type
|
|
25
|
+
self.typeIdentifier = ticket.type.identifier
|
|
26
|
+
self.redeemed = ticket.redeemed
|
|
27
|
+
self.name = ticket.display?.name
|
|
28
|
+
self.description = ticket.display?.description
|
|
29
|
+
self.thumbnail = ticket.display?.thumbnail?.uri()
|
|
30
|
+
self.ticketID = id
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fun constructResult(_ ticket: &LostAndFound.Ticket?, id:UInt64?) : LostAndFoundHelper.Ticket? {
|
|
36
|
+
if ticket != nil {
|
|
37
|
+
return LostAndFoundHelper.Ticket(ticket!, id: id)
|
|
38
|
+
}
|
|
39
|
+
return nil
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import "MetadataViews"
|
|
2
|
+
|
|
3
|
+
// NFTCatalog
|
|
4
|
+
//
|
|
5
|
+
// A general purpose NFT registry for Flow NonFungibleTokens.
|
|
6
|
+
//
|
|
7
|
+
// Each catalog entry stores data about the NFT including
|
|
8
|
+
// its collection identifier, nft type, storage and public paths, etc.
|
|
9
|
+
//
|
|
10
|
+
// To make an addition to the catalog you can propose an NFT and provide its metadata.
|
|
11
|
+
// An Admin can approve a proposal which would add the NFT to the catalog
|
|
12
|
+
|
|
13
|
+
pub contract NFTCatalog {
|
|
14
|
+
// EntryAdded
|
|
15
|
+
// An NFT collection has been added to the catalog
|
|
16
|
+
pub event EntryAdded(
|
|
17
|
+
collectionIdentifier : String,
|
|
18
|
+
contractName : String,
|
|
19
|
+
contractAddress : Address,
|
|
20
|
+
nftType : Type,
|
|
21
|
+
storagePath: StoragePath,
|
|
22
|
+
publicPath: PublicPath,
|
|
23
|
+
privatePath: PrivatePath,
|
|
24
|
+
publicLinkedType : Type,
|
|
25
|
+
privateLinkedType : Type,
|
|
26
|
+
displayName : String,
|
|
27
|
+
description: String,
|
|
28
|
+
externalURL : String
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
// EntryUpdated
|
|
32
|
+
// An NFT Collection has been updated in the catalog
|
|
33
|
+
pub event EntryUpdated(
|
|
34
|
+
collectionIdentifier : String,
|
|
35
|
+
contractName : String,
|
|
36
|
+
contractAddress : Address,
|
|
37
|
+
nftType : Type,
|
|
38
|
+
storagePath: StoragePath,
|
|
39
|
+
publicPath: PublicPath,
|
|
40
|
+
privatePath: PrivatePath,
|
|
41
|
+
publicLinkedType : Type,
|
|
42
|
+
privateLinkedType : Type,
|
|
43
|
+
displayName : String,
|
|
44
|
+
description: String,
|
|
45
|
+
externalURL : String
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
// EntryRemoved
|
|
49
|
+
// An NFT Collection has been removed from the catalog
|
|
50
|
+
pub event EntryRemoved(collectionIdentifier : String, nftType: Type)
|
|
51
|
+
|
|
52
|
+
// ProposalEntryAdded
|
|
53
|
+
// A new proposal to make an addtion to the catalog has been made
|
|
54
|
+
pub event ProposalEntryAdded(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address)
|
|
55
|
+
|
|
56
|
+
// ProposalEntryUpdated
|
|
57
|
+
// A proposal has been updated
|
|
58
|
+
pub event ProposalEntryUpdated(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address)
|
|
59
|
+
|
|
60
|
+
// ProposalEntryRemoved
|
|
61
|
+
// A proposal has been removed from storage
|
|
62
|
+
pub event ProposalEntryRemoved(proposalID : UInt64)
|
|
63
|
+
|
|
64
|
+
pub let ProposalManagerStoragePath: StoragePath
|
|
65
|
+
|
|
66
|
+
pub let ProposalManagerPublicPath: PublicPath
|
|
67
|
+
|
|
68
|
+
access(self) let catalog: {String : NFTCatalog.NFTCatalogMetadata} // { collectionIdentifier -> Metadata }
|
|
69
|
+
access(self) let catalogTypeData: {String : {String : Bool}} // Additional view to go from { NFT Type Identifier -> {Collection Identifier : Bool } }
|
|
70
|
+
|
|
71
|
+
access(self) let catalogProposals : {UInt64 : NFTCatalogProposal} // { ProposalID : Metadata }
|
|
72
|
+
|
|
73
|
+
access(self) var totalProposals : UInt64
|
|
74
|
+
|
|
75
|
+
// NFTCatalogProposalManager
|
|
76
|
+
// Used to authenticate proposals made to the catalog
|
|
77
|
+
|
|
78
|
+
pub resource interface NFTCatalogProposalManagerPublic {
|
|
79
|
+
pub fun getCurrentProposalEntry(): String?
|
|
80
|
+
}
|
|
81
|
+
pub resource NFTCatalogProposalManager : NFTCatalogProposalManagerPublic {
|
|
82
|
+
access(self) var currentProposalEntry: String?
|
|
83
|
+
|
|
84
|
+
pub fun getCurrentProposalEntry(): String? {
|
|
85
|
+
return self.currentProposalEntry
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fun setCurrentProposalEntry(identifier: String?) {
|
|
89
|
+
self.currentProposalEntry = identifier
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
init () {
|
|
93
|
+
self.currentProposalEntry = nil
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
pub resource Snapshot {
|
|
99
|
+
pub var catalogSnapshot: {String : NFTCatalogMetadata}
|
|
100
|
+
pub var shouldUseSnapshot: Bool
|
|
101
|
+
|
|
102
|
+
pub fun setPartialSnapshot(_ snapshotKey: String, _ snapshotEntry: NFTCatalogMetadata) {
|
|
103
|
+
self.catalogSnapshot[snapshotKey] = snapshotEntry
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub fun setShouldUseSnapshot(_ shouldUseSnapshot: Bool) {
|
|
107
|
+
self.shouldUseSnapshot = shouldUseSnapshot
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
pub fun getCatalogSnapshot(): {String : NFTCatalogMetadata} {
|
|
111
|
+
return self.catalogSnapshot
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
init() {
|
|
115
|
+
self.shouldUseSnapshot = false
|
|
116
|
+
self.catalogSnapshot = {}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
pub fun createEmptySnapshot(): @Snapshot {
|
|
121
|
+
return <- create Snapshot()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// NFTCollectionData
|
|
125
|
+
// Represents information about an NFT collection resource
|
|
126
|
+
// Note: Not suing the struct from Metadata standard due to
|
|
127
|
+
// inability to store functions
|
|
128
|
+
pub struct NFTCollectionData {
|
|
129
|
+
|
|
130
|
+
pub let storagePath : StoragePath
|
|
131
|
+
pub let publicPath : PublicPath
|
|
132
|
+
pub let privatePath: PrivatePath
|
|
133
|
+
pub let publicLinkedType: Type
|
|
134
|
+
pub let privateLinkedType: Type
|
|
135
|
+
|
|
136
|
+
init(
|
|
137
|
+
storagePath : StoragePath,
|
|
138
|
+
publicPath : PublicPath,
|
|
139
|
+
privatePath : PrivatePath,
|
|
140
|
+
publicLinkedType : Type,
|
|
141
|
+
privateLinkedType : Type
|
|
142
|
+
) {
|
|
143
|
+
self.storagePath = storagePath
|
|
144
|
+
self.publicPath = publicPath
|
|
145
|
+
self.privatePath = privatePath
|
|
146
|
+
self.publicLinkedType = publicLinkedType
|
|
147
|
+
self.privateLinkedType = privateLinkedType
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// NFTCatalogMetadata
|
|
152
|
+
// Represents data about an NFT
|
|
153
|
+
pub struct NFTCatalogMetadata {
|
|
154
|
+
pub let contractName : String
|
|
155
|
+
pub let contractAddress : Address
|
|
156
|
+
pub let nftType: Type
|
|
157
|
+
pub let collectionData: NFTCollectionData
|
|
158
|
+
pub let collectionDisplay: MetadataViews.NFTCollectionDisplay
|
|
159
|
+
|
|
160
|
+
init (contractName : String, contractAddress : Address, nftType: Type, collectionData : NFTCollectionData, collectionDisplay : MetadataViews.NFTCollectionDisplay) {
|
|
161
|
+
self.contractName = contractName
|
|
162
|
+
self.contractAddress = contractAddress
|
|
163
|
+
self.nftType = nftType
|
|
164
|
+
self.collectionData = collectionData
|
|
165
|
+
self.collectionDisplay = collectionDisplay
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// NFTCatalogProposal
|
|
170
|
+
// Represents a proposal to the catalog
|
|
171
|
+
// Includes data about an NFT
|
|
172
|
+
pub struct NFTCatalogProposal {
|
|
173
|
+
pub let collectionIdentifier : String
|
|
174
|
+
pub let metadata : NFTCatalogMetadata
|
|
175
|
+
pub let message : String
|
|
176
|
+
pub let status : String
|
|
177
|
+
pub let proposer : Address
|
|
178
|
+
pub let createdTime : UFix64
|
|
179
|
+
|
|
180
|
+
init(collectionIdentifier : String, metadata : NFTCatalogMetadata, message : String, status : String, proposer : Address) {
|
|
181
|
+
self.collectionIdentifier = collectionIdentifier
|
|
182
|
+
self.metadata = metadata
|
|
183
|
+
self.message = message
|
|
184
|
+
self.status = status
|
|
185
|
+
self.proposer = proposer
|
|
186
|
+
self.createdTime = getCurrentBlock().timestamp
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/*
|
|
191
|
+
DEPRECATED
|
|
192
|
+
If obtaining all elements from the catalog is essential, please
|
|
193
|
+
use the getCatalogKeys and forEachCatalogKey methods instead.
|
|
194
|
+
*/
|
|
195
|
+
pub fun getCatalog() : {String : NFTCatalogMetadata} {
|
|
196
|
+
let snapshot = self.account.borrow<&NFTCatalog.Snapshot>(from: /storage/CatalogSnapshot)
|
|
197
|
+
if snapshot != nil {
|
|
198
|
+
let snapshot = snapshot!
|
|
199
|
+
if snapshot.shouldUseSnapshot {
|
|
200
|
+
return snapshot.getCatalogSnapshot()
|
|
201
|
+
} else {
|
|
202
|
+
return self.catalog
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
return self.catalog
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
pub fun getCatalogKeys(): [String] {
|
|
210
|
+
return self.catalog.keys
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
pub fun forEachCatalogKey(_ function: ((String): Bool)) {
|
|
214
|
+
self.catalog.forEachKey(function)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
pub fun getCatalogEntry(collectionIdentifier : String) : NFTCatalogMetadata? {
|
|
218
|
+
return self.catalog[collectionIdentifier]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
pub fun getCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? {
|
|
222
|
+
return self.catalogTypeData[nftTypeIdentifier]
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
pub fun getCatalogTypeData() : {String : {String : Bool}} {
|
|
226
|
+
return self.catalogTypeData
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Propose an NFT collection to the catalog
|
|
230
|
+
// @param collectionIdentifier: The unique name assinged to this nft collection
|
|
231
|
+
// @param metadata: The Metadata for the NFT collection that will be stored in the catalog
|
|
232
|
+
// @param message: A message to the catalog owners
|
|
233
|
+
// @param proposer: Who is making the proposition(the address needs to be verified)
|
|
234
|
+
pub fun proposeNFTMetadata(collectionIdentifier : String, metadata : NFTCatalogMetadata, message : String, proposer : Address) : UInt64 {
|
|
235
|
+
let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath)
|
|
236
|
+
|
|
237
|
+
assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager")
|
|
238
|
+
|
|
239
|
+
let proposerManagerRef = proposerManagerCap.borrow()!
|
|
240
|
+
|
|
241
|
+
assert(proposerManagerRef.getCurrentProposalEntry()! == collectionIdentifier, message: "Expected proposal entry does not match entry for the proposer")
|
|
242
|
+
|
|
243
|
+
let catalogProposal = NFTCatalogProposal(collectionIdentifier : collectionIdentifier, metadata : metadata, message : message, status: "IN_REVIEW", proposer: proposer)
|
|
244
|
+
self.totalProposals = self.totalProposals + 1
|
|
245
|
+
self.catalogProposals[self.totalProposals] = catalogProposal
|
|
246
|
+
|
|
247
|
+
emit ProposalEntryAdded(proposalID : self.totalProposals, collectionIdentifier : collectionIdentifier, message: catalogProposal.message, status: catalogProposal.status, proposer: catalogProposal.proposer)
|
|
248
|
+
return self.totalProposals
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Withdraw a proposal from the catalog
|
|
252
|
+
// @param proposalID: The ID of proposal you want to withdraw
|
|
253
|
+
pub fun withdrawNFTProposal(proposalID : UInt64) {
|
|
254
|
+
pre {
|
|
255
|
+
self.catalogProposals[proposalID] != nil : "Invalid Proposal ID"
|
|
256
|
+
}
|
|
257
|
+
let proposal = self.catalogProposals[proposalID]!
|
|
258
|
+
let proposer = proposal.proposer
|
|
259
|
+
|
|
260
|
+
let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath)
|
|
261
|
+
|
|
262
|
+
assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager")
|
|
263
|
+
|
|
264
|
+
let proposerManagerRef = proposerManagerCap.borrow()!
|
|
265
|
+
|
|
266
|
+
assert(proposerManagerRef.getCurrentProposalEntry()! == proposal.collectionIdentifier, message: "Expected proposal entry does not match entry for the proposer")
|
|
267
|
+
|
|
268
|
+
self.removeCatalogProposal(proposalID : proposalID)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
pub fun getCatalogProposals() : {UInt64 : NFTCatalogProposal} {
|
|
272
|
+
return self.catalogProposals
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
pub fun getCatalogProposalEntry(proposalID : UInt64) : NFTCatalogProposal? {
|
|
276
|
+
return self.catalogProposals[proposalID]
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
pub fun getCatalogProposalKeys() : [UInt64] {
|
|
280
|
+
return self.catalogProposals.keys
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pub fun forEachCatalogProposalKey(_ function: ((UInt64): Bool)) {
|
|
284
|
+
self.catalogProposals.forEachKey(function)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fun createNFTCatalogProposalManager(): @NFTCatalogProposalManager {
|
|
288
|
+
return <-create NFTCatalogProposalManager()
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
access(account) fun addCatalogEntry(collectionIdentifier : String, metadata: NFTCatalogMetadata) {
|
|
292
|
+
pre {
|
|
293
|
+
self.catalog[collectionIdentifier] == nil : "The nft name has already been added to the catalog"
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
self.addCatalogTypeEntry(collectionIdentifier : collectionIdentifier , metadata: metadata)
|
|
297
|
+
|
|
298
|
+
self.catalog[collectionIdentifier] = metadata
|
|
299
|
+
|
|
300
|
+
emit EntryAdded(
|
|
301
|
+
collectionIdentifier : collectionIdentifier,
|
|
302
|
+
contractName : metadata.contractName,
|
|
303
|
+
contractAddress : metadata.contractAddress,
|
|
304
|
+
nftType: metadata.nftType,
|
|
305
|
+
storagePath: metadata.collectionData.storagePath,
|
|
306
|
+
publicPath: metadata.collectionData.publicPath,
|
|
307
|
+
privatePath: metadata.collectionData.privatePath,
|
|
308
|
+
publicLinkedType : metadata.collectionData.publicLinkedType,
|
|
309
|
+
privateLinkedType : metadata.collectionData.privateLinkedType,
|
|
310
|
+
displayName : metadata.collectionDisplay.name,
|
|
311
|
+
description: metadata.collectionDisplay.description,
|
|
312
|
+
externalURL : metadata.collectionDisplay.externalURL.url
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
access(account) fun updateCatalogEntry(collectionIdentifier : String , metadata: NFTCatalogMetadata) {
|
|
317
|
+
pre {
|
|
318
|
+
self.catalog[collectionIdentifier] != nil : "Invalid collection identifier"
|
|
319
|
+
}
|
|
320
|
+
// remove previous nft type entry
|
|
321
|
+
self.removeCatalogTypeEntry(collectionIdentifier : collectionIdentifier , metadata: metadata)
|
|
322
|
+
// add updated nft type entry
|
|
323
|
+
self.addCatalogTypeEntry(collectionIdentifier : collectionIdentifier , metadata: metadata)
|
|
324
|
+
|
|
325
|
+
self.catalog[collectionIdentifier] = metadata
|
|
326
|
+
|
|
327
|
+
let nftType = metadata.nftType
|
|
328
|
+
|
|
329
|
+
emit EntryUpdated(
|
|
330
|
+
collectionIdentifier : collectionIdentifier,
|
|
331
|
+
contractName : metadata.contractName,
|
|
332
|
+
contractAddress : metadata.contractAddress,
|
|
333
|
+
nftType: metadata.nftType,
|
|
334
|
+
storagePath: metadata.collectionData.storagePath,
|
|
335
|
+
publicPath: metadata.collectionData.publicPath,
|
|
336
|
+
privatePath: metadata.collectionData.privatePath,
|
|
337
|
+
publicLinkedType : metadata.collectionData.publicLinkedType,
|
|
338
|
+
privateLinkedType : metadata.collectionData.privateLinkedType,
|
|
339
|
+
displayName : metadata.collectionDisplay.name,
|
|
340
|
+
description: metadata.collectionDisplay.description,
|
|
341
|
+
externalURL : metadata.collectionDisplay.externalURL.url
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
access(account) fun removeCatalogEntry(collectionIdentifier : String) {
|
|
346
|
+
pre {
|
|
347
|
+
self.catalog[collectionIdentifier] != nil : "Invalid collection identifier"
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
let removedType = self.removeCatalogTypeEntry(collectionIdentifier : collectionIdentifier , metadata: self.catalog[collectionIdentifier]!)
|
|
351
|
+
self.catalog.remove(key: collectionIdentifier)
|
|
352
|
+
|
|
353
|
+
emit EntryRemoved(collectionIdentifier : collectionIdentifier, nftType: removedType)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// This function is not preferred, and was used for the following issue:
|
|
357
|
+
// https://github.com/onflow/cadence/issues/2649
|
|
358
|
+
// If a contract's type is no longer resolvable in cadence and crashing,
|
|
359
|
+
// this function can be used to remove it from the catalog.
|
|
360
|
+
access(account) fun removeCatalogEntryUnsafe(collectionIdentifier: String, nftTypeIdentifier: String) {
|
|
361
|
+
// Remove the catalog entry
|
|
362
|
+
self.catalog.remove(key: collectionIdentifier)
|
|
363
|
+
|
|
364
|
+
// Remove the type entry
|
|
365
|
+
if (self.catalogTypeData[nftTypeIdentifier]!.keys.length == 1) {
|
|
366
|
+
self.catalogTypeData.remove(key: nftTypeIdentifier)
|
|
367
|
+
} else {
|
|
368
|
+
self.catalogTypeData[nftTypeIdentifier]!.remove(key: collectionIdentifier)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
access(account) fun updateCatalogProposal(proposalID: UInt64, proposalMetadata : NFTCatalogProposal) {
|
|
373
|
+
self.catalogProposals[proposalID] = proposalMetadata
|
|
374
|
+
|
|
375
|
+
emit ProposalEntryUpdated(proposalID : proposalID, collectionIdentifier : proposalMetadata.collectionIdentifier, message: proposalMetadata.message, status: proposalMetadata.status, proposer: proposalMetadata.proposer)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
access(account) fun removeCatalogProposal(proposalID : UInt64) {
|
|
379
|
+
self.catalogProposals.remove(key : proposalID)
|
|
380
|
+
|
|
381
|
+
emit ProposalEntryRemoved(proposalID : proposalID)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
access(contract) fun addCatalogTypeEntry(collectionIdentifier : String , metadata: NFTCatalogMetadata) {
|
|
385
|
+
if self.catalogTypeData[metadata.nftType.identifier] != nil {
|
|
386
|
+
let typeData : {String : Bool} = self.catalogTypeData[metadata.nftType.identifier]!
|
|
387
|
+
assert(self.catalogTypeData[metadata.nftType.identifier]![collectionIdentifier] == nil, message : "The nft name has already been added to the catalog")
|
|
388
|
+
typeData[collectionIdentifier] = true
|
|
389
|
+
self.catalogTypeData[metadata.nftType.identifier] = typeData
|
|
390
|
+
} else {
|
|
391
|
+
let typeData : {String : Bool} = {}
|
|
392
|
+
typeData[collectionIdentifier] = true
|
|
393
|
+
self.catalogTypeData[metadata.nftType.identifier] = typeData
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
access(contract) fun removeCatalogTypeEntry(collectionIdentifier : String , metadata: NFTCatalogMetadata): Type {
|
|
398
|
+
let prevMetadata = self.catalog[collectionIdentifier]!
|
|
399
|
+
let prevCollectionsForType = self.catalogTypeData[prevMetadata.nftType.identifier]!
|
|
400
|
+
prevCollectionsForType.remove(key : collectionIdentifier)
|
|
401
|
+
if prevCollectionsForType.length == 0 {
|
|
402
|
+
self.catalogTypeData.remove(key: prevMetadata.nftType.identifier)
|
|
403
|
+
} else {
|
|
404
|
+
self.catalogTypeData[prevMetadata.nftType.identifier] = prevCollectionsForType
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return metadata.nftType
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
init() {
|
|
411
|
+
self.ProposalManagerStoragePath = /storage/nftCatalogProposalManager
|
|
412
|
+
self.ProposalManagerPublicPath = /public/nftCatalogProposalManager
|
|
413
|
+
|
|
414
|
+
self.totalProposals = 0
|
|
415
|
+
self.catalog = {}
|
|
416
|
+
self.catalogTypeData = {}
|
|
417
|
+
|
|
418
|
+
self.catalogProposals = {}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import "NFTCatalog"
|
|
2
|
+
|
|
3
|
+
// NFTCatalogAdmin
|
|
4
|
+
//
|
|
5
|
+
// An admin contract that defines an admin resource and
|
|
6
|
+
// a proxy resource to receive a capability that lets you make changes to the NFT Catalog
|
|
7
|
+
// and manage proposals
|
|
8
|
+
|
|
9
|
+
pub contract NFTCatalogAdmin {
|
|
10
|
+
|
|
11
|
+
// AddProposalAccepted
|
|
12
|
+
// Emitted when a proposal to add a new catalog item has been approved by an admin
|
|
13
|
+
pub event AddProposalAccepted(
|
|
14
|
+
proposer: Address,
|
|
15
|
+
collectionIdentifier : String,
|
|
16
|
+
contractName : String,
|
|
17
|
+
contractAddress : Address,
|
|
18
|
+
displayName : String
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
// UpdateProposalAccepted
|
|
22
|
+
// Emitted when a proposal to update a catalog item has been approved by an admin
|
|
23
|
+
pub event UpdateProposalAccepted(
|
|
24
|
+
proposer: Address,
|
|
25
|
+
collectionIdentifier : String,
|
|
26
|
+
contractName : String,
|
|
27
|
+
contractAddress : Address,
|
|
28
|
+
displayName : String
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
// ProposalRejected
|
|
32
|
+
// Emitted when a proposal to add or update a catalog item has been rejected.
|
|
33
|
+
pub event ProposalRejected(
|
|
34
|
+
proposer: Address,
|
|
35
|
+
collectionIdentifier : String,
|
|
36
|
+
contractName : String,
|
|
37
|
+
contractAddress : Address,
|
|
38
|
+
displayName : String
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
pub let AdminPrivatePath: PrivatePath
|
|
42
|
+
pub let AdminStoragePath: StoragePath
|
|
43
|
+
|
|
44
|
+
pub let AdminProxyPublicPath: PublicPath
|
|
45
|
+
pub let AdminProxyStoragePath: StoragePath
|
|
46
|
+
|
|
47
|
+
// Admin
|
|
48
|
+
// Admin resource to manage NFT Catalog
|
|
49
|
+
pub resource Admin {
|
|
50
|
+
|
|
51
|
+
pub fun addCatalogEntry(collectionIdentifier: String, metadata : NFTCatalog.NFTCatalogMetadata) {
|
|
52
|
+
NFTCatalog.addCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fun updateCatalogEntry(collectionIdentifier : String , metadata : NFTCatalog.NFTCatalogMetadata) {
|
|
56
|
+
NFTCatalog.updateCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fun removeCatalogEntry(collectionIdentifier : String) {
|
|
60
|
+
NFTCatalog.removeCatalogEntry(collectionIdentifier : collectionIdentifier)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fun removeCatalogEntryUnsafe(collectionIdentifier : String, nftTypeIdentifier: String) {
|
|
64
|
+
NFTCatalog.removeCatalogEntryUnsafe(collectionIdentifier : collectionIdentifier, nftTypeIdentifier: nftTypeIdentifier)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fun approveCatalogProposal(proposalID : UInt64) {
|
|
68
|
+
pre {
|
|
69
|
+
NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID"
|
|
70
|
+
NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal"
|
|
71
|
+
}
|
|
72
|
+
let catalogProposalEntry = NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!
|
|
73
|
+
let newCatalogProposalEntry = NFTCatalog.NFTCatalogProposal(collectionIdentifier : catalogProposalEntry.collectionIdentifier, metadata : catalogProposalEntry.metadata, message : catalogProposalEntry.message, status: "APPROVED", proposer: catalogProposalEntry.proposer)
|
|
74
|
+
NFTCatalog.updateCatalogProposal(proposalID : proposalID, proposalMetadata : newCatalogProposalEntry)
|
|
75
|
+
|
|
76
|
+
if NFTCatalog.getCatalogEntry(collectionIdentifier : NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.collectionIdentifier) == nil {
|
|
77
|
+
NFTCatalog.addCatalogEntry(collectionIdentifier: newCatalogProposalEntry.collectionIdentifier, metadata : newCatalogProposalEntry.metadata)
|
|
78
|
+
emit AddProposalAccepted(
|
|
79
|
+
proposer: newCatalogProposalEntry.proposer,
|
|
80
|
+
collectionIdentifier : newCatalogProposalEntry.collectionIdentifier,
|
|
81
|
+
contractName : newCatalogProposalEntry.metadata.contractName,
|
|
82
|
+
contractAddress : newCatalogProposalEntry.metadata.contractAddress,
|
|
83
|
+
displayName : newCatalogProposalEntry.metadata.collectionDisplay.name
|
|
84
|
+
)
|
|
85
|
+
} else {
|
|
86
|
+
NFTCatalog.updateCatalogEntry(collectionIdentifier: newCatalogProposalEntry.collectionIdentifier, metadata: newCatalogProposalEntry.metadata)
|
|
87
|
+
emit UpdateProposalAccepted(
|
|
88
|
+
proposer: newCatalogProposalEntry.proposer,
|
|
89
|
+
collectionIdentifier : newCatalogProposalEntry.collectionIdentifier,
|
|
90
|
+
contractName : newCatalogProposalEntry.metadata.contractName,
|
|
91
|
+
contractAddress : newCatalogProposalEntry.metadata.contractAddress,
|
|
92
|
+
displayName : newCatalogProposalEntry.metadata.collectionDisplay.name
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub fun rejectCatalogProposal(proposalID : UInt64) {
|
|
98
|
+
pre {
|
|
99
|
+
NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID"
|
|
100
|
+
NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal"
|
|
101
|
+
}
|
|
102
|
+
let catalogProposalEntry = NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!
|
|
103
|
+
let newCatalogProposalEntry = NFTCatalog.NFTCatalogProposal(collectionIdentifier : catalogProposalEntry.collectionIdentifier, metadata : catalogProposalEntry.metadata, message : catalogProposalEntry.message, status: "REJECTED", proposer: catalogProposalEntry.proposer)
|
|
104
|
+
NFTCatalog.updateCatalogProposal(proposalID : proposalID, proposalMetadata : newCatalogProposalEntry)
|
|
105
|
+
emit ProposalRejected(
|
|
106
|
+
proposer: newCatalogProposalEntry.proposer,
|
|
107
|
+
collectionIdentifier : newCatalogProposalEntry.collectionIdentifier,
|
|
108
|
+
contractName : newCatalogProposalEntry.metadata.contractName,
|
|
109
|
+
contractAddress : newCatalogProposalEntry.metadata.contractAddress,
|
|
110
|
+
displayName : newCatalogProposalEntry.metadata.collectionDisplay.name
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
pub fun removeCatalogProposal(proposalID : UInt64) {
|
|
115
|
+
pre {
|
|
116
|
+
NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID"
|
|
117
|
+
}
|
|
118
|
+
NFTCatalog.removeCatalogProposal(proposalID : proposalID)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
init () {}
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// AdminProxy
|
|
126
|
+
// A proxy resource that can store
|
|
127
|
+
// a capability to admin controls
|
|
128
|
+
pub resource interface IAdminProxy {
|
|
129
|
+
pub fun addCapability(capability : Capability<&Admin>)
|
|
130
|
+
pub fun hasCapability() : Bool
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
pub resource AdminProxy : IAdminProxy {
|
|
134
|
+
|
|
135
|
+
access(self) var capability : Capability<&Admin>?
|
|
136
|
+
|
|
137
|
+
pub fun addCapability(capability : Capability<&Admin>) {
|
|
138
|
+
pre {
|
|
139
|
+
capability.check() : "Invalid Admin Capability"
|
|
140
|
+
self.capability == nil : "Admin Proxy already set"
|
|
141
|
+
}
|
|
142
|
+
self.capability = capability
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
pub fun getCapability() : Capability<&Admin>? {
|
|
146
|
+
return self.capability
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
pub fun hasCapability() : Bool {
|
|
150
|
+
return self.capability != nil
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
init() {
|
|
154
|
+
self.capability = nil
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
pub fun createAdminProxy() : @AdminProxy {
|
|
160
|
+
return <- create AdminProxy()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
init () {
|
|
164
|
+
self.AdminProxyPublicPath = /public/nftCatalogAdminProxy
|
|
165
|
+
self.AdminProxyStoragePath = /storage/nftCatalogAdminProxy
|
|
166
|
+
|
|
167
|
+
self.AdminPrivatePath = /private/nftCatalogAdmin
|
|
168
|
+
self.AdminStoragePath = /storage/nftCatalogAdmin
|
|
169
|
+
|
|
170
|
+
let admin <- create Admin()
|
|
171
|
+
|
|
172
|
+
self.account.save(<-admin, to: self.AdminStoragePath)
|
|
173
|
+
self.account.link<&Admin>(self.AdminPrivatePath, target: self.AdminStoragePath)
|
|
174
|
+
}
|
|
175
|
+
}
|