@flowtyio/flow-contracts 0.0.11 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ import "NonFungibleToken"
2
+
3
+ pub contract TopShotLocking {
4
+
5
+ // -----------------------------------------------------------------------
6
+ // TopShotLocking contract Events
7
+ // -----------------------------------------------------------------------
8
+
9
+ // Emitted when a Moment is locked
10
+ pub event MomentLocked(id: UInt64, duration: UFix64, expiryTimestamp: UFix64)
11
+
12
+ // Emitted when a Moment is unlocked
13
+ pub event MomentUnlocked(id: UInt64)
14
+
15
+ // Dictionary of locked NFTs
16
+ // TopShot nft resource id is the key
17
+ // locked until timestamp is the value
18
+ access(self) var lockedNFTs: {UInt64: UFix64}
19
+
20
+ // Dictionary of NFTs overridden to be unlocked
21
+ access(self) var unlockableNFTs: {UInt64: Bool} // nft resource id is the key
22
+
23
+ // isLocked Returns a boolean indicating if an nft exists in the lockedNFTs dictionary
24
+ //
25
+ // Parameters: nftRef: A reference to the NFT resource
26
+ //
27
+ // Returns: true if NFT is locked
28
+ pub fun isLocked(nftRef: &NonFungibleToken.NFT): Bool {
29
+ return self.lockedNFTs.containsKey(nftRef.id)
30
+ }
31
+
32
+ // getLockExpiry Returns the unix timestamp when an nft is unlockable
33
+ //
34
+ // Parameters: nftRef: A reference to the NFT resource
35
+ //
36
+ // Returns: unix timestamp
37
+ pub fun getLockExpiry(nftRef: &NonFungibleToken.NFT): UFix64 {
38
+ if !self.lockedNFTs.containsKey(nftRef.id) {
39
+ panic("NFT is not locked")
40
+ }
41
+ return self.lockedNFTs[nftRef.id]!
42
+ }
43
+
44
+ // lockNFT Takes an NFT resource and adds its unique identifier to the lockedNFTs dictionary
45
+ //
46
+ // Parameters: nft: NFT resource
47
+ // duration: number of seconds the NFT will be locked for
48
+ //
49
+ // Returns: the NFT resource
50
+ pub fun lockNFT(nft: @NonFungibleToken.NFT, duration: UFix64): @NonFungibleToken.NFT {
51
+ let TopShotNFTType: Type = CompositeType("A.TOPSHOTADDRESS.TopShot.NFT")!
52
+ if !nft.isInstance(TopShotNFTType) {
53
+ panic("NFT is not a TopShot NFT")
54
+ }
55
+
56
+ if self.lockedNFTs.containsKey(nft.id) {
57
+ // already locked - short circuit and return the nft
58
+ return <- nft
59
+ }
60
+
61
+ let expiryTimestamp = getCurrentBlock().timestamp + duration
62
+
63
+ self.lockedNFTs[nft.id] = expiryTimestamp
64
+
65
+ emit MomentLocked(id: nft.id, duration: duration, expiryTimestamp: expiryTimestamp)
66
+
67
+ return <- nft
68
+ }
69
+
70
+ // unlockNFT Takes an NFT resource and removes it from the lockedNFTs dictionary
71
+ //
72
+ // Parameters: nft: NFT resource
73
+ //
74
+ // Returns: the NFT resource
75
+ //
76
+ // NFT must be eligible for unlocking by an admin
77
+ pub fun unlockNFT(nft: @NonFungibleToken.NFT): @NonFungibleToken.NFT {
78
+ if !self.lockedNFTs.containsKey(nft.id) {
79
+ // nft is not locked, short circuit and return the nft
80
+ return <- nft
81
+ }
82
+
83
+ let lockExpiryTimestamp: UFix64 = self.lockedNFTs[nft.id]!
84
+ let isPastExpiry: Bool = getCurrentBlock().timestamp >= lockExpiryTimestamp
85
+
86
+ let isUnlockableOverridden: Bool = self.unlockableNFTs.containsKey(nft.id)
87
+
88
+ if !(isPastExpiry || isUnlockableOverridden) {
89
+ panic("NFT is not eligible to be unlocked, expires at ".concat(lockExpiryTimestamp.toString()))
90
+ }
91
+
92
+ self.unlockableNFTs.remove(key: nft.id)
93
+ self.lockedNFTs.remove(key: nft.id)
94
+
95
+ emit MomentUnlocked(id: nft.id)
96
+
97
+ return <- nft
98
+ }
99
+
100
+ // getIDs Returns the ids of all locked Top Shot NFT tokens
101
+ //
102
+ // Returns: array of ids
103
+ //
104
+ pub fun getIDs(): [UInt64] {
105
+ return self.lockedNFTs.keys
106
+ }
107
+
108
+ // getExpiry Returns the timestamp when a locked token is eligible for unlock
109
+ //
110
+ // Parameters: tokenID: the nft id of the locked token
111
+ //
112
+ // Returns: a unix timestamp in seconds
113
+ //
114
+ pub fun getExpiry(tokenID: UInt64): UFix64? {
115
+ return self.lockedNFTs[tokenID]
116
+ }
117
+
118
+ // getLockedNFTsLength Returns the count of locked tokens
119
+ //
120
+ // Returns: an integer containing the number of locked tokens
121
+ //
122
+ pub fun getLockedNFTsLength(): Int {
123
+ return self.lockedNFTs.length
124
+ }
125
+
126
+ // Admin is a special authorization resource that
127
+ // allows the owner to override the lock on a moment
128
+ //
129
+ pub resource Admin {
130
+ // createNewAdmin creates a new Admin resource
131
+ //
132
+ pub fun createNewAdmin(): @Admin {
133
+ return <-create Admin()
134
+ }
135
+
136
+ // markNFTUnlockable marks a given nft as being
137
+ // unlockable, overridding the expiry timestamp
138
+ // the nft owner will still need to send an unlock transaction to unlock
139
+ //
140
+ pub fun markNFTUnlockable(nftRef: &NonFungibleToken.NFT) {
141
+ TopShotLocking.unlockableNFTs[nftRef.id] = true
142
+ }
143
+
144
+ // unlocks all NFTs
145
+ pub fun unlockAll() {
146
+ TopShotLocking.lockedNFTs = {}
147
+ TopShotLocking.unlockableNFTs = {}
148
+ }
149
+ }
150
+
151
+ // -----------------------------------------------------------------------
152
+ // TopShotLocking initialization function
153
+ // -----------------------------------------------------------------------
154
+ //
155
+ init() {
156
+ self.lockedNFTs = {}
157
+ self.unlockableNFTs = {}
158
+
159
+ // Create a single admin resource
160
+ let admin <- create Admin()
161
+
162
+ // Store it in private account storage in `init` so only the admin can use it
163
+ self.account.save(<-admin, to: /storage/TopShotLockingAdmin)
164
+ }
165
+ }
@@ -0,0 +1,238 @@
1
+ import "OffersV2"
2
+ import "FungibleToken"
3
+ import "NonFungibleToken"
4
+ import "Resolver"
5
+
6
+ // DapperOffersV2
7
+ //
8
+ // Each account that wants to create offers for NFTs installs an DapperOffer
9
+ // resource and creates individual Offers for NFTs within it.
10
+ //
11
+ // The DapperOffer resource contains the methods to add, remove, borrow and
12
+ // get details on Offers contained within it.
13
+ //
14
+ pub contract DapperOffersV2 {
15
+ // DapperOffersV2
16
+ // This contract has been deployed.
17
+ // Event consumers can now expect events from this contract.
18
+ //
19
+ pub event DapperOffersInitialized()
20
+
21
+ /// DapperOfferInitialized
22
+ // A DapperOffer resource has been created.
23
+ //
24
+ pub event DapperOfferInitialized(DapperOfferResourceId: UInt64)
25
+
26
+ // DapperOfferDestroyed
27
+ // A DapperOffer resource has been destroyed.
28
+ // Event consumers can now stop processing events from this resource.
29
+ //
30
+ pub event DapperOfferDestroyed(DapperOfferResourceId: UInt64)
31
+
32
+
33
+ // DapperOfferPublic
34
+ // An interface providing a useful public interface to a Offer.
35
+ //
36
+ pub resource interface DapperOfferPublic {
37
+ // getOfferIds
38
+ // Get a list of Offer ids created by the resource.
39
+ //
40
+ pub fun getOfferIds(): [UInt64]
41
+ // borrowOffer
42
+ // Borrow an Offer to either accept the Offer or get details on the Offer.
43
+ //
44
+ pub fun borrowOffer(offerId: UInt64): &OffersV2.Offer{OffersV2.OfferPublic}?
45
+ // cleanup
46
+ // Remove an Offer
47
+ //
48
+ pub fun cleanup(offerId: UInt64)
49
+ // addProxyCapability
50
+ // Assign proxy capabilities (DapperOfferProxyManager) to an DapperOffer resource.
51
+ //
52
+ pub fun addProxyCapability(
53
+ account: Address,
54
+ cap: Capability<&DapperOffer{DapperOffersV2.DapperOfferProxyManager}>
55
+ )
56
+ }
57
+
58
+ // DapperOfferManager
59
+ // An interface providing a management interface for an DapperOffer resource.
60
+ //
61
+ pub resource interface DapperOfferManager {
62
+ // createOffer
63
+ // Allows the DapperOffer owner to create Offers.
64
+ //
65
+ pub fun createOffer(
66
+ vaultRefCapability: Capability<&{FungibleToken.Provider, FungibleToken.Balance}>,
67
+ nftReceiverCapability: Capability<&{NonFungibleToken.CollectionPublic}>,
68
+ nftType: Type,
69
+ amount: UFix64,
70
+ royalties: [OffersV2.Royalty],
71
+ offerParamsString: {String:String},
72
+ offerParamsUFix64: {String:UFix64},
73
+ offerParamsUInt64: {String:UInt64},
74
+ resolverCapability: Capability<&{Resolver.ResolverPublic}>,
75
+ ): UInt64
76
+ // removeOffer
77
+ // Allows the DapperOffer owner to remove offers
78
+ //
79
+ pub fun removeOffer(offerId: UInt64)
80
+ }
81
+
82
+ // DapperOfferProxyManager
83
+ // An interface providing removeOffer on behalf of an DapperOffer owner.
84
+ //
85
+ pub resource interface DapperOfferProxyManager {
86
+ // removeOffer
87
+ // Allows the DapperOffer owner to remove offers
88
+ //
89
+ pub fun removeOffer(offerId: UInt64)
90
+ // removeOfferFromProxy
91
+ // Allows the DapperOffer proxy owner to remove offers
92
+ //
93
+ pub fun removeOfferFromProxy(account: Address, offerId: UInt64)
94
+ }
95
+
96
+
97
+ // DapperOffer
98
+ // A resource that allows its owner to manage a list of Offers, and anyone to interact with them
99
+ // in order to query their details and accept the Offers for NFTs that they represent.
100
+ //
101
+ pub resource DapperOffer : DapperOfferManager, DapperOfferPublic, DapperOfferProxyManager {
102
+ // The dictionary of Address to DapperOfferProxyManager capabilities.
103
+ access(self) var removeOfferCapability: {Address:Capability<&DapperOffer{DapperOffersV2.DapperOfferProxyManager}>}
104
+ // The dictionary of Offer uuids to Offer resources.
105
+ access(self) var offers: @{UInt64:OffersV2.Offer}
106
+
107
+ // addProxyCapability
108
+ // Assign proxy capabilities (DapperOfferProxyManager) to an DapperOffer resource.
109
+ //
110
+ pub fun addProxyCapability(account: Address, cap: Capability<&DapperOffer{DapperOffersV2.DapperOfferProxyManager}>) {
111
+ pre {
112
+ cap.borrow() != nil: "Invalid admin capability"
113
+ }
114
+ self.removeOfferCapability[account] = cap
115
+ }
116
+
117
+ // removeOfferFromProxy
118
+ // Allows the DapperOffer proxy owner to remove offers
119
+ //
120
+ pub fun removeOfferFromProxy(account: Address, offerId: UInt64) {
121
+ pre {
122
+ self.removeOfferCapability[account] != nil:
123
+ "Cannot remove offers until the token admin has deposited the account registration capability"
124
+ }
125
+
126
+ let adminRef = self.removeOfferCapability[account]!.borrow()!
127
+
128
+ adminRef.removeOffer(offerId: offerId)
129
+ }
130
+
131
+
132
+ // createOffer
133
+ // Allows the DapperOffer owner to create Offers.
134
+ //
135
+ pub fun createOffer(
136
+ vaultRefCapability: Capability<&{FungibleToken.Provider, FungibleToken.Balance}>,
137
+ nftReceiverCapability: Capability<&{NonFungibleToken.CollectionPublic}>,
138
+ nftType: Type,
139
+ amount: UFix64,
140
+ royalties: [OffersV2.Royalty],
141
+ offerParamsString: {String:String},
142
+ offerParamsUFix64: {String:UFix64},
143
+ offerParamsUInt64: {String:UInt64},
144
+ resolverCapability: Capability<&{Resolver.ResolverPublic}>,
145
+ ): UInt64 {
146
+ let offer <- OffersV2.makeOffer(
147
+ vaultRefCapability: vaultRefCapability,
148
+ nftReceiverCapability: nftReceiverCapability,
149
+ nftType: nftType,
150
+ amount: amount,
151
+ royalties: royalties,
152
+ offerParamsString: offerParamsString,
153
+ offerParamsUFix64: offerParamsUFix64,
154
+ offerParamsUInt64: offerParamsUInt64,
155
+ resolverCapability: resolverCapability,
156
+ )
157
+
158
+ let offerId = offer.uuid
159
+ let dummy <- self.offers[offerId] <- offer
160
+ destroy dummy
161
+
162
+ return offerId
163
+ }
164
+
165
+ // removeOffer
166
+ // Remove an Offer that has not yet been accepted from the collection and destroy it.
167
+ //
168
+ pub fun removeOffer(offerId: UInt64) {
169
+ destroy self.offers.remove(key: offerId) ?? panic("missing offer")
170
+ }
171
+
172
+ // getOfferIds
173
+ // Returns an array of the Offer resource IDs that are in the collection
174
+ //
175
+ pub fun getOfferIds(): [UInt64] {
176
+ return self.offers.keys
177
+ }
178
+
179
+ // borrowOffer
180
+ // Returns a read-only view of the Offer for the given OfferID if it is contained by this collection.
181
+ //
182
+ pub fun borrowOffer(offerId: UInt64): &OffersV2.Offer{OffersV2.OfferPublic}? {
183
+ if self.offers[offerId] != nil {
184
+ return (&self.offers[offerId] as &OffersV2.Offer{OffersV2.OfferPublic}?)!
185
+ } else {
186
+ return nil
187
+ }
188
+ }
189
+
190
+ // cleanup
191
+ // Remove an Offer *if* it has been accepted.
192
+ // Anyone can call, but at present it only benefits the account owner to do so.
193
+ // Kind purchasers can however call it if they like.
194
+ //
195
+ pub fun cleanup(offerId: UInt64) {
196
+ pre {
197
+ self.offers[offerId] != nil: "could not find Offer with given id"
198
+ }
199
+ let offer <- self.offers.remove(key: offerId)!
200
+ assert(offer.getDetails().purchased == true, message: "Offer is not purchased, only admin can remove")
201
+ destroy offer
202
+ }
203
+
204
+ // constructor
205
+ //
206
+ init() {
207
+ self.removeOfferCapability = {}
208
+ self.offers <- {}
209
+ // Let event consumers know that this storefront will no longer exist.
210
+ emit DapperOfferInitialized(DapperOfferResourceId: self.uuid)
211
+ }
212
+
213
+ // destructor
214
+ //
215
+ destroy() {
216
+ destroy self.offers
217
+ // Let event consumers know that this storefront exists.
218
+ emit DapperOfferDestroyed(DapperOfferResourceId: self.uuid)
219
+ }
220
+ }
221
+
222
+ // createDapperOffer
223
+ // Make creating an DapperOffer publicly accessible.
224
+ //
225
+ pub fun createDapperOffer(): @DapperOffer {
226
+ return <-create DapperOffer()
227
+ }
228
+
229
+ pub let DapperOffersStoragePath: StoragePath
230
+ pub let DapperOffersPublicPath: PublicPath
231
+
232
+ init () {
233
+ self.DapperOffersStoragePath = /storage/DapperOffersV2
234
+ self.DapperOffersPublicPath = /public/DapperOffersV2
235
+
236
+ emit DapperOffersInitialized()
237
+ }
238
+ }