@flowtyio/flow-contracts 0.1.0-beta.1 → 0.1.0-beta.3
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.
- package/contracts/example/ExampleNFT.cdc +422 -0
- package/contracts/example/ExampleToken.cdc +235 -0
- package/contracts/lost-and-found/FeeEstimator.cdc +14 -22
- package/contracts/lost-and-found/LostAndFound.cdc +185 -177
- package/contracts/lost-and-found/LostAndFoundHelper.cdc +12 -12
- package/flow.json +17 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import "FlowStorageFees"
|
|
|
3
3
|
import "FlowToken"
|
|
4
4
|
import "NonFungibleToken"
|
|
5
5
|
import "MetadataViews"
|
|
6
|
+
|
|
6
7
|
import "FeeEstimator"
|
|
7
8
|
|
|
8
9
|
// LostAndFound
|
|
@@ -26,49 +27,44 @@ import "FeeEstimator"
|
|
|
26
27
|
// - NonFunigibleToken.Receiver
|
|
27
28
|
// - FungibleToken.Receiver
|
|
28
29
|
// - LostAndFound.ResourceReceiver (This is a placeholder so that non NFT and FT resources can be utilized here)
|
|
29
|
-
|
|
30
|
+
access(all) contract LostAndFound {
|
|
30
31
|
access(contract) let storageFees: {UInt64: UFix64}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
access(all) let LostAndFoundPublicPath: PublicPath
|
|
34
|
+
access(all) let LostAndFoundStoragePath: StoragePath
|
|
35
|
+
access(all) let DepositorPublicPath: PublicPath
|
|
36
|
+
access(all) let DepositorStoragePath: StoragePath
|
|
37
|
+
|
|
38
|
+
access(all) event TicketDeposited(redeemer: Address, ticketID: UInt64, type: Type, memo: String?, name: String?, description: String?, thumbnail: String?)
|
|
39
|
+
access(all) event TicketRedeemed(redeemer: Address, ticketID: UInt64, type: Type)
|
|
40
|
+
access(all) event BinDestroyed(redeemer: Address, type: Type)
|
|
41
|
+
access(all) event ShelfDestroyed(redeemer: Address)
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
access(all) event DepositorCreated(uuid: UInt64)
|
|
44
|
+
access(all) event DepositorBalanceLow(uuid: UInt64, threshold: UFix64, balance: UFix64)
|
|
45
|
+
access(all) event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64)
|
|
46
|
+
access(all) event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64)
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
pub event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64)
|
|
45
|
-
pub event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64)
|
|
48
|
+
access(all) entitlement Deposit
|
|
49
|
+
access(all) entitlement Withdraw
|
|
46
50
|
|
|
47
51
|
// Placeholder receiver so that any resource can be supported, not just FT and NFT Receivers
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
access(all) resource interface AnyResourceReceiver {
|
|
53
|
+
access(Deposit) fun deposit(item: @AnyResource)
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
access(all) resource DepositEstimate {
|
|
57
|
+
access(Withdraw) var item: @AnyResource?
|
|
58
|
+
access(all) let storageFee: UFix64
|
|
55
59
|
|
|
56
60
|
init(item: @AnyResource, storageFee: UFix64) {
|
|
57
61
|
self.item <- item
|
|
58
62
|
self.storageFee = storageFee
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
return <-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
destroy() {
|
|
67
|
-
pre {
|
|
68
|
-
self.item == nil: "cannot destroy with non-null item"
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
destroy self.item
|
|
65
|
+
access(Withdraw) fun withdraw(): @AnyResource {
|
|
66
|
+
let item <- self.item <- nil
|
|
67
|
+
return <-item!
|
|
72
68
|
}
|
|
73
69
|
}
|
|
74
70
|
|
|
@@ -77,24 +73,30 @@ pub contract LostAndFound {
|
|
|
77
73
|
// - memo: An optional message to attach to this ticket
|
|
78
74
|
// - redeemer: The address which is allowed to withdraw the item from this ticket
|
|
79
75
|
// - redeemed: Whether the ticket has been redeemed. This can only be set by the LostAndFound contract
|
|
80
|
-
|
|
76
|
+
access(all) resource Ticket {
|
|
81
77
|
// The item to be redeemed
|
|
82
78
|
access(contract) var item: @AnyResource?
|
|
83
79
|
// An optional message to attach to this item.
|
|
84
|
-
|
|
80
|
+
access(all) let memo: String?
|
|
85
81
|
// an optional Display view so that frontend's that borrow this ticket know how to show it
|
|
86
|
-
|
|
82
|
+
access(all) let display: MetadataViews.Display?
|
|
87
83
|
// The address that it allowed to withdraw the item fromt this ticket
|
|
88
|
-
|
|
84
|
+
access(all) let redeemer: Address
|
|
89
85
|
//The type of the resource (non-optional) so that bins can represent the true type of an item
|
|
90
|
-
|
|
86
|
+
access(all) let type: Type
|
|
91
87
|
// State maintained by LostAndFound
|
|
92
|
-
|
|
88
|
+
access(all) var redeemed: Bool
|
|
93
89
|
|
|
94
90
|
// flow token amount used to store this ticket is returned when the ticket is redeemed
|
|
95
|
-
access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault
|
|
91
|
+
access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault>?
|
|
96
92
|
|
|
97
|
-
init (
|
|
93
|
+
init (
|
|
94
|
+
item: @AnyResource,
|
|
95
|
+
memo: String?,
|
|
96
|
+
display: MetadataViews.Display?,
|
|
97
|
+
redeemer: Address,
|
|
98
|
+
flowTokenRepayment: Capability<&FlowToken.Vault>?
|
|
99
|
+
) {
|
|
98
100
|
self.type = item.getType()
|
|
99
101
|
self.item <- item
|
|
100
102
|
self.memo = memo
|
|
@@ -105,40 +107,40 @@ pub contract LostAndFound {
|
|
|
105
107
|
self.flowTokenRepayment = flowTokenRepayment
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
access(all) view fun itemType(): Type {
|
|
109
111
|
return self.type
|
|
110
112
|
}
|
|
111
113
|
|
|
112
|
-
|
|
114
|
+
access(all) fun checkItem(): Bool {
|
|
113
115
|
return self.item != nil
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
// A function to get depositor address / flow Repayment address
|
|
117
|
-
|
|
119
|
+
access(all) fun getFlowRepaymentAddress() : Address? {
|
|
118
120
|
return self.flowTokenRepayment?.address
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
// If this is an instance of NFT, return the id , otherwise return nil
|
|
122
|
-
|
|
123
|
-
if self.type.isSubtype(of: Type<@NonFungibleToken.NFT>()) {
|
|
124
|
-
let ref = (&self.item as
|
|
125
|
-
let nft = ref as! &NonFungibleToken.NFT
|
|
126
|
-
return nft.
|
|
124
|
+
access(all) fun getNonFungibleTokenID() : UInt64? {
|
|
125
|
+
if self.type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) {
|
|
126
|
+
let ref = (&self.item as &AnyResource?)!
|
|
127
|
+
let nft = ref as! &{NonFungibleToken.NFT}
|
|
128
|
+
return nft.getID()
|
|
127
129
|
}
|
|
128
130
|
return nil
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
// If this is an instance of FT, return the vault balance , otherwise return nil
|
|
132
|
-
|
|
133
|
-
if self.type.isSubtype(of: Type<@FungibleToken.Vault>()) {
|
|
134
|
-
let ref = (&self.item as
|
|
135
|
-
let ft = ref as! &FungibleToken.Vault
|
|
136
|
-
return ft.
|
|
134
|
+
access(all) fun getFungibleTokenBalance() : UFix64? {
|
|
135
|
+
if self.type.isSubtype(of: Type<@{FungibleToken.Vault}>()) {
|
|
136
|
+
let ref = (&self.item as &AnyResource?)!
|
|
137
|
+
let ft = ref as! &{FungibleToken.Vault}
|
|
138
|
+
return ft.getBalance()
|
|
137
139
|
}
|
|
138
140
|
return nil
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
access(Withdraw) fun withdraw(receiver: Capability) {
|
|
142
144
|
pre {
|
|
143
145
|
receiver.address == self.redeemer: "receiver address and redeemer must match"
|
|
144
146
|
!self.redeemed: "already redeemed"
|
|
@@ -147,25 +149,25 @@ pub contract LostAndFound {
|
|
|
147
149
|
var redeemableItem <- self.item <- nil
|
|
148
150
|
let cap = receiver.borrow<&AnyResource>()!
|
|
149
151
|
|
|
150
|
-
if cap.isInstance(Type<@NonFungibleToken.Collection>()) {
|
|
151
|
-
let target = receiver.borrow<&
|
|
152
|
-
let token <- redeemableItem as! @NonFungibleToken.NFT?
|
|
152
|
+
if cap.isInstance(Type<@{NonFungibleToken.Collection}>()) {
|
|
153
|
+
let target = receiver.borrow<&{NonFungibleToken.Collection}>()!
|
|
154
|
+
let token <- redeemableItem as! @{NonFungibleToken.NFT}?
|
|
153
155
|
self.redeemed = true
|
|
154
156
|
emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType())
|
|
155
157
|
target.deposit(token: <- token!)
|
|
156
158
|
return
|
|
157
|
-
} else if cap.isInstance(Type<@FungibleToken.Vault>()) {
|
|
158
|
-
let target = receiver.borrow<&
|
|
159
|
-
let token <- redeemableItem as! @FungibleToken.Vault?
|
|
159
|
+
} else if cap.isInstance(Type<@{FungibleToken.Vault}>()) {
|
|
160
|
+
let target = receiver.borrow<&{FungibleToken.Receiver}>()!
|
|
161
|
+
let token <- redeemableItem as! @{FungibleToken.Vault}?
|
|
160
162
|
self.redeemed = true
|
|
161
163
|
emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType())
|
|
162
164
|
target.deposit(from: <- token!)
|
|
163
165
|
return
|
|
164
|
-
} else if cap.isInstance(Type<@
|
|
165
|
-
let target = receiver.borrow
|
|
166
|
+
} else if cap.isInstance(Type<@{LostAndFound.AnyResourceReceiver}>()) {
|
|
167
|
+
let target = receiver.borrow<auth(Deposit) &{LostAndFound.AnyResourceReceiver}>()!
|
|
166
168
|
self.redeemed = true
|
|
167
169
|
emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: redeemableItem.getType())
|
|
168
|
-
target.deposit(
|
|
170
|
+
target.deposit(item: <- redeemableItem)
|
|
169
171
|
return
|
|
170
172
|
} else{
|
|
171
173
|
panic("cannot redeem resource to receiver")
|
|
@@ -180,15 +182,13 @@ pub contract LostAndFound {
|
|
|
180
182
|
return <-redeemableItem!
|
|
181
183
|
}
|
|
182
184
|
|
|
183
|
-
|
|
184
|
-
destroy () {
|
|
185
|
+
access(contract) fun safeDestroy() {
|
|
185
186
|
pre {
|
|
186
187
|
self.redeemed: "Ticket has not been redeemed"
|
|
187
188
|
self.item == nil: "can only destroy if not holding any item"
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
LostAndFound.storageFees.remove(key: self.uuid)
|
|
191
|
-
destroy <-self.item
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -196,11 +196,11 @@ pub contract LostAndFound {
|
|
|
196
196
|
// A Bin is a resource that gathers tickets whos item have the same type.
|
|
197
197
|
// For instance, if two TopShot Moments are deposited to the same redeemer, only one bin
|
|
198
198
|
// will be made which will contain both tickets to redeem each individual moment.
|
|
199
|
-
|
|
199
|
+
access(all) resource Bin {
|
|
200
200
|
access(contract) let tickets: @{UInt64:Ticket}
|
|
201
201
|
access(contract) let type: Type
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
access(all) let flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?
|
|
204
204
|
|
|
205
205
|
init (type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) {
|
|
206
206
|
self.tickets <- {}
|
|
@@ -208,11 +208,11 @@ pub contract LostAndFound {
|
|
|
208
208
|
self.flowTokenRepayment = flowTokenRepayment
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
return &self.tickets[id]
|
|
211
|
+
access(all) fun borrowTicket(id: UInt64): &LostAndFound.Ticket? {
|
|
212
|
+
return &self.tickets[id]
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
access(all) fun borrowAllTicketsByType(): [&LostAndFound.Ticket] {
|
|
216
216
|
let tickets: [&LostAndFound.Ticket] = []
|
|
217
217
|
let ids = self.tickets.keys
|
|
218
218
|
for id in ids {
|
|
@@ -243,7 +243,7 @@ pub contract LostAndFound {
|
|
|
243
243
|
emit TicketDeposited(redeemer: redeemer, ticketID: ticketID, type: self.type, memo: memo, name: name, description: description, thumbnail: thumbnail)
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
access(all) fun getTicketIDs(): [UInt64] {
|
|
247
247
|
return self.tickets.keys
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -252,16 +252,17 @@ pub contract LostAndFound {
|
|
|
252
252
|
return <- ticket!
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
access(contract) fun safeDestroy() {
|
|
256
|
+
pre {
|
|
257
|
+
self.tickets.length == 0: "cannot destroy bin with tickets in it"
|
|
258
|
+
}
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
// A shelf is our top-level organization resource.
|
|
262
263
|
// It groups bins by type to help make discovery of the assets that a
|
|
263
264
|
// redeeming address can claim.
|
|
264
|
-
|
|
265
|
+
access(all) resource Shelf {
|
|
265
266
|
access(self) let bins: @{String: Bin}
|
|
266
267
|
access(self) let identifierToType: {String: Type}
|
|
267
268
|
access(self) let redeemer: Address
|
|
@@ -274,11 +275,11 @@ pub contract LostAndFound {
|
|
|
274
275
|
self.flowTokenRepayment = flowTokenRepayment
|
|
275
276
|
}
|
|
276
277
|
|
|
277
|
-
|
|
278
|
+
access(all) fun getOwner(): Address {
|
|
278
279
|
return self.owner!.address
|
|
279
280
|
}
|
|
280
281
|
|
|
281
|
-
|
|
282
|
+
access(all) fun getRedeemableTypes(): [Type] {
|
|
282
283
|
let types: [Type] = []
|
|
283
284
|
for k in self.bins.keys {
|
|
284
285
|
let t = self.identifierToType[k]!
|
|
@@ -289,26 +290,26 @@ pub contract LostAndFound {
|
|
|
289
290
|
return types
|
|
290
291
|
}
|
|
291
292
|
|
|
292
|
-
|
|
293
|
+
access(all) fun hasType(type: Type): Bool {
|
|
293
294
|
return self.bins[type.identifier] != nil
|
|
294
295
|
}
|
|
295
296
|
|
|
296
|
-
|
|
297
|
-
return &self.bins[type.identifier]
|
|
297
|
+
access(all) fun borrowBin(type: Type): &LostAndFound.Bin? {
|
|
298
|
+
return &self.bins[type.identifier]
|
|
298
299
|
}
|
|
299
300
|
|
|
300
301
|
access(contract) fun ensureBin(type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?): &Bin {
|
|
301
302
|
if !self.bins.containsKey(type.identifier) {
|
|
302
|
-
let storageBefore = LostAndFound.account.
|
|
303
|
+
let storageBefore = LostAndFound.account.storage.used
|
|
303
304
|
let bin <- create Bin(type: type, flowTokenRepayment: flowTokenRepayment)
|
|
304
305
|
let uuid = bin.uuid
|
|
305
306
|
let oldValue <- self.bins.insert(key: type.identifier, <-bin)
|
|
306
|
-
LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.
|
|
307
|
+
LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore)
|
|
307
308
|
self.identifierToType[type.identifier] = type
|
|
308
309
|
destroy oldValue
|
|
309
310
|
}
|
|
310
311
|
|
|
311
|
-
return (&self.bins[type.identifier]
|
|
312
|
+
return (&self.bins[type.identifier])!
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
access(contract) fun deposit(ticket: @LostAndFound.Ticket, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) {
|
|
@@ -324,7 +325,7 @@ pub contract LostAndFound {
|
|
|
324
325
|
// Only one of the three receiver options can be specified, and an optional maximum number of tickets
|
|
325
326
|
// to redeem can be picked to prevent gas issues in case there are large numbers of tickets to be
|
|
326
327
|
// redeemed at once.
|
|
327
|
-
|
|
328
|
+
access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) {
|
|
328
329
|
pre {
|
|
329
330
|
receiver.address == self.redeemer: "receiver must match the redeemer of this shelf"
|
|
330
331
|
self.bins.containsKey(type.identifier): "no bin for provided type"
|
|
@@ -343,7 +344,7 @@ pub contract LostAndFound {
|
|
|
343
344
|
}
|
|
344
345
|
|
|
345
346
|
// Redeem a specific ticket instead of all of a certain type.
|
|
346
|
-
|
|
347
|
+
access(Withdraw) fun redeem(type: Type, ticketID: UInt64, receiver: Capability) {
|
|
347
348
|
pre {
|
|
348
349
|
receiver.address == self.redeemer: "receiver must match the redeemer of this shelf"
|
|
349
350
|
self.bins.containsKey(type.identifier): "no bin for provided type"
|
|
@@ -360,6 +361,8 @@ pub contract LostAndFound {
|
|
|
360
361
|
let repaymentVault <- refundProvider.withdraw(amount: LostAndFound.storageFees[uuid]!)
|
|
361
362
|
refundCap!.borrow()!.deposit(from: <-repaymentVault)
|
|
362
363
|
}
|
|
364
|
+
|
|
365
|
+
ticket.safeDestroy()
|
|
363
366
|
destroy ticket
|
|
364
367
|
|
|
365
368
|
if borrowedBin.getTicketIDs().length == 0 {
|
|
@@ -374,77 +377,81 @@ pub contract LostAndFound {
|
|
|
374
377
|
let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!)
|
|
375
378
|
flowTokenRepayment!.borrow()!.deposit(from: <-vault)
|
|
376
379
|
}
|
|
380
|
+
|
|
381
|
+
bin.safeDestroy()
|
|
377
382
|
destroy bin
|
|
378
383
|
}
|
|
379
384
|
}
|
|
380
385
|
|
|
381
|
-
|
|
382
|
-
|
|
386
|
+
access(contract) fun safeDestroy() {
|
|
387
|
+
pre {
|
|
388
|
+
self.bins.length == 0: "cannot destroy a shelf with bins in it"
|
|
389
|
+
}
|
|
383
390
|
LostAndFound.storageFees.remove(key: self.uuid)
|
|
384
391
|
}
|
|
385
392
|
}
|
|
386
393
|
|
|
387
|
-
access(contract) fun getFlowProvider(): &FlowToken.Vault
|
|
388
|
-
return self.account.borrow
|
|
394
|
+
access(contract) fun getFlowProvider(): auth(FungibleToken.Withdrawable) &FlowToken.Vault {
|
|
395
|
+
return self.account.storage.borrow<auth(FungibleToken.Withdrawable) &FlowToken.Vault>(from: /storage/flowTokenVault)!
|
|
389
396
|
}
|
|
390
397
|
|
|
391
398
|
// ShelfManager is a light-weight wrapper to get our shelves into storage.
|
|
392
|
-
|
|
399
|
+
access(all) resource ShelfManager {
|
|
393
400
|
access(self) let shelves: @{Address: Shelf}
|
|
394
401
|
|
|
395
402
|
init() {
|
|
396
403
|
self.shelves <- {}
|
|
397
404
|
}
|
|
398
405
|
|
|
399
|
-
access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault
|
|
406
|
+
access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault>?): &LostAndFound.Shelf {
|
|
400
407
|
if !self.shelves.containsKey(addr) {
|
|
401
|
-
let storageBefore = LostAndFound.account.
|
|
408
|
+
let storageBefore = LostAndFound.account.storage.used
|
|
402
409
|
let shelf <- create Shelf(redeemer: addr, flowTokenRepayment: flowTokenRepayment)
|
|
403
410
|
let uuid = shelf.uuid
|
|
404
411
|
let oldValue <- self.shelves.insert(key: addr, <-shelf)
|
|
405
412
|
|
|
406
|
-
LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.
|
|
413
|
+
LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore)
|
|
407
414
|
destroy oldValue
|
|
408
415
|
}
|
|
409
416
|
|
|
410
|
-
return (&self.shelves[addr]
|
|
417
|
+
return (&self.shelves[addr])!
|
|
411
418
|
}
|
|
412
419
|
|
|
413
|
-
|
|
420
|
+
access(all) fun deposit(
|
|
414
421
|
redeemer: Address,
|
|
415
422
|
item: @AnyResource,
|
|
416
423
|
memo: String?,
|
|
417
424
|
display: MetadataViews.Display?,
|
|
418
|
-
storagePayment: &FungibleToken.Vault,
|
|
419
|
-
flowTokenRepayment: Capability<&FlowToken.Vault
|
|
425
|
+
storagePayment: auth(FungibleToken.Withdrawable) &{FungibleToken.Vault},
|
|
426
|
+
flowTokenRepayment: Capability<&FlowToken.Vault>?
|
|
420
427
|
) : UInt64 {
|
|
421
428
|
pre {
|
|
422
429
|
flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid"
|
|
423
430
|
storagePayment.getType() == Type<@FlowToken.Vault>(): "storage payment must be in flow tokens"
|
|
424
431
|
}
|
|
425
432
|
let receiver = LostAndFound.account
|
|
426
|
-
.
|
|
433
|
+
.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)!
|
|
427
434
|
.borrow()!
|
|
428
435
|
|
|
429
436
|
|
|
430
|
-
let storageBeforeShelf = LostAndFound.account.
|
|
437
|
+
let storageBeforeShelf = LostAndFound.account.storage.used
|
|
431
438
|
let shelf = self.ensureShelf(redeemer, flowTokenRepayment: flowTokenRepayment)
|
|
432
|
-
if LostAndFound.account.
|
|
439
|
+
if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil {
|
|
433
440
|
receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[shelf.uuid]!))
|
|
434
441
|
}
|
|
435
442
|
|
|
436
|
-
let storageBeforeBin = LostAndFound.account.
|
|
443
|
+
let storageBeforeBin = LostAndFound.account.storage.used
|
|
437
444
|
let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: flowTokenRepayment)
|
|
438
|
-
if LostAndFound.account.
|
|
445
|
+
if LostAndFound.account.storage.used != storageBeforeBin {
|
|
439
446
|
receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[bin.uuid]!))
|
|
440
447
|
}
|
|
441
448
|
|
|
442
|
-
let storageBefore = LostAndFound.account.
|
|
449
|
+
let storageBefore = LostAndFound.account.storage.used
|
|
443
450
|
let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: flowTokenRepayment)
|
|
444
451
|
let uuid = ticket.uuid
|
|
445
452
|
let flowTokenRepayment = ticket.flowTokenRepayment
|
|
446
453
|
shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment)
|
|
447
|
-
let storageUsedAfter = LostAndFound.account.
|
|
454
|
+
let storageUsedAfter = LostAndFound.account.storage.used
|
|
448
455
|
let storageFee = FeeEstimator.storageUsedToFlowAmount(storageUsedAfter - storageBefore)
|
|
449
456
|
LostAndFound.storageFees[uuid] = storageFee
|
|
450
457
|
|
|
@@ -453,20 +460,20 @@ pub contract LostAndFound {
|
|
|
453
460
|
return uuid
|
|
454
461
|
}
|
|
455
462
|
|
|
456
|
-
|
|
457
|
-
return &self.shelves[redeemer]
|
|
463
|
+
access(all) fun borrowShelf(redeemer: Address): &LostAndFound.Shelf? {
|
|
464
|
+
return &self.shelves[redeemer]
|
|
458
465
|
}
|
|
459
466
|
|
|
460
467
|
// deleteShelf
|
|
461
468
|
//
|
|
462
469
|
// delete a shelf if it has no redeemable types
|
|
463
|
-
|
|
464
|
-
let storageBefore = LostAndFound.account.
|
|
470
|
+
access(all) fun deleteShelf(_ addr: Address) {
|
|
471
|
+
let storageBefore = LostAndFound.account.storage.used
|
|
465
472
|
assert(self.shelves.containsKey(addr), message: "shelf does not exist")
|
|
466
473
|
let tmp <- self.shelves[addr] <- nil
|
|
467
474
|
let shelf <-! tmp!
|
|
468
475
|
|
|
469
|
-
assert(shelf.getRedeemableTypes().length
|
|
476
|
+
assert(shelf.getRedeemableTypes().length == 0, message: "shelf still has redeemable types")
|
|
470
477
|
let flowTokenRepayment = shelf.flowTokenRepayment
|
|
471
478
|
let uuid = shelf.uuid
|
|
472
479
|
if flowTokenRepayment != nil && flowTokenRepayment!.check() && LostAndFound.storageFees[uuid] != nil {
|
|
@@ -474,23 +481,27 @@ pub contract LostAndFound {
|
|
|
474
481
|
let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!)
|
|
475
482
|
flowTokenRepayment!.borrow()!.deposit(from: <-vault)
|
|
476
483
|
}
|
|
484
|
+
|
|
485
|
+
shelf.safeDestroy()
|
|
477
486
|
destroy shelf
|
|
478
487
|
emit ShelfDestroyed(redeemer: addr)
|
|
479
488
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
489
|
+
|
|
490
|
+
access(contract) fun safeDestroy() {
|
|
491
|
+
pre {
|
|
492
|
+
self.shelves.length == 0: "cannot destroy shelf manager when it has shelves"
|
|
493
|
+
}
|
|
483
494
|
}
|
|
484
495
|
}
|
|
485
496
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
497
|
+
access(all) resource interface DepositorPublic {
|
|
498
|
+
access(all) fun balance(): UFix64
|
|
499
|
+
access(all) fun addFlowTokens(vault: @FlowToken.Vault)
|
|
489
500
|
}
|
|
490
501
|
|
|
491
|
-
|
|
502
|
+
access(all) resource Depositor: DepositorPublic {
|
|
492
503
|
access(self) let flowTokenVault: @FlowToken.Vault
|
|
493
|
-
|
|
504
|
+
access(all) let flowTokenRepayment: Capability<&FlowToken.Vault>
|
|
494
505
|
access(self) var lowBalanceThreshold: UFix64?
|
|
495
506
|
|
|
496
507
|
access(self) fun checkForLowBalance(): Bool {
|
|
@@ -502,45 +513,45 @@ pub contract LostAndFound {
|
|
|
502
513
|
return false
|
|
503
514
|
}
|
|
504
515
|
|
|
505
|
-
|
|
516
|
+
access(Mutate) fun setLowBalanceThreshold(threshold: UFix64?) {
|
|
506
517
|
self.lowBalanceThreshold = threshold
|
|
507
518
|
}
|
|
508
519
|
|
|
509
|
-
|
|
520
|
+
access(Mutate) fun getLowBalanceThreshold(): UFix64? {
|
|
510
521
|
return self.lowBalanceThreshold
|
|
511
522
|
}
|
|
512
523
|
|
|
513
|
-
|
|
524
|
+
access(Deposit) fun deposit(
|
|
514
525
|
redeemer: Address,
|
|
515
526
|
item: @AnyResource,
|
|
516
527
|
memo: String?,
|
|
517
528
|
display: MetadataViews.Display?
|
|
518
529
|
) : UInt64 {
|
|
519
530
|
let receiver = LostAndFound.account
|
|
520
|
-
.
|
|
531
|
+
.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)!
|
|
521
532
|
.borrow()!
|
|
522
533
|
|
|
523
|
-
let storageBeforeShelf = LostAndFound.account.
|
|
534
|
+
let storageBeforeShelf = LostAndFound.account.storage.used
|
|
524
535
|
let shelfManager = LostAndFound.borrowShelfManager()
|
|
525
536
|
let shelf = shelfManager.ensureShelf(redeemer, flowTokenRepayment: self.flowTokenRepayment)
|
|
526
|
-
if LostAndFound.account.
|
|
537
|
+
if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil {
|
|
527
538
|
receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[shelf.uuid]!))
|
|
528
539
|
}
|
|
529
540
|
|
|
530
|
-
let storageBeforeBin = LostAndFound.account.
|
|
541
|
+
let storageBeforeBin = LostAndFound.account.storage.used
|
|
531
542
|
let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: self.flowTokenRepayment)
|
|
532
|
-
if storageBeforeBin != LostAndFound.account.
|
|
543
|
+
if storageBeforeBin != LostAndFound.account.storage.used {
|
|
533
544
|
receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[bin.uuid]!))
|
|
534
545
|
}
|
|
535
546
|
|
|
536
|
-
let storageBefore = LostAndFound.account.
|
|
547
|
+
let storageBefore = LostAndFound.account.storage.used
|
|
537
548
|
let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: self.flowTokenRepayment)
|
|
538
549
|
|
|
539
550
|
let flowTokenRepayment = ticket.flowTokenRepayment
|
|
540
551
|
let uuid = ticket.uuid
|
|
541
|
-
shelf
|
|
552
|
+
shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment)
|
|
542
553
|
|
|
543
|
-
let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.
|
|
554
|
+
let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore)
|
|
544
555
|
LostAndFound.storageFees[uuid] = storageFee
|
|
545
556
|
|
|
546
557
|
let storagePaymentVault <- self.withdrawTokens(amount: storageFee)
|
|
@@ -549,69 +560,67 @@ pub contract LostAndFound {
|
|
|
549
560
|
return uuid
|
|
550
561
|
}
|
|
551
562
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
563
|
+
access(Deposit) fun trySendResource(
|
|
564
|
+
item: @AnyResource,
|
|
565
|
+
cap: Capability,
|
|
566
|
+
memo: String?,
|
|
567
|
+
display: MetadataViews.Display?
|
|
557
568
|
) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
cap.borrow<&{NonFungibleToken.CollectionPublic}>()!.deposit(token: <-nft)
|
|
562
|
-
} else if cap.check<&{NonFungibleToken.Receiver}>() {
|
|
563
|
-
let nft <- item as! @NonFungibleToken.NFT
|
|
564
|
-
cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft)
|
|
569
|
+
if cap.check<&{NonFungibleToken.Collection}>() {
|
|
570
|
+
let nft <- item as! @{NonFungibleToken.NFT}
|
|
571
|
+
cap.borrow<&{NonFungibleToken.Collection}>()!.deposit(token: <-nft)
|
|
565
572
|
} else if cap.check<&{FungibleToken.Receiver}>() {
|
|
566
|
-
let vault <- item as! @FungibleToken.Vault
|
|
573
|
+
let vault <- item as! @{FungibleToken.Vault}
|
|
567
574
|
cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault)
|
|
568
575
|
} else {
|
|
569
576
|
self.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display)
|
|
570
577
|
}
|
|
571
578
|
}
|
|
572
579
|
|
|
573
|
-
|
|
580
|
+
access(Mutate) fun withdrawTokens(amount: UFix64): @{FungibleToken.Vault} {
|
|
574
581
|
let tokens <-self.flowTokenVault.withdraw(amount: amount)
|
|
575
582
|
emit DepositorTokensWithdrawn(uuid: self.uuid, tokens: amount, balance: self.flowTokenVault.balance)
|
|
576
583
|
self.checkForLowBalance()
|
|
577
584
|
return <-tokens
|
|
578
585
|
}
|
|
579
586
|
|
|
580
|
-
|
|
587
|
+
access(all) fun addFlowTokens(vault: @FlowToken.Vault) {
|
|
581
588
|
let tokensAdded = vault.balance
|
|
582
589
|
self.flowTokenVault.deposit(from: <-vault)
|
|
583
590
|
emit DepositorTokensAdded(uuid: self.uuid, tokens: tokensAdded, balance: self.flowTokenVault.balance)
|
|
584
591
|
self.checkForLowBalance()
|
|
585
592
|
}
|
|
586
593
|
|
|
587
|
-
|
|
594
|
+
access(all) fun balance(): UFix64 {
|
|
588
595
|
return self.flowTokenVault.balance
|
|
589
596
|
}
|
|
590
597
|
|
|
591
|
-
init(_ flowTokenRepayment: Capability<&FlowToken.Vault
|
|
598
|
+
init(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?) {
|
|
592
599
|
self.flowTokenRepayment = flowTokenRepayment
|
|
593
600
|
|
|
594
601
|
let vault <- FlowToken.createEmptyVault()
|
|
595
|
-
self.flowTokenVault <- vault
|
|
602
|
+
self.flowTokenVault <- vault
|
|
596
603
|
self.lowBalanceThreshold = lowBalanceThreshold
|
|
597
604
|
}
|
|
598
605
|
|
|
599
|
-
|
|
600
|
-
|
|
606
|
+
access(contract) fun safeDestroy() {
|
|
607
|
+
pre {
|
|
608
|
+
self.flowTokenVault.balance == 0.0: "depositor still has flow tokens to be withdrawn"
|
|
609
|
+
}
|
|
601
610
|
}
|
|
602
611
|
}
|
|
603
612
|
|
|
604
|
-
|
|
613
|
+
access(all) fun createDepositor(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?): @Depositor {
|
|
605
614
|
let depositor <- create Depositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold)
|
|
606
615
|
emit DepositorCreated(uuid: depositor.uuid)
|
|
607
616
|
return <- depositor
|
|
608
617
|
}
|
|
609
618
|
|
|
610
|
-
|
|
611
|
-
return self.account.
|
|
619
|
+
access(all) fun borrowShelfManager(): &LostAndFound.ShelfManager {
|
|
620
|
+
return self.account.capabilities.get<&LostAndFound.ShelfManager>(LostAndFound.LostAndFoundPublicPath)!.borrow()!
|
|
612
621
|
}
|
|
613
622
|
|
|
614
|
-
|
|
623
|
+
access(all) fun borrowAllTicketsByType(addr: Address, type: Type): [&LostAndFound.Ticket] {
|
|
615
624
|
let manager = LostAndFound.borrowShelfManager()
|
|
616
625
|
let shelf = manager.borrowShelf(redeemer: addr)
|
|
617
626
|
if shelf == nil {
|
|
@@ -626,7 +635,7 @@ pub contract LostAndFound {
|
|
|
626
635
|
return bin!.borrowAllTicketsByType()
|
|
627
636
|
}
|
|
628
637
|
|
|
629
|
-
|
|
638
|
+
access(all) fun borrowAllTickets(addr: Address): [&LostAndFound.Ticket] {
|
|
630
639
|
let manager = LostAndFound.borrowShelfManager()
|
|
631
640
|
let shelf = manager.borrowShelf(redeemer: addr)
|
|
632
641
|
if shelf == nil {
|
|
@@ -634,7 +643,7 @@ pub contract LostAndFound {
|
|
|
634
643
|
}
|
|
635
644
|
|
|
636
645
|
let types = shelf!.getRedeemableTypes()
|
|
637
|
-
let allTickets
|
|
646
|
+
let allTickets: [&Ticket] = []
|
|
638
647
|
|
|
639
648
|
for type in types {
|
|
640
649
|
let tickets = LostAndFound.borrowAllTicketsByType(addr: addr, type: type)
|
|
@@ -644,19 +653,19 @@ pub contract LostAndFound {
|
|
|
644
653
|
return allTickets
|
|
645
654
|
}
|
|
646
655
|
|
|
647
|
-
|
|
656
|
+
access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) {
|
|
648
657
|
let manager = LostAndFound.borrowShelfManager()
|
|
649
|
-
let shelf = manager.borrowShelf(redeemer: receiver.address)
|
|
658
|
+
let shelf = manager.borrowShelf(redeemer: receiver.address)!
|
|
650
659
|
assert(shelf != nil, message: "shelf not found")
|
|
651
660
|
|
|
652
|
-
shelf
|
|
653
|
-
let remainingTypes = shelf
|
|
661
|
+
shelf.redeemAll(type: type, max: max, receiver: receiver)
|
|
662
|
+
let remainingTypes = shelf.getRedeemableTypes()
|
|
654
663
|
if remainingTypes.length == 0 {
|
|
655
664
|
manager.deleteShelf(receiver.address)
|
|
656
665
|
}
|
|
657
666
|
}
|
|
658
667
|
|
|
659
|
-
|
|
668
|
+
access(all) fun estimateDeposit(
|
|
660
669
|
redeemer: Address,
|
|
661
670
|
item: @AnyResource,
|
|
662
671
|
memo: String?,
|
|
@@ -677,7 +686,7 @@ pub contract LostAndFound {
|
|
|
677
686
|
}
|
|
678
687
|
}
|
|
679
688
|
|
|
680
|
-
let ftReceiver = LostAndFound.account.
|
|
689
|
+
let ftReceiver = LostAndFound.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)
|
|
681
690
|
let ticket <- create LostAndFound.Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: ftReceiver)
|
|
682
691
|
let tmpEstimate <- FeeEstimator.estimateDeposit(item: <-ticket)
|
|
683
692
|
let tmpItem <- tmpEstimate.withdraw() as! @LostAndFound.Ticket
|
|
@@ -689,7 +698,7 @@ pub contract LostAndFound {
|
|
|
689
698
|
return <- estimate
|
|
690
699
|
}
|
|
691
700
|
|
|
692
|
-
|
|
701
|
+
access(all) fun getRedeemableTypes(_ addr: Address): [Type] {
|
|
693
702
|
let manager = LostAndFound.borrowShelfManager()
|
|
694
703
|
let shelf = manager.borrowShelf(redeemer: addr)
|
|
695
704
|
if shelf == nil {
|
|
@@ -699,13 +708,13 @@ pub contract LostAndFound {
|
|
|
699
708
|
return shelf!.getRedeemableTypes()
|
|
700
709
|
}
|
|
701
710
|
|
|
702
|
-
|
|
711
|
+
access(all) fun deposit(
|
|
703
712
|
redeemer: Address,
|
|
704
713
|
item: @AnyResource,
|
|
705
714
|
memo: String?,
|
|
706
715
|
display: MetadataViews.Display?,
|
|
707
|
-
storagePayment: &FungibleToken.Vault,
|
|
708
|
-
flowTokenRepayment: Capability<&FlowToken.Vault
|
|
716
|
+
storagePayment: auth(FungibleToken.Withdrawable) &{FungibleToken.Vault},
|
|
717
|
+
flowTokenRepayment: Capability<&FlowToken.Vault>?
|
|
709
718
|
) : UInt64 {
|
|
710
719
|
pre {
|
|
711
720
|
flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid"
|
|
@@ -716,29 +725,26 @@ pub contract LostAndFound {
|
|
|
716
725
|
return shelfManager.deposit(redeemer: redeemer, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment)
|
|
717
726
|
}
|
|
718
727
|
|
|
719
|
-
|
|
720
|
-
|
|
728
|
+
access(all) fun trySendResource(
|
|
729
|
+
item: @AnyResource,
|
|
721
730
|
cap: Capability,
|
|
722
731
|
memo: String?,
|
|
723
732
|
display: MetadataViews.Display?,
|
|
724
|
-
storagePayment: &FungibleToken.Vault,
|
|
725
|
-
flowTokenRepayment: Capability<&FlowToken.Vault
|
|
733
|
+
storagePayment: auth(FungibleToken.Withdrawable) &{FungibleToken.Vault},
|
|
734
|
+
flowTokenRepayment: Capability<&FlowToken.Vault>
|
|
726
735
|
) {
|
|
727
|
-
if cap.check<&{NonFungibleToken.
|
|
728
|
-
let nft <-
|
|
729
|
-
cap.borrow<&{NonFungibleToken.
|
|
730
|
-
} else if cap.check<&{NonFungibleToken.Receiver}>() {
|
|
731
|
-
let nft <- resource as! @NonFungibleToken.NFT
|
|
732
|
-
cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft)
|
|
736
|
+
if cap.check<&{NonFungibleToken.Collection}>() {
|
|
737
|
+
let nft <- item as! @{NonFungibleToken.NFT}
|
|
738
|
+
cap.borrow<&{NonFungibleToken.Collection}>()!.deposit(token: <-nft)
|
|
733
739
|
} else if cap.check<&{FungibleToken.Receiver}>() {
|
|
734
|
-
let vault <-
|
|
740
|
+
let vault <- item as! @{FungibleToken.Vault}
|
|
735
741
|
cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault)
|
|
736
742
|
} else {
|
|
737
|
-
LostAndFound.deposit(redeemer: cap.address, item: <-
|
|
743
|
+
LostAndFound.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment)
|
|
738
744
|
}
|
|
739
745
|
}
|
|
740
746
|
|
|
741
|
-
|
|
747
|
+
access(all) fun getAddress(): Address {
|
|
742
748
|
return self.account.address
|
|
743
749
|
}
|
|
744
750
|
|
|
@@ -751,8 +757,10 @@ pub contract LostAndFound {
|
|
|
751
757
|
self.DepositorStoragePath = /storage/lostAndFoundDepositor
|
|
752
758
|
|
|
753
759
|
let manager <- create ShelfManager()
|
|
754
|
-
self.account.save(<-manager, to: self.LostAndFoundStoragePath)
|
|
755
|
-
|
|
760
|
+
self.account.storage.save(<-manager, to: self.LostAndFoundStoragePath)
|
|
761
|
+
|
|
762
|
+
let cap = self.account.capabilities.storage.issue<&LostAndFound.ShelfManager>(self.LostAndFoundStoragePath)
|
|
763
|
+
self.account.capabilities.publish(cap, at: self.LostAndFoundPublicPath)
|
|
756
764
|
}
|
|
757
765
|
}
|
|
758
766
|
|