Smart Contract

DisruptArtMarketplaceFlow

A.cd946ef9b13804c6.DisruptArtMarketplaceFlow

Deployed

5h ago
Mar 01, 2026, 07:12:18 AM UTC

Dependents

0 imports
1// DisruptArt Marketplace Smart Contract
2// NFT Marketplace : www.DisruptArt.io
3// Owner           : Disrupt Art, INC.
4// Developer       : www.blaze.ws
5// Version         : 0.0.1
6// Blockchain      : Flow www.onFlow.org
7
8
9// FLOW FUNGIBLE TOKEN mainnet
10// 
11import FungibleToken from 0xf233dcee88fe0abe
12// Testnet wallet address
13import DisruptArt from 0xcd946ef9b13804c6
14
15// This contract allows users to list their DisruptArt NFT for sale. 
16// Other users can purchase these NFTs with FLOW token.
17
18pub contract DisruptArtMarketplaceFlow {
19
20  // Event that is emitted when a new Disruptnow NFT is put up for sale
21  pub event ForSale(id: UInt64, price: UFix64)
22
23  // Event that is emitted when the NFT price changes
24  pub event PriceChanged(id: UInt64, newPrice: UFix64)
25
26  // Event that is emitted when a NFT token is purchased
27  pub event TokenPurchased(id: UInt64, price: UFix64)
28
29  // Event that is emitted when a seller withdraws their NFT from the sale
30  pub event SaleWithdrawn(id: UInt64)
31
32  // Market operator Address 
33  pub var marketAddress : Address
34  // Market operator fee percentage 
35  pub var marketFee : UFix64
36  // creator royality
37  pub var royality : UFix64
38
39  /// Path where the `SaleCollection` is stored
40  pub let marketStoragePath: StoragePath
41
42  /// Path where the public capability for the `SaleCollection` is
43  pub let marketPublicPath: PublicPath
44    
45
46  // Interface public methods that are used for NFT sales actions
47
48  pub resource interface SalePublic {
49    pub fun purchase(id: UInt64, recipient: &{DisruptArt.DisruptArtCollectionPublic}, payment: @FungibleToken.Vault)
50    pub fun purchaseGroup(tokens: [UInt64], recipient: &{DisruptArt.DisruptArtCollectionPublic}, payment: @FungibleToken.Vault)
51    pub fun idPrice(id: UInt64): UFix64?
52    pub fun tokenCreator(id: UInt64): Address??
53    pub fun currentTokenOwner(id: UInt64): Address??
54    pub fun isResale(id: UInt64): Bool?
55    pub fun getIDs(): [UInt64]
56  }
57
58  // SaleCollection
59  //
60  // NFT Collection object that allows a user to list their NFT for sale
61  // where others can send fungible tokens to purchase it
62  //
63  pub resource SaleCollection: SalePublic {
64
65    // Dictionary of the NFTs that the user is putting up for sale
66    pub var forSale: @{UInt64: DisruptArt.NFT}
67
68    // Dictionary of the prices for each NFT by ID
69    pub var prices: {UInt64: UFix64}
70
71    // Dictionary of the prices for each NFT by ID
72    pub var creators: {UInt64: Address?}
73
74    // Dictionary of sale type (either sale/resale)
75    pub var resale: {UInt64: Bool}
76
77    // Dictionary of token owner
78    pub var seller : {UInt64: Address?}
79
80    // The fungible token vault of the owner of this sale.
81    // When someone buys a token, this resource can deposit
82    // tokens into their account.
83    access(account) let ownerVault: Capability<&AnyResource{FungibleToken.Receiver}>
84
85    init (vault: Capability<&AnyResource{FungibleToken.Receiver}>) {
86        self.forSale <- {}
87        self.ownerVault = vault
88        self.prices = {}
89        self.creators = {}
90        self.resale = {}
91        self.seller = {}
92    }
93
94    // Withdraw gives the owner the opportunity to remove a NFT from sale
95    pub fun withdraw(id: UInt64): @DisruptArt.NFT {
96        // remove the price
97        self.prices.remove(key: id)
98        self.creators.remove(key: id)
99        self.resale.remove(key: id)
100        self.seller.remove(key: id)
101        // remove and return the token
102        let token <- self.forSale.remove(key: id) ?? panic("missing NFT")
103        return <-token
104    }
105     
106    // List NFTs in market collection
107    pub fun listForSaleGroup(sellerRef: &DisruptArt.Collection, tokens: [UInt64], price: UFix64) {
108       
109        pre {
110            tokens.length > 0:
111                "No Token found. Please provide tokens!"
112            self.tokensExist(tokens: tokens, ids: sellerRef.getIDs()):
113                "Token is not available!"
114        }
115
116        var count = 0
117        while count < tokens.length {
118            let token <- sellerRef.withdraw(withdrawID: tokens[count]) as! @DisruptArt.NFT
119            self.listForSale(token: <- token, price: price)
120            count = count + 1
121        }
122    }
123
124    // lists an NFT for sale in this collection
125    pub fun listForSale(token: @DisruptArt.NFT, price: UFix64) {
126        let id = token.id
127
128        // Store the price in the price array
129        self.prices[id] = price
130
131        self.creators[id] = token.creator
132
133        self.seller[id] = self.owner?.address
134
135        self.resale[id] = (token.creator == self.owner?.address) ? false : true
136
137        // Put NFT into the forSale dictionary
138        let oldToken <- self.forSale[id] <- token
139        destroy oldToken
140
141        emit ForSale(id: id, price: price)
142    }
143
144    // Change price of a group of tokens
145    pub fun changePrice(tokens: [UInt64],newPrice: UFix64) {        
146        pre {
147            tokens.length > 0:
148                "Please provide tokens!"
149            self.tokensExist(tokens:tokens, ids: self.forSale.keys):
150                "Tokens not available"
151        }
152        var count = 0
153        while count < tokens.length {
154            self.prices[tokens[count]] = newPrice
155            emit PriceChanged(id: tokens[count], newPrice: newPrice)
156            count = count + 1
157        }
158    }
159
160    pub fun tokensExist(tokens: [UInt64], ids: [UInt64]):Bool {
161        var count = 0
162        // let ids = self.forSale.keys
163        while count < tokens.length {
164            if(ids.contains(tokens[count])) {
165                count = count + 1
166            } else {
167                return false
168            } 
169        }
170        return true
171    }
172
173    pub fun tokensTotalPrice(tokens: [UInt64]):UFix64 {
174        var count = 0
175        var price:UFix64 = 0.0 
176        while count < tokens.length {
177            price = price + self.prices[tokens[count]]!
178            count = count + 1
179        }
180        return price
181    }
182
183    // Purchase : Allows am user send FLOW to purchase a NFT that is for sale
184    pub fun purchaseGroup(tokens: [UInt64], recipient: &{DisruptArt.DisruptArtCollectionPublic}, payment: @FungibleToken.Vault) {
185       
186        pre {
187            tokens.length > 0:
188                "Please provide tokens!"
189            self.tokensExist(tokens: tokens, ids: self.forSale.keys):
190                "Tokens are not available"
191            payment.balance >= self.tokensTotalPrice(tokens:tokens) :
192                "Not enough FLOW to purchase this NFT token"
193        }
194
195        let totalTokens = UFix64(tokens.length)
196
197        var count = 0
198        while count < tokens.length {
199           let tokenCut <- payment.withdraw(amount:  self.prices[tokens[count]]!)
200           self.purchase(id: tokens[count], recipient:recipient, payment: <-tokenCut)
201           count = count + 1
202        }
203        
204        let disruptartvaultRef =  getAccount(DisruptArtMarketplaceFlow.marketAddress)
205                                  .getCapability(/public/flowTokenReceiver)
206                                  .borrow<&{FungibleToken.Receiver}>()
207                                  ?? panic("failed to borrow reference to DisruptArtMarketplace vault")
208
209        disruptartvaultRef.deposit(from: <-payment)
210    }
211
212
213    // Purchase: Allows an user to send FLOW to purchase a NFT that is for sale
214    pub fun purchase(id: UInt64, recipient: &{DisruptArt.DisruptArtCollectionPublic}, payment: @FungibleToken.Vault) {
215        pre {
216            self.forSale[id] != nil && self.prices[id] != nil:
217                "No token matching this ID for sale!"
218            payment.balance >= self.prices[id]! :
219                "Not enough FLOW to purchase NFT"
220        }
221     
222        let totalamount = payment.balance
223
224        let owner = self.creators[id]!!
225
226        // Disruptvalut reference
227        let disruptartvaultRef =  getAccount(DisruptArtMarketplaceFlow.marketAddress)
228                                  .getCapability(/public/flowTokenReceiver)
229                                .borrow<&{FungibleToken.Receiver}>()
230                                ?? panic("failed to borrow reference to DisruptArtMarketplace vault")
231        // Creator vault reference
232        let creatorvaultRef =  getAccount(owner)
233                                 .getCapability(/public/flowTokenReceiver)
234                                .borrow<&{FungibleToken.Receiver}>()
235                                ?? panic("failed to borrow reference to owner vault") 
236       
237        // Seller vault reference
238        let vaultRef = self.ownerVault.borrow()
239            ?? panic("Could not borrow reference to owner token vault")
240
241        let marketShare = self.flowshare(price:self.prices[id]!, commission:DisruptArtMarketplaceFlow.marketFee)
242        let royalityShare = self.flowshare(price:self.prices[id]!, commission:DisruptArtMarketplaceFlow.royality)
243        
244        let marketCut <- payment.withdraw(amount: marketShare)
245        let royalityCut <- payment.withdraw(amount: royalityShare)
246
247        disruptartvaultRef.deposit(from: <-marketCut)
248        // Royalty to the original creator / minted user if this is a resale.
249        if(self.resale[id]!) {
250            creatorvaultRef.deposit(from: <-royalityCut)
251        } else {
252            disruptartvaultRef.deposit(from: <-royalityCut)
253        }
254
255        // After Marketplace fee & royalty fee deposit the balance FLOW to seller's wallet
256        vaultRef.deposit(from: <-payment)
257
258        // Deposit the NFT token into the buyer's collection storage
259        recipient.deposit(token: <-self.withdraw(id: id))
260
261        self.prices[id] = nil
262        self.creators[id] = nil
263        self.resale[id] = nil
264        self.seller[id] = nil
265
266        emit TokenPurchased(id: id, price: totalamount)
267    }
268
269    pub fun flowshare(price:UFix64, commission:UFix64):UFix64 {
270            return (price / 100.0 ) * commission
271    }
272
273    // Return the FLOW price of a specific token that is listed for sale.
274    pub fun idPrice(id: UInt64): UFix64? {
275        return self.prices[id]
276    }
277
278    pub fun isResale(id: UInt64): Bool? {
279        return self.resale[id]
280    }
281
282    // Returns the owner / original minter of a specific NFT token in the sale
283    pub fun tokenCreator(id: UInt64): Address?? {
284        return self.creators[id]
285    }
286
287    pub fun currentTokenOwner(id: UInt64): Address?? {
288        return self.seller[id]
289    }
290
291    // getIDs returns an array of token IDs that are for sale
292    pub fun getIDs(): [UInt64] {
293        return self.forSale.keys
294    }
295
296    // Withdraw NFTs from DisruptArtMarketplace
297    pub fun saleWithdrawn(tokens : [UInt64]) {
298       pre {
299            tokens.length > 0:
300                "Please provide NFT tokens!"
301            self.tokensExist(tokens:tokens, ids: self.forSale.keys):
302                "Tokens are not available"
303       }
304
305       var count = 0
306       let owner = self.seller[tokens[0]]!!
307       let receiver = getAccount(owner)
308              .getCapability(DisruptArt.disruptArtPublicPath)
309              .borrow<&{DisruptArt.DisruptArtCollectionPublic}>()
310               ?? panic("Could not get receiver reference to the NFT Collection")
311
312       while count < tokens.length {
313          // Deposit the NFT back into the seller collection
314          receiver.deposit(token: <-self.withdraw(id: tokens[count]))
315          emit SaleWithdrawn(id: tokens[count])
316          count = count + 1
317       }
318    } 
319
320    destroy() {
321        destroy self.forSale
322    }
323  }
324
325  // createCollection returns a new collection resource to the caller
326  pub fun createSaleCollection(ownerVault: Capability<&AnyResource{FungibleToken.Receiver}>): @SaleCollection {
327    return <- create SaleCollection(vault: ownerVault)
328  }
329
330  pub resource Admin {
331    pub fun changeoperator(newOperator: Address, marketCommission: UFix64, royality: UFix64 ) {
332        DisruptArtMarketplaceFlow.marketAddress = newOperator
333        DisruptArtMarketplaceFlow.marketFee = marketCommission
334        DisruptArtMarketplaceFlow.royality = royality
335    } 
336  }
337
338  init() {
339    self.marketAddress = 0x420f47f16a214100
340    // 5% Marketplace Fee
341    self.marketFee = 5.0
342    // 10% Royalty reward for original creater / minter for every re-sale
343    self.royality = 10.0
344
345    self.marketPublicPath = /public/DisruptArtFlowNFTSale
346
347    self.marketStoragePath = /storage/DisruptArtFlowNFTSale
348
349    self.account.save(<- create Admin(), to:/storage/DisruptArtFlowMarketAdmin)
350  } 
351
352}
353