Smart Contract
StarlyCardBid
A.5b82f21c0edf76e3.StarlyCardBid
1import StarlyCard from 0x5b82f21c0edf76e3
2import FungibleToken from 0xf233dcee88fe0abe
3import NonFungibleToken from 0x1d7e57aa55817448
4import StarlyCardStaking from 0x29fcd0b5e444242a
5import StakedStarlyCard from 0x29fcd0b5e444242a
6import StarlyCardMarket from 0x5b82f21c0edf76e3
7
8pub contract StarlyCardBid {
9
10 pub var totalCount: UInt64
11
12 pub event StarlyCardBidCreated(
13 bidID: UInt64,
14 nftID: UInt64,
15 starlyID: String,
16 bidPrice: UFix64,
17 bidVaultType: String,
18 bidderAddress: Address)
19
20 pub event StarlyCardBidAccepted(
21 bidID: UInt64,
22 nftID: UInt64,
23 starlyID: String)
24
25 // Declined by the card owner
26 pub event StarlyCardBidDeclined(
27 bidID: UInt64,
28 nftID: UInt64,
29 starlyID: String)
30
31 // Bid cancelled by the bidder
32 pub event StarlyCardBidCancelled(
33 bidID: UInt64,
34 nftID: UInt64,
35 starlyID: String)
36
37 // Bid invalidated due to changed conditions, i.e. remaining resource
38 pub event StarlyCardBidInvalidated(
39 bidID: UInt64,
40 nftID: UInt64,
41 starlyID: String)
42
43 // Paths
44 pub let CollectionStoragePath: StoragePath
45 pub let CollectionPublicPath: PublicPath
46
47 pub resource interface BidPublicView {
48 pub let id: UInt64
49 pub let nftID: UInt64
50 pub let starlyID: String
51 pub let remainingResource: UFix64
52 pub let bidPrice: UFix64
53 pub let bidVaultType: Type
54 }
55
56 pub resource Bid: BidPublicView {
57 pub let id: UInt64
58
59 pub let nftID: UInt64
60 pub let starlyID: String
61
62 // card's remainig resource
63 pub let remainingResource: UFix64
64
65 // The price offered by the bidder
66 pub let bidPrice: UFix64
67 // The Type of the FungibleToken that payments must be made in
68 pub let bidVaultType: Type
69 access(self) let bidVault: @FungibleToken.Vault
70
71 pub let bidderAddress: Address
72 access(self) let bidderFungibleReceiver: Capability<&{FungibleToken.Receiver}>
73
74 pub fun accept(
75 bidderCardCollection: &StarlyCard.Collection{StarlyCard.StarlyCardCollectionPublic},
76 sellerFungibleReceiver: Capability<&{FungibleToken.Receiver}>,
77 sellerCardCollection: Capability<&StarlyCard.Collection{NonFungibleToken.Provider}>,
78 sellerStakedCardCollection: &StakedStarlyCard.Collection,
79 sellerMarketCollection: &StarlyCardMarket.Collection
80 ) {
81 pre {
82 self.bidVault.balance == self.bidPrice: "The amount of locked funds is incorrect"
83 }
84
85 let currentRemainingResource = StarlyCardStaking.getRemainingResourceWithDefault(starlyID: self.starlyID)
86 if currentRemainingResource != self.remainingResource {
87 emit StarlyCardBidInvalidated(bidID: self.id, nftID: self.nftID, starlyID: self.starlyID)
88 return
89 }
90
91 self.unstakeCardIfStaked(sellerStakedCardCollection: sellerStakedCardCollection)
92 self.removeMarketSaleOfferIfExists(sellerMarketCollection: sellerMarketCollection)
93
94 // transfer card
95 let nft <- sellerCardCollection.borrow()!.withdraw(withdrawID: self.nftID)
96 bidderCardCollection.deposit(token: <- nft)
97
98 sellerFungibleReceiver.borrow()!.deposit(from: <- self.bidVault.withdraw(amount: self.bidPrice))
99
100 emit StarlyCardBidAccepted(bidID: self.id, nftID: self.nftID, starlyID: self.starlyID)
101 }
102
103 access(self) fun removeMarketSaleOfferIfExists(sellerMarketCollection: &StarlyCardMarket.Collection) {
104 let marketOfferIds = sellerMarketCollection.getSaleOfferIDs()
105 if marketOfferIds.contains(self.nftID) {
106 let offer <- sellerMarketCollection.remove(itemID: self.nftID)
107 destroy offer
108 }
109 }
110
111 access(self) fun unstakeCardIfStaked(sellerStakedCardCollection: &StakedStarlyCard.Collection) {
112 let stakeIds = sellerStakedCardCollection.getIDs()
113 for stakeId in stakeIds {
114 let cardStake = sellerStakedCardCollection.borrowStakePrivate(id: stakeId)
115 if cardStake.getStarlyID() == self.starlyID {
116 sellerStakedCardCollection.unstake(id: stakeId)
117 return
118 }
119 }
120 }
121
122 init(
123 nftID: UInt64,
124 starlyID: String,
125 bidPrice: UFix64,
126 bidVaultType: Type,
127 bidderAddress: Address,
128 bidderFungibleReceiver: Capability<&{FungibleToken.Receiver}>,
129 bidderFungibleProvider: &AnyResource{FungibleToken.Provider}
130 ) {
131 pre {
132 bidPrice > 0.0: "The bid price must be non zero"
133 bidderFungibleProvider.isInstance(bidVaultType): "Wrong Bid fungible provider type"
134 }
135
136 self.id = StarlyCardBid.totalCount
137 self.nftID = nftID
138 self.starlyID = starlyID
139 self.bidPrice = bidPrice
140 self.bidVaultType = bidVaultType
141 self.bidderAddress = bidderAddress
142 self.bidderFungibleReceiver = bidderFungibleReceiver
143
144 self.remainingResource = StarlyCardStaking.getRemainingResourceWithDefault(starlyID: starlyID)
145
146 self.bidVault <- bidderFungibleProvider.withdraw(amount: bidPrice)
147
148 StarlyCardBid.totalCount = StarlyCardBid.totalCount + (1 as UInt64)
149
150 emit StarlyCardBidCreated(
151 bidID: self.id,
152 nftID: self.nftID,
153 starlyID: self.starlyID,
154 bidPrice: self.bidPrice,
155 bidVaultType: self.bidVaultType.identifier,
156 bidderAddress: self.bidderAddress
157 )
158 }
159
160 destroy () {
161 if self.bidVault.balance > 0.0 {
162 // return back to the bidder
163 self.bidderFungibleReceiver.borrow()!.deposit(from: <- self.bidVault)
164 } else {
165 destroy self.bidVault
166 }
167 }
168 }
169
170 pub resource interface CollectionManager {
171 pub fun insert(bid: @StarlyCardBid.Bid)
172 pub fun remove(bidID: UInt64): @Bid
173 pub fun cancel(bidID: UInt64)
174 }
175
176 pub resource interface CollectionPublic {
177 pub fun getBidIDs(): [UInt64]
178
179 pub fun borrowBid(bidID: UInt64): &Bid{BidPublicView}?
180
181 pub fun accept(
182 bidID: UInt64,
183 bidderCardCollection: &StarlyCard.Collection{StarlyCard.StarlyCardCollectionPublic},
184 sellerFungibleReceiver: Capability<&{FungibleToken.Receiver}>,
185 sellerCardCollection: Capability<&StarlyCard.Collection{NonFungibleToken.Provider}>,
186 sellerStakedCardCollection: &StakedStarlyCard.Collection,
187 sellerMarketCollection: &StarlyCardMarket.Collection)
188
189 pub fun decline(bidID: UInt64)
190 }
191
192 pub resource Collection : CollectionManager, CollectionPublic {
193 pub var bids: @{UInt64: Bid}
194
195 pub fun getBidIDs(): [UInt64] {
196 return self.bids.keys
197 }
198
199 pub fun borrowBid(bidID: UInt64): &Bid{BidPublicView}? {
200 if self.bids[bidID] == nil {
201 return nil
202 }
203
204 return &self.bids[bidID] as &Bid{BidPublicView}?
205 }
206
207 pub fun insert(bid: @StarlyCardBid.Bid) {
208 let oldBid <- self.bids[bid.id] <- bid
209 destroy oldBid
210 }
211
212 pub fun remove(bidID: UInt64): @Bid {
213 return <- (self.bids.remove(key: bidID) ?? panic("missing bid"))
214 }
215
216 pub fun accept(
217 bidID: UInt64,
218 bidderCardCollection: &StarlyCard.Collection{StarlyCard.StarlyCardCollectionPublic},
219 sellerFungibleReceiver: Capability<&{FungibleToken.Receiver}>,
220 sellerCardCollection: Capability<&StarlyCard.Collection{NonFungibleToken.Provider}>,
221 sellerStakedCardCollection: &StakedStarlyCard.Collection,
222 sellerMarketCollection: &StarlyCardMarket.Collection
223 ) {
224 let bid <- self.remove(bidID: bidID)
225 bid.accept(
226 bidderCardCollection: bidderCardCollection,
227 sellerFungibleReceiver: sellerFungibleReceiver,
228 sellerCardCollection: sellerCardCollection,
229 sellerStakedCardCollection: sellerStakedCardCollection,
230 sellerMarketCollection: sellerMarketCollection
231 )
232 destroy bid
233 }
234
235 pub fun decline(bidID: UInt64) {
236 let bid <- self.remove(bidID: bidID)
237 emit StarlyCardBidDeclined(bidID: bidID, nftID: bid.nftID, starlyID: bid.starlyID)
238 destroy bid
239 }
240
241 pub fun cancel(bidID: UInt64) {
242 let bid <- self.remove(bidID: bidID)
243 emit StarlyCardBidCancelled(bidID: bidID, nftID: bid.nftID, starlyID: bid.starlyID)
244 destroy bid
245 }
246
247 destroy () {
248 destroy self.bids
249 }
250
251 init () {
252 self.bids <- {}
253 }
254 }
255
256 pub fun createBid(
257 nftID: UInt64,
258 starlyID: String,
259 bidPrice: UFix64,
260 bidVaultType: Type,
261 bidderAddress: Address,
262 bidderFungibleReceiver: Capability<&{FungibleToken.Receiver}>,
263 bidderFungibleProvider: &AnyResource{FungibleToken.Provider}
264 ): @Bid {
265 return <- create Bid(
266 nftID: nftID,
267 starlyID: starlyID,
268 bidPrice: bidPrice,
269 bidVaultType: bidVaultType,
270 bidderAddress: bidderAddress,
271 bidderFungibleReceiver: bidderFungibleReceiver,
272 bidderFungibleProvider: bidderFungibleProvider
273 )
274 }
275
276 pub fun createEmptyCollection(): @Collection {
277 return <- create Collection()
278 }
279
280 init() {
281 self.totalCount = 0
282 self.CollectionStoragePath = /storage/starlyCardBidCollection
283 self.CollectionPublicPath = /public/starlyCardBidCollection
284 }
285}