Smart Contract
FlowYieldVaults
A.b1d63873c3cc9f79.FlowYieldVaults
1// standards
2import FungibleToken from 0xf233dcee88fe0abe
3import Burner from 0xf233dcee88fe0abe
4import ViewResolver from 0x1d7e57aa55817448
5// DeFiActions
6import DeFiActions from 0x6d888f175c158410
7import FlowYieldVaultsClosedBeta from 0xb1d63873c3cc9f79
8
9/// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION
10/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11///
12access(all) contract FlowYieldVaults {
13
14 /* --- FIELDS --- */
15
16 /// Canonical StoragePath for where YieldVaultManager should be stored
17 access(all) let YieldVaultManagerStoragePath: StoragePath
18 /// Canonical PublicPath for where YieldVaultManager Capability should be published
19 access(all) let YieldVaultManagerPublicPath: PublicPath
20 /// Canonical StoragePath for where StrategyFactory should be stored
21 access(all) let FactoryStoragePath: StoragePath
22 /// Canonical PublicPath for where StrategyFactory Capability should be published
23 access(all) let FactoryPublicPath: PublicPath
24
25 /* --- EVENTS --- */
26
27 access(all) event CreatedYieldVault(
28 id: UInt64,
29 uuid: UInt64,
30 strategyType: String,
31 tokenType: String,
32 initialAmount: UFix64,
33 creator: Address?
34 )
35 access(all) event DepositedToYieldVault(
36 id: UInt64,
37 strategyType: String,
38 tokenType: String,
39 amount: UFix64,
40 owner: Address?,
41 fromUUID: UInt64
42 )
43 access(all) event WithdrawnFromYieldVault(
44 id: UInt64,
45 strategyType: String,
46 tokenType: String,
47 amount: UFix64,
48 owner: Address?,
49 toUUID: UInt64
50 )
51 access(all) event AddedToManager(
52 id: UInt64,
53 strategyType: String,
54 owner: Address?,
55 managerUUID: UInt64,
56 tokenType: String
57 )
58 access(all) event BurnedYieldVault(
59 id: UInt64,
60 strategyType: String,
61 tokenType: String,
62 remainingBalance: UFix64,
63 owner: Address?
64 )
65
66 /* --- CONSTRUCTS --- */
67
68 /// Strategy
69 ///
70 /// A Strategy is meant to encapsulate the Sink/Source entrypoints allowing for flows into and out of stacked
71 /// DeFiActions components. These compositions are intended to capitalize on some yield-bearing opportunity so that
72 /// a Strategy bears yield on that which is deposited into it, albeit not without some risk. A Strategy then can be
73 /// thought of as the top-level of a nesting of DeFiActions connectors & adapters where one can deposit & withdraw
74 /// funds into the composed DeFi workflows.
75 ///
76 /// While two types of strategies may not highly differ with respect to their fields, the stacking of DeFiActions
77 /// components & connections they provide access to likely do. This difference in wiring is why the Strategy is a
78 /// resource - because the Type and uniqueness of composition of a given Strategy must be preserved as that is its
79 /// distinguishing factor. These qualities are preserved by restricting the party who can construct it, which for
80 /// resources is within the contract that defines it.
81 ///
82 /// TODO: Consider making Sink/Source multi-asset - we could then make Strategy a composite Sink, Source & do away
83 /// with the added layer of abstraction introduced by a StrategyComposer.
84 access(all) resource interface Strategy : DeFiActions.IdentifiableResource, Burner.Burnable {
85 /// Returns the type of Vaults that this Strategy instance can handle
86 access(all) view fun getSupportedCollateralTypes(): {Type: Bool}
87 /// Returns whether the provided Vault type is supported by this Strategy instance
88 access(all) view fun isSupportedCollateralType(_ type: Type): Bool {
89 return self.getSupportedCollateralTypes()[type] ?? false
90 }
91 /// Returns the balance of the given token available for withdrawal. Note that this may be an estimate due to
92 /// the lack of guarantees inherent to DeFiActions Sources
93 access(all) fun availableBalance(ofToken: Type): UFix64
94 /// Deposits up to the balance of the referenced Vault into this Strategy
95 access(all) fun deposit(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
96 pre {
97 self.isSupportedCollateralType(from.getType()):
98 "Cannot deposit Vault \(from.getType().identifier) to Strategy \(self.getType().identifier) - unsupported deposit type"
99 }
100 }
101 /// Withdraws from this Strategy and returns the resulting Vault of the requested token Type
102 access(FungibleToken.Withdraw) fun withdraw(maxAmount: UFix64, ofToken: Type): @{FungibleToken.Vault} {
103 post {
104 result.getType() == ofToken:
105 "Invalid Vault returns - requests \(ofToken.identifier) but returned \(result.getType().identifier)"
106 }
107 }
108 }
109
110 /// StrategyComposer
111 ///
112 /// A StrategyComposer is responsible for stacking DeFiActions connectors in a manner that composes a final Strategy.
113 /// Since DeFiActions Sink/Source only support single assets and some Strategies may be multi-asset, we deal with
114 /// building a Strategy distinctly from encapsulating the top-level DFA connectors acting as entrypoints in to the
115 /// DeFiActions stack.
116 ///
117 /// TODO: Consider making Sink/Source multi-asset - we could then make Strategy a composite Sink, Source & do away
118 /// with the added layer of abstraction introduced by a StrategyComposer.
119 access(all) resource interface StrategyComposer {
120 /// Returns the Types of Strategies composed by this StrategyComposer
121 access(all) view fun getComposedStrategyTypes(): {Type: Bool}
122 /// Returns the Vault types which can be used to initialize a given Strategy
123 access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool}
124 /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the
125 /// provided Vault type
126 access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool}
127 /// Composes a Strategy of the given type with the provided funds
128 access(all) fun createStrategy(
129 _ type: Type,
130 uniqueID: DeFiActions.UniqueIdentifier,
131 withFunds: @{FungibleToken.Vault}
132 ): @{Strategy} {
133 pre {
134 self.getSupportedInitializationVaults(forStrategy: type)[withFunds.getType()] == true:
135 "Cannot initialize Strategy \(type.identifier) with Vault \(withFunds.getType().identifier) - unsupported initialization Vault"
136 self.getComposedStrategyTypes()[type] == true:
137 "Strategy \(type.identifier) is unsupported by StrategyComposer \(self.getType().identifier)"
138 }
139 }
140 }
141
142 /// StrategyFactory
143 ///
144 /// This resource enables the management of StrategyComposers and the construction of the Strategies they compose.
145 ///
146 access(all) resource StrategyFactory {
147 /// A mapping of StrategyComposers indexed on the related Strategies they can compose
148 access(self) let composers: @{Type: {StrategyComposer}}
149
150 init() {
151 self.composers <- {}
152 }
153
154 /// Returns the Strategy types that can be produced by this StrategyFactory
155 access(all) view fun getSupportedStrategies(): [Type] {
156 return self.composers.keys
157 }
158 /// Returns the Vaults that can be used to initialize a Strategy of the given Type
159 access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} {
160 return self.composers[forStrategy]?.getSupportedInitializationVaults(forStrategy: forStrategy) ?? {}
161 }
162 /// Returns the Vaults that can be deposited to a Strategy initialized with the provided Type
163 access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool} {
164 return self.composers[forStrategy]
165 ?.getSupportedInstanceVaults(forStrategy: forStrategy, initializedWith: initializedWith)
166 ?? {}
167 }
168 /// Initializes a new Strategy of the given type with the provided Vault, identifying all associated DeFiActions
169 /// components by the provided UniqueIdentifier
170 access(all)
171 fun createStrategy(_ type: Type, uniqueID: DeFiActions.UniqueIdentifier, withFunds: @{FungibleToken.Vault}): @{Strategy} {
172 pre {
173 self.composers[type] != nil: "Strategy \(type.identifier) is unsupported"
174 }
175 post {
176 result.getType() == type:
177 "Invalid Strategy returned - expected \(type.identifier) but returned \(result.getType().identifier)"
178 }
179 return <- self._borrowComposer(forStrategy: type)
180 .createStrategy(type, uniqueID: uniqueID, withFunds: <-withFunds)
181 }
182 /// Sets the provided Strategy and Composer association in the StrategyFactory
183 access(Mutate) fun addStrategyComposer(_ strategy: Type, composer: @{StrategyComposer}) {
184 pre {
185 strategy.isSubtype(of: Type<@{Strategy}>()):
186 "Invalid Strategy Type \(strategy.identifier) - provided Type does not implement the Strategy interface"
187 composer.getComposedStrategyTypes()[strategy] == true:
188 "Strategy \(strategy.identifier) cannot be composed by StrategyComposer \(composer.getType().identifier)"
189 }
190 let old <- self.composers[strategy] <- composer
191 Burner.burn(<-old)
192 }
193 /// Removes the Strategy from this StrategyFactory and returns whether the value existed or not
194 access(Mutate) fun removeStrategy(_ strategy: Type): Bool {
195 if let removed <- self.composers.remove(key: strategy) {
196 Burner.burn(<-removed)
197 return true
198 }
199 return false
200 }
201 /// Returns a reference to the StrategyComposer for the requested Strategy type, reverting if none exists
202 access(self) view fun _borrowComposer(forStrategy: Type): &{StrategyComposer} {
203 return &self.composers[forStrategy] as &{StrategyComposer}?
204 ?? panic("Could not borrow StrategyComposer for Strategy \(forStrategy.identifier)")
205 }
206 }
207
208 /// StrategyComposerIssuer
209 ///
210 /// This resource enables the issuance of StrategyComposers, thus safeguarding the issuance of Strategies which
211 /// may utilize resource consumption (i.e. account storage). Contracts defining Strategies that do not require
212 /// such protections may wish to expose Strategy creation publicly via public Capabilities.
213 access(all) resource interface StrategyComposerIssuer {
214 /// Returns the StrategyComposer types supported by this issuer
215 access(all) view fun getSupportedComposers(): {Type: Bool}
216 /// Returns the requested StrategyComposer. If the requested type is unsupported, a revert should be expected
217 access(all) fun issueComposer(_ type: Type): @{StrategyComposer} {
218 post {
219 result.getType() == type:
220 "Invalid StrategyComposer returned - requested \(type.identifier) but returned \(result.getType().identifier)"
221 }
222 }
223 }
224
225 /// YieldVault
226 ///
227 /// A YieldVault is a resource enabling the management of a composed Strategy
228 ///
229 access(all) resource YieldVault : Burner.Burnable, FungibleToken.Receiver, ViewResolver.Resolver {
230 /// The UniqueIdentifier that identifies all related DeFiActions connectors used in the encapsulated Strategy
231 access(contract) let uniqueID: DeFiActions.UniqueIdentifier
232 /// The type of Vault this YieldVault can receive as a deposit and provides as a withdrawal
233 access(self) let vaultType: Type
234 /// The Strategy granting top-level access to the yield-bearing DeFiActions stack
235 access(self) var strategy: @{Strategy}?
236
237 init(strategyType: Type, withVault: @{FungibleToken.Vault}) {
238 self.uniqueID = DeFiActions.createUniqueIdentifier()
239 self.vaultType = withVault.getType()
240 let _strategy <- FlowYieldVaults.createStrategy(
241 type: strategyType,
242 uniqueID: self.uniqueID,
243 withFunds: <-withVault
244 )
245 assert(_strategy.isSupportedCollateralType(self.vaultType),
246 message: "Vault type \(self.vaultType.identifier) is not supported by Strategy \(strategyType.identifier)")
247 self.strategy <-_strategy
248 }
249
250 /// Returns the YieldVault's ID as defined by it's DeFiActions.UniqueIdentifier.id
251 access(all) view fun id(): UInt64 {
252 return self.uniqueID.id
253 }
254 /// Returns the type identifier of the Vault this YieldVault operates on
255 access(all) view fun getVaultTypeIdentifier(): String {
256 return self.vaultType.identifier
257 }
258 /// Returns the balance of the YieldVault's vaultType available via the encapsulated Strategy
259 access(all) fun getYieldVaultBalance(): UFix64 {
260 return self._borrowStrategy().availableBalance(ofToken: self.vaultType)
261 }
262 /// Burner.Burnable conformance - emits the BurnedYieldVault event when burned
263 access(contract) fun burnCallback() {
264 emit BurnedYieldVault(
265 id: self.uniqueID.id,
266 strategyType: self.getStrategyType(),
267 tokenType: self.getVaultTypeIdentifier(),
268 remainingBalance: self.getYieldVaultBalance(),
269 owner: self.owner?.address
270 )
271 let _strategy <- self.strategy <- nil
272 // Force unwrap to ensure burnCallback is called on the Strategy
273 Burner.burn(<-_strategy!)
274 }
275 /// TODO: FlowYieldVaults specific views
276 access(all) view fun getViews(): [Type] {
277 return []
278 }
279 /// TODO: FlowYieldVaults specific view resolution
280 access(all) fun resolveView(_ view: Type): AnyStruct? {
281 return nil
282 }
283 /// Deposits the provided Vault to the Strategy
284 access(all) fun deposit(from: @{FungibleToken.Vault}) {
285 pre {
286 self.isSupportedVaultType(type: from.getType()):
287 "Deposited vault of type \(from.getType().identifier) is not supported by this YieldVault"
288 }
289 let amount = from.balance
290 emit DepositedToYieldVault(
291 id: self.uniqueID.id,
292 strategyType: self.getStrategyType(),
293 tokenType: from.getType().identifier,
294 amount: from.balance,
295 owner: self.owner?.address,
296 fromUUID: from.uuid
297 )
298 self._borrowStrategy().deposit(from: &from as auth(FungibleToken.Withdraw) &{FungibleToken.Vault})
299 assert(
300 from.balance == 0.0,
301 message: "Deposit amount \(amount) of \(self.vaultType.identifier) could not be deposited to YieldVault \(self.id())"
302 )
303 Burner.burn(<-from)
304 }
305 /// Returns the Vaults types supported by this YieldVault as a mapping associated with their current support status
306 access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
307 return self._borrowStrategy().getSupportedCollateralTypes()
308 }
309 /// Returns whether the given Vault type is supported by this YieldVault
310 access(all) view fun isSupportedVaultType(type: Type): Bool {
311 return self.getSupportedVaultTypes()[type] ?? false
312 }
313 /// Returns the strategy type identifier for this YieldVault
314 access(all) view fun getStrategyType(): String {
315 return self.strategy.getType().identifier
316 }
317 /// Withdraws the requested amount from the Strategy
318 access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} {
319 post {
320 result.balance == amount:
321 "Invalid Vault balance returned - requested \(amount) but returned \(result.balance)"
322
323 self.vaultType == result.getType():
324 "Invalid Vault returned - expected \(self.vaultType.identifier) but returned \(result.getType().identifier)"
325 }
326 let available = self._borrowStrategy().availableBalance(ofToken: self.vaultType)
327 assert(amount <= available,
328 message: "Requested amount \(amount) is greater than withdrawable balance of \(available)")
329
330 let res <- self._borrowStrategy().withdraw(maxAmount: amount, ofToken: self.vaultType)
331
332 emit WithdrawnFromYieldVault(
333 id: self.uniqueID.id,
334 strategyType: self.getStrategyType(),
335 tokenType: res.getType().identifier,
336 amount: amount,
337 owner: self.owner?.address,
338 toUUID: res.uuid
339 )
340
341 return <- res
342 }
343 /// Returns an authorized reference to the encapsulated Strategy
344 access(self) view fun _borrowStrategy(): auth(FungibleToken.Withdraw) &{Strategy} {
345 return &self.strategy as auth(FungibleToken.Withdraw) &{Strategy}?
346 ?? panic("Unknown error - could not borrow Strategy for YieldVault #\(self.id())")
347 }
348 }
349
350 /// YieldVaultManager
351 ///
352 /// A YieldVaultManager encapsulates nested YieldVault resources. Through a YieldVaultManager, one can create, manage, and close
353 /// out inner YieldVault resources.
354 ///
355 access(all) resource YieldVaultManager : ViewResolver.ResolverCollection {
356 /// The open YieldVaults managed by this YieldVaultManager
357 access(self) let yieldVaults: @{UInt64: YieldVault}
358
359 init() {
360 self.yieldVaults <- {}
361 }
362
363 /// Borrows the unauthorized YieldVault with the given id, returning `nil` if none exists
364 access(all) view fun borrowYieldVault(id: UInt64): &YieldVault? {
365 return &self.yieldVaults[id]
366 }
367 /// Borrows the YieldVault with the given ID as a ViewResolver.Resolver, returning `nil` if none exists
368 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
369 return &self.yieldVaults[id]
370 }
371 /// Returns the YieldVault IDs managed by this YieldVaultManager
372 access(all) view fun getIDs(): [UInt64] {
373 return self.yieldVaults.keys
374 }
375 /// Returns the number of open YieldVaults currently managed by this YieldVaultManager
376 access(all) view fun getNumberOfYieldVaults(): Int {
377 return self.yieldVaults.length
378 }
379 /// Creates a new YieldVault executing the specified Strategy with the provided funds.
380 /// Returns the newly created YieldVault ID.
381 access(all) fun createYieldVault(
382 betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge,
383 strategyType: Type,
384 withVault: @{FungibleToken.Vault}
385 ): UInt64 {
386 pre {
387 FlowYieldVaultsClosedBeta.validateBeta(self.owner?.address!, betaRef):
388 "Invalid Beta Ref"
389 }
390 let balance = withVault.balance
391 let type = withVault.getType()
392 let yieldVault <-create YieldVault(strategyType: strategyType, withVault: <-withVault)
393 let newID = yieldVault.uniqueID.id
394
395 emit CreatedYieldVault(
396 id: newID,
397 uuid: yieldVault.uuid,
398 strategyType: strategyType.identifier,
399 tokenType: type.identifier,
400 initialAmount: balance,
401 creator: self.owner?.address
402 )
403
404 self.addYieldVault(betaRef: betaRef, <-yieldVault)
405
406 return newID
407 }
408 /// Adds an open YieldVault to this YieldVaultManager resource. This effectively transfers ownership of the newly added
409 /// YieldVault to the owner of this YieldVaultManager
410 access(all) fun addYieldVault(betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge, _ yieldVault: @YieldVault) {
411 pre {
412 self.yieldVaults[yieldVault.uniqueID.id] == nil:
413 "Collision with YieldVault ID \(yieldVault.uniqueID.id) - a YieldVault with this ID already exists"
414
415 FlowYieldVaultsClosedBeta.validateBeta(self.owner?.address!, betaRef):
416 "Invalid Beta Ref"
417 }
418 emit AddedToManager(
419 id: yieldVault.uniqueID.id,
420 strategyType: yieldVault.getStrategyType(),
421 owner: self.owner?.address,
422 managerUUID: self.uuid,
423 tokenType: yieldVault.getVaultTypeIdentifier()
424 )
425 self.yieldVaults[yieldVault.uniqueID.id] <-! yieldVault
426 }
427 /// Deposits additional funds to the specified YieldVault, reverting if none exists with the provided ID
428 access(all) fun depositToYieldVault(betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge, _ id: UInt64, from: @{FungibleToken.Vault}) {
429 pre {
430 self.yieldVaults[id] != nil:
431 "No YieldVault with ID \(id) found"
432
433 FlowYieldVaultsClosedBeta.validateBeta(self.owner?.address!, betaRef):
434 "Invalid Beta Ref"
435 }
436 let yieldVault = (&self.yieldVaults[id] as &YieldVault?)!
437 yieldVault.deposit(from: <-from)
438 }
439 access(self) fun _withdrawYieldVault(id: UInt64): @ YieldVault {
440 pre {
441 self.yieldVaults[id] != nil:
442 "No YieldVault with ID \(id) found"
443 }
444 return <- self.yieldVaults.remove(key: id)!
445 }
446 /// Withdraws the specified YieldVault, reverting if none exists with the provided ID
447 access(FungibleToken.Withdraw) fun withdrawYieldVault(betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge, id: UInt64): @ YieldVault {
448 pre {
449 self.yieldVaults[id] != nil:
450 "No YieldVault with ID \(id) found"
451
452 FlowYieldVaultsClosedBeta.validateBeta(self.owner?.address!, betaRef):
453 "Invalid Beta Ref"
454 }
455 return <- self._withdrawYieldVault(id: id)
456 }
457 /// Withdraws funds from the specified YieldVault in the given amount. The resulting Vault Type will be whatever
458 /// denomination is supported by the YieldVault, so callers should examine the YieldVault to know the resulting Vault to
459 /// expect
460 access(FungibleToken.Withdraw) fun withdrawFromYieldVault(_ id: UInt64, amount: UFix64): @{FungibleToken.Vault} {
461 pre {
462 self.yieldVaults[id] != nil:
463 "No YieldVault with ID \(id) found"
464 }
465 let yieldVault = (&self.yieldVaults[id] as auth(FungibleToken.Withdraw) &YieldVault?)!
466 return <- yieldVault.withdraw(amount: amount)
467 }
468 /// Withdraws and returns all available funds from the specified YieldVault, destroying the YieldVault and access to any
469 /// Strategy-related wiring with it
470 access(FungibleToken.Withdraw) fun closeYieldVault(_ id: UInt64): @{FungibleToken.Vault} {
471 pre {
472 self.yieldVaults[id] != nil:
473 "No YieldVault with ID \(id) found"
474 }
475
476 let yieldVault <- self._withdrawYieldVault(id: id)
477 let res <- yieldVault.withdraw(amount: yieldVault.getYieldVaultBalance())
478 Burner.burn(<-yieldVault)
479 return <-res
480 }
481 }
482
483 /* --- PUBLIC METHODS --- */
484
485 /// Returns the Types of Strategies that can be used in YieldVaults
486 access(all) view fun getSupportedStrategies(): [Type] {
487 return self._borrowFactory().getSupportedStrategies()
488 }
489 /// Returns the Vault types which can be used to initialize a given Strategy
490 access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} {
491 return self._borrowFactory().getSupportedInitializationVaults(forStrategy: forStrategy)
492 }
493 /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the
494 /// provided Vault type
495 access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool} {
496 return self._borrowFactory().getSupportedInstanceVaults(forStrategy: forStrategy, initializedWith: initializedWith)
497 }
498 /// Creates a Strategy of the requested Type using the provided Vault as an initial deposit
499 access(all) fun createStrategy(type: Type, uniqueID: DeFiActions.UniqueIdentifier, withFunds: @{FungibleToken.Vault}): @{Strategy} {
500 return <- self._borrowFactory().createStrategy(type, uniqueID: uniqueID, withFunds: <-withFunds)
501 }
502 /// Creates a YieldVaultManager used to create and manage YieldVaults
503 access(all) fun createYieldVaultManager(betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge): @ YieldVaultManager {
504 return <-create YieldVaultManager()
505 }
506 /// Creates a StrategyFactory resource
507 access(all) fun createStrategyFactory(): @StrategyFactory {
508 return <- create StrategyFactory()
509 }
510
511 /* --- INTERNAL METHODS --- */
512
513 /// Returns a reference to the StrategyFactory stored in this contract's account storage
514 access(self) view fun _borrowFactory(): &StrategyFactory {
515 return self.account.storage.borrow<&StrategyFactory>(from: self.FactoryStoragePath)
516 ?? panic("Could not borrow reference to StrategyFactory from \(self.FactoryStoragePath)")
517 }
518
519 init() {
520 var pathIdentifier = "FlowYieldVaultsYieldVaultManager_\(self.account.address)"
521 self.YieldVaultManagerStoragePath = StoragePath(identifier: pathIdentifier)!
522 self.YieldVaultManagerPublicPath = PublicPath(identifier: pathIdentifier)!
523
524 pathIdentifier = "FlowYieldVaultsStrategyFactory_\(self.account.address)"
525 self.FactoryStoragePath = StoragePath(identifier: pathIdentifier)!
526 self.FactoryPublicPath = PublicPath(identifier: pathIdentifier)!
527
528 // configure a StrategyFactory in storage and publish a public Capability
529 self.account.storage.save(<-create StrategyFactory(), to: self.FactoryStoragePath)
530 let cap = self.account.capabilities.storage.issue<&StrategyFactory>(self.FactoryStoragePath)
531 self.account.capabilities.publish(cap, at: self.FactoryPublicPath)
532 }
533}
534