Smart Contract

SomePlaceManager

A.667a16294a089ef8.SomePlaceManager

Deployed

2h ago
Feb 28, 2026, 09:22:11 PM UTC

Dependents

0 imports
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}