Smart Contract

StarlyCardBid

A.5b82f21c0edf76e3.StarlyCardBid

Deployed

16h ago
Feb 28, 2026, 02:30:51 AM UTC

Dependents

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