Smart Contract
BlackMarketplace
A.117396d8a72ad372.BlackMarketplace
1// Black Hunter's Market
2// Yosh! -swt
3//
4//
5import FungibleToken from 0xf233dcee88fe0abe
6import FUSD from 0x3c5959b568896393
7import NonFungibleToken from 0x1d7e57aa55817448
8import NFTDayTreasureChest from 0x117396d8a72ad372
9
10access(all)
11contract BlackMarketplace{
12
13 access(all) entitlement SaleCollectionOwner
14
15 // -----------------------------------------------------------------------
16 // BlackMarketplace Events
17 // -----------------------------------------------------------------------
18 access(all)
19 event ForSale(id: UInt64, price: UFix64)
20
21 access(all)
22 event PriceChanged(id: UInt64, newPrice: UFix64)
23
24 access(all)
25 event TokenPurchased(id: UInt64, price: UFix64, from: Address, to: Address)
26
27 access(all)
28 event RoyaltyPaid(id: UInt64, amount: UFix64, to: Address, name: String)
29
30 access(all)
31 event SaleWithdrawn(id: UInt64)
32
33 // -----------------------------------------------------------------------
34 // Named Paths
35 // -----------------------------------------------------------------------
36 access(all)
37 let CollectionStoragePath: StoragePath
38
39 access(all)
40 let CollectionPublicPath: PublicPath
41
42 access(all)
43 let marketplaceWallet: Capability<&FUSD.Vault>
44
45 access(contract)
46 var whitelistUsed: [Address]
47
48 access(contract)
49 var sellers: [Address]
50
51 access(all)
52 resource interface SalePublic{
53 access(all)
54 fun purchaseWithWhitelist(
55 tokenID: UInt64,
56 recipientCap: Capability<&{NFTDayTreasureChest.NFTDayTreasureChestCollectionPublic}>,
57 buyTokens: @{FungibleToken.Vault}
58 ): Void
59
60 access(all)
61 fun purchaseWithTreasureChest(
62 tokenID: UInt64,
63 recipientCap: Capability<&{NFTDayTreasureChest.NFTDayTreasureChestCollectionPublic}>,
64 buyTokens: @{FungibleToken.Vault},
65 chest: @NFTDayTreasureChest.NFT
66 ): @NFTDayTreasureChest.NFT
67
68 access(all) view
69 fun idPrice(tokenID: UInt64): UFix64?
70
71 access(all) view
72 fun getIDs(): [UInt64]
73 }
74
75 access(all) resource SaleCollection: SalePublic{
76 access(self) var forSale: @{UInt64: NFTDayTreasureChest.NFT}
77
78 access(self)
79 var prices:{ UInt64: UFix64}
80
81 access(account)
82 let ownerVault: Capability<&{FungibleToken.Receiver}>
83
84 init(vault: Capability<&{FungibleToken.Receiver}>){
85 self.forSale <-{}
86 self.ownerVault = vault
87 self.prices ={}
88 }
89
90 access(SaleCollectionOwner)
91 fun withdraw(tokenID: UInt64): @NFTDayTreasureChest.NFT{
92 self.prices.remove(key: tokenID)
93 let token <- self.forSale.remove(key: tokenID) ?? panic("missing NFT")
94 emit SaleWithdrawn(id: tokenID)
95 return <-token
96 }
97
98 access(SaleCollectionOwner)
99 fun listForSale(token: @NFTDayTreasureChest.NFT, price: UFix64){
100 let id = token.id
101 self.prices[id] = price
102 let oldToken <- self.forSale[id] <- token
103 destroy oldToken
104 if !BlackMarketplace.sellers.contains((self.owner!).address){
105 BlackMarketplace.sellers.append((self.owner!).address)
106 }
107 emit ForSale(id: id, price: price)
108 }
109
110 access(SaleCollectionOwner)
111 fun changePrice(tokenID: UInt64, newPrice: UFix64){
112 self.prices[tokenID] = newPrice
113 emit PriceChanged(id: tokenID, newPrice: newPrice)
114 }
115
116 // Requires a whitelist to purchase
117 access(all)
118 fun purchaseWithWhitelist(tokenID: UInt64, recipientCap: Capability<&{NFTDayTreasureChest.NFTDayTreasureChestCollectionPublic}>, buyTokens: @{FungibleToken.Vault}){
119 pre{
120 self.forSale[tokenID] != nil && self.prices[tokenID] != nil:
121 "No token matching this ID for sale!"
122 buyTokens.balance >= self.prices[tokenID] ?? 0.0:
123 "Not enough tokens to by the NFT!"
124 !BlackMarketplace.whitelistUsed.contains(((recipientCap.borrow()!).owner!).address):
125 "Cannot purchase: Whitelist used"
126 NFTDayTreasureChest.getWhitelist().contains(((recipientCap.borrow()!).owner!).address):
127 "Cannot purchase: Must be whitelisted"
128 }
129 let recipient = recipientCap.borrow()!
130 let price = self.prices[tokenID]!
131 self.prices[tokenID] = nil
132 let vaultRef = self.ownerVault.borrow() ?? panic("Could not borrow reference to owner token vault")
133 let token <- self.withdraw(tokenID: tokenID)
134 let marketplaceWallet = BlackMarketplace.marketplaceWallet.borrow()!
135 let marketplaceFee = price * 0.05 // 5% marketplace cut
136
137 marketplaceWallet.deposit(from: <-buyTokens.withdraw(amount: marketplaceFee))
138 emit RoyaltyPaid(id: tokenID, amount: marketplaceFee, to: (marketplaceWallet.owner!).address, name: "Marketplace")
139 vaultRef.deposit(from: <-buyTokens)
140 recipient.deposit(token: <-token)
141 BlackMarketplace.whitelistUsed.append((recipient.owner!).address)
142 emit TokenPurchased(id: tokenID, price: price, from: (vaultRef.owner!).address, to: (recipient.owner!).address)
143 }
144
145 // Requires a chest to purchase
146 access(all)
147 fun purchaseWithTreasureChest(tokenID: UInt64, recipientCap: Capability<&{NFTDayTreasureChest.NFTDayTreasureChestCollectionPublic}>, buyTokens: @{FungibleToken.Vault}, chest: @NFTDayTreasureChest.NFT): @NFTDayTreasureChest.NFT{
148 pre{
149 self.forSale[tokenID] != nil && self.prices[tokenID] != nil:
150 "No token matching this ID for sale!"
151 buyTokens.balance >= self.prices[tokenID] ?? 0.0:
152 "Not enough tokens to by the NFT!"
153 }
154 let recipient = recipientCap.borrow()!
155 let price = self.prices[tokenID]!
156 self.prices[tokenID] = nil
157 let vaultRef = self.ownerVault.borrow() ?? panic("Could not borrow reference to owner token vault")
158 let token <- self.withdraw(tokenID: tokenID)
159 let marketplaceWallet = BlackMarketplace.marketplaceWallet.borrow()!
160 let marketplaceFee = price * 0.05 // 5% marketplace cut
161
162 marketplaceWallet.deposit(from: <-buyTokens.withdraw(amount: marketplaceFee))
163 emit RoyaltyPaid(id: tokenID, amount: marketplaceFee, to: (marketplaceWallet.owner!).address, name: "Marketplace")
164 vaultRef.deposit(from: <-buyTokens)
165 recipient.deposit(token: <-token)
166 emit TokenPurchased(id: tokenID, price: price, from: (vaultRef.owner!).address, to: (recipient.owner!).address)
167 return <-chest
168 }
169
170 access(all) view
171 fun idPrice(tokenID: UInt64): UFix64?{
172 return self.prices[tokenID]
173 }
174
175 access(all) view
176 fun getIDs(): [UInt64]{
177 return self.forSale.keys
178 }
179 }
180
181 access(all)
182 fun createSaleCollection(ownerVault: Capability<&{FungibleToken.Receiver}>): @SaleCollection{
183 return <-create SaleCollection(vault: ownerVault)
184 }
185
186 access(all) view
187 fun getWhitelistUsed(): [Address]{
188 return self.whitelistUsed
189 }
190
191 access(all) view
192 fun getSellers(): [Address]{
193 return self.sellers
194 }
195
196 init(){
197 self.CollectionStoragePath = /storage/BasicBeastsBlackMarketplace
198 self.CollectionPublicPath = /public/BasicBeastsBlackMarketplace
199 if self.account.storage.borrow<&FUSD.Vault>(from: /storage/fusdVault) == nil{
200 // Create a new FUSD Vault and put it in storage
201 self.account.storage.save(<-FUSD.createEmptyVault(vaultType: Type<@FUSD.Vault>()), to: /storage/fusdVault)
202
203 // Create a public capability to the Vault that only exposes
204 // the deposit function through the Receiver interface
205 var capability_1 = self.account.capabilities.storage.issue<&FUSD.Vault>(/storage/fusdVault)
206 self.account.capabilities.publish(capability_1, at: /public/fusdReceiver)
207
208 // Create a public capability to the Vault that only exposes
209 // the balance field through the Balance interface
210 var capability_2 = self.account.capabilities.storage.issue<&FUSD.Vault>(/storage/fusdVault)
211 self.account.capabilities.publish(capability_2, at: /public/fusdBalance)
212 }
213 self.marketplaceWallet = self.account.capabilities.get<&FUSD.Vault>(/public/fusdReceiver)!
214 self.whitelistUsed = []
215 self.sellers = []
216 }
217}
218