Smart Contract
SomePlaceManager
A.667a16294a089ef8.SomePlaceManager
1/*
2 Description: Administrative Contract for SomePlace NFT Collectibles
3
4 Exposes all functionality for an administrator of SomePlace to
5 make creations and modifications pertaining to SomePlace Collectibles
6*/
7
8import FungibleToken from 0xf233dcee88fe0abe
9import NonFungibleToken from 0x1d7e57aa55817448
10import SomePlaceCollectible from 0x667a16294a089ef8
11import FlowToken from 0x1654653399040a61
12import FUSD from 0x3c5959b568896393
13import SomePlacePrimarySaleHelper from 0x667a16294a089ef8
14
15pub contract SomePlaceManager {
16 pub let ManagerStoragePath: StoragePath
17 pub let ManagerPublicPath: PublicPath
18
19 // -----------------------------------------------------------------------
20 // SomePlace Manager Events
21 // -----------------------------------------------------------------------
22 pub event SetMetadataUpdated(setID: UInt64)
23 pub event EditionMetadataUpdated(setID: UInt64, editionNumber: UInt64)
24 pub event EditionTraitsUpdated(setID: UInt64, editionNumber: UInt64)
25 pub event PublicSalePriceUpdated(setID: UInt64, fungibleTokenType: String, price: UFix64?)
26 pub event PublicSaleTimeUpdated(setID: UInt64, startTime: UFix64?, endTime: UFix64?)
27
28 // Allows for access to where SomePlace FUSD funds should head towards.
29 // Mapping of `FungibleToken Identifier` -> `Receiver Capability`
30 // Currently usable is FLOW and FUSD as payment receivers
31 access(self) var adminPaymentReceivers: { String : Capability<&{FungibleToken.Receiver}> }
32
33
34 pub resource interface ManagerPublic {
35 pub fun mintNftFromPublicSaleWithFUSD(setID: UInt64, quantity: UInt32, vault: @FungibleToken.Vault): @SomePlaceCollectible.Collection
36 pub fun mintNftFromPublicSaleWithFLOW(setID: UInt64, quantity: UInt32, vault: @FungibleToken.Vault): @SomePlaceCollectible.Collection
37 }
38
39 pub resource Manager: ManagerPublic {
40
41 /*
42 Set creation
43 */
44 pub fun addNFTSet(maxNumberOfEditions: UInt64, metadata: {String:String}): UInt64 {
45 let setID = SomePlaceCollectible.addNFTSet(maxNumberOfEditions: maxNumberOfEditions, metadata: metadata)
46 return setID
47 }
48
49 /*
50 Modification of properties and metadata for a set
51 */
52
53 pub fun updateSetMetadata(setID: UInt64, metadata: {String: String}) {
54 SomePlaceCollectible.updateSetMetadata(setID: setID, metadata: metadata)
55 emit SetMetadataUpdated(setID: setID)
56 }
57
58 pub fun updateEditionMetadata(setID: UInt64, editionNumber: UInt64, metadata: {String: String}) {
59 SomePlaceCollectible.updateEditionMetadata(setID: setID, editionNumber: editionNumber, metadata: metadata)
60 emit EditionMetadataUpdated(setID: setID, editionNumber: editionNumber)
61 }
62
63 pub fun updateEditionTraits(setID: UInt64, editionNumber: UInt64, traits: {String: String}) {
64 SomePlaceCollectible.updateEditionTraits(setID: setID, editionNumber: editionNumber, traits: traits)
65 emit EditionTraitsUpdated(setID: setID, editionNumber: editionNumber)
66 }
67
68 pub fun updateFLOWPublicSalePrice(setID: UInt64, price: UFix64?) {
69 SomePlaceCollectible.updateFLOWPublicSalePrice(setID: setID, price: price)
70 emit PublicSalePriceUpdated(setID: setID, fungibleTokenType: "FLOW", price: price)
71 }
72
73 pub fun updateFUSDPublicSalePrice(setID: UInt64, price: UFix64?) {
74 SomePlaceCollectible.updateFUSDPublicSalePrice(setID: setID, price: price)
75 emit PublicSalePriceUpdated(setID: setID, fungibleTokenType: "FUSD", price: price)
76 }
77
78 pub fun updatePublicSaleStartTime(setID: UInt64, startTime: UFix64?) {
79 SomePlaceCollectible.updatePublicSaleStartTime(setID: setID, startTime: startTime)
80 let setMetadata = SomePlaceCollectible.getMetadataForSetID(setID: setID)!
81 emit PublicSaleTimeUpdated(
82 setID: setID,
83 startTime: setMetadata.getPublicSaleStartTime(),
84 endTime: setMetadata.getPublicSaleEndTime()
85 )
86 }
87
88 pub fun updatePublicSaleEndTime(setID: UInt64, endTime: UFix64?) {
89 SomePlaceCollectible.updatePublicSaleEndTime(setID: setID, endTime: endTime)
90 let setMetadata = SomePlaceCollectible.getMetadataForSetID(setID: setID)!
91 emit PublicSaleTimeUpdated(
92 setID: setID,
93 startTime: setMetadata.getPublicSaleStartTime(),
94 endTime: setMetadata.getPublicSaleEndTime()
95 )
96 }
97
98 /*
99 Modification of manager properties
100 */
101 // fungibleTokenType is expected to be 'FLOW' or 'FUSD'
102 pub fun setAdminPaymentReceiver(fungibleTokenType: String, paymentReceiver: Capability<&{FungibleToken.Receiver}>) {
103 SomePlaceManager.setAdminPaymentReceiver(fungibleTokenType: fungibleTokenType, paymentReceiver: paymentReceiver)
104 }
105
106
107 /* Minting functions */
108
109 // Mint a single next edition NFT
110 access(self) fun mintSequentialEditionNFT(setID: UInt64): @SomePlaceCollectible.NFT {
111 return <-SomePlaceCollectible.mintSequentialEditionNFT(setID: setID)
112 }
113
114 // Mint many editions of NFTs
115 pub fun batchMintSequentialEditionNFTs(setID: UInt64, quantity: UInt32): @SomePlaceCollectible.Collection {
116 pre {
117 quantity >= 1 && quantity <= 10 : "May only mint between 1 and 10 collectibles at a single time."
118 }
119 let collection <- SomePlaceCollectible.createEmptyCollection() as! @SomePlaceCollectible.Collection
120 var counter: UInt32 = 0
121 while (counter < quantity) {
122 collection.deposit(token: <-self.mintSequentialEditionNFT(setID: setID))
123 counter = counter + 1
124 }
125 return <-collection
126 }
127
128 // Mint a specific edition of an NFT
129 pub fun mintNFT(setID: UInt64, editionNumber: UInt64): @SomePlaceCollectible.NFT {
130 return <-SomePlaceCollectible.mintNFT(setID: setID, editionNumber: editionNumber)
131 }
132
133 // Allows direct minting of a NFT as part of a public sale.
134 // This function takes in a vault that can be of multiple types of fungible tokens.
135 // The proper fungible token is to be checked prior to this function call
136 access(self) fun mintNftFromPublicSale(setID: UInt64, quantity: UInt32, vault: @FungibleToken.Vault,
137 price: UFix64, paymentReceiver: Capability<&{FungibleToken.Receiver}>): @SomePlaceCollectible.Collection {
138 pre {
139 quantity >= 1 && quantity <= 2 : "May only mint between 1 and 2 collectibles at a time"
140 SomePlaceCollectible.getMetadataForSetID(setID: setID) != nil :
141 "SetID does not exist"
142 SomePlaceCollectible.getMetadataForSetID(setID: setID)!.isPublicSaleActive() :
143 "Public minting is not currently allowed"
144 }
145 let totalPrice = price * UFix64(quantity)
146
147 // Ensure that the provided balance is equal to our expected price for the NFTs
148 assert(totalPrice == vault.balance)
149
150 // Mint `quantity` number of NFTs from this drop to the collection
151 var counter = UInt32(0)
152 let uuids: [UInt64] = []
153 let collection <- SomePlaceCollectible.createEmptyCollection() as! @SomePlaceCollectible.Collection
154 while (counter < quantity) {
155 let collectible <- SomePlacePrimarySaleHelper.retrieveAvailableNFT()
156 assert(SomePlaceCollectible.getCollectibleDataForNftByUUID(uuid: collectible.uuid)!.getSetID() == setID)
157 uuids.append(collectible.uuid)
158 collection.deposit(token: <-collectible)
159 counter = counter + UInt32(1)
160 }
161 let adminPaymentReceiver = paymentReceiver.borrow()!
162 adminPaymentReceiver.deposit(from: <-vault)
163 return <-collection
164 }
165
166
167 /*
168 Public functions
169 */
170 // Ensure that the passed in vault is FUSD, and pass the expected FUSD sale price for this set
171 pub fun mintNftFromPublicSaleWithFUSD(setID: UInt64, quantity: UInt32, vault: @FungibleToken.Vault): @SomePlaceCollectible.Collection {
172 pre {
173 SomePlaceCollectible.getMetadataForSetID(setID: setID)!.getFUSDPublicSalePrice() != nil :
174 "Public sale price not set for this set"
175 }
176 let fusdVault <- vault as! @FUSD.Vault
177 let price = SomePlaceCollectible.getMetadataForSetID(setID: setID)!.getFUSDPublicSalePrice()!
178 let paymentReceiver = SomePlaceManager.adminPaymentReceivers["FUSD"]!
179 return <-self.mintNftFromPublicSale(setID: setID, quantity: quantity, vault: <-fusdVault, price: price,
180 paymentReceiver: paymentReceiver)
181 }
182
183 // Ensure that the passed in vault is a FLOW vault, and pass the expected FLOW sale price for this set
184 pub fun mintNftFromPublicSaleWithFLOW(setID: UInt64, quantity: UInt32, vault: @FungibleToken.Vault): @SomePlaceCollectible.Collection {
185 pre {
186 SomePlaceCollectible.getMetadataForSetID(setID: setID)!.getFLOWPublicSalePrice() != nil :
187 "Public sale price not set for this set"
188 }
189 let flowVault <- vault as! @FlowToken.Vault
190 let price = SomePlaceCollectible.getMetadataForSetID(setID: setID)!.getFLOWPublicSalePrice()!
191 let paymentReceiver = SomePlaceManager.adminPaymentReceivers["FLOW"]!
192 return <-self.mintNftFromPublicSale(setID: setID, quantity: quantity, vault: <-flowVault, price: price,
193 paymentReceiver: paymentReceiver)
194 }
195
196 }
197
198 /* Mutating functions */
199 access(contract) fun setAdminPaymentReceiver(fungibleTokenType: String, paymentReceiver: Capability<&{FungibleToken.Receiver}>) {
200 pre {
201 fungibleTokenType == "FLOW" || fungibleTokenType == "FUSD" : "Must provide either flow or fusd as fungible token keys"
202 paymentReceiver.borrow() != nil : "Invalid payment receivier capability provided"
203 fungibleTokenType == "FLOW" && paymentReceiver.borrow()!.isInstance(Type<@FlowToken.Vault>()) : "Invalid flow token vault provided"
204 fungibleTokenType == "FUSD" && paymentReceiver.borrow()!.isInstance(Type<@FUSD.Vault>()) : "Invalid flow token vault provided"
205 }
206 self.adminPaymentReceivers[fungibleTokenType] = paymentReceiver
207 }
208
209 /* Public Functions */
210 pub fun getManagerPublic(): Capability<&SomePlaceManager.Manager{SomePlaceManager.ManagerPublic}> {
211 return self.account.getCapability<&SomePlaceManager.Manager{SomePlaceManager.ManagerPublic}>(self.ManagerPublicPath)
212 }
213
214 init() {
215 self.ManagerStoragePath = /storage/somePlaceManager
216 self.ManagerPublicPath = /public/somePlaceManager
217 self.account.save(<- create Manager(), to: self.ManagerStoragePath)
218 self.account.link<&SomePlaceManager.Manager{SomePlaceManager.ManagerPublic}>(self.ManagerPublicPath, target: self.ManagerStoragePath)
219
220 // If FUSD isn't setup on this manager account already, set it up - it is required to receive funds
221 // and redirect sales of NFTs where we've lost the FUSD vault access to a seller on secondary market
222 let existingVault = self.account.borrow<&FUSD.Vault>(from: /storage/fusdVault)
223 if (existingVault == nil) {
224 self.account.save(<-FUSD.createEmptyVault(), to: /storage/fusdVault)
225 self.account.link<&FUSD.Vault{FungibleToken.Receiver}>(
226 /public/fusdReceiver,
227 target: /storage/fusdVault
228 )
229 self.account.link<&FUSD.Vault{FungibleToken.Balance}>(
230 /public/fusdBalance,
231 target: /storage/fusdVault
232 )
233 }
234
235 self.adminPaymentReceivers = {}
236 self.adminPaymentReceivers["FUSD"] = self.account.getCapability<&FUSD.Vault{FungibleToken.Receiver}>(/public/fusdReceiver)
237 self.adminPaymentReceivers["FLOW"] = self.account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver)
238 }
239}