@flowtyio/flow-contracts 0.1.0-beta.30 → 0.1.0-beta.32

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.
@@ -1,5 +1,6 @@
1
1
  import "FlowToken"
2
2
  import "FungibleToken"
3
+ import "FungibleTokenRouter"
3
4
 
4
5
  access(all) contract ContractManager {
5
6
  access(all) let StoragePath: StoragePath
@@ -9,11 +10,24 @@ access(all) contract ContractManager {
9
10
 
10
11
  access(all) resource Manager {
11
12
  access(self) let acct: Capability<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>
13
+ access(self) let routerCap: Capability<auth(FungibleTokenRouter.Owner) &FungibleTokenRouter.Router>
14
+
15
+ access(all) let data: {String: AnyStruct}
16
+ access(all) let resources: @{String: AnyResource}
12
17
 
13
18
  access(Manage) fun borrowContractAccount(): auth(Contracts) &Account {
14
19
  return self.acct.borrow()!
15
20
  }
16
21
 
22
+ access(Manage) fun addOverride(type: Type, addr: Address) {
23
+ let router = self.routerCap.borrow() ?? panic("fungible token router is not valid")
24
+ router.addOverride(type: type, addr: addr)
25
+ }
26
+
27
+ access(Manage) fun getSwitchboard(): auth(FungibleTokenRouter.Owner) &FungibleTokenRouter.Router {
28
+ return self.routerCap.borrow()!
29
+ }
30
+
17
31
  access(all) fun addFlowTokensToAccount(_ tokens: @FlowToken.Vault) {
18
32
  self.acct.borrow()!.storage.borrow<&{FungibleToken.Receiver}>(from: /storage/flowTokenVault)!.deposit(from: <-tokens)
19
33
  }
@@ -22,7 +36,7 @@ access(all) contract ContractManager {
22
36
  return getAccount(self.acct.address)
23
37
  }
24
38
 
25
- init(tokens: @FlowToken.Vault) {
39
+ init(tokens: @FlowToken.Vault, defaultRouterAddress: Address) {
26
40
  pre {
27
41
  tokens.balance >= 0.001: "minimum balance of 0.001 required for initialization"
28
42
  }
@@ -32,11 +46,23 @@ access(all) contract ContractManager {
32
46
  assert(self.acct.check(), message: "failed to setup account capability")
33
47
 
34
48
  acct.storage.borrow<&{FungibleToken.Receiver}>(from: /storage/flowTokenVault)!.deposit(from: <-tokens)
49
+
50
+ let router <- FungibleTokenRouter.createRouter(defaultAddress: defaultRouterAddress)
51
+ acct.storage.save(<-router, to: FungibleTokenRouter.StoragePath)
52
+
53
+ let receiver = acct.capabilities.storage.issue<&{FungibleToken.Receiver}>(FungibleTokenRouter.StoragePath)
54
+ assert(receiver.check(), message: "invalid switchboard receiver capability")
55
+ acct.capabilities.publish(receiver, at: FungibleTokenRouter.PublicPath)
56
+
57
+ self.routerCap = acct.capabilities.storage.issue<auth(FungibleTokenRouter.Owner) &FungibleTokenRouter.Router>(FungibleTokenRouter.StoragePath)
58
+
59
+ self.data = {}
60
+ self.resources <- {}
35
61
  }
36
62
  }
37
63
 
38
- access(all) fun createManager(tokens: @FlowToken.Vault): @Manager {
39
- return <- create Manager(tokens: <- tokens)
64
+ access(all) fun createManager(tokens: @FlowToken.Vault, defaultRouterAddress: Address): @Manager {
65
+ return <- create Manager(tokens: <- tokens, defaultRouterAddress: defaultRouterAddress)
40
66
  }
41
67
 
42
68
  init() {
@@ -2,7 +2,7 @@ import "FungibleToken"
2
2
  import "MetadataViews"
3
3
 
4
4
  import "FlowtyDrops"
5
- import "FlowtySwitchers"
5
+ import "FlowtyActiveCheckers"
6
6
  import "FlowtyAddressVerifiers"
7
7
  import "FlowtyPricers"
8
8
 
@@ -22,7 +22,7 @@ access(all) contract DropFactory {
22
22
  }
23
23
 
24
24
  // This drop is always on and never ends.
25
- let switcher = FlowtySwitchers.AlwaysOn()
25
+ let activeChecker = FlowtyActiveCheckers.AlwaysOn()
26
26
 
27
27
  // All addresses are allowed to participate
28
28
  let addressVerifier = FlowtyAddressVerifiers.AllowAll(maxPerMint: 10)
@@ -30,7 +30,7 @@ access(all) contract DropFactory {
30
30
  // The cost of each mint is the same, and only permits one token type as payment
31
31
  let pricer = FlowtyPricers.FlatPrice(price: price, paymentTokenType: paymentTokenType)
32
32
 
33
- let phaseDetails = FlowtyDrops.PhaseDetails(switcher: switcher, display: nil, pricer: pricer, addressVerifier: addressVerifier)
33
+ let phaseDetails = FlowtyDrops.PhaseDetails(activeChecker: activeChecker, display: nil, pricer: pricer, addressVerifier: addressVerifier)
34
34
  let phase <- FlowtyDrops.createPhase(details: phaseDetails)
35
35
 
36
36
 
@@ -54,8 +54,8 @@ access(all) contract DropFactory {
54
54
  paymentTokenType.isSubtype(of: Type<@{FungibleToken.Vault}>()): "paymentTokenType must be a FungibleToken"
55
55
  }
56
56
 
57
- // This switcher turns on at a set unix timestamp (or is on by default if nil), and ends at the specified end date if provided
58
- let switcher = FlowtySwitchers.TimestampSwitch(start: startUnix, end: endUnix)
57
+ // This ActiveChecker turns on at a set unix timestamp (or is on by default if nil), and ends at the specified end date if provided
58
+ let activeChecker = FlowtyActiveCheckers.TimestampChecker(start: startUnix, end: endUnix)
59
59
 
60
60
  // All addresses are allowed to participate
61
61
  let addressVerifier = FlowtyAddressVerifiers.AllowAll(maxPerMint: 10)
@@ -63,7 +63,7 @@ access(all) contract DropFactory {
63
63
  // The cost of each mint is the same, and only permits one token type as payment
64
64
  let pricer = FlowtyPricers.FlatPrice(price: price, paymentTokenType: paymentTokenType)
65
65
 
66
- let phaseDetails = FlowtyDrops.PhaseDetails(switcher: switcher, display: nil, pricer: pricer, addressVerifier: addressVerifier)
66
+ let phaseDetails = FlowtyDrops.PhaseDetails(activeChecker: activeChecker, display: nil, pricer: pricer, addressVerifier: addressVerifier)
67
67
  let phase <- FlowtyDrops.createPhase(details: phaseDetails)
68
68
 
69
69
  let nftType = CompositeType(nftTypeIdentifier) ?? panic("invalid nft type identifier")
@@ -96,7 +96,7 @@ access(all) contract DropTypes {
96
96
  access(all) let id: UInt64
97
97
  access(all) let index: Int
98
98
 
99
- access(all) let switcherType: String
99
+ access(all) let activeCheckerType: String
100
100
  access(all) let pricerType: String
101
101
  access(all) let addressVerifierType: String
102
102
 
@@ -124,15 +124,15 @@ access(all) contract DropTypes {
124
124
  self.index = index
125
125
  self.id = phase.uuid
126
126
 
127
- let d = phase.getDetails()
128
- self.switcherType = d.switcher.getType().identifier
127
+ let d: FlowtyDrops.PhaseDetails = phase.getDetails()
128
+ self.activeCheckerType = d.activeChecker.getType().identifier
129
129
  self.pricerType = d.pricer.getType().identifier
130
130
  self.addressVerifierType = d.addressVerifier.getType().identifier
131
131
 
132
- self.hasStarted = d.switcher.hasStarted()
133
- self.hasEnded = d.switcher.hasEnded()
134
- self.start = d.switcher.getStart()
135
- self.end = d.switcher.getEnd()
132
+ self.hasStarted = d.activeChecker.hasStarted()
133
+ self.hasEnded = d.activeChecker.hasEnded()
134
+ self.start = d.activeChecker.getStart()
135
+ self.end = d.activeChecker.getEnd()
136
136
 
137
137
  self.paymentTypes = []
138
138
  for pt in d.pricer.getPaymentTypes() {
@@ -259,6 +259,10 @@ access(all) contract DropTypes {
259
259
  phaseSummaries.append(summary)
260
260
  }
261
261
 
262
+ if CompositeType(dropDetails.nftType) == nil {
263
+ continue
264
+ }
265
+
262
266
  summaries.append(DropSummary(
263
267
  id: drop!.uuid,
264
268
  display: dropDetails.display,
@@ -1,14 +1,14 @@
1
1
  import "FlowtyDrops"
2
2
 
3
3
  /*
4
- This contract contains implementations for the FlowtyDrops.Switcher struct interface.
5
- You can use these implementations, or your own, for switches when configuring a drop
4
+ This contract contains implementations for the FlowtyDrops.ActiveChecker struct interface.
5
+ You can use these implementations, or your own, to configure when a phase in a drop is active
6
6
  */
7
- access(all) contract FlowtySwitchers {
7
+ access(all) contract FlowtyActiveCheckers {
8
8
  /*
9
- The AlwaysOn Switcher is always on and never ends.
9
+ The AlwaysOn ActiveChecker is always on and never ends.
10
10
  */
11
- access(all) struct AlwaysOn: FlowtyDrops.Switcher {
11
+ access(all) struct AlwaysOn: FlowtyDrops.ActiveChecker {
12
12
  access(all) view fun hasStarted(): Bool {
13
13
  return true
14
14
  }
@@ -27,10 +27,10 @@ access(all) contract FlowtySwitchers {
27
27
  }
28
28
 
29
29
  /*
30
- The manual switcher is used to explicitly toggle a drop.
31
- This version of switcher allows a creator to turn on or off a drop at will
30
+ The manual checker is used to explicitly toggle a drop.
31
+ This version of checker allows a creator to turn on or off a drop at will
32
32
  */
33
- access(all) struct ManualSwitch: FlowtyDrops.Switcher {
33
+ access(all) struct ManualChecker: FlowtyDrops.ActiveChecker {
34
34
  access(self) var started: Bool
35
35
  access(self) var ended: Bool
36
36
 
@@ -65,10 +65,10 @@ access(all) contract FlowtySwitchers {
65
65
  }
66
66
 
67
67
  /*
68
- TimestampSwitch uses block timestamps to determine if a phase or drop is live or not.
69
- A timestamp switcher has a start and an end time.
68
+ TimestampChecker uses block timestamps to determine if a phase or drop is live or not.
69
+ A timestamp checker has a start and an end time.
70
70
  */
71
- access(all) struct TimestampSwitch: FlowtyDrops.Switcher {
71
+ access(all) struct TimestampChecker: FlowtyDrops.ActiveChecker {
72
72
  access(all) var start: UInt64?
73
73
  access(all) var end: UInt64?
74
74
 
@@ -2,14 +2,16 @@ import "NonFungibleToken"
2
2
  import "FungibleToken"
3
3
  import "MetadataViews"
4
4
  import "AddressUtils"
5
+ import "FungibleTokenMetadataViews"
6
+ import "FungibleTokenRouter"
5
7
 
6
8
  access(all) contract FlowtyDrops {
7
9
  access(all) let ContainerStoragePath: StoragePath
8
10
  access(all) let ContainerPublicPath: PublicPath
9
11
 
10
- access(all) event DropAdded(address: Address, id: UInt64, name: String, description: String, imageUrl: String, start: UInt64?, end: UInt64?)
12
+ access(all) event DropAdded(address: Address, id: UInt64, name: String, description: String, imageUrl: String, start: UInt64?, end: UInt64?, nftType: String)
11
13
  access(all) event Minted(address: Address, dropID: UInt64, phaseID: UInt64, nftID: UInt64, nftType: String)
12
- access(all) event PhaseAdded(dropID: UInt64, dropAddress: Address, id: UInt64, index: Int, switcherType: String, pricerType: String, addressVerifierType: String)
14
+ access(all) event PhaseAdded(dropID: UInt64, dropAddress: Address, id: UInt64, index: Int, activeCheckerType: String, pricerType: String, addressVerifierType: String)
13
15
  access(all) event PhaseRemoved(dropID: UInt64, dropAddress: Address, id: UInt64)
14
16
 
15
17
  access(all) entitlement Owner
@@ -27,12 +29,52 @@ access(all) contract FlowtyDrops {
27
29
  phaseIndex: Int,
28
30
  expectedType: Type,
29
31
  receiverCap: Capability<&{NonFungibleToken.CollectionPublic}>,
30
- commissionReceiver: Capability<&{FungibleToken.Receiver}>,
32
+ commissionReceiver: Capability<&{FungibleToken.Receiver}>?,
31
33
  data: {String: AnyStruct}
32
34
  ): @{FungibleToken.Vault}
33
35
  access(all) fun getDetails(): DropDetails
34
36
  }
35
37
 
38
+ // A phase represents a stage of a drop. Some drops will only have one
39
+ // phase, while others could have many. For example, a drop with an allow list
40
+ // and a public mint would likely have two phases.
41
+ access(all) resource Phase: PhasePublic {
42
+ access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid)
43
+
44
+ access(all) let details: PhaseDetails
45
+
46
+ access(all) let data: {String: AnyStruct}
47
+ access(all) let resources: @{String: AnyResource}
48
+
49
+ // returns whether this phase of a drop has started.
50
+ access(all) fun isActive(): Bool {
51
+ return self.details.activeChecker.hasStarted() && !self.details.activeChecker.hasEnded()
52
+ }
53
+
54
+ access(all) fun getDetails(): PhaseDetails {
55
+ return self.details
56
+ }
57
+
58
+ access(EditPhase) fun borrowActiveCheckerAuth(): auth(Mutate) &{ActiveChecker} {
59
+ return &self.details.activeChecker
60
+ }
61
+
62
+ access(EditPhase) fun borrowPricerAuth(): auth(Mutate) &{Pricer} {
63
+ return &self.details.pricer
64
+ }
65
+
66
+ access(EditPhase) fun borrowAddressVerifierAuth(): auth(Mutate) &{AddressVerifier} {
67
+ return &self.details.addressVerifier
68
+ }
69
+
70
+ init(details: PhaseDetails) {
71
+ self.details = details
72
+
73
+ self.data = {}
74
+ self.resources <- {}
75
+ }
76
+ }
77
+
36
78
  access(all) resource Drop: DropPublic {
37
79
  access(all) event ResourceDestroyed(
38
80
  uuid: UInt64 = self.uuid,
@@ -47,13 +89,16 @@ access(all) contract FlowtyDrops {
47
89
  access(self) let details: DropDetails
48
90
  access(self) let minterCap: Capability<&{Minter}>
49
91
 
92
+ access(all) let data: {String: AnyStruct}
93
+ access(all) let resources: @{String: AnyResource}
94
+
50
95
  access(all) fun mint(
51
96
  payment: @{FungibleToken.Vault},
52
97
  amount: Int,
53
98
  phaseIndex: Int,
54
99
  expectedType: Type,
55
100
  receiverCap: Capability<&{NonFungibleToken.CollectionPublic}>,
56
- commissionReceiver: Capability<&{FungibleToken.Receiver}>,
101
+ commissionReceiver: Capability<&{FungibleToken.Receiver}>?,
57
102
  data: {String: AnyStruct}
58
103
  ): @{FungibleToken.Vault} {
59
104
  pre {
@@ -74,16 +119,18 @@ access(all) contract FlowtyDrops {
74
119
  let withdrawn <- payment.withdraw(amount: paymentAmount) // make sure that we have a fresh vault resource
75
120
 
76
121
  // take commission
77
- let commission <- withdrawn.withdraw(amount: self.details.commissionRate * withdrawn.balance)
78
- commissionReceiver.borrow()!.deposit(from: <-commission)
122
+ if commissionReceiver != nil && commissionReceiver!.check() {
123
+ let commission <- withdrawn.withdraw(amount: self.details.commissionRate * withdrawn.balance)
124
+ commissionReceiver!.borrow()!.deposit(from: <-commission)
125
+ }
79
126
 
80
127
  assert(phase.details.pricer.getPrice(num: amount, paymentTokenType: withdrawn.getType(), minter: receiverCap.address) * (1.0 - self.details.commissionRate) == withdrawn.balance, message: "incorrect payment amount")
81
128
  assert(phase.details.pricer.getPaymentTypes().contains(withdrawn.getType()), message: "unsupported payment type")
82
129
 
83
130
  // mint the nfts
84
131
  let minter = self.minterCap.borrow() ?? panic("minter capability could not be borrowed")
85
- let mintedNFTs <- minter.mint(payment: <-withdrawn, amount: amount, phase: phase, data: data)
86
- assert(phase.details.switcher.hasStarted() && !phase.details.switcher.hasEnded(), message: "phase is not active")
132
+ let mintedNFTs: @[{NonFungibleToken.NFT}] <- minter.mint(payment: <-withdrawn, amount: amount, phase: phase, data: data)
133
+ assert(phase.details.activeChecker.hasStarted() && !phase.details.activeChecker.hasEnded(), message: "phase is not active")
87
134
  assert(mintedNFTs.length == amount, message: "incorrect number of items returned")
88
135
 
89
136
  // distribute to receiver
@@ -123,8 +170,8 @@ access(all) contract FlowtyDrops {
123
170
  var count = 0
124
171
  while count < self.phases.length {
125
172
  let ref = self.borrowPhasePublic(index: count)
126
- let switcher = ref.getDetails().switcher
127
- if switcher.hasStarted() && !switcher.hasEnded() {
173
+ let activeChecker = ref.getDetails().activeChecker
174
+ if activeChecker.hasStarted() && !activeChecker.hasEnded() {
128
175
  arr.append(ref)
129
176
  }
130
177
 
@@ -152,7 +199,7 @@ access(all) contract FlowtyDrops {
152
199
  dropAddress: self.owner!.address,
153
200
  id: phase.uuid,
154
201
  index: self.phases.length,
155
- switcherType: phase.details.switcher.getType().identifier,
202
+ activeCheckerType: phase.details.activeChecker.getType().identifier,
156
203
  pricerType: phase.details.pricer.getType().identifier,
157
204
  addressVerifierType: phase.details.addressVerifier.getType().identifier
158
205
  )
@@ -182,6 +229,9 @@ access(all) contract FlowtyDrops {
182
229
  self.phases <- phases
183
230
  self.details = details
184
231
  self.minterCap = minterCap
232
+
233
+ self.data = {}
234
+ self.resources <- {}
185
235
  }
186
236
  }
187
237
 
@@ -193,6 +243,8 @@ access(all) contract FlowtyDrops {
193
243
  access(all) let commissionRate: UFix64
194
244
  access(all) let nftType: String
195
245
 
246
+ access(all) let data: {String: AnyStruct}
247
+
196
248
  access(contract) fun addMinted(num: Int, addr: Address) {
197
249
  self.totalMinted = self.totalMinted + num
198
250
  if self.minters[addr] == nil {
@@ -203,22 +255,27 @@ access(all) contract FlowtyDrops {
203
255
  }
204
256
 
205
257
  init(display: MetadataViews.Display, medias: MetadataViews.Medias?, commissionRate: UFix64, nftType: String) {
258
+ pre {
259
+ nftType != "": "nftType should be a composite type identifier"
260
+ }
261
+
206
262
  self.display = display
207
263
  self.medias = medias
208
264
  self.totalMinted = 0
209
265
  self.commissionRate = commissionRate
210
266
  self.minters = {}
211
267
  self.nftType = nftType
268
+ self.data = {}
212
269
  }
213
270
  }
214
271
 
215
- // A switcher represents a phase being on or off, and holds information
272
+ // An ActiveChecker represents a phase being on or off, and holds information
216
273
  // about whether a phase has started or not.
217
- access(all) struct interface Switcher {
218
- // Signal that a phase has started. If the phase has not ended, it means that this switcher's phase
274
+ access(all) struct interface ActiveChecker {
275
+ // Signal that a phase has started. If the phase has not ended, it means that this activeChecker's phase
219
276
  // is active
220
277
  access(all) view fun hasStarted(): Bool
221
- // Signal that a phase has ended. If a switcher has ended, minting will not work. That could mean
278
+ // Signal that a phase has ended. If an ActiveChecker has ended, minting will not work. That could mean
222
279
  // the drop is over, or it could mean another phase has begun.
223
280
  access(all) view fun hasEnded(): Bool
224
281
 
@@ -226,40 +283,6 @@ access(all) contract FlowtyDrops {
226
283
  access(all) view fun getEnd(): UInt64?
227
284
  }
228
285
 
229
- // A phase represents a stage of a drop. Some drops will only have one
230
- // phase, while others could have many. For example, a drop with an allow list
231
- // and a public mint would likely have two phases.
232
- access(all) resource Phase: PhasePublic {
233
- access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid)
234
-
235
- access(all) let details: PhaseDetails
236
-
237
- // returns whether this phase of a drop has started.
238
- access(all) fun isActive(): Bool {
239
- return self.details.switcher.hasStarted() && !self.details.switcher.hasEnded()
240
- }
241
-
242
- access(all) fun getDetails(): PhaseDetails {
243
- return self.details
244
- }
245
-
246
- access(EditPhase) fun borrowSwitchAuth(): auth(Mutate) &{Switcher} {
247
- return &self.details.switcher
248
- }
249
-
250
- access(EditPhase) fun borrowPricerAuth(): auth(Mutate) &{Pricer} {
251
- return &self.details.pricer
252
- }
253
-
254
- access(EditPhase) fun borrowAddressVerifierAuth(): auth(Mutate) &{AddressVerifier} {
255
- return &self.details.addressVerifier
256
- }
257
-
258
- init(details: PhaseDetails) {
259
- self.details = details
260
- }
261
- }
262
-
263
286
  access(all) resource interface PhasePublic {
264
287
  // What does a phase need to be able to answer/manage?
265
288
  // - What are the details of the phase being interactive with?
@@ -272,7 +295,7 @@ access(all) contract FlowtyDrops {
272
295
 
273
296
  access(all) struct PhaseDetails {
274
297
  // handles whether a phase is on or not
275
- access(all) let switcher: {Switcher}
298
+ access(all) let activeChecker: {ActiveChecker}
276
299
 
277
300
  // display information about a phase
278
301
  access(all) let display: MetadataViews.Display?
@@ -286,8 +309,8 @@ access(all) contract FlowtyDrops {
286
309
  // placecholder data dictionary to allow new fields to be accessed
287
310
  access(all) let data: {String: AnyStruct}
288
311
 
289
- init(switcher: {Switcher}, display: MetadataViews.Display?, pricer: {Pricer}, addressVerifier: {AddressVerifier}) {
290
- self.switcher = switcher
312
+ init(activeChecker: {ActiveChecker}, display: MetadataViews.Display?, pricer: {Pricer}, addressVerifier: {AddressVerifier}) {
313
+ self.activeChecker = activeChecker
291
314
  self.display = display
292
315
  self.pricer = pricer
293
316
  self.addressVerifier = addressVerifier
@@ -314,8 +337,8 @@ access(all) contract FlowtyDrops {
314
337
  access(all) resource interface Minter {
315
338
  access(contract) fun mint(payment: @{FungibleToken.Vault}, amount: Int, phase: &FlowtyDrops.Phase, data: {String: AnyStruct}): @[{NonFungibleToken.NFT}] {
316
339
  let resourceAddress = AddressUtils.parseAddress(self.getType())!
317
- let receiver = getAccount(resourceAddress).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver).borrow()
318
- ?? panic("invalid flow token receiver")
340
+ let receiver = getAccount(resourceAddress).capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenRouter.PublicPath).borrow()
341
+ ?? panic("missing receiver at fungible token router path")
319
342
  receiver.deposit(from: <-payment)
320
343
 
321
344
  let nfts: @[{NonFungibleToken.NFT}] <- []
@@ -357,6 +380,9 @@ access(all) contract FlowtyDrops {
357
380
  access(all) resource Container: ContainerPublic {
358
381
  access(self) let drops: @{UInt64: Drop}
359
382
 
383
+ access(all) let data: {String: AnyStruct}
384
+ access(all) let resources: @{String: AnyResource}
385
+
360
386
  access(Owner) fun addDrop(_ drop: @Drop) {
361
387
  let details = drop.getDetails()
362
388
 
@@ -371,8 +397,9 @@ access(all) contract FlowtyDrops {
371
397
  name: details.display.name,
372
398
  description: details.display.description,
373
399
  imageUrl: details.display.thumbnail.uri(),
374
- start: firstPhaseDetails.switcher.getStart(),
375
- end: firstPhaseDetails.switcher.getEnd()
400
+ start: firstPhaseDetails.activeChecker.getStart(),
401
+ end: firstPhaseDetails.activeChecker.getEnd(),
402
+ nftType: details.nftType
376
403
  )
377
404
  destroy self.drops.insert(key: drop.uuid, <-drop)
378
405
  }
@@ -399,6 +426,9 @@ access(all) contract FlowtyDrops {
399
426
 
400
427
  init() {
401
428
  self.drops <- {}
429
+
430
+ self.data = {}
431
+ self.resources <- {}
402
432
  }
403
433
  }
404
434
 
@@ -416,7 +446,7 @@ access(all) contract FlowtyDrops {
416
446
 
417
447
  access(all) fun getMinterStoragePath(type: Type): StoragePath {
418
448
  let segments = type.identifier.split(separator: ".")
419
- let identifier = "FlowtyDrops_Minter_".concat(segments[1]).concat(segments[2])
449
+ let identifier = "FlowtyDrops_Minter_".concat(segments[1]).concat("_").concat(segments[2])
420
450
  return StoragePath(identifier: identifier)!
421
451
  }
422
452
 
@@ -1,6 +1,8 @@
1
1
  import "ContractInitializer"
2
2
  import "NFTMetadata"
3
3
  import "FlowtyDrops"
4
+ import "NonFungibleToken"
5
+ import "UniversalCollection"
4
6
 
5
7
  access(all) contract OpenEditionInitializer: ContractInitializer {
6
8
  access(all) fun initialize(contractAcct: auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account, params: {String: AnyStruct}): NFTMetadata.InitializedCaps {
@@ -9,18 +11,15 @@ access(all) contract OpenEditionInitializer: ContractInitializer {
9
11
  params["data"]!.getType() == Type<NFTMetadata.Metadata>(): "data param must be of type NFTMetadata.Metadata"
10
12
  params["collectionInfo"] != nil: "missing param collectionInfo"
11
13
  params["collectionInfo"]!.getType() == Type<NFTMetadata.CollectionInfo>(): "collectionInfo param must be of type NFTMetadata.CollectionInfo"
14
+ params["type"] != nil: "missing param type"
15
+ params["type"]!.getType() == Type<Type>(): "type param must be of type Type"
12
16
  }
13
17
 
14
18
  let data = params["data"]! as! NFTMetadata.Metadata
15
19
  let collectionInfo = params["collectionInfo"]! as! NFTMetadata.CollectionInfo
16
20
 
17
- let acct: auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account = Account(payer: contractAcct)
18
- let cap = acct.capabilities.account.issue<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>()
19
-
20
- let t = self.getType()
21
- let contractName = t.identifier.split(separator: ".")[2]
22
-
23
- self.account.storage.save(cap, to: StoragePath(identifier: "metadataAuthAccount_".concat(contractName))!)
21
+ let nftType = params["type"]! as! Type
22
+ let contractName = nftType.identifier.split(separator: ".")[2]
24
23
 
25
24
  // do we have information to setup a drop as well?
26
25
  if params.containsKey("dropDetails") && params.containsKey("phaseDetails") && params.containsKey("minterController") {
@@ -30,7 +29,7 @@ access(all) contract OpenEditionInitializer: ContractInitializer {
30
29
  let phaseDetails = params["phaseDetails"]! as! [FlowtyDrops.PhaseDetails]
31
30
 
32
31
  assert(minterCap.check(), message: "invalid minter capability")
33
-
32
+ assert(CompositeType(dropDetails.nftType) != nil, message: "dropDetails.nftType must be a valid CompositeType")
34
33
 
35
34
  let phases: @[FlowtyDrops.Phase] <- []
36
35
  for p in phaseDetails {
@@ -38,21 +37,21 @@ access(all) contract OpenEditionInitializer: ContractInitializer {
38
37
  }
39
38
 
40
39
  let drop <- FlowtyDrops.createDrop(details: dropDetails, minterCap: minterCap, phases: <- phases)
41
- if acct.storage.borrow<&AnyResource>(from: FlowtyDrops.ContainerStoragePath) == nil {
42
- acct.storage.save(<- FlowtyDrops.createContainer(), to: FlowtyDrops.ContainerStoragePath)
40
+ if contractAcct.storage.borrow<&AnyResource>(from: FlowtyDrops.ContainerStoragePath) == nil {
41
+ contractAcct.storage.save(<- FlowtyDrops.createContainer(), to: FlowtyDrops.ContainerStoragePath)
43
42
 
44
- acct.capabilities.unpublish(FlowtyDrops.ContainerPublicPath)
45
- acct.capabilities.publish(
46
- acct.capabilities.storage.issue<&{FlowtyDrops.ContainerPublic}>(FlowtyDrops.ContainerStoragePath),
43
+ contractAcct.capabilities.unpublish(FlowtyDrops.ContainerPublicPath)
44
+ contractAcct.capabilities.publish(
45
+ contractAcct.capabilities.storage.issue<&{FlowtyDrops.ContainerPublic}>(FlowtyDrops.ContainerStoragePath),
47
46
  at: FlowtyDrops.ContainerPublicPath
48
47
  )
49
48
  }
50
49
 
51
- let container = acct.storage.borrow<auth(FlowtyDrops.Owner) &FlowtyDrops.Container>(from: FlowtyDrops.ContainerStoragePath)
50
+ let container = contractAcct.storage.borrow<auth(FlowtyDrops.Owner) &FlowtyDrops.Container>(from: FlowtyDrops.ContainerStoragePath)
52
51
  ?? panic("drops container not found")
53
52
  container.addDrop(<- drop)
54
53
  }
55
54
 
56
- return NFTMetadata.initialize(acct: acct, collectionInfo: collectionInfo, collectionType: self.getType())
55
+ return NFTMetadata.initialize(acct: contractAcct, collectionInfo: collectionInfo, nftType: nftType)
57
56
  }
58
57
  }
@@ -82,12 +82,12 @@ access(all) contract interface BaseCollection: ViewResolver {
82
82
  )
83
83
  case Type<MetadataViews.NFTCollectionDisplay>():
84
84
  let c = getAccount(addr).contracts.borrow<&{BaseCollection}>(name: segments[2])!
85
- let md = c.MetadataCap.borrow()
86
- if md == nil {
85
+ let tmp = c.MetadataCap.borrow()
86
+ if tmp == nil {
87
87
  return nil
88
88
  }
89
89
 
90
- return md!.collectionInfo.collectionDisplay
90
+ return tmp!.collectionInfo.getDisplay()
91
91
  case Type<FlowtyDrops.DropResolver>():
92
92
  return FlowtyDrops.DropResolver(cap: acct.capabilities.get<&{FlowtyDrops.ContainerPublic}>(FlowtyDrops.ContainerPublicPath))
93
93
  }
@@ -9,8 +9,16 @@ access(all) contract NFTMetadata {
9
9
  access(all) struct CollectionInfo {
10
10
  access(all) var collectionDisplay: MetadataViews.NFTCollectionDisplay
11
11
 
12
+ access(all) let data: {String: AnyStruct}
13
+
14
+ access(all) fun getDisplay(): MetadataViews.NFTCollectionDisplay {
15
+ return self.collectionDisplay
16
+ }
17
+
12
18
  init(collectionDisplay: MetadataViews.NFTCollectionDisplay) {
13
19
  self.collectionDisplay = collectionDisplay
20
+
21
+ self.data = {}
14
22
  }
15
23
  }
16
24
 
@@ -24,8 +32,9 @@ access(all) contract NFTMetadata {
24
32
  access(all) let traits: MetadataViews.Traits?
25
33
  access(all) let editions: MetadataViews.Editions?
26
34
  access(all) let externalURL: MetadataViews.ExternalURL?
35
+ access(all) let royalties: MetadataViews.Royalties?
27
36
 
28
- access(all) let data: {String: AnyStruct} // general-purpose data bucket
37
+ access(all) let data: {String: AnyStruct}
29
38
 
30
39
  init(
31
40
  name: String,
@@ -34,6 +43,7 @@ access(all) contract NFTMetadata {
34
43
  traits: MetadataViews.Traits?,
35
44
  editions: MetadataViews.Editions?,
36
45
  externalURL: MetadataViews.ExternalURL?,
46
+ royalties: MetadataViews.Royalties?,
37
47
  data: {String: AnyStruct}
38
48
  ) {
39
49
  self.name = name
@@ -43,6 +53,7 @@ access(all) contract NFTMetadata {
43
53
  self.traits = traits
44
54
  self.editions = editions
45
55
  self.externalURL = externalURL
56
+ self.royalties = royalties
46
57
 
47
58
  self.data = {}
48
59
  }
@@ -53,6 +64,9 @@ access(all) contract NFTMetadata {
53
64
  access(all) let metadata: {UInt64: Metadata}
54
65
  access(all) var frozen: Bool
55
66
 
67
+ access(all) let data: {String: AnyStruct}
68
+ access(all) let resources: @{String: AnyResource}
69
+
56
70
  access(all) fun borrowMetadata(id: UInt64): &Metadata? {
57
71
  return &self.metadata[id]
58
72
  }
@@ -74,6 +88,9 @@ access(all) contract NFTMetadata {
74
88
  self.collectionInfo = collectionInfo
75
89
  self.metadata = {}
76
90
  self.frozen = false
91
+
92
+ self.data = {}
93
+ self.resources <- {}
77
94
  }
78
95
  }
79
96
 
@@ -81,9 +98,13 @@ access(all) contract NFTMetadata {
81
98
  access(all) let pubCap: Capability<&Container>
82
99
  access(all) let ownerCap: Capability<auth(Owner) &Container>
83
100
 
101
+ access(all) let data: {String: AnyStruct}
102
+
84
103
  init(pubCap: Capability<&Container>, ownerCap: Capability<auth(Owner) &Container>) {
85
104
  self.pubCap = pubCap
86
105
  self.ownerCap = ownerCap
106
+
107
+ self.data = {}
87
108
  }
88
109
  }
89
110
 
@@ -91,8 +112,8 @@ access(all) contract NFTMetadata {
91
112
  return <- create Container(collectionInfo: collectionInfo)
92
113
  }
93
114
 
94
- access(all) fun initialize(acct: auth(Storage, Capabilities) &Account, collectionInfo: CollectionInfo, collectionType: Type): InitializedCaps {
95
- let storagePath = self.getCollectionStoragePath(type: collectionType)
115
+ access(all) fun initialize(acct: auth(Storage, Capabilities) &Account, collectionInfo: CollectionInfo, nftType: Type): InitializedCaps {
116
+ let storagePath = self.getCollectionStoragePath(type: nftType)
96
117
  let container <- self.createContainer(collectionInfo: collectionInfo)
97
118
  acct.storage.save(<-container, to: storagePath)
98
119
  let pubCap = acct.capabilities.storage.issue<&Container>(storagePath)
@@ -35,6 +35,7 @@ access(all) contract OpenEditionNFT: BaseCollection {
35
35
  self.totalSupply = 0
36
36
  self.account.storage.save(<- create NFTMinter(), to: FlowtyDrops.getMinterStoragePath(type: self.getType()))
37
37
  params["minterController"] = self.account.capabilities.storage.issue<&{FlowtyDrops.Minter}>(FlowtyDrops.getMinterStoragePath(type: self.getType()))
38
+ params["type"] = Type<@NFT>()
38
39
 
39
40
  self.MetadataCap = ContractBorrower.borrowInitializer(typeIdentifier: initializeIdentifier).initialize(contractAcct: self.account, params: params).pubCap
40
41
  }
@@ -11,9 +11,10 @@ access(all) contract OpenEditionTemplate: ContractFactoryTemplate {
11
11
  "NFTMetadata",
12
12
  "UniversalCollection",
13
13
  "ContractBorrower",
14
- "BaseCollection"
14
+ "BaseCollection",
15
+ "ViewResolver"
15
16
  ]).concat("\n\n")
16
- .concat("access(all) contract ").concat(name).concat(": BaseCollection {\n")
17
+ .concat("access(all) contract ").concat(name).concat(": BaseCollection, ViewResolver {\n")
17
18
  .concat(" access(all) var MetadataCap: Capability<&NFTMetadata.Container>\n")
18
19
  .concat(" access(all) var totalSupply: UInt64\n")
19
20
  .concat("\n\n")
@@ -42,6 +43,7 @@ access(all) contract OpenEditionTemplate: ContractFactoryTemplate {
42
43
  .concat(" let minter <- create NFTMinter()\n")
43
44
  .concat(" self.account.storage.save(<-minter, to: FlowtyDrops.getMinterStoragePath(type: self.getType()))\n")
44
45
  .concat(" params[\"minterController\"] = self.account.capabilities.storage.issue<&{FlowtyDrops.Minter}>(FlowtyDrops.getMinterStoragePath(type: self.getType()))\n")
46
+ .concat(" params[\"type\"] = Type<@NFT>()\n")
45
47
  .concat("\n\n")
46
48
  .concat(" self.MetadataCap = ContractBorrower.borrowInitializer(typeIdentifier: initializeIdentifier).initialize(contractAcct: self.account, params: params).pubCap\n")
47
49
  .concat(" }\n")
@@ -7,6 +7,9 @@ access(all) contract UniversalCollection {
7
7
  access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
8
8
  access(all) var nftType: Type
9
9
 
10
+ access(all) let data: {String: AnyStruct}
11
+ access(all) let resources: @{String: AnyResource}
12
+
10
13
  access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
11
14
  return <- create Collection(nftType: self.nftType)
12
15
  }
@@ -14,6 +17,9 @@ access(all) contract UniversalCollection {
14
17
  init (nftType: Type) {
15
18
  self.ownedNFTs <- {}
16
19
  self.nftType = nftType
20
+
21
+ self.data = {}
22
+ self.resources <- {}
17
23
  }
18
24
  }
19
25
 
@@ -65,14 +65,12 @@ access(all) contract FungibleTokenRouter {
65
65
  vaultDataOpt = md as! FungibleTokenMetadataViews.FTVaultData
66
66
  }
67
67
 
68
- let vaultData = vaultDataOpt ?? panic("vault data could not be retrieved")
68
+ let vaultData = vaultDataOpt ?? panic("vault data could not be retrieved for type ".concat(tokenType.identifier))
69
69
  let receiver = getAccount(destination).capabilities.get<&{FungibleToken.Receiver}>(vaultData.receiverPath)
70
70
  assert(receiver.check(), message: "no receiver found at path: ".concat(vaultData.receiverPath.toString()))
71
71
 
72
72
  emit TokensRouted(tokenType: tokenType.identifier, amount: from.balance, to: destination)
73
73
  receiver.borrow()!.deposit(from: <-from)
74
-
75
- panic("Could not find FungibleTokenMetadataViews.FTVaultData on depositing tokens")
76
74
  }
77
75
 
78
76
  access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
package/flow.json CHANGED
@@ -359,7 +359,7 @@
359
359
  "source": "./contracts/flowty-drops/ContractManager.cdc",
360
360
  "aliases": {
361
361
  "testing": "0x0000000000000006",
362
- "testnet": "0xd20430774404a7e8",
362
+ "testnet": "0x772a10c786851a1b",
363
363
  "emulator": "0xf8d6e0586b0a20c7"
364
364
  }
365
365
  },
@@ -367,7 +367,7 @@
367
367
  "source": "./contracts/flowty-drops/initializers/ContractInitializer.cdc",
368
368
  "aliases": {
369
369
  "testing": "0x0000000000000006",
370
- "testnet": "0xd20430774404a7e8",
370
+ "testnet": "0x772a10c786851a1b",
371
371
  "emulator": "0xf8d6e0586b0a20c7"
372
372
  }
373
373
  },
@@ -375,7 +375,7 @@
375
375
  "source": "./contracts/flowty-drops/initializers/ContractBorrower.cdc",
376
376
  "aliases": {
377
377
  "testing": "0x0000000000000006",
378
- "testnet": "0xd20430774404a7e8",
378
+ "testnet": "0x772a10c786851a1b",
379
379
  "emulator": "0xf8d6e0586b0a20c7"
380
380
  }
381
381
  },
@@ -383,7 +383,7 @@
383
383
  "source": "./contracts/flowty-drops/initializers/OpenEditionInitializer.cdc",
384
384
  "aliases": {
385
385
  "testing": "0x0000000000000006",
386
- "testnet": "0xd20430774404a7e8",
386
+ "testnet": "0x772a10c786851a1b",
387
387
  "emulator": "0xf8d6e0586b0a20c7"
388
388
  }
389
389
  },
@@ -391,7 +391,7 @@
391
391
  "source": "./contracts/flowty-drops/nft/BaseCollection.cdc",
392
392
  "aliases": {
393
393
  "testing": "0x0000000000000006",
394
- "testnet": "0xd20430774404a7e8",
394
+ "testnet": "0x772a10c786851a1b",
395
395
  "emulator": "0xf8d6e0586b0a20c7"
396
396
  }
397
397
  },
@@ -399,7 +399,7 @@
399
399
  "source": "./contracts/flowty-drops/nft/ContractFactoryTemplate.cdc",
400
400
  "aliases": {
401
401
  "testing": "0x0000000000000006",
402
- "testnet": "0xd20430774404a7e8",
402
+ "testnet": "0x772a10c786851a1b",
403
403
  "emulator": "0xf8d6e0586b0a20c7"
404
404
  }
405
405
  },
@@ -407,7 +407,7 @@
407
407
  "source": "./contracts/flowty-drops/nft/ContractFactory.cdc",
408
408
  "aliases": {
409
409
  "testing": "0x0000000000000006",
410
- "testnet": "0xd20430774404a7e8",
410
+ "testnet": "0x772a10c786851a1b",
411
411
  "emulator": "0xf8d6e0586b0a20c7"
412
412
  }
413
413
  },
@@ -415,7 +415,7 @@
415
415
  "source": "./contracts/flowty-drops/nft/OpenEditionTemplate.cdc",
416
416
  "aliases": {
417
417
  "testing": "0x0000000000000006",
418
- "testnet": "0xd20430774404a7e8",
418
+ "testnet": "0x772a10c786851a1b",
419
419
  "emulator": "0xf8d6e0586b0a20c7"
420
420
  }
421
421
  },
@@ -423,7 +423,7 @@
423
423
  "source": "./contracts/flowty-drops/nft/UniversalCollection.cdc",
424
424
  "aliases": {
425
425
  "testing": "0x0000000000000006",
426
- "testnet": "0xd20430774404a7e8",
426
+ "testnet": "0x772a10c786851a1b",
427
427
  "emulator": "0xf8d6e0586b0a20c7"
428
428
  }
429
429
  },
@@ -431,7 +431,7 @@
431
431
  "source": "./contracts/flowty-drops/nft/BaseNFT.cdc",
432
432
  "aliases": {
433
433
  "testing": "0x0000000000000006",
434
- "testnet": "0xd20430774404a7e8",
434
+ "testnet": "0x772a10c786851a1b",
435
435
  "emulator": "0xf8d6e0586b0a20c7"
436
436
  }
437
437
  },
@@ -439,7 +439,7 @@
439
439
  "source": "./contracts/flowty-drops/nft/NFTMetadata.cdc",
440
440
  "aliases": {
441
441
  "testing": "0x0000000000000006",
442
- "testnet": "0xd20430774404a7e8",
442
+ "testnet": "0x772a10c786851a1b",
443
443
  "emulator": "0xf8d6e0586b0a20c7"
444
444
  }
445
445
  },
@@ -447,7 +447,7 @@
447
447
  "source": "./contracts/flowty-drops/FlowtyDrops.cdc",
448
448
  "aliases": {
449
449
  "testing": "0x0000000000000006",
450
- "testnet": "0xd20430774404a7e8",
450
+ "testnet": "0x772a10c786851a1b",
451
451
  "emulator": "0xf8d6e0586b0a20c7"
452
452
  }
453
453
  },
@@ -455,15 +455,15 @@
455
455
  "source": "./contracts/flowty-drops/DropFactory.cdc",
456
456
  "aliases": {
457
457
  "testing": "0x0000000000000006",
458
- "testnet": "0xd20430774404a7e8",
458
+ "testnet": "0x772a10c786851a1b",
459
459
  "emulator": "0xf8d6e0586b0a20c7"
460
460
  }
461
461
  },
462
- "FlowtySwitchers": {
463
- "source": "./contracts/flowty-drops/FlowtySwitchers.cdc",
462
+ "FlowtyActiveCheckers": {
463
+ "source": "./contracts/flowty-drops/FlowtyActiveCheckers.cdc",
464
464
  "aliases": {
465
465
  "testing": "0x0000000000000006",
466
- "testnet": "0xd20430774404a7e8",
466
+ "testnet": "0x772a10c786851a1b",
467
467
  "emulator": "0xf8d6e0586b0a20c7"
468
468
  }
469
469
  },
@@ -471,7 +471,7 @@
471
471
  "source": "./contracts/flowty-drops/FlowtyPricers.cdc",
472
472
  "aliases": {
473
473
  "testing": "0x0000000000000006",
474
- "testnet": "0xd20430774404a7e8",
474
+ "testnet": "0x772a10c786851a1b",
475
475
  "emulator": "0xf8d6e0586b0a20c7"
476
476
  }
477
477
  },
@@ -479,7 +479,7 @@
479
479
  "source": "./contracts/flowty-drops/FlowtyAddressVerifiers.cdc",
480
480
  "aliases": {
481
481
  "testing": "0x0000000000000006",
482
- "testnet": "0xd20430774404a7e8",
482
+ "testnet": "0x772a10c786851a1b",
483
483
  "emulator": "0xf8d6e0586b0a20c7"
484
484
  }
485
485
  },
@@ -487,7 +487,7 @@
487
487
  "source": "./contracts/flowty-drops/DropTypes.cdc",
488
488
  "aliases": {
489
489
  "testing": "0x0000000000000006",
490
- "testnet": "0x3d49bb33997bd91e",
490
+ "testnet": "0x934da91a977f1ac4",
491
491
  "emulator": "0xf8d6e0586b0a20c7"
492
492
  }
493
493
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowtyio/flow-contracts",
3
- "version": "0.1.0-beta.30",
3
+ "version": "0.1.0-beta.32",
4
4
  "main": "index.json",
5
5
  "description": "An NPM package for common flow contracts",
6
6
  "author": "flowtyio",