@@ -128,6 +128,176 @@ access(all) contract FlowVaultsStrategies {
128128 return { Type <@FlowToken.Vault >(): true }
129129 }
130130
131+ /// Composes a Strategy of the given type with the provided funds
132+ access (all ) fun createStrategy (
133+ _ type : Type ,
134+ uniqueID : DeFiActions .UniqueIdentifier ,
135+ withFunds : @{FungibleToken .Vault }
136+ ): @{FlowVaults .Strategy } {
137+ // this PriceOracle is mocked and will be shared by all components used in the TracerStrategy
138+ // TODO: add ERC4626 price oracle
139+ let oracle = MockOracle .PriceOracle ()
140+
141+ // assign token types
142+
143+ let moetTokenType : Type = Type <@MOET.Vault >()
144+ let yieldTokenType = Type <@YieldToken.Vault >()
145+ // assign collateral & flow token types
146+ let collateralType = withFunds .getType ()
147+
148+ // configure and AutoBalancer for this stack
149+ let autoBalancer = FlowVaultsAutoBalancers ._initNewAutoBalancer (
150+ oracle : oracle , // used to determine value of deposits & when to rebalance
151+ vaultType : yieldTokenType , // the type of Vault held by the AutoBalancer
152+ lowerThreshold : 0.95 , // set AutoBalancer to pull from rebalanceSource when balance is 5% below value of deposits
153+ upperThreshold : 1.05 , // set AutoBalancer to push to rebalanceSink when balance is 5% below value of deposits
154+ rebalanceSink : nil , // nil on init - will be set once a PositionSink is available
155+ rebalanceSource : nil , // nil on init - not set for TracerStrategy
156+ uniqueID : uniqueID // identifies AutoBalancer as part of this Strategy
157+ )
158+ // enables deposits of YieldToken to the AutoBalancer
159+ let abaSink = autoBalancer .createBalancerSink () ?? panic (" Could not retrieve Sink from AutoBalancer with id \( uniqueID .id ) " )
160+ // enables withdrawals of YieldToken from the AutoBalancer
161+ let abaSource = autoBalancer .createBalancerSource () ?? panic (" Could not retrieve Sink from AutoBalancer with id \( uniqueID .id ) " )
162+
163+ // init Stable <> YIELD swappers
164+ //
165+ // Stable -> YieldToken
166+ let stableToYieldSwapper = MockSwapper .Swapper (
167+ inVault : moetTokenType ,
168+ outVault : yieldTokenType ,
169+ uniqueID : uniqueID
170+ )
171+ // YieldToken -> Stable
172+ let yieldToStableSwapper = MockSwapper .Swapper (
173+ inVault : yieldTokenType ,
174+ outVault : moetTokenType ,
175+ uniqueID : uniqueID
176+ )
177+
178+ // init SwapSink directing swapped funds to AutoBalancer
179+ //
180+ // Swaps provided Stable to YieldToken & deposits to the AutoBalancer
181+ let abaSwapSink = SwapConnectors .SwapSink (swapper : stableToYieldSwapper , sink : abaSink , uniqueID : uniqueID )
182+ // Swaps YieldToken & provides swapped Stable, sourcing YieldToken from the AutoBalancer
183+ let abaSwapSource = SwapConnectors .SwapSource (swapper : yieldToStableSwapper , source : abaSource , uniqueID : uniqueID )
184+
185+ // open a FlowALP position
186+ let poolCap = FlowVaultsStrategies .account .storage .load <Capability <auth (FlowALP.EParticipant , FlowALP.EPosition ) &FlowALP.Pool >>(
187+ from : FlowALP .PoolCapStoragePath
188+ ) ?? panic (" Missing pool capability" )
189+
190+ let poolRef = poolCap .borrow () ?? panic (" Invalid Pool Cap" )
191+
192+ let pid = poolRef .createPosition (
193+ funds : <- withFunds ,
194+ issuanceSink : abaSwapSink ,
195+ repaymentSource : abaSwapSource ,
196+ pushToDrawDownSink : true
197+ )
198+ let position = FlowALP .Position (id : pid , pool : poolCap )
199+ FlowVaultsStrategies .account .storage .save (poolCap , to : FlowALP .PoolCapStoragePath )
200+
201+ // get Sink & Source connectors relating to the new Position
202+ let positionSink = position .createSinkWithOptions (type : collateralType , pushToDrawDownSink : true )
203+ let positionSource = position .createSourceWithOptions (type : collateralType , pullFromTopUpSource : true ) // TODO: may need to be false
204+
205+ // init YieldToken -> FLOW Swapper
206+ let yieldToFlowSwapper = MockSwapper .Swapper (
207+ inVault : yieldTokenType ,
208+ outVault : collateralType ,
209+ uniqueID : uniqueID
210+ )
211+ // allows for YieldToken to be deposited to the Position
212+ let positionSwapSink = SwapConnectors .SwapSink (swapper : yieldToFlowSwapper , sink : positionSink , uniqueID : uniqueID )
213+
214+ // set the AutoBalancer's rebalance Sink which it will use to deposit overflown value,
215+ // recollateralizing the position
216+ autoBalancer .setSink (positionSwapSink , updateSinkID : true )
217+
218+ return <- create TracerStrategy (
219+ id : DeFiActions .createUniqueIdentifier (),
220+ collateralType : collateralType ,
221+ position : position
222+ )
223+ }
224+ }
225+
226+ /// This strategy uses mUSDC vaults
227+ access (all ) resource mUSDCStrategy : FlowVaults .Strategy , DeFiActions .IdentifiableResource {
228+ /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
229+ /// specific Identifier to associated connectors on construction
230+ access (contract ) var uniqueID : DeFiActions .UniqueIdentifier ?
231+ access (self ) let position : FlowALP .Position
232+ access (self ) var sink : {DeFiActions .Sink }
233+ access (self ) var source : {DeFiActions .Source }
234+
235+ init (id : DeFiActions .UniqueIdentifier , collateralType : Type , position : FlowALP .Position ) {
236+ self .uniqueID = id
237+ self .position = position
238+ self .sink = position .createSink (type : collateralType )
239+ self .source = position .createSourceWithOptions (type : collateralType , pullFromTopUpSource : true )
240+ }
241+
242+ // Inherited from FlowVaults.Strategy default implementation
243+ // access(all) view fun isSupportedCollateralType(_ type: Type): Bool
244+
245+ access (all ) view fun getSupportedCollateralTypes (): {Type : Bool } {
246+ return { self .sink .getSinkType (): true }
247+ }
248+ /// Returns the amount available for withdrawal via the inner Source
249+ access (all ) fun availableBalance (ofToken : Type ): UFix64 {
250+ return ofToken == self .source .getSourceType () ? self .source .minimumAvailable () : 0.0
251+ }
252+ /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference
253+ access (all ) fun deposit (from : auth (FungibleToken.Withdraw ) &{FungibleToken .Vault }) {
254+ self .sink .depositCapacity (from : from )
255+ }
256+ /// Withdraws up to the max amount, returning the withdrawn Vault. If the requested token type is unsupported,
257+ /// an empty Vault is returned.
258+ access (FungibleToken.Withdraw ) fun withdraw (maxAmount : UFix64 , ofToken : Type ): @{FungibleToken .Vault } {
259+ if ofToken ! = self .source .getSourceType () {
260+ return <- DeFiActionsUtils .getEmptyVault (ofToken )
261+ }
262+ return <- self .source .withdrawAvailable (maxAmount : maxAmount )
263+ }
264+ /// Executed when a Strategy is burned, cleaning up the Strategy's stored AutoBalancer
265+ access (contract ) fun burnCallback () {
266+ FlowVaultsAutoBalancers ._cleanupAutoBalancer (id : self .id ()! )
267+ }
268+ access (all ) fun getComponentInfo (): DeFiActions .ComponentInfo {
269+ return DeFiActions .ComponentInfo (
270+ type : self .getType (),
271+ id : self .id (),
272+ innerComponents : []
273+ )
274+ }
275+ access (contract ) view fun copyID (): DeFiActions .UniqueIdentifier ? {
276+ return self .uniqueID
277+ }
278+ access (contract ) fun setID (_ id : DeFiActions .UniqueIdentifier ? ) {
279+ self .uniqueID = id
280+ }
281+ }
282+
283+ /// This StrategyComposer builds a mUSDCStrategy
284+ access (all ) resource mUSDCStrategyComposer : FlowVaults .StrategyComposer {
285+ /// Returns the Types of Strategies composed by this StrategyComposer
286+ access (all ) view fun getComposedStrategyTypes (): {Type : Bool } {
287+ return { Type <@mUSDCStrategy >(): true }
288+ }
289+
290+ /// Returns the Vault types which can be used to initialize a given Strategy
291+ access (all ) view fun getSupportedInitializationVaults (forStrategy : Type ): {Type : Bool } {
292+ return { Type <@FlowToken.Vault >(): true }
293+ }
294+
295+ /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the
296+ /// provided Vault type
297+ access (all ) view fun getSupportedInstanceVaults (forStrategy : Type , initializedWith : Type ): {Type : Bool } {
298+ return { Type <@FlowToken.Vault >(): true }
299+ }
300+
131301 /// Composes a Strategy of the given type with the provided funds
132302 access (all ) fun createStrategy (
133303 _ type : Type ,
0 commit comments