Skip to content

Commit ea94fb9

Browse files
authored
Merge pull request #72 from onflow/fix/rebalance-tests-flowalp-submodule
Fix: Rebalance tests - Initialize FlowALP submodule and revert incomplete UniswapV3 integration
2 parents 2164bf4 + 4c7ecde commit ea94fb9

4 files changed

Lines changed: 199 additions & 16 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
2+
.pr-drafts/
23
# flow
34
*.pkey
45
!local/mock-incrementfi.pkey

cadence/contracts/FlowVaultsAutoBalancers.cdc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ access(all) contract FlowVaultsAutoBalancers {
7979
self.account.capabilities.publish(publicCap, at: publicPath)
8080

8181
// issue private capability & set within AutoBalancer
82-
let authorizedCap = self.account.capabilities.storage.issue<auth(FungibleToken.Withdraw, FlowTransactionScheduler.Execute
83-
) &DeFiActions.AutoBalancer>(storagePath)
82+
let authorizedCap = self.account.capabilities.storage.issue<auth(FungibleToken.Withdraw, FlowTransactionScheduler.Execute) &DeFiActions.AutoBalancer>(storagePath)
8483
autoBalancerRef.setSelfCapability(authorizedCap)
8584

8685
// ensure proper configuration before closing

cadence/contracts/FlowVaultsStrategies.cdc

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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,

flow.json

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,6 @@
6060
"testnet": "c16c0b1229843606"
6161
}
6262
},
63-
"FlowTransactionScheduler": {
64-
"source": "mainnet://e467b9dd11fa00df.FlowTransactionScheduler",
65-
"aliases": {
66-
"emulator": "f8d6e0586b0a20c7",
67-
"mainnet": "e467b9dd11fa00df",
68-
"testnet": "8c5303eaa26202d6"
69-
}
70-
},
71-
"FlowTransactionSchedulerUtils": {
72-
"source": "mainnet://e467b9dd11fa00df.FlowTransactionSchedulerUtils",
73-
"aliases": {
74-
"mainnet": "e467b9dd11fa00df"
75-
}
76-
},
7763
"FlowVaults": {
7864
"source": "cadence/contracts/FlowVaults.cdc",
7965
"aliases": {
@@ -358,6 +344,15 @@
358344
"testnet": "dfc20aee650fcbdf"
359345
}
360346
},
347+
"FlowFees": {
348+
"source": "mainnet://f919ee77447b7497.FlowFees",
349+
"hash": "d02bc8295c0434cf2b0a96a77d992f49f52e7865debda84e7a21e176e163a680",
350+
"aliases": {
351+
"emulator": "e5a8b7f23e8b548f",
352+
"mainnet": "f919ee77447b7497",
353+
"testnet": "912d5440f7e3769e"
354+
}
355+
},
361356
"FlowStorageFees": {
362357
"source": "mainnet://e467b9dd11fa00df.FlowStorageFees",
363358
"hash": "e38d8a95f6518b8ff46ce57dfa37b4b850b3638f33d16333096bc625b6d9b51a",
@@ -376,6 +371,24 @@
376371
"testnet": "7e60df042a9c0868"
377372
}
378373
},
374+
"FlowTransactionScheduler": {
375+
"source": "mainnet://e467b9dd11fa00df.FlowTransactionScheduler",
376+
"hash": "312885f5fa3bc70327dfb59edc5da6d30b826002c322db8c566ddf17099310ac",
377+
"aliases": {
378+
"emulator": "f8d6e0586b0a20c7",
379+
"mainnet": "e467b9dd11fa00df",
380+
"testnet": "8c5303eaa26202d6"
381+
}
382+
},
383+
"FlowTransactionSchedulerUtils": {
384+
"source": "mainnet://e467b9dd11fa00df.FlowTransactionSchedulerUtils",
385+
"hash": "2e26d0bf8e6278b79880a47cb3cd55c499777fb96d76bde3f647b546805bc470",
386+
"aliases": {
387+
"emulator": "f8d6e0586b0a20c7",
388+
"mainnet": "e467b9dd11fa00df",
389+
"testnet": "8c5303eaa26202d6"
390+
}
391+
},
379392
"FungibleToken": {
380393
"source": "mainnet://f233dcee88fe0abe.FungibleToken",
381394
"hash": "23c1159cf99b2b039b6b868d782d57ae39b8d784045d81597f100a4782f0285b",

0 commit comments

Comments
 (0)