diff --git a/README.md b/README.md index 074a6334..1cfbf480 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The main contract that orchestrates the entire yield farming system: - **YieldVault Resource**: Represents a user's position in a specific strategy - **YieldVaultManager**: Manages multiple YieldVault positions for a user account -#### 2. FlowYieldVaultsStrategies.cdc - Strategy Implementations +#### 2. MockStrategies.cdc - Strategy Implementations Implements specific yield strategies: @@ -63,28 +63,32 @@ Mock FungibleToken implementations representing: | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0xd27920b6384e2a78 | DeFiActions | TBD | -| FlowALP | 0xd27920b6384e2a78 | FlowALP | TBD | +| FlowALPv0 | 0xd27920b6384e2a78 | FlowALPv0 | TBD | | FlowYieldVaults | 0xd27920b6384e2a78 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategies | 0xd27920b6384e2a78 | FlowYieldVaultsStrategies | TBD | +| FlowYieldVaultsStrategiesV2 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV2 | TBD | +| PMStrategiesV1 | 0xd27920b6384e2a78 | PMStrategiesV1 | TBD | | MOET | 0xd27920b6384e2a78 | MOET | 0x51f5cc5f50afb81e8f23c926080fa38c3024b238 | | USDC | 0xdfc20aee650fcbdf | EVMVMBridgedToken_d431955d55a99ef69beb96ba34718d0f9fbc91b1 | 0xd431955D55a99EF69BEb96BA34718d0f9fBc91b1 | +| PYUSD0 | 0xdfc20aee650fcbdf | EVMVMBridgedToken_d7d43ab7b365f0d0789ae83f4385fa710ffdc98f | 0xd7d43ab7b365f0d0789aE83F4385fA710FfdC98F | | wBTC | 0xdfc20aee650fcbdf | EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6 | 0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6 | | wETH | 0xdfc20aee650fcbdf | EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848 | 0x059A77239daFa770977DD9f1E98632C3E4559848 | -| mUSDC (ERC4626) | 0xdfc20aee650fcbdf | EVMVMBridgedToken_4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95 | 0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95 | +| FUSDEV (ERC4626) | 0xdfc20aee650fcbdf | EVMVMBridgedToken_61b44d19486ee492449e83c1201581c754e9e1e1 | 0x61b44D19486EE492449E83C1201581C754e9e1E1 | #### Mainnet | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0x6d888f175c158410 | DeFiActions | TBD | -| FlowALP | 0x6b00ff876c299c61 | FlowALP | TBD | +| FlowALPv0 | 0x6b00ff876c299c61 | FlowALPv0 | TBD | | FlowYieldVaults | 0xb1d63873c3cc9f79 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategies | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategies | TBD | +| FlowYieldVaultsStrategiesV2 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV2 | TBD | +| PMStrategiesV1 | 0xb1d63873c3cc9f79 | PMStrategiesV1 | TBD | | MOET | 0x6b00ff876c299c61 | MOET | 0x213979bB8A9A86966999b3AA797C1fcf3B967ae2 | | USDC | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_f1815bd50389c46847f0bda824ec8da914045d14 | 0xF1815bd50389c46847f0Bda824eC8da914045D14 | | USDF | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabed | 0x2aabea2058b5ac2d339b163c6ab6f2b6d53aabed | +| PYUSD0 | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750 | 0x99aF3EeA856556646C98c8B9b2548Fe815240750 | | cbBTC | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_a0197b2044d28b08be34d98b23c9312158ea9a18 | 0xA0197b2044D28b08Be34d98b23c9312158Ea9A18 | | wETH | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590 | 0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590 | -| tauUSDF (ERC4626) | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_c52E820d2D6207D18667a97e2c6Ac22eB26E803c | 0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c | +| FUSDEV (ERC4626) | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_d069d989e2f44b70c65347d1853c0c67e10a9f8d | 0xd069d989e2F44B70c65347d1853C0c67e10a9F8D | ## How the System Works @@ -573,7 +577,7 @@ Position Health = Effective Collateral / Effective Debt #### Health Computation Function ```cadence -// From FlowALP.cdc +// From FlowALPv0.cdc access(all) fun healthComputation(effectiveCollateral: UFix64, effectiveDebt: UFix64): UFix64 { if effectiveCollateral == 0.0 { return 0.0 @@ -969,7 +973,7 @@ flow transactions send cadence/transactions/mocks/swapper/set_liquidity_connecto # Step 5: Create YieldVault position echo "Creating YieldVault position with $INITIAL_DEPOSIT FLOW..." flow transactions send cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ - "A.045a1763c93006ca.FlowYieldVaultsStrategies.TracerStrategy" \ + "A.045a1763c93006ca.MockStrategies.TracerStrategy" \ "A.0ae53cb6e3f42a79.FlowToken.Vault" \ $INITIAL_DEPOSIT \ --signer test-account diff --git a/cadence/contracts/FlowYieldVaults.cdc b/cadence/contracts/FlowYieldVaults.cdc index ccf618ea..a3e3ae95 100644 --- a/cadence/contracts/FlowYieldVaults.cdc +++ b/cadence/contracts/FlowYieldVaults.cdc @@ -319,6 +319,7 @@ access(all) contract FlowYieldVaults { post { result.balance == amount: "Invalid Vault balance returned - requested \(amount) but returned \(result.balance)" + self.vaultType == result.getType(): "Invalid Vault returned - expected \(self.vaultType.identifier) but returned \(result.getType().identifier)" } diff --git a/cadence/contracts/FlowYieldVaultsStrategies.cdc b/cadence/contracts/FlowYieldVaultsStrategies.cdc deleted file mode 100644 index 70b398ed..00000000 --- a/cadence/contracts/FlowYieldVaultsStrategies.cdc +++ /dev/null @@ -1,703 +0,0 @@ -// standards -import "FungibleToken" -import "FlowToken" -import "EVM" -// DeFiActions -import "DeFiActionsUtils" -import "DeFiActions" -import "SwapConnectors" -import "FungibleTokenConnectors" -// amm integration -import "UniswapV3SwapConnectors" -import "ERC4626SwapConnectors" -import "ERC4626Utils" -// Lending protocol -import "FlowALPv1" -// FlowYieldVaults platform -import "FlowYieldVaultsClosedBeta" -import "FlowYieldVaults" -import "FlowYieldVaultsAutoBalancers" -// scheduler -import "FlowTransactionScheduler" -import "FlowYieldVaultsSchedulerRegistry" -// tokens -import "YieldToken" -import "MOET" -// vm bridge -import "FlowEVMBridgeConfig" -import "FlowEVMBridgeUtils" -import "FlowEVMBridge" -// live oracles -import "ERC4626PriceOracles" -// mocks -import "MockOracle" -import "MockSwapper" - -/// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION -/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -/// -/// FlowYieldVaultsStrategies -/// -/// This contract defines Strategies used in the FlowYieldVaults platform. -/// -/// A Strategy instance can be thought of as objects wrapping a stack of DeFiActions connectors wired together to -/// (optimally) generate some yield on initial deposits. Strategies can be simple such as swapping into a yield-bearing -/// asset (such as stFLOW) or more complex DeFiActions stacks. -/// -/// A StrategyComposer is tasked with the creation of a supported Strategy. It's within the stacking of DeFiActions -/// connectors that the true power of the components lies. -/// -access(all) contract FlowYieldVaultsStrategies { - - access(all) let univ3FactoryEVMAddress: EVM.EVMAddress - access(all) let univ3RouterEVMAddress: EVM.EVMAddress - access(all) let univ3QuoterEVMAddress: EVM.EVMAddress - access(all) let yieldTokenEVMAddress: EVM.EVMAddress - - /// Canonical StoragePath where the StrategyComposerIssuer should be stored - access(all) let IssuerStoragePath: StoragePath - - /// This is the first Strategy implementation, wrapping a @FlowALPv1.Position along with its related Sink & - /// Source. While this object is a simple wrapper for the top-level collateralized position, the true magic of the - /// DeFiActions is in the stacking of the related connectors. This stacking logic can be found in the - /// TracerStrategyComposer construct. - access(all) resource TracerStrategy : FlowYieldVaults.Strategy, DeFiActions.IdentifiableResource { - /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol- - /// specific Identifier to associated connectors on construction - access(contract) var uniqueID: DeFiActions.UniqueIdentifier? - access(self) let position: @FlowALPv1.Position - access(self) var sink: {DeFiActions.Sink} - access(self) var source: {DeFiActions.Source} - - init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: @FlowALPv1.Position) { - self.uniqueID = id - self.sink = position.createSink(type: collateralType) - self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) - self.position <-position - } - - // Inherited from FlowYieldVaults.Strategy default implementation - // access(all) view fun isSupportedCollateralType(_ type: Type): Bool - - access(all) view fun getSupportedCollateralTypes(): {Type: Bool} { - return { self.sink.getSinkType(): true } - } - /// Returns the amount available for withdrawal via the inner Source - access(all) fun availableBalance(ofToken: Type): UFix64 { - return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 - } - /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference - access(all) fun deposit(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) { - self.sink.depositCapacity(from: from) - } - /// Withdraws up to the max amount, returning the withdrawn Vault. If the requested token type is unsupported, - /// an empty Vault is returned. - access(FungibleToken.Withdraw) fun withdraw(maxAmount: UFix64, ofToken: Type): @{FungibleToken.Vault} { - if ofToken != self.source.getSourceType() { - return <- DeFiActionsUtils.getEmptyVault(ofToken) - } - return <- self.source.withdrawAvailable(maxAmount: maxAmount) - } - /// Executed when a Strategy is burned, cleaning up the Strategy's stored AutoBalancer - access(contract) fun burnCallback() { - FlowYieldVaultsAutoBalancers._cleanupAutoBalancer(id: self.id()!) - } - access(all) fun getComponentInfo(): DeFiActions.ComponentInfo { - return DeFiActions.ComponentInfo( - type: self.getType(), - id: self.id(), - innerComponents: [] - ) - } - access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? { - return self.uniqueID - } - access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) { - self.uniqueID = id - } - } - - /// This StrategyComposer builds a TracerStrategy - access(all) resource TracerStrategyComposer : FlowYieldVaults.StrategyComposer { - /// Returns the Types of Strategies composed by this StrategyComposer - access(all) view fun getComposedStrategyTypes(): {Type: Bool} { - return { Type<@TracerStrategy>(): true } - } - - /// Returns the Vault types which can be used to initialize a given Strategy - access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} { - return { Type<@FlowToken.Vault>(): true } - } - - /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the - /// provided Vault type - access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool} { - return { Type<@FlowToken.Vault>(): true } - } - - /// Composes a Strategy of the given type with the provided funds - access(all) fun createStrategy( - _ type: Type, - uniqueID: DeFiActions.UniqueIdentifier, - withFunds: @{FungibleToken.Vault} - ): @{FlowYieldVaults.Strategy} { - // this PriceOracle is mocked and will be shared by all components used in the TracerStrategy - // TODO: add ERC4626 price oracle - let oracle = MockOracle.PriceOracle() - - // assign token types - - let moetTokenType: Type = Type<@MOET.Vault>() - let yieldTokenType = Type<@YieldToken.Vault>() - // assign collateral & flow token types - let collateralType = withFunds.getType() - - // Create recurring config for automatic rebalancing - let recurringConfig = FlowYieldVaultsStrategies._createRecurringConfig(withID: uniqueID) - - // configure and AutoBalancer for this stack with native recurring scheduling - let autoBalancer = FlowYieldVaultsAutoBalancers._initNewAutoBalancer( - oracle: oracle, // used to determine value of deposits & when to rebalance - vaultType: yieldTokenType, // the type of Vault held by the AutoBalancer - lowerThreshold: 0.95, // set AutoBalancer to pull from rebalanceSource when balance is 5% below value of deposits - upperThreshold: 1.05, // set AutoBalancer to push to rebalanceSink when balance is 5% below value of deposits - rebalanceSink: nil, // nil on init - will be set once a PositionSink is available - rebalanceSource: nil, // nil on init - not set for TracerStrategy - recurringConfig: recurringConfig, // enables native AutoBalancer self-scheduling - uniqueID: uniqueID // identifies AutoBalancer as part of this Strategy - ) - // enables deposits of YieldToken to the AutoBalancer - let abaSink = autoBalancer.createBalancerSink() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") - // enables withdrawals of YieldToken from the AutoBalancer - let abaSource = autoBalancer.createBalancerSource() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") - - // init Stable <> YIELD swappers - // - // Stable -> YieldToken - let stableToYieldSwapper = MockSwapper.Swapper( - inVault: moetTokenType, - outVault: yieldTokenType, - uniqueID: uniqueID - ) - // YieldToken -> Stable - let yieldToStableSwapper = MockSwapper.Swapper( - inVault: yieldTokenType, - outVault: moetTokenType, - uniqueID: uniqueID - ) - - // init SwapSink directing swapped funds to AutoBalancer - // - // Swaps provided Stable to YieldToken & deposits to the AutoBalancer - let abaSwapSink = SwapConnectors.SwapSink(swapper: stableToYieldSwapper, sink: abaSink, uniqueID: uniqueID) - // Swaps YieldToken & provides swapped Stable, sourcing YieldToken from the AutoBalancer - let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToStableSwapper, source: abaSource, uniqueID: uniqueID) - - // open a FlowALP position - let poolCap = FlowYieldVaultsStrategies.account.storage.load>( - from: FlowALPv1.PoolCapStoragePath - ) ?? panic("Missing pool capability") - - let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") - - let position <- poolRef.createPosition( - funds: <-withFunds, - issuanceSink: abaSwapSink, - repaymentSource: abaSwapSource, - pushToDrawDownSink: true - ) - FlowYieldVaultsStrategies.account.storage.save(poolCap, to: FlowALPv1.PoolCapStoragePath) - - // get Sink & Source connectors relating to the new Position - let positionSink = position.createSinkWithOptions(type: collateralType, pushToDrawDownSink: true) - let positionSource = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) // TODO: may need to be false - - // init YieldToken -> FLOW Swapper - let yieldToFlowSwapper = MockSwapper.Swapper( - inVault: yieldTokenType, - outVault: collateralType, - uniqueID: uniqueID - ) - // allows for YieldToken to be deposited to the Position - let positionSwapSink = SwapConnectors.SwapSink(swapper: yieldToFlowSwapper, sink: positionSink, uniqueID: uniqueID) - - // set the AutoBalancer's rebalance Sink which it will use to deposit overflown value, - // recollateralizing the position - autoBalancer.setSink(positionSwapSink, updateSinkID: true) - - // Use the same uniqueID passed to createStrategy so Strategy.burnCallback - // calls _cleanupAutoBalancer with the correct ID - return <-create TracerStrategy( - id: uniqueID, - collateralType: collateralType, - position: <- position - ) - } - } - - /// This strategy uses mUSDC vaults - access(all) resource mUSDCStrategy : FlowYieldVaults.Strategy, DeFiActions.IdentifiableResource { - /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol- - /// specific Identifier to associated connectors on construction - access(contract) var uniqueID: DeFiActions.UniqueIdentifier? - access(self) let position: @FlowALPv1.Position - access(self) var sink: {DeFiActions.Sink} - access(self) var source: {DeFiActions.Source} - - init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: @FlowALPv1.Position) { - self.uniqueID = id - self.sink = position.createSink(type: collateralType) - self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) - self.position <-position - } - - // Inherited from FlowYieldVaults.Strategy default implementation - // access(all) view fun isSupportedCollateralType(_ type: Type): Bool - - access(all) view fun getSupportedCollateralTypes(): {Type: Bool} { - return { self.sink.getSinkType(): true } - } - /// Returns the amount available for withdrawal via the inner Source - access(all) fun availableBalance(ofToken: Type): UFix64 { - return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 - } - /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference - access(all) fun deposit(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) { - self.sink.depositCapacity(from: from) - } - /// Withdraws up to the max amount, returning the withdrawn Vault. If the requested token type is unsupported, - /// an empty Vault is returned. - access(FungibleToken.Withdraw) fun withdraw(maxAmount: UFix64, ofToken: Type): @{FungibleToken.Vault} { - if ofToken != self.source.getSourceType() { - return <- DeFiActionsUtils.getEmptyVault(ofToken) - } - return <- self.source.withdrawAvailable(maxAmount: maxAmount) - } - /// Executed when a Strategy is burned, cleaning up the Strategy's stored AutoBalancer - access(contract) fun burnCallback() { - FlowYieldVaultsAutoBalancers._cleanupAutoBalancer(id: self.id()!) - } - access(all) fun getComponentInfo(): DeFiActions.ComponentInfo { - return DeFiActions.ComponentInfo( - type: self.getType(), - id: self.id(), - innerComponents: [ - self.sink.getComponentInfo(), - self.source.getComponentInfo() - ] - ) - } - access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? { - return self.uniqueID - } - access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) { - self.uniqueID = id - } - } - - /// This StrategyComposer builds a mUSDCStrategy - access(all) resource mUSDCStrategyComposer : FlowYieldVaults.StrategyComposer { - /// { Strategy Type: { Collateral Type: { String: AnyStruct } } } - access(self) let config: {Type: {Type: {String: AnyStruct}}} - - init(_ config: {Type: {Type: {String: AnyStruct}}}) { - self.config = config - } - - /// Returns the Types of Strategies composed by this StrategyComposer - access(all) view fun getComposedStrategyTypes(): {Type: Bool} { - let composed: {Type: Bool} = {} - for t in self.config.keys { - composed[t] = true - } - return composed - } - - /// Returns the Vault types which can be used to initialize a given Strategy - access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} { - let supported: {Type: Bool} = {} - if let strategyConfig = &self.config[forStrategy] as &{Type: {String: AnyStruct}}? { - for collateralType in strategyConfig.keys { - supported[collateralType] = true - } - } - return supported - } - - /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the - /// provided Vault type - access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool} { - let supportedInitVaults = self.getSupportedInitializationVaults(forStrategy: forStrategy) - if supportedInitVaults[initializedWith] == true { - return { initializedWith: true } - } - return {} - } - - /// Composes a Strategy of the given type with the provided funds - /// TODO: Open up for multiple collateral types - access(all) fun createStrategy( - _ type: Type, - uniqueID: DeFiActions.UniqueIdentifier, - withFunds: @{FungibleToken.Vault} - ): @{FlowYieldVaults.Strategy} { - let collateralType = withFunds.getType() - let strategyConfig = self.config[type] - ?? panic("Could not find a config for Strategy \(type.identifier) initialized with \(collateralType.identifier)") - let collateralConfig = strategyConfig[collateralType] - ?? panic("Could not find config for collateral \(collateralType.identifier) when creating Strategy \(type.identifier)") - - // assign token types & associated EVM Addresses - let moetTokenType: Type = Type<@MOET.Vault>() - let moetTokenEVMAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: moetTokenType) - ?? panic("Token Vault type \(moetTokenType.identifier) has not yet been registered with the VMbridge") - let yieldTokenEVMAddress = collateralConfig["yieldTokenEVMAddress"] as? EVM.EVMAddress ?? panic("Could not find \"yieldTokenEVMAddress\" in config") - let yieldTokenType = FlowEVMBridgeConfig.getTypeAssociated(with: yieldTokenEVMAddress) - ?? panic("Could not retrieve the VM Bridge associated Type for the yield token address \(yieldTokenEVMAddress.toString())") - - // assign underlying asset EVM address & type - assumed to be stablecoin for the tracer strategy - let underlying4626AssetEVMAddress = ERC4626Utils.underlyingAssetEVMAddress( - vault: yieldTokenEVMAddress - ) ?? panic("Could not get the underlying asset's EVM address for ERC4626Vault \(yieldTokenEVMAddress.toString())") - let underlying4626AssetType = FlowEVMBridgeConfig.getTypeAssociated(with: underlying4626AssetEVMAddress) - ?? panic("Could not retrieve the VM Bridge associated Type for the ERC4626 underlying asset \(underlying4626AssetEVMAddress.toString())") - - // create the oracle for the assets to be held in the AutoBalancer retrieving the NAV of the 4626 vault - let yieldTokenOracle = ERC4626PriceOracles.PriceOracle( - vault: yieldTokenEVMAddress, - asset: underlying4626AssetType, - // asset: moetTokenType, // TODO: make a composite oracle that returns the price denominated in MOET - uniqueID: uniqueID - ) - - // Create recurring config for automatic rebalancing - let recurringConfig = FlowYieldVaultsStrategies._createRecurringConfig(withID: uniqueID) - - // configure and AutoBalancer for this stack with native recurring scheduling - let autoBalancer = FlowYieldVaultsAutoBalancers._initNewAutoBalancer( - oracle: yieldTokenOracle, // used to determine value of deposits & when to rebalance - vaultType: yieldTokenType, // the type of Vault held by the AutoBalancer - lowerThreshold: 0.95, // set AutoBalancer to pull from rebalanceSource when balance is 5% below value of deposits - upperThreshold: 1.05, // set AutoBalancer to push to rebalanceSink when balance is 5% below value of deposits - rebalanceSink: nil, // nil on init - will be set once a PositionSink is available - rebalanceSource: nil, // nil on init - not set for TracerStrategy - recurringConfig: recurringConfig, // enables native AutoBalancer self-scheduling - uniqueID: uniqueID // identifies AutoBalancer as part of this Strategy - ) - // enables deposits of YieldToken to the AutoBalancer - let abaSink = autoBalancer.createBalancerSink() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") - // enables withdrawals of YieldToken from the AutoBalancer - let abaSource = autoBalancer.createBalancerSource() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") - - // create MOET <-> YIELD swappers - // - // get Uniswap V3 addresses from config - let univ3FactoryEVMAddress = collateralConfig["univ3FactoryEVMAddress"] as? EVM.EVMAddress ?? panic("Could not find \"univ3FactoryEVMAddress\" in config") - let univ3RouterEVMAddress = collateralConfig["univ3RouterEVMAddress"] as? EVM.EVMAddress ?? panic("Could not find \"univ3RouterEVMAddress\" in config") - let univ3QuoterEVMAddress = collateralConfig["univ3QuoterEVMAddress"] as? EVM.EVMAddress ?? panic("Could not find \"univ3QuoterEVMAddress\" in config") - // MOET -> YIELD - MOET can swap to YieldToken via two primary routes - // - via AMM swap pairing MOET <-> YIELD - // - via 4626 vault, swapping first to underlying asset then depositing to the 4626 vault - // MOET -> YIELD high-level Swapper then contains - // - MultiSwapper aggregates across two sub-swappers - // - MOET -> YIELD (UniV3 Swapper) - // - SequentialSwapper - // - MOET -> UNDERLYING (UniV3 Swapper) - // - UNDERLYING -> YIELD (ERC4626Swapper) - let moetToYieldAMMSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: univ3FactoryEVMAddress, - routerAddress: univ3RouterEVMAddress, - quoterAddress: univ3QuoterEVMAddress, - tokenPath: [moetTokenEVMAddress, yieldTokenEVMAddress], - feePath: [100], - inVault: moetTokenType, - outVault: yieldTokenType, - coaCapability: FlowYieldVaultsStrategies._getCOACapability(), - uniqueID: uniqueID - ) - // Swap MOET -> UNDERLYING via AMM - let moetToUnderlyingAssetSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: univ3FactoryEVMAddress, - routerAddress: univ3RouterEVMAddress, - quoterAddress: univ3QuoterEVMAddress, - tokenPath: [moetTokenEVMAddress, underlying4626AssetEVMAddress], - feePath: [100], - inVault: moetTokenType, - outVault: underlying4626AssetType, - coaCapability: FlowYieldVaultsStrategies._getCOACapability(), - uniqueID: uniqueID - ) - // Swap UNDERLYING -> YIELD via ERC4626 Vault - let underlyingTo4626Swapper = ERC4626SwapConnectors.Swapper( - asset: underlying4626AssetType, - vault: yieldTokenEVMAddress, - coa: FlowYieldVaultsStrategies._getCOACapability(), - feeSource: FlowYieldVaultsStrategies._createFeeSource(withID: uniqueID), - uniqueID: uniqueID - ) - // Compose v3 swapper & 4626 swapper into sequential swapper for MOET -> UNDERLYING -> YIELD - let moetToYieldSeqSwapper = SwapConnectors.SequentialSwapper( - swappers: [moetToUnderlyingAssetSwapper, underlyingTo4626Swapper], - uniqueID: uniqueID - ) - // Finally, add the two MOET -> YIELD swappers into an aggregate MultiSwapper - let moetToYieldSwapper = SwapConnectors.MultiSwapper( - inVault: moetTokenType, - outVault: yieldTokenType, - swappers: [moetToYieldAMMSwapper, moetToYieldSeqSwapper], - uniqueID: uniqueID - ) - - // YIELD -> MOET - // - Targets the MOET <-> YIELD pool as the only route since withdraws from the ERC4626 Vault are async - let yieldToMOETSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: univ3FactoryEVMAddress, - routerAddress: univ3RouterEVMAddress, - quoterAddress: univ3QuoterEVMAddress, - tokenPath: [yieldTokenEVMAddress, moetTokenEVMAddress], - feePath: [100], - inVault: yieldTokenType, - outVault: moetTokenType, - coaCapability: FlowYieldVaultsStrategies._getCOACapability(), - uniqueID: uniqueID - ) - - // init SwapSink directing swapped funds to AutoBalancer - // - // Swaps provided MOET to YIELD & deposits to the AutoBalancer - let abaSwapSink = SwapConnectors.SwapSink(swapper: moetToYieldSwapper, sink: abaSink, uniqueID: uniqueID) - // Swaps YIELD & provides swapped MOET, sourcing YIELD from the AutoBalancer - let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToMOETSwapper, source: abaSource, uniqueID: uniqueID) - - // open a FlowALP position - let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( - from: FlowALPv1.PoolCapStoragePath - ) ?? panic("Missing or invalid pool capability") - let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") - - let position <- poolRef.createPosition( - funds: <-withFunds, - issuanceSink: abaSwapSink, - repaymentSource: abaSwapSource, - pushToDrawDownSink: true - ) - - // get Sink & Source connectors relating to the new Position - let positionSink = position.createSinkWithOptions(type: collateralType, pushToDrawDownSink: true) - let positionSource = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) - - // init YieldToken -> FLOW Swapper - // - // get UniswapV3 path configs - let collateralUniV3AddressPathConfig = collateralConfig["yieldToCollateralUniV3AddressPaths"] as? {Type: [EVM.EVMAddress]} - ?? panic("Could not find UniswapV3 address paths config when creating Strategy \(type.identifier) with collateral \(collateralType.identifier)") - let uniV3AddressPath = collateralUniV3AddressPathConfig[collateralType] - ?? panic("Could not find UniswapV3 address path for collateral type \(collateralType.identifier)") - assert(uniV3AddressPath.length > 1, message: "Invalid Uniswap V3 swap path length of \(uniV3AddressPath.length)") - assert(uniV3AddressPath[0].equals(yieldTokenEVMAddress), - message: "UniswapV3 swap path does not match - expected path[0] to be \(yieldTokenEVMAddress.toString()) but found \(uniV3AddressPath[0].toString())") - let collateralUniV3FeePathConfig = collateralConfig["yieldToCollateralUniV3FeePaths"] as? {Type: [UInt32]} - ?? panic("Could not find UniswapV3 fee paths config when creating Strategy \(type.identifier) with collateral \(collateralType.identifier)") - let uniV3FeePath = collateralUniV3FeePathConfig[collateralType] - ?? panic("Could not find UniswapV3 fee path for collateral type \(collateralType.identifier)") - assert(uniV3FeePath.length > 0, message: "Invalid Uniswap V3 fee path length of \(uniV3FeePath.length)") - // initialize the swapper used for recollateralization of the lending position as YIELD increases in value - let yieldToFlowSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: univ3FactoryEVMAddress, - routerAddress: univ3RouterEVMAddress, - quoterAddress: univ3QuoterEVMAddress, - tokenPath: uniV3AddressPath, - feePath: uniV3FeePath, - inVault: yieldTokenType, - outVault: collateralType, - coaCapability: FlowYieldVaultsStrategies._getCOACapability(), - uniqueID: uniqueID - ) - // allows for YIELD to be deposited to the Position as the collateral basis - let positionSwapSink = SwapConnectors.SwapSink(swapper: yieldToFlowSwapper, sink: positionSink, uniqueID: uniqueID) - - // set the AutoBalancer's rebalance Sink which it will use to deposit overflown value, recollateralizing - // the position - autoBalancer.setSink(positionSwapSink, updateSinkID: true) - - // Use the same uniqueID passed to createStrategy so Strategy.burnCallback - // calls _cleanupAutoBalancer with the correct ID - return <-create mUSDCStrategy( - id: uniqueID, - collateralType: collateralType, - position: <-position - ) - } - } - - access(all) entitlement Configure - - /// This resource enables the issuance of StrategyComposers, thus safeguarding the issuance of Strategies which - /// may utilize resource consumption (i.e. account storage). Since TracerStrategy creation consumes account storage - /// via configured AutoBalancers - access(all) resource StrategyComposerIssuer : FlowYieldVaults.StrategyComposerIssuer { - /// { StrategyComposer Type: { Strategy Type: { Collateral Type: { String: AnyStruct } } } } - access(all) let configs: {Type: {Type: {Type: {String: AnyStruct}}}} - - init(configs: {Type: {Type: {Type: {String: AnyStruct}}}}) { - self.configs = configs - } - - access(all) view fun getSupportedComposers(): {Type: Bool} { - return { - Type<@mUSDCStrategyComposer>(): true, - Type<@TracerStrategyComposer>(): true - } - } - access(all) fun issueComposer(_ type: Type): @{FlowYieldVaults.StrategyComposer} { - pre { - self.getSupportedComposers()[type] == true: - "Unsupported StrategyComposer \(type.identifier) requested" - (&self.configs[type] as &{Type: {Type: {String: AnyStruct}}}?) != nil: - "Could not find config for StrategyComposer \(type.identifier)" - } - switch type { - case Type<@mUSDCStrategyComposer>(): - return <- create mUSDCStrategyComposer(self.configs[type]!) - case Type<@TracerStrategyComposer>(): - return <- create TracerStrategyComposer() - default: - panic("Unsupported StrategyComposer \(type.identifier) requested") - } - } - access(Configure) fun upsertConfigFor(composer: Type, config: {Type: {Type: {String: AnyStruct}}}) { - pre { - self.getSupportedComposers()[composer] == true: - "Unsupported StrategyComposer Type \(composer.identifier)" - } - for stratType in config.keys { - assert(stratType.isSubtype(of: Type<@{FlowYieldVaults.Strategy}>()), - message: "Invalid config key \(stratType.identifier) - not a FlowYieldVaults.Strategy Type") - for collateralType in config[stratType]!.keys { - assert(collateralType.isSubtype(of: Type<@{FungibleToken.Vault}>()), - message: "Invalid config key at config[\(stratType.identifier)] - \(collateralType.identifier) is not a FungibleToken.Vault") - } - } - self.configs[composer] = config - } - } - - /// Returns the COA capability for this account - /// TODO: this is temporary until we have a better way to pass user's COAs to inner connectors - access(self) - fun _getCOACapability(): Capability { - let coaCap = self.account.capabilities.storage.issue(/storage/evm) - assert(coaCap.check(), message: "Could not issue COA capability") - return coaCap - } - - /// Returns a FungibleTokenConnectors.VaultSinkAndSource used to subsidize cross VM token movement in contract- - /// defined strategies. - access(self) - fun _createFeeSource(withID: DeFiActions.UniqueIdentifier?): {DeFiActions.Sink, DeFiActions.Source} { - let capPath = /storage/strategiesFeeSource - if self.account.storage.type(at: capPath) == nil { - let cap = self.account.capabilities.storage.issue(/storage/flowTokenVault) - self.account.storage.save(cap, to: capPath) - } - let vaultCap = self.account.storage.copy>(from: capPath) - ?? panic("Could not find fee source Capability at \(capPath)") - return FungibleTokenConnectors.VaultSinkAndSource( - min: nil, - max: nil, - vault: vaultCap, - uniqueID: withID - ) - } - - /// Creates an AutoBalancerRecurringConfig for scheduled rebalancing. - /// The txnFunder uses the contract's FlowToken vault to pay for scheduling fees. - access(self) - fun _createRecurringConfig(withID: DeFiActions.UniqueIdentifier?): DeFiActions.AutoBalancerRecurringConfig { - // Create txnFunder that can provide/accept FLOW for scheduling fees - let txnFunder = self._createTxnFunder(withID: withID) - - return DeFiActions.AutoBalancerRecurringConfig( - interval: 60 * 10, // Rebalance every 10 minutes - priority: FlowTransactionScheduler.Priority.Medium, - executionEffort: 999, - forceRebalance: false, - txnFunder: txnFunder - ) - } - - /// Creates a Sink+Source for the AutoBalancer to use for scheduling fees - access(self) - fun _createTxnFunder(withID: DeFiActions.UniqueIdentifier?): {DeFiActions.Sink, DeFiActions.Source} { - let capPath = /storage/autoBalancerTxnFunder - if self.account.storage.type(at: capPath) == nil { - let cap = self.account.capabilities.storage.issue(/storage/flowTokenVault) - self.account.storage.save(cap, to: capPath) - } - let vaultCap = self.account.storage.copy>(from: capPath) - ?? panic("Could not find txnFunder Capability at \(capPath)") - return FungibleTokenConnectors.VaultSinkAndSource( - min: nil, - max: nil, - vault: vaultCap, - uniqueID: withID - ) - } - - init( - univ3FactoryEVMAddress: String, - univ3RouterEVMAddress: String, - univ3QuoterEVMAddress: String, - yieldTokenEVMAddress: String, - recollateralizationUniV3AddressPath: [String], - recollateralizationUniV3FeePath: [UInt32], - ) { - self.univ3FactoryEVMAddress = EVM.addressFromString(univ3FactoryEVMAddress) - self.univ3RouterEVMAddress = EVM.addressFromString(univ3RouterEVMAddress) - self.univ3QuoterEVMAddress = EVM.addressFromString(univ3QuoterEVMAddress) - self.yieldTokenEVMAddress = EVM.addressFromString(yieldTokenEVMAddress) - self.IssuerStoragePath = StoragePath(identifier: "FlowYieldVaultsStrategyComposerIssuer_\(self.account.address)")! - - let initialCollateralType = Type<@FlowToken.Vault>() - let moetType = Type<@MOET.Vault>() - let moetEVMAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: Type<@MOET.Vault>()) - ?? panic("Could not find EVM address for \(moetType.identifier) - ensure the asset is onboarded to the VM Bridge") - let yieldTokenEVMAddress = EVM.addressFromString(yieldTokenEVMAddress) - - let swapAddressPath: [EVM.EVMAddress] = [] - for hex in recollateralizationUniV3AddressPath { - swapAddressPath.append(EVM.addressFromString(hex)) - } - - let configs: {Type: {Type: {Type: {String: AnyStruct}}}} = { - Type<@mUSDCStrategyComposer>(): { - Type<@mUSDCStrategy>(): { - initialCollateralType: { - "univ3FactoryEVMAddress": self.univ3FactoryEVMAddress, - "univ3RouterEVMAddress": self.univ3RouterEVMAddress, - "univ3QuoterEVMAddress": self.univ3QuoterEVMAddress, - "yieldTokenEVMAddress": self.yieldTokenEVMAddress, - "yieldToCollateralUniV3AddressPaths": { - initialCollateralType: swapAddressPath - }, - "yieldToCollateralUniV3FeePaths": { - initialCollateralType: recollateralizationUniV3FeePath - } - } - } - }, - Type<@TracerStrategyComposer>(): { - Type<@TracerStrategy>(): {} - } - } - self.account.storage.save(<-create StrategyComposerIssuer(configs: configs), to: self.IssuerStoragePath) - - // TODO: this is temporary until we have a better way to pass user's COAs to inner connectors - // create a COA in this account - if self.account.storage.type(at: /storage/evm) == nil { - self.account.storage.save(<-EVM.createCadenceOwnedAccount(), to: /storage/evm) - let cap = self.account.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(/storage/evm) - self.account.capabilities.publish(cap, at: /public/evm) - } - } -} diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc similarity index 81% rename from cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc rename to cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index 0c0ceac7..05f61355 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -9,9 +9,10 @@ import "FungibleTokenConnectors" // amm integration import "UniswapV3SwapConnectors" import "ERC4626SwapConnectors" +import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol -import "FlowALPv1" +import "FlowALPv0" // FlowYieldVaults platform import "FlowYieldVaults" import "FlowYieldVaultsAutoBalancers" @@ -24,7 +25,7 @@ import "FlowEVMBridgeConfig" // live oracles import "ERC4626PriceOracles" -/// FlowYieldVaultsStrategiesV1_1 +/// FlowYieldVaultsStrategiesV2 /// /// This contract defines Strategies used in the FlowYieldVaults platform. /// @@ -35,7 +36,7 @@ import "ERC4626PriceOracles" /// A StrategyComposer is tasked with the creation of a supported Strategy. It's within the stacking of DeFiActions /// connectors that the true power of the components lies. /// -access(all) contract FlowYieldVaultsStrategiesV1_1 { +access(all) contract FlowYieldVaultsStrategiesV2 { access(all) let univ3FactoryEVMAddress: EVM.EVMAddress access(all) let univ3RouterEVMAddress: EVM.EVMAddress @@ -71,16 +72,16 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } } - /// This strategy uses mUSDF vaults - access(all) resource mUSDFStrategy : FlowYieldVaults.Strategy, DeFiActions.IdentifiableResource { + /// This strategy uses FUSDEV vault + access(all) resource FUSDEVStrategy : FlowYieldVaults.Strategy, DeFiActions.IdentifiableResource { /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol- /// specific Identifier to associated connectors on construction access(contract) var uniqueID: DeFiActions.UniqueIdentifier? - access(self) let position: @FlowALPv1.Position + access(self) let position: @FlowALPv0.Position access(self) var sink: {DeFiActions.Sink} access(self) var source: {DeFiActions.Source} - init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: @FlowALPv1.Position) { + init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: @FlowALPv0.Position) { self.uniqueID = id self.sink = position.createSink(type: collateralType) self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) @@ -178,12 +179,12 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } } - /// This StrategyComposer builds a mUSDFStrategy - access(all) resource mUSDFStrategyComposer : FlowYieldVaults.StrategyComposer { - /// { Strategy Type: { Collateral Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig } } - access(self) let config: {Type: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}} + /// This StrategyComposer builds a Strategy that uses MorphoERC4626 vault + access(all) resource MorphoERC4626StrategyComposer : FlowYieldVaults.StrategyComposer { + /// { Strategy Type: { Collateral Type: FlowYieldVaultsStrategiesV2.CollateralConfig } } + access(self) let config: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}} - init(_ config: {Type: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}}) { + init(_ config: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}}) { self.config = config } @@ -199,7 +200,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { /// Returns the Vault types which can be used to initialize a given Strategy access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} { let supported: {Type: Bool} = {} - if let strategyConfig = &self.config[forStrategy] as &{Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}? { + if let strategyConfig = &self.config[forStrategy] as &{Type: FlowYieldVaultsStrategiesV2.CollateralConfig}? { for collateralType in strategyConfig.keys { supported[collateralType] = true } @@ -228,6 +229,9 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { uniqueID: DeFiActions.UniqueIdentifier, withFunds: @{FungibleToken.Vault} ): @{FlowYieldVaults.Strategy} { + pre { + self.config[type] != nil: "Unsupported strategy type \(type.identifier)" + } let collateralType = withFunds.getType() let collateralConfig = self._getCollateralConfig( @@ -245,7 +249,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { ) // Create recurring config for automatic rebalancing - let recurringConfig = FlowYieldVaultsStrategiesV1_1._createRecurringConfig(withID: uniqueID) + let recurringConfig = FlowYieldVaultsStrategiesV2._createRecurringConfig(withID: uniqueID) // Create/store/publish/register AutoBalancer (returns authorized ref) let balancerIO = self._initAutoBalancerAndIO( @@ -256,15 +260,9 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { ) // Swappers: MOET <-> YIELD (YIELD is ERC4626 vault token) - let moetToYieldSwapper = self._createMoetToYieldSwapper(tokens: tokens, uniqueID: uniqueID) + let moetToYieldSwapper = self._createMoetToYieldSwapper(strategyType: type, tokens: tokens, uniqueID: uniqueID) - let yieldToMoetSwapper = self._createUniV3Swapper( - tokenPath: [tokens.yieldTokenEVMAddress, tokens.moetTokenEVMAddress], - feePath: [100], - inVault: tokens.yieldTokenType, - outVault: tokens.moetTokenType, - uniqueID: uniqueID - ) + let yieldToMoetSwapper = self._createYieldToMoetSwapper(strategyType: type, tokens: tokens, uniqueID: uniqueID) // AutoBalancer-directed swap IO let abaSwapSink = SwapConnectors.SwapSink( @@ -278,7 +276,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { uniqueID: uniqueID ) - // Open FlowALP position + // Open FlowALPv0 position let position <- self._openCreditPosition( funds: <-withFunds, issuanceSink: abaSwapSink, @@ -306,11 +304,16 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { // Set AutoBalancer sink for overflow -> recollateralize balancerIO.autoBalancer.setSink(positionSwapSink, updateSinkID: true) - return <-create FlowYieldVaultsStrategiesV1_1.mUSDFStrategy( - id: uniqueID, - collateralType: collateralType, - position: <-position - ) + switch type { + case Type<@FUSDEVStrategy>(): + return <-create FUSDEVStrategy( + id: uniqueID, + collateralType: collateralType, + position: <-position + ) + default: + panic("Unsupported strategy type \(type.identifier)") + } } /* =========================== @@ -320,7 +323,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { access(self) fun _getCollateralConfig( strategyType: Type, collateralType: Type - ): FlowYieldVaultsStrategiesV1_1.CollateralConfig { + ): FlowYieldVaultsStrategiesV2.CollateralConfig { let strategyConfig = self.config[strategyType] ?? panic( "Could not find a config for Strategy \(strategyType.identifier) initialized with \(collateralType.identifier)" @@ -333,8 +336,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } access(self) fun _resolveTokenBundle( - collateralConfig: FlowYieldVaultsStrategiesV1_1.CollateralConfig - ): FlowYieldVaultsStrategiesV1_1.TokenBundle { + collateralConfig: FlowYieldVaultsStrategiesV2.CollateralConfig + ): FlowYieldVaultsStrategiesV2.TokenBundle { // MOET let moetTokenType = Type<@MOET.Vault>() let moetTokenEVMAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: moetTokenType) @@ -357,7 +360,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { "Could not retrieve the VM Bridge associated Type for the ERC4626 underlying asset \(underlying4626AssetEVMAddress.toString())" ) - return FlowYieldVaultsStrategiesV1_1.TokenBundle( + return FlowYieldVaultsStrategiesV2.TokenBundle( moetTokenType: moetTokenType, moetTokenEVMAddress: moetTokenEVMAddress, yieldTokenType: yieldTokenType, @@ -387,20 +390,21 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { uniqueID: DeFiActions.UniqueIdentifier ): UniswapV3SwapConnectors.Swapper { return UniswapV3SwapConnectors.Swapper( - factoryAddress: FlowYieldVaultsStrategiesV1_1.univ3FactoryEVMAddress, - routerAddress: FlowYieldVaultsStrategiesV1_1.univ3RouterEVMAddress, - quoterAddress: FlowYieldVaultsStrategiesV1_1.univ3QuoterEVMAddress, + factoryAddress: FlowYieldVaultsStrategiesV2.univ3FactoryEVMAddress, + routerAddress: FlowYieldVaultsStrategiesV2.univ3RouterEVMAddress, + quoterAddress: FlowYieldVaultsStrategiesV2.univ3QuoterEVMAddress, tokenPath: tokenPath, feePath: feePath, inVault: inVault, outVault: outVault, - coaCapability: FlowYieldVaultsStrategiesV1_1._getCOACapability(), + coaCapability: FlowYieldVaultsStrategiesV2._getCOACapability(), uniqueID: uniqueID ) } access(self) fun _createMoetToYieldSwapper( - tokens: FlowYieldVaultsStrategiesV1_1.TokenBundle, + strategyType: Type, + tokens: FlowYieldVaultsStrategiesV2.TokenBundle, uniqueID: DeFiActions.UniqueIdentifier ): SwapConnectors.MultiSwapper { // Direct MOET -> YIELD via AMM @@ -422,16 +426,28 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { ) // UNDERLYING -> YIELD via ERC4626 vault - let underlyingTo4626 = ERC4626SwapConnectors.Swapper( - asset: tokens.underlying4626AssetType, - vault: tokens.yieldTokenEVMAddress, - coa: FlowYieldVaultsStrategiesV1_1._getCOACapability(), - feeSource: FlowYieldVaultsStrategiesV1_1._createFeeSource(withID: uniqueID), - uniqueID: uniqueID - ) + // Morpho vaults use MorphoERC4626SwapConnectors; standard ERC4626 vaults use ERC4626SwapConnectors + var underlyingTo4626: {DeFiActions.Swapper}? = nil + if strategyType == Type<@FUSDEVStrategy>() { + underlyingTo4626 = MorphoERC4626SwapConnectors.Swapper( + vaultEVMAddress: tokens.yieldTokenEVMAddress, + coa: FlowYieldVaultsStrategiesV2._getCOACapability(), + feeSource: FlowYieldVaultsStrategiesV2._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: false + ) + } else { + underlyingTo4626 = ERC4626SwapConnectors.Swapper( + asset: tokens.underlying4626AssetType, + vault: tokens.yieldTokenEVMAddress, + coa: FlowYieldVaultsStrategiesV2._getCOACapability(), + feeSource: FlowYieldVaultsStrategiesV2._createFeeSource(withID: uniqueID), + uniqueID: uniqueID + ) + } let seq = SwapConnectors.SequentialSwapper( - swappers: [moetToUnderlying, underlyingTo4626], + swappers: [moetToUnderlying, underlyingTo4626!], uniqueID: uniqueID ) @@ -443,12 +459,67 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { ) } + access(self) fun _createYieldToMoetSwapper( + strategyType: Type, + tokens: FlowYieldVaultsStrategiesV2.TokenBundle, + uniqueID: DeFiActions.UniqueIdentifier + ): SwapConnectors.MultiSwapper { + // Direct YIELD -> MOET via AMM + let yieldToMoetAMM = self._createUniV3Swapper( + tokenPath: [tokens.yieldTokenEVMAddress, tokens.moetTokenEVMAddress], + feePath: [100], + inVault: tokens.yieldTokenType, + outVault: tokens.moetTokenType, + uniqueID: uniqueID + ) + + // Reverse path: Morpho vaults support direct redeem; standard ERC4626 vaults use AMM-only path + if strategyType == Type<@FUSDEVStrategy>() { + // YIELD -> UNDERLYING redeem via MorphoERC4626 vault + let yieldToUnderlying = MorphoERC4626SwapConnectors.Swapper( + vaultEVMAddress: tokens.yieldTokenEVMAddress, + coa: FlowYieldVaultsStrategiesV2._getCOACapability(), + feeSource: FlowYieldVaultsStrategiesV2._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: true + ) + // UNDERLYING -> MOET via AMM + let underlyingToMoet = self._createUniV3Swapper( + tokenPath: [tokens.underlying4626AssetEVMAddress, tokens.moetTokenEVMAddress], + feePath: [100], + inVault: tokens.underlying4626AssetType, + outVault: tokens.moetTokenType, + uniqueID: uniqueID + ) + + let seq = SwapConnectors.SequentialSwapper( + swappers: [yieldToUnderlying, underlyingToMoet], + uniqueID: uniqueID + ) + + return SwapConnectors.MultiSwapper( + inVault: tokens.yieldTokenType, + outVault: tokens.moetTokenType, + swappers: [yieldToMoetAMM, seq], + uniqueID: uniqueID + ) + } else { + // Standard ERC4626: AMM-only reverse (no synchronous redeem support) + return SwapConnectors.MultiSwapper( + inVault: tokens.yieldTokenType, + outVault: tokens.moetTokenType, + swappers: [yieldToMoetAMM], + uniqueID: uniqueID + ) + } + } + access(self) fun _initAutoBalancerAndIO( oracle: {DeFiActions.PriceOracle}, yieldTokenType: Type, recurringConfig: DeFiActions.AutoBalancerRecurringConfig?, uniqueID: DeFiActions.UniqueIdentifier - ): FlowYieldVaultsStrategiesV1_1.AutoBalancerIO { + ): FlowYieldVaultsStrategiesV2.AutoBalancerIO { // NOTE: This stores the AutoBalancer in FlowYieldVaultsAutoBalancers storage and returns an authorized ref. let autoBalancerRef = FlowYieldVaultsAutoBalancers._initNewAutoBalancer( @@ -467,7 +538,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { let source = autoBalancerRef.createBalancerSource() ?? panic("Could not retrieve Source from AutoBalancer with id \(uniqueID.id)") - return FlowYieldVaultsStrategiesV1_1.AutoBalancerIO( + return FlowYieldVaultsStrategiesV2.AutoBalancerIO( autoBalancer: autoBalancerRef, sink: sink, source: source @@ -478,10 +549,10 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { funds: @{FungibleToken.Vault}, issuanceSink: {DeFiActions.Sink}, repaymentSource: {DeFiActions.Source} - ): @FlowALPv1.Position { - let poolCap = FlowYieldVaultsStrategiesV1_1.account.storage.copy< - Capability - >(from: FlowALPv1.PoolCapStoragePath) + ): @FlowALPv0.Position { + let poolCap = FlowYieldVaultsStrategiesV2.account.storage.copy< + Capability + >(from: FlowALPv0.PoolCapStoragePath) ?? panic("Missing or invalid pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") @@ -497,7 +568,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } access(self) fun _createYieldToCollateralSwapper( - collateralConfig: FlowYieldVaultsStrategiesV1_1.CollateralConfig, + collateralConfig: FlowYieldVaultsStrategiesV2.CollateralConfig, yieldTokenEVMAddress: EVM.EVMAddress, yieldTokenType: Type, collateralType: Type, @@ -553,10 +624,10 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { /// may utilize resource consumption (i.e. account storage). Since Strategy creation consumes account storage /// via configured AutoBalancers access(all) resource StrategyComposerIssuer : FlowYieldVaults.StrategyComposerIssuer { - /// { StrategyComposer Type: { Strategy Type: { Collateral Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig } } } - access(all) var configs: {Type: {Type: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}}} + /// { StrategyComposer Type: { Strategy Type: { Collateral Type: FlowYieldVaultsStrategiesV2.CollateralConfig } } } + access(all) var configs: {Type: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}}} - init(configs: {Type: {Type: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}}}) { + init(configs: {Type: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}}}) { self.configs = configs } @@ -575,12 +646,12 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { access(all) view fun getSupportedComposers(): {Type: Bool} { return { - Type<@mUSDFStrategyComposer>(): true + Type<@MorphoERC4626StrategyComposer>(): true } } access(self) view fun isSupportedComposer(_ type: Type): Bool { - return type == Type<@mUSDFStrategyComposer>() + return type == Type<@MorphoERC4626StrategyComposer>() } access(all) fun issueComposer(_ type: Type): @{FlowYieldVaults.StrategyComposer} { pre { @@ -590,8 +661,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { "Could not find config for StrategyComposer \(type.identifier)" } switch type { - case Type<@mUSDFStrategyComposer>(): - return <- create mUSDFStrategyComposer(self.configs[type]!) + case Type<@MorphoERC4626StrategyComposer>(): + return <- create MorphoERC4626StrategyComposer(self.configs[type]!) default: panic("Unsupported StrategyComposer \(type.identifier) requested") } @@ -600,7 +671,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { access(Configure) fun upsertConfigFor( composer: Type, - config: {Type: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}} + config: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}} ) { pre { self.isSupportedComposer(composer) == true: @@ -624,7 +695,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { for stratType in config.keys { let newPerCollateral = config[stratType]! let existingPerCollateral = mergedComposerConfig[stratType] ?? {} - var mergedPerCollateral: {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} = existingPerCollateral + var mergedPerCollateral: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} = existingPerCollateral for collateralType in newPerCollateral.keys { mergedPerCollateral[collateralType] = newPerCollateral[collateralType]! @@ -653,7 +724,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } // Base struct with shared addresses - var base = FlowYieldVaultsStrategiesV1_1.makeCollateralConfig( + var base = FlowYieldVaultsStrategiesV2.makeCollateralConfig( yieldTokenEVMAddress: yieldTokenEVMAddress, yieldToCollateralAddressPath: yieldToCollateralAddressPath, yieldToCollateralFeePath: yieldToCollateralFeePath @@ -670,8 +741,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } access(Configure) fun purgeConfig() { self.configs = { - Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} + Type<@MorphoERC4626StrategyComposer>(): { + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} } } } @@ -747,7 +818,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { self.univ3FactoryEVMAddress = EVM.addressFromString(univ3FactoryEVMAddress) self.univ3RouterEVMAddress = EVM.addressFromString(univ3RouterEVMAddress) self.univ3QuoterEVMAddress = EVM.addressFromString(univ3QuoterEVMAddress) - self.IssuerStoragePath = StoragePath(identifier: "FlowYieldVaultsStrategyV1_1ComposerIssuer_\(self.account.address)")! + self.IssuerStoragePath = StoragePath(identifier: "FlowYieldVaultsStrategyV2ComposerIssuer_\(self.account.address)")! self.config = {} let moetType = Type<@MOET.Vault>() @@ -756,8 +827,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } let configs = { - Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): ({} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}) + Type<@MorphoERC4626StrategyComposer>(): { + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} } } self.account.storage.save(<-create StrategyComposerIssuer(configs: configs), to: self.IssuerStoragePath) diff --git a/cadence/contracts/mocks/MockFlowALPConsumer.cdc b/cadence/contracts/mocks/MockFlowALPConsumer.cdc index e08fdcdd..fb396eeb 100644 --- a/cadence/contracts/mocks/MockFlowALPConsumer.cdc +++ b/cadence/contracts/mocks/MockFlowALPConsumer.cdc @@ -1,7 +1,7 @@ import "FungibleToken" import "DeFiActions" -import "FlowALPv1" +import "FlowALPv0" /// THIS CONTRACT IS NOT SAFE FOR PRODUCTION - FOR TEST USE ONLY /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -24,7 +24,7 @@ access(all) contract MockFlowALPConsumer { pushToDrawDownSink: Bool ): @PositionWrapper { return <- create PositionWrapper( - position: FlowALPv1.openPosition( + position: FlowALPv0.openPosition( collateral: <-collateral, issuanceSink: issuanceSink, repaymentSource: repaymentSource, @@ -36,20 +36,20 @@ access(all) contract MockFlowALPConsumer { /// A simple resource encapsulating a FlowALP Position access(all) resource PositionWrapper { - access(self) let position: FlowALPv1.Position + access(self) let position: FlowALPv0.Position - init(position: FlowALPv1.Position) { + init(position: FlowALPv0.Position) { self.position = position } /// NOT SAFE FOR PRODUCTION /// /// Returns a reference to the wrapped Position - access(all) fun borrowPosition(): &FlowALPv1.Position { + access(all) fun borrowPosition(): &FlowALPv0.Position { return &self.position } - access(all) fun borrowPositionForWithdraw(): auth(FungibleToken.Withdraw) &FlowALPv1.Position { + access(all) fun borrowPositionForWithdraw(): auth(FungibleToken.Withdraw) &FlowALPv0.Position { return &self.position } } diff --git a/cadence/contracts/mocks/MockStrategies.cdc b/cadence/contracts/mocks/MockStrategies.cdc new file mode 100644 index 00000000..84fbdcc1 --- /dev/null +++ b/cadence/contracts/mocks/MockStrategies.cdc @@ -0,0 +1,352 @@ +// standards +import "FungibleToken" +import "FlowToken" +import "EVM" +// DeFiActions +import "DeFiActionsUtils" +import "DeFiActions" +import "SwapConnectors" +import "FungibleTokenConnectors" +// Lending protocol +import "FlowALPv0" +// FlowYieldVaults platform +import "FlowYieldVaultsClosedBeta" +import "FlowYieldVaults" +import "FlowYieldVaultsAutoBalancers" +// scheduler +import "FlowTransactionScheduler" +// tokens +import "YieldToken" +import "MOET" +// mocks +import "MockOracle" +import "MockSwapper" + +/// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION +/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +/// +/// MockStrategies +/// +/// This contract defines Strategies used in the FlowYieldVaults platform. +/// +/// A Strategy instance can be thought of as objects wrapping a stack of DeFiActions connectors wired together to +/// (optimally) generate some yield on initial deposits. Strategies can be simple such as swapping into a yield-bearing +/// asset (such as stFLOW) or more complex DeFiActions stacks. +/// +/// A StrategyComposer is tasked with the creation of a supported Strategy. It's within the stacking of DeFiActions +/// connectors that the true power of the components lies. +/// +access(all) contract MockStrategies { + + /// Canonical StoragePath where the StrategyComposerIssuer should be stored + access(all) let IssuerStoragePath: StoragePath + + /// This is the first Strategy implementation, wrapping a @FlowALPv0.Position along with its related Sink & + /// Source. While this object is a simple wrapper for the top-level collateralized position, the true magic of the + /// DeFiActions is in the stacking of the related connectors. This stacking logic can be found in the + /// TracerStrategyComposer construct. + access(all) resource TracerStrategy : FlowYieldVaults.Strategy, DeFiActions.IdentifiableResource { + /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol- + /// specific Identifier to associated connectors on construction + access(contract) var uniqueID: DeFiActions.UniqueIdentifier? + access(self) let position: @FlowALPv0.Position + access(self) var sink: {DeFiActions.Sink} + access(self) var source: {DeFiActions.Source} + + init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: @FlowALPv0.Position) { + self.uniqueID = id + self.sink = position.createSink(type: collateralType) + self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) + self.position <-position + } + + // Inherited from FlowYieldVaults.Strategy default implementation + // access(all) view fun isSupportedCollateralType(_ type: Type): Bool + + access(all) view fun getSupportedCollateralTypes(): {Type: Bool} { + return { self.sink.getSinkType(): true } + } + /// Returns the amount available for withdrawal via the inner Source + access(all) fun availableBalance(ofToken: Type): UFix64 { + return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 + } + /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference + access(all) fun deposit(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) { + self.sink.depositCapacity(from: from) + } + /// Withdraws up to the max amount, returning the withdrawn Vault. If the requested token type is unsupported, + /// an empty Vault is returned. + access(FungibleToken.Withdraw) fun withdraw(maxAmount: UFix64, ofToken: Type): @{FungibleToken.Vault} { + if ofToken != self.source.getSourceType() { + return <- DeFiActionsUtils.getEmptyVault(ofToken) + } + return <- self.source.withdrawAvailable(maxAmount: maxAmount) + } + /// Executed when a Strategy is burned, cleaning up the Strategy's stored AutoBalancer + access(contract) fun burnCallback() { + FlowYieldVaultsAutoBalancers._cleanupAutoBalancer(id: self.id()!) + } + access(all) fun getComponentInfo(): DeFiActions.ComponentInfo { + return DeFiActions.ComponentInfo( + type: self.getType(), + id: self.id(), + innerComponents: [] + ) + } + access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? { + return self.uniqueID + } + access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) { + self.uniqueID = id + } + } + + /// This StrategyComposer builds a TracerStrategy + access(all) resource TracerStrategyComposer : FlowYieldVaults.StrategyComposer { + /// Returns the Types of Strategies composed by this StrategyComposer + access(all) view fun getComposedStrategyTypes(): {Type: Bool} { + return { Type<@TracerStrategy>(): true } + } + + /// Returns the Vault types which can be used to initialize a given Strategy + access(all) view fun getSupportedInitializationVaults(forStrategy: Type): {Type: Bool} { + return { Type<@FlowToken.Vault>(): true } + } + + /// Returns the Vault types which can be deposited to a given Strategy instance if it was initialized with the + /// provided Vault type + access(all) view fun getSupportedInstanceVaults(forStrategy: Type, initializedWith: Type): {Type: Bool} { + return { Type<@FlowToken.Vault>(): true } + } + + /// Composes a Strategy of the given type with the provided funds + access(all) fun createStrategy( + _ type: Type, + uniqueID: DeFiActions.UniqueIdentifier, + withFunds: @{FungibleToken.Vault} + ): @{FlowYieldVaults.Strategy} { + // this PriceOracle is mocked and will be shared by all components used in the TracerStrategy + let oracle = MockOracle.PriceOracle() + + // assign token types + + let moetTokenType: Type = Type<@MOET.Vault>() + let yieldTokenType = Type<@YieldToken.Vault>() + // assign collateral & flow token types + let collateralType = withFunds.getType() + + // Create recurring config for automatic rebalancing + let recurringConfig = MockStrategies._createRecurringConfig(withID: uniqueID) + + // configure and AutoBalancer for this stack with native recurring scheduling + let autoBalancer = FlowYieldVaultsAutoBalancers._initNewAutoBalancer( + oracle: oracle, // used to determine value of deposits & when to rebalance + vaultType: yieldTokenType, // the type of Vault held by the AutoBalancer + lowerThreshold: 0.95, // set AutoBalancer to pull from rebalanceSource when balance is 5% below value of deposits + upperThreshold: 1.05, // set AutoBalancer to push to rebalanceSink when balance is 5% below value of deposits + rebalanceSink: nil, // nil on init - will be set once a PositionSink is available + rebalanceSource: nil, // nil on init - not set for TracerStrategy + recurringConfig: recurringConfig, // enables native AutoBalancer self-scheduling + uniqueID: uniqueID // identifies AutoBalancer as part of this Strategy + ) + // enables deposits of YieldToken to the AutoBalancer + let abaSink = autoBalancer.createBalancerSink() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") + // enables withdrawals of YieldToken from the AutoBalancer + let abaSource = autoBalancer.createBalancerSource() ?? panic("Could not retrieve Sink from AutoBalancer with id \(uniqueID.id)") + + // init Stable <> YIELD swappers + // + // Stable -> YieldToken + let stableToYieldSwapper = MockSwapper.Swapper( + inVault: moetTokenType, + outVault: yieldTokenType, + uniqueID: uniqueID + ) + // YieldToken -> Stable + let yieldToStableSwapper = MockSwapper.Swapper( + inVault: yieldTokenType, + outVault: moetTokenType, + uniqueID: uniqueID + ) + + // init SwapSink directing swapped funds to AutoBalancer + // + // Swaps provided Stable to YieldToken & deposits to the AutoBalancer + let abaSwapSink = SwapConnectors.SwapSink(swapper: stableToYieldSwapper, sink: abaSink, uniqueID: uniqueID) + // Swaps YieldToken & provides swapped Stable, sourcing YieldToken from the AutoBalancer + let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToStableSwapper, source: abaSource, uniqueID: uniqueID) + + // open a FlowALP position + let poolCap = MockStrategies.account.storage.load>( + from: FlowALPv0.PoolCapStoragePath + ) ?? panic("Missing pool capability") + + let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") + + let position <- poolRef.createPosition( + funds: <-withFunds, + issuanceSink: abaSwapSink, + repaymentSource: abaSwapSource, + pushToDrawDownSink: true + ) + MockStrategies.account.storage.save(poolCap, to: FlowALPv0.PoolCapStoragePath) + + // get Sink & Source connectors relating to the new Position + let positionSink = position.createSinkWithOptions(type: collateralType, pushToDrawDownSink: true) + let positionSource = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) // TODO: may need to be false + + // init YieldToken -> FLOW Swapper + let yieldToFlowSwapper = MockSwapper.Swapper( + inVault: yieldTokenType, + outVault: collateralType, + uniqueID: uniqueID + ) + // allows for YieldToken to be deposited to the Position + let positionSwapSink = SwapConnectors.SwapSink(swapper: yieldToFlowSwapper, sink: positionSink, uniqueID: uniqueID) + + // set the AutoBalancer's rebalance Sink which it will use to deposit overflown value, + // recollateralizing the position + autoBalancer.setSink(positionSwapSink, updateSinkID: true) + + // Use the same uniqueID passed to createStrategy so Strategy.burnCallback + // calls _cleanupAutoBalancer with the correct ID + return <-create TracerStrategy( + id: uniqueID, + collateralType: collateralType, + position: <- position + ) + } + } + + access(all) entitlement Configure + + /// This resource enables the issuance of StrategyComposers, thus safeguarding the issuance of Strategies which + /// may utilize resource consumption (i.e. account storage). Since TracerStrategy creation consumes account storage + /// via configured AutoBalancers + access(all) resource StrategyComposerIssuer : FlowYieldVaults.StrategyComposerIssuer { + /// { StrategyComposer Type: { Strategy Type: { Collateral Type: { String: AnyStruct } } } } + access(all) let configs: {Type: {Type: {Type: {String: AnyStruct}}}} + + init(configs: {Type: {Type: {Type: {String: AnyStruct}}}}) { + self.configs = configs + } + + access(all) view fun getSupportedComposers(): {Type: Bool} { + return { + Type<@TracerStrategyComposer>(): true + } + } + access(all) fun issueComposer(_ type: Type): @{FlowYieldVaults.StrategyComposer} { + pre { + self.getSupportedComposers()[type] == true: + "Unsupported StrategyComposer \(type.identifier) requested" + (&self.configs[type] as &{Type: {Type: {String: AnyStruct}}}?) != nil: + "Could not find config for StrategyComposer \(type.identifier)" + } + switch type { + case Type<@TracerStrategyComposer>(): + return <- create TracerStrategyComposer() + default: + panic("Unsupported StrategyComposer \(type.identifier) requested") + } + } + access(Configure) fun upsertConfigFor(composer: Type, config: {Type: {Type: {String: AnyStruct}}}) { + pre { + self.getSupportedComposers()[composer] == true: + "Unsupported StrategyComposer Type \(composer.identifier)" + } + for stratType in config.keys { + assert(stratType.isSubtype(of: Type<@{FlowYieldVaults.Strategy}>()), + message: "Invalid config key \(stratType.identifier) - not a FlowYieldVaults.Strategy Type") + for collateralType in config[stratType]!.keys { + assert(collateralType.isSubtype(of: Type<@{FungibleToken.Vault}>()), + message: "Invalid config key at config[\(stratType.identifier)] - \(collateralType.identifier) is not a FungibleToken.Vault") + } + } + self.configs[composer] = config + } + } + + /// Returns the COA capability for this account + /// TODO: this is temporary until we have a better way to pass user's COAs to inner connectors + access(self) + fun _getCOACapability(): Capability { + let coaCap = self.account.capabilities.storage.issue(/storage/evm) + assert(coaCap.check(), message: "Could not issue COA capability") + return coaCap + } + + /// Returns a FungibleTokenConnectors.VaultSinkAndSource used to subsidize cross VM token movement in contract- + /// defined strategies. + access(self) + fun _createFeeSource(withID: DeFiActions.UniqueIdentifier?): {DeFiActions.Sink, DeFiActions.Source} { + let capPath = /storage/strategiesFeeSource + if self.account.storage.type(at: capPath) == nil { + let cap = self.account.capabilities.storage.issue(/storage/flowTokenVault) + self.account.storage.save(cap, to: capPath) + } + let vaultCap = self.account.storage.copy>(from: capPath) + ?? panic("Could not find fee source Capability at \(capPath)") + return FungibleTokenConnectors.VaultSinkAndSource( + min: nil, + max: nil, + vault: vaultCap, + uniqueID: withID + ) + } + + /// Creates an AutoBalancerRecurringConfig for scheduled rebalancing. + /// The txnFunder uses the contract's FlowToken vault to pay for scheduling fees. + access(self) + fun _createRecurringConfig(withID: DeFiActions.UniqueIdentifier?): DeFiActions.AutoBalancerRecurringConfig { + // Create txnFunder that can provide/accept FLOW for scheduling fees + let txnFunder = self._createTxnFunder(withID: withID) + + return DeFiActions.AutoBalancerRecurringConfig( + interval: 60 * 10, // Rebalance every 10 minutes + priority: FlowTransactionScheduler.Priority.Medium, + executionEffort: 999, + forceRebalance: false, + txnFunder: txnFunder + ) + } + + /// Creates a Sink+Source for the AutoBalancer to use for scheduling fees + access(self) + fun _createTxnFunder(withID: DeFiActions.UniqueIdentifier?): {DeFiActions.Sink, DeFiActions.Source} { + let capPath = /storage/autoBalancerTxnFunder + if self.account.storage.type(at: capPath) == nil { + let cap = self.account.capabilities.storage.issue(/storage/flowTokenVault) + self.account.storage.save(cap, to: capPath) + } + let vaultCap = self.account.storage.copy>(from: capPath) + ?? panic("Could not find txnFunder Capability at \(capPath)") + return FungibleTokenConnectors.VaultSinkAndSource( + min: nil, + max: nil, + vault: vaultCap, + uniqueID: withID + ) + } + + init() { + self.IssuerStoragePath = StoragePath(identifier: "FlowYieldVaultsStrategyComposerIssuer_\(self.account.address)")! + + let initialCollateralType = Type<@FlowToken.Vault>() + + let configs: {Type: {Type: {Type: {String: AnyStruct}}}} = { + Type<@TracerStrategyComposer>(): { + Type<@TracerStrategy>(): {} + } + } + self.account.storage.save(<-create StrategyComposerIssuer(configs: configs), to: self.IssuerStoragePath) + + // TODO: this is temporary until we have a better way to pass user's COAs to inner connectors + // create a COA in this account + if self.account.storage.type(at: /storage/evm) == nil { + self.account.storage.save(<-EVM.createCadenceOwnedAccount(), to: /storage/evm) + let cap = self.account.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(/storage/evm) + self.account.capabilities.publish(cap, at: /public/evm) + } + } +} diff --git a/cadence/scripts/diag_bridge_associations.cdc b/cadence/scripts/diag_bridge_associations.cdc new file mode 100644 index 00000000..9057eed9 --- /dev/null +++ b/cadence/scripts/diag_bridge_associations.cdc @@ -0,0 +1,31 @@ +import "EVM" +import "FlowToken" +import "FlowEVMBridgeConfig" + +/// Check bridge type/address associations for syWFLOWv and FUSDEV +/// Run: flow scripts execute cadence/scripts/diag_bridge_associations.cdc --network mainnet +access(all) fun main(): {String: String} { + let result: {String: String} = {} + + let syWFLOWvAddr = EVM.addressFromString("0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597") + let fusdEvAddr = EVM.addressFromString("0xd069d989e2F44B70c65347d1853C0c67e10a9F8D") + let wflowAddr = EVM.addressFromString("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e") + + // Bridge type associations for vault EVM addresses + let syWFLOWvType = FlowEVMBridgeConfig.getTypeAssociated(with: syWFLOWvAddr) + result["1_syWFLOWv_typeAssociation"] = syWFLOWvType?.identifier ?? "nil" + + let fusdEvType = FlowEVMBridgeConfig.getTypeAssociated(with: fusdEvAddr) + result["2_FUSDEV_typeAssociation"] = fusdEvType?.identifier ?? "nil" + + // FlowToken -> EVM address + let flowTokenType = Type<@FlowToken.Vault>() + let flowEVMAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) + result["3_FlowToken_evmAddress"] = flowEVMAddr?.toString() ?? "nil" + + // WFLOW -> Cadence type + let wflowType = FlowEVMBridgeConfig.getTypeAssociated(with: wflowAddr) + result["4_WFLOW_typeAssociation"] = wflowType?.identifier ?? "nil" + + return result +} diff --git a/cadence/scripts/diag_check_pool.cdc b/cadence/scripts/diag_check_pool.cdc new file mode 100644 index 00000000..55e00f0e --- /dev/null +++ b/cadence/scripts/diag_check_pool.cdc @@ -0,0 +1,26 @@ +import "EVM" + +access(all) fun main( + factoryHex: String, + tokenAHex: String, + tokenBHex: String, + fee: UInt256 +): String { + let factory = EVM.addressFromString(factoryHex) + let res = EVM.dryCall( + from: factory, + to: factory, + data: EVM.encodeABIWithSignature( + "getPool(address,address,uint24)", + [EVM.addressFromString(tokenAHex), EVM.addressFromString(tokenBHex), fee] + ), + gasLimit: 1_000_000, + value: EVM.Balance(attoflow: 0) + ) + if res.status != EVM.Status.successful { + return "CALL FAILED: ".concat(res.errorMessage) + } + let decoded = EVM.decodeABI(types: [Type()], data: res.data) + if decoded.length == 0 { return "NO RESULT" } + return (decoded[0] as! EVM.EVMAddress).toString() +} diff --git a/cadence/scripts/diag_evm_vault_state.cdc b/cadence/scripts/diag_evm_vault_state.cdc new file mode 100644 index 00000000..0dda8da5 --- /dev/null +++ b/cadence/scripts/diag_evm_vault_state.cdc @@ -0,0 +1,35 @@ +import "EVM" +import "ERC4626Utils" + +/// Check totalAssets and totalSupply for syWFLOWv and FUSDEV vaults +/// Run: flow scripts execute cadence/scripts/diag_evm_vault_state.cdc --network mainnet +access(all) fun main(): {String: String} { + let result: {String: String} = {} + + let syWFLOWvAddr = EVM.addressFromString("0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597") + let fusdEvAddr = EVM.addressFromString("0xd069d989e2F44B70c65347d1853C0c67e10a9F8D") + + // syWFLOWv underlying asset + let syWFLOWvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: syWFLOWvAddr) + result["1_syWFLOWv_underlying"] = syWFLOWvUnderlying?.toString() ?? "nil" + + // syWFLOWv totalAssets and totalSupply + let syWFLOWvTotalAssets = ERC4626Utils.totalAssets(vault: syWFLOWvAddr) + result["2_syWFLOWv_totalAssets"] = syWFLOWvTotalAssets?.toString() ?? "nil" + + let syWFLOWvTotalShares = ERC4626Utils.totalShares(vault: syWFLOWvAddr) + result["3_syWFLOWv_totalShares"] = syWFLOWvTotalShares?.toString() ?? "nil" + + // FUSDEV underlying asset + let fusdEvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: fusdEvAddr) + result["4_FUSDEV_underlying"] = fusdEvUnderlying?.toString() ?? "nil" + + // FUSDEV totalAssets and totalSupply + let fusdEvTotalAssets = ERC4626Utils.totalAssets(vault: fusdEvAddr) + result["5_FUSDEV_totalAssets"] = fusdEvTotalAssets?.toString() ?? "nil" + + let fusdEvTotalShares = ERC4626Utils.totalShares(vault: fusdEvAddr) + result["6_FUSDEV_totalShares"] = fusdEvTotalShares?.toString() ?? "nil" + + return result +} diff --git a/cadence/scripts/diag_get_moet_evm.cdc b/cadence/scripts/diag_get_moet_evm.cdc new file mode 100644 index 00000000..2ea8405f --- /dev/null +++ b/cadence/scripts/diag_get_moet_evm.cdc @@ -0,0 +1,9 @@ +import "EVM" +import "FlowEVMBridgeConfig" +import "MOET" + +access(all) fun main(): String? { + let evmAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: Type<@MOET.Vault>()) + if evmAddr == nil { return nil } + return evmAddr!.toString() +} diff --git a/cadence/scripts/diag_sywflowv.cdc b/cadence/scripts/diag_sywflowv.cdc new file mode 100644 index 00000000..6c68c997 --- /dev/null +++ b/cadence/scripts/diag_sywflowv.cdc @@ -0,0 +1,50 @@ +import "EVM" +import "FlowToken" +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" +import "ERC4626Utils" + +/// Diagnostic script to check syWFLOWv and FUSDEV vault state on mainnet. +/// Run: flow scripts execute cadence/scripts/diag_sywflowv.cdc --network mainnet +/// +access(all) fun main(): {String: String} { + let result: {String: String} = {} + + let syWFLOWvAddr = EVM.addressFromString("0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597") + let fusdEvAddr = EVM.addressFromString("0xd069d989e2F44B70c65347d1853C0c67e10a9F8D") + + // Bridge type associations + let syWFLOWvType = FlowEVMBridgeConfig.getTypeAssociated(with: syWFLOWvAddr) + result["1_syWFLOWv_typeAssociation"] = syWFLOWvType?.identifier ?? "nil" + + let fusdEvType = FlowEVMBridgeConfig.getTypeAssociated(with: fusdEvAddr) + result["2_FUSDEV_typeAssociation"] = fusdEvType?.identifier ?? "nil" + + // Underlying asset EVM addresses + let syWFLOWvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: syWFLOWvAddr) + result["3_syWFLOWv_underlying"] = syWFLOWvUnderlying?.toString() ?? "nil" + + let fusdEvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: fusdEvAddr) + result["4_FUSDEV_underlying"] = fusdEvUnderlying?.toString() ?? "nil" + + // FlowToken EVM address association + let flowTokenType = Type<@FlowToken.Vault>() + let flowEVMAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) + result["5_FlowToken_evmAddress"] = flowEVMAddr?.toString() ?? "nil" + + // syWFLOWv totalAssets and totalSupply + let syWFLOWvTotalAssets = ERC4626Utils.totalAssets(vault: syWFLOWvAddr) + result["6_syWFLOWv_totalAssets"] = syWFLOWvTotalAssets?.toString() ?? "nil" + + let syWFLOWvTotalShares = ERC4626Utils.totalShares(vault: syWFLOWvAddr) + result["7_syWFLOWv_totalShares"] = syWFLOWvTotalShares?.toString() ?? "nil" + + // FUSDEV totalAssets and totalSupply (working reference) + let fusdEvTotalAssets = ERC4626Utils.totalAssets(vault: fusdEvAddr) + result["8_FUSDEV_totalAssets"] = fusdEvTotalAssets?.toString() ?? "nil" + + let fusdEvTotalShares = ERC4626Utils.totalShares(vault: fusdEvAddr) + result["9_FUSDEV_totalShares"] = fusdEvTotalShares?.toString() ?? "nil" + + return result +} diff --git a/cadence/scripts/diag_univ3_dust.cdc b/cadence/scripts/diag_univ3_dust.cdc new file mode 100644 index 00000000..64fdb8d2 --- /dev/null +++ b/cadence/scripts/diag_univ3_dust.cdc @@ -0,0 +1,134 @@ +import "EVM" +import "FlowEVMBridgeUtils" + +/// Diagnostic script: reads a live V3 pool's sqrtPriceX96 from the mainnet +/// fork, computes the worst-case ceil-then-swap overshoot, and proves the +/// dust is capped at 0.00000001 UFix64. + +access(all) fun main( + factoryHex: String, + tokenAHex: String, + tokenBHex: String, + fee: UInt256 +): {String: AnyStruct} { + let factory = EVM.addressFromString(factoryHex) + let tokenA = EVM.addressFromString(tokenAHex) + let tokenB = EVM.addressFromString(tokenBHex) + + // --- inline EVMAmountUtils rounding ---------------------------------- + fun toCadenceOut(_ amt: UInt256, _ decimals: UInt8): UFix64 { + if decimals <= 8 { + return FlowEVMBridgeUtils.uint256ToUFix64(value: amt, decimals: decimals) + } + let q = FlowEVMBridgeUtils.pow(base: 10, exponent: decimals - 8) + return FlowEVMBridgeUtils.uint256ToUFix64(value: amt - (amt % q), decimals: decimals) + } + + fun toCadenceIn(_ amt: UInt256, _ decimals: UInt8): UFix64 { + if decimals <= 8 { + return FlowEVMBridgeUtils.uint256ToUFix64(value: amt, decimals: decimals) + } + let q = FlowEVMBridgeUtils.pow(base: 10, exponent: decimals - 8) + let rem = amt % q + var padded = amt + if rem != UInt256(0) { padded = amt + (q - rem) } + return FlowEVMBridgeUtils.uint256ToUFix64(value: padded, decimals: decimals) + } + + // --- EVM helpers --------------------------------------------------------- + fun dryCall(_ to: EVM.EVMAddress, _ data: [UInt8]): EVM.Result { + return EVM.dryCall( + from: factory, to: to, data: data, + gasLimit: 1_000_000, value: EVM.Balance(attoflow: 0) + ) + } + + // 1) Look up pool address + let poolRes = dryCall(factory, EVM.encodeABIWithSignature( + "getPool(address,address,uint24)", [tokenA, tokenB, fee] + )) + assert(poolRes.status == EVM.Status.successful, message: "getPool failed") + let poolAddr = EVM.decodeABI(types: [Type()], data: poolRes.data)[0] as! EVM.EVMAddress + assert(poolAddr.toString() != "0000000000000000000000000000000000000000", message: "pool does not exist") + + // 2) Read slot0 → sqrtPriceX96 + let slot0Res = dryCall(poolAddr, EVM.encodeABIWithSignature("slot0()", [])) + assert(slot0Res.status == EVM.Status.successful, message: "slot0 failed") + let sqrtPriceX96 = EVM.decodeABI(types: [Type()], data: slot0Res.data)[0] as! UInt256 + + // 3) Read token0 to determine direction + let t0Res = dryCall(poolAddr, EVM.encodeABIWithSignature("token0()", [])) + let token0 = EVM.decodeABI(types: [Type()], data: t0Res.data)[0] as! EVM.EVMAddress + + // 4) Read token decimals + let decA = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: tokenA) + let decB = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: tokenB) + let aIsToken0 = token0.toString() == tokenA.toString() + let dec0: UInt8 = aIsToken0 ? decA : decB + let dec1: UInt8 = aIsToken0 ? decB : decA + + // 5) Compute price ratio from sqrtPriceX96 + // price = (sqrtPriceX96 / 2^96)^2 + // price of token0 in token1 units: token1_amount / token0_amount + // We need to account for decimal differences + let Q96: UInt256 = UInt256(1) << 96 + + // --- Worst-case dust computation --- + // The worst-case input overshoot is quantum - 1 wei + // When the swap connector ceils input to UFix64, it overshoots by at most 1 quantum + // quantum_in = 10^(inputDecimals - 8) for 18-decimal tokens = 10^10 + let quantumA = FlowEVMBridgeUtils.pow(base: 10, exponent: decA > 8 ? decA - 8 : 0) + let quantumB = FlowEVMBridgeUtils.pow(base: 10, exponent: decB > 8 ? decB - 8 : 0) + + // 6) Simulate: pick a concrete non-quantum-aligned input amount and compute the dust + // Use 1.000000002 * 10^18 as a sample quoter result (in tokenA wei) + let sampleQuoterResult: UInt256 = UInt256(1000000002) * FlowEVMBridgeUtils.pow(base: 10, exponent: decA > 8 ? decA - 8 - 1 : 0) + + // Ceil to UFix64 + let ceiledUFix = toCadenceIn(sampleQuoterResult, decA) + let ceiledWei = FlowEVMBridgeUtils.ufix64ToUInt256(value: ceiledUFix, decimals: decA) + let inputOvershoot = ceiledWei - sampleQuoterResult + + // Compute approximate output overshoot using pool price + // For a swap of tokenA → tokenB (assuming A is token0): + // outputWei ≈ inputWei × price = inputWei × (sqrtPriceX96^2 / Q96^2) × 10^(dec0-dec1) + // but for dust analysis, we just need the output overshoot from the input overshoot + // outputOvershootWei ≈ inputOvershoot × (sqrtPriceX96^2) / Q96^2 [adjusted for decimals] + // + // Simpler: compute both the exact and ceiled output in UFix64 + // desiredOut = toCadenceOut(desiredOutWei) + // actualOut = toCadenceOut(desiredOutWei + outputOvershootWei) + // dust = actualOut - desiredOut + + // For any single swap, the dust is bounded by the output quantum: + // dust <= 0.00000001 UFix64 + // Proof: ceil increases input by < quantumA. Even if price amplifies + // this overshoot, the floor operation on the output can only shift by + // at most 1 quantumB in UFix64 terms, because: + // - toCadenceOut floors to quantum boundary + // - The capped bridgeUFix in _swapExactIn clamps output to amountOutMin + + // Concrete verification with this pool's price: + // floor(ceiledInput) - floor(exactInput) in UFix64 shows the gap + let exactOutUFix = toCadenceOut(sampleQuoterResult, decA) + let ceiledOutUFix = ceiledUFix // ceil of same amount + + return { + "poolAddress": poolAddr.toString(), + "sqrtPriceX96": sqrtPriceX96, + "token0": token0.toString(), + "tokenA_decimals": decA, + "tokenB_decimals": decB, + "quantumA_wei": quantumA, + "quantumB_wei": quantumB, + "sampleQuoterResult_wei": sampleQuoterResult, + "ceiledInput_UFix64": ceiledUFix, + "ceiledInput_wei": ceiledWei, + "inputOvershoot_wei": inputOvershoot, + "inputOvershoot_ltQuantum": inputOvershoot < quantumA, + "floor_of_sample_UFix64": exactOutUFix, + "ceil_of_sample_UFix64": ceiledOutUFix, + "ceil_minus_floor_UFix64": ceiledOutUFix - exactOutUFix, + "dust_capped_at_one_quantum": (ceiledOutUFix - exactOutUFix) <= 0.00000001 + } +} diff --git a/cadence/scripts/flow-yield-vaults/get_complete_user_position_info.cdc b/cadence/scripts/flow-yield-vaults/get_complete_user_position_info.cdc index 3da31b54..9347bfb8 100644 --- a/cadence/scripts/flow-yield-vaults/get_complete_user_position_info.cdc +++ b/cadence/scripts/flow-yield-vaults/get_complete_user_position_info.cdc @@ -1,6 +1,6 @@ import "FlowYieldVaults" import "FlowYieldVaultsAutoBalancers" -import "FlowALPv1" +import "FlowALPv0" import "MockOracle" import "YieldToken" import "MOET" @@ -231,13 +231,13 @@ fun main(address: Address): CompleteUserSummary { let netWorth = estimatedCollateralValue + yieldTokenValue - estimatedDebtValue - // Get the actual position health from FlowALPv1.Pool + // Get the actual position health from FlowALPv0.Pool // FlowALP positions use sequential IDs (0, 1, 2, ...) while yield vault IDs are different var actualHealth: UFix128 = 999.0 - // Try to get the real health from FlowALPv1.Pool using sequential position IDs - let protocolAddress = Type<@FlowALPv1.Pool>().address! - if let pool = getAccount(protocolAddress).capabilities.borrow<&FlowALPv1.Pool>(FlowALPv1.PoolPublicPath) { + // Try to get the real health from FlowALPv0.Pool using sequential position IDs + let protocolAddress = Type<@FlowALPv0.Pool>().address! + if let pool = getAccount(protocolAddress).capabilities.borrow<&FlowALPv0.Pool>(FlowALPv0.PoolPublicPath) { // Since we can't directly map yield vault IDs to position IDs, we'll try sequential IDs // This assumes positions are created in order (0, 1, 2, ...) let positionIndex = UInt64(positions.length) // Use the current position index diff --git a/cadence/tests/atomic_registration_gc_test.cdc b/cadence/tests/atomic_registration_gc_test.cdc index e6e45874..f4a7b89a 100644 --- a/cadence/tests/atomic_registration_gc_test.cdc +++ b/cadence/tests/atomic_registration_gc_test.cdc @@ -2,18 +2,17 @@ import Test import BlockchainHelpers import "test_helpers.cdc" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerRegistry" import "FlowToken" import "MOET" import "YieldToken" -import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -63,8 +62,8 @@ access(all) fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/rebalance_scenario1_test.cdc b/cadence/tests/rebalance_scenario1_test.cdc index 31a582ec..c604fb0e 100644 --- a/cadence/tests/rebalance_scenario1_test.cdc +++ b/cadence/tests/rebalance_scenario1_test.cdc @@ -6,13 +6,13 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -67,8 +67,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/rebalance_scenario2_test.cdc b/cadence/tests/rebalance_scenario2_test.cdc index dfac8324..4beb8734 100644 --- a/cadence/tests/rebalance_scenario2_test.cdc +++ b/cadence/tests/rebalance_scenario2_test.cdc @@ -6,15 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -153,8 +152,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/rebalance_scenario3a_test.cdc b/cadence/tests/rebalance_scenario3a_test.cdc index 73ba3754..7e778f12 100644 --- a/cadence/tests/rebalance_scenario3a_test.cdc +++ b/cadence/tests/rebalance_scenario3a_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -29,7 +29,7 @@ access(all) fun getFlowCollateralFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@FlowToken.Vault>() { // Credit means it's a deposit (collateral) - if balance.direction == FlowALPv1.BalanceDirection.Credit { + if balance.direction == FlowALPv0.BalanceDirection.Credit { return balance.balance } } @@ -43,7 +43,7 @@ access(all) fun getMOETDebtFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@MOET.Vault>() { // Debit means it's borrowed (debt) - if balance.direction == FlowALPv1.BalanceDirection.Debit { + if balance.direction == FlowALPv0.BalanceDirection.Debit { return balance.balance } } @@ -96,8 +96,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) @@ -280,7 +280,7 @@ fun test_RebalanceYieldVaultScenario3A() { let positionDetails = getPositionDetails(pid: 1, beFailed: false) var positionFlowBalance = 0.0 for balance in positionDetails.balances { - if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv1.BalanceDirection.Credit { + if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv0.BalanceDirection.Credit { positionFlowBalance = balance.balance break } diff --git a/cadence/tests/rebalance_scenario3b_test.cdc b/cadence/tests/rebalance_scenario3b_test.cdc index 050c49ee..069d83aa 100644 --- a/cadence/tests/rebalance_scenario3b_test.cdc +++ b/cadence/tests/rebalance_scenario3b_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -96,8 +96,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) @@ -276,7 +276,7 @@ fun test_RebalanceYieldVaultScenario3B() { let positionDetails = getPositionDetails(pid: 1, beFailed: false) var positionFlowBalance = 0.0 for balance in positionDetails.balances { - if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv1.BalanceDirection.Credit { + if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv0.BalanceDirection.Credit { positionFlowBalance = balance.balance break } diff --git a/cadence/tests/rebalance_scenario3c_test.cdc b/cadence/tests/rebalance_scenario3c_test.cdc index 907f34a3..ef340e7e 100644 --- a/cadence/tests/rebalance_scenario3c_test.cdc +++ b/cadence/tests/rebalance_scenario3c_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -29,7 +29,7 @@ access(all) fun getFlowCollateralFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@FlowToken.Vault>() { // Credit means it's a deposit (collateral) - if balance.direction == FlowALPv1.BalanceDirection.Credit { + if balance.direction == FlowALPv0.BalanceDirection.Credit { return balance.balance } } @@ -43,7 +43,7 @@ access(all) fun getMOETDebtFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@MOET.Vault>() { // Debit means it's borrowed (debt) - if balance.direction == FlowALPv1.BalanceDirection.Debit { + if balance.direction == FlowALPv0.BalanceDirection.Debit { return balance.balance } } @@ -96,8 +96,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/rebalance_scenario3d_test.cdc b/cadence/tests/rebalance_scenario3d_test.cdc index a9eb2f48..4a80a0eb 100644 --- a/cadence/tests/rebalance_scenario3d_test.cdc +++ b/cadence/tests/rebalance_scenario3d_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -29,7 +29,7 @@ access(all) fun getFlowCollateralFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@FlowToken.Vault>() { // Credit means it's a deposit (collateral) - if balance.direction == FlowALPv1.BalanceDirection.Credit { + if balance.direction == FlowALPv0.BalanceDirection.Credit { return balance.balance } } @@ -43,7 +43,7 @@ access(all) fun getMOETDebtFromPosition(pid: UInt64): UFix64 { for balance in positionDetails.balances { if balance.vaultType == Type<@MOET.Vault>() { // Debit means it's borrowed (debt) - if balance.direction == FlowALPv1.BalanceDirection.Debit { + if balance.direction == FlowALPv0.BalanceDirection.Debit { return balance.balance } } @@ -96,8 +96,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/rebalance_yield_test.cdc b/cadence/tests/rebalance_yield_test.cdc index 0b8361e6..bbe9cce3 100644 --- a/cadence/tests/rebalance_yield_test.cdc +++ b/cadence/tests/rebalance_yield_test.cdc @@ -7,13 +7,13 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -66,8 +66,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/scheduled_rebalance_integration_test.cdc b/cadence/tests/scheduled_rebalance_integration_test.cdc index 9ceeae26..c9d79875 100644 --- a/cadence/tests/scheduled_rebalance_integration_test.cdc +++ b/cadence/tests/scheduled_rebalance_integration_test.cdc @@ -6,7 +6,7 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerV1" import "FlowTransactionScheduler" import "FlowYieldVaultsSchedulerRegistry" @@ -16,7 +16,7 @@ access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -82,8 +82,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) log("Strategy composer added") diff --git a/cadence/tests/scheduled_rebalance_scenario_test.cdc b/cadence/tests/scheduled_rebalance_scenario_test.cdc index b6090282..08d42bda 100644 --- a/cadence/tests/scheduled_rebalance_scenario_test.cdc +++ b/cadence/tests/scheduled_rebalance_scenario_test.cdc @@ -6,7 +6,7 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerV1" import "FlowTransactionScheduler" import "FlowYieldVaultsSchedulerRegistry" @@ -16,7 +16,7 @@ access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -87,8 +87,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/scheduled_supervisor_test.cdc b/cadence/tests/scheduled_supervisor_test.cdc index a9ce48f5..eada6f15 100644 --- a/cadence/tests/scheduled_supervisor_test.cdc +++ b/cadence/tests/scheduled_supervisor_test.cdc @@ -6,7 +6,7 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerV1" import "FlowTransactionScheduler" import "DeFiActions" @@ -16,7 +16,7 @@ access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -73,8 +73,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/scheduler_edge_cases_test.cdc b/cadence/tests/scheduler_edge_cases_test.cdc index e5377096..c1348263 100644 --- a/cadence/tests/scheduler_edge_cases_test.cdc +++ b/cadence/tests/scheduler_edge_cases_test.cdc @@ -6,7 +6,7 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerV1" import "FlowYieldVaultsSchedulerRegistry" import "FlowTransactionScheduler" @@ -15,7 +15,7 @@ access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -69,8 +69,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index f05b0b20..87aedce0 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -4,7 +4,7 @@ import "EVM" import "MetadataViews" import "FlowToken" import "MOET" -import "FlowALPv1" +import "FlowALPv0" access(all) let serviceAccount = Test.serviceAccount() @@ -180,7 +180,7 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) - // FlowALPv1 contracts + // FlowALPv0 contracts let initialMoetSupply = 0.0 err = Test.deployContract( name: "MOET", @@ -189,8 +189,8 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) err = Test.deployContract( - name: "FlowALPv1", - path: "../../lib/FlowALP/cadence/contracts/FlowALPv1.cdc", + name: "FlowALPv0", + path: "../../lib/FlowALP/cadence/contracts/FlowALPv0.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -310,6 +310,20 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "MorphoERC4626SinkConnectors", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + err = Test.deployContract( + name: "MorphoERC4626SwapConnectors", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + let onboarder = Test.createAccount() transferFlow(signer: serviceAccount, recipient: onboarder.address, amount: 100.0) let onboardMoet = _executeTransaction( @@ -320,22 +334,15 @@ access(all) fun deployContracts() { Test.expect(onboardMoet, Test.beSucceeded()) err = Test.deployContract( - name: "FlowYieldVaultsStrategies", - path: "../contracts/FlowYieldVaultsStrategies.cdc", - arguments: [ - "0x986Cb42b0557159431d48fE0A40073296414d410", - "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", - "0x8dd92c8d0C3b304255fF9D98ae59c3385F88360C", - "0xaCCF0c4EeD4438Ad31Cd340548f4211a465B6528", - [] as [String], - [] as [UInt32] - ] + name: "MockStrategies", + path: "../contracts/mocks/MockStrategies.cdc", + arguments: [] ) Test.expect(err, Test.beNil()) err = Test.deployContract( - name: "FlowYieldVaultsStrategiesV1_1", - path: "../contracts/FlowYieldVaultsStrategiesV1_1.cdc", + name: "FlowYieldVaultsStrategiesV2", + path: "../contracts/FlowYieldVaultsStrategiesV2.cdc", arguments: [ "0x986Cb42b0557159431d48fE0A40073296414d410", "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", @@ -449,13 +456,13 @@ fun getAutoBalancerCurrentValue(id: UInt64): UFix64? { } access(all) -fun getPositionDetails(pid: UInt64, beFailed: Bool): FlowALPv1.PositionDetails { +fun getPositionDetails(pid: UInt64, beFailed: Bool): FlowALPv0.PositionDetails { let res = _executeScript("../../lib/FlowALP/cadence/scripts/flow-alp/position_details.cdc", [pid] ) Test.expect(res, beFailed ? Test.beFailed() : Test.beSucceeded()) - return res.returnValue as! FlowALPv1.PositionDetails + return res.returnValue as! FlowALPv0.PositionDetails } access(all) @@ -601,14 +608,14 @@ fun rebalanceYieldVault(signer: Test.TestAccount, id: UInt64, force: Bool, beFai access(all) fun getLastPositionOpenedEvent(_ evts: [AnyStruct]): AnyStruct { // can't return event types directly, they must be cast by caller - Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv1.Opened event but found none") - return evts[evts.length - 1] as! FlowALPv1.Opened + Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv0.Opened event but found none") + return evts[evts.length - 1] as! FlowALPv0.Opened } access(all) fun getLastPositionDepositedEvent(_ evts: [AnyStruct]): AnyStruct { // can't return event types directly, they must be cast by caller - Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv1.Deposited event but found none") - return evts[evts.length - 1] as! FlowALPv1.Deposited + Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv0.Deposited event but found none") + return evts[evts.length - 1] as! FlowALPv0.Deposited } /* --- Mock helpers --- */ @@ -688,7 +695,7 @@ access(all) fun setupBetaAccess(): Void { // Returns the balance for a given Vault 'Type' if present, otherwise nil. access(all) fun findBalance( - details: FlowALPv1.PositionDetails, + details: FlowALPv0.PositionDetails, vaultType: Type ): UFix64? { for b in details.balances { diff --git a/cadence/tests/tracer_strategy_test.cdc b/cadence/tests/tracer_strategy_test.cdc index eba977ea..455e8742 100644 --- a/cadence/tests/tracer_strategy_test.cdc +++ b/cadence/tests/tracer_strategy_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -72,8 +72,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) @@ -162,7 +162,7 @@ fun test_RebalanceYieldVaultSucceeds() { amount: fundingAmount, beFailed: false ) - let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv0.Opened).pid var yieldVaultIDs = getYieldVaultIDs(address: user.address) Test.assert(yieldVaultIDs != nil, message: "Expected user's YieldVault IDs to be non-nil but encountered nil") @@ -186,7 +186,7 @@ fun test_RebalanceYieldVaultSucceeds() { // for now we can use events to intercept fund flows between pre- and post- Position & AutoBalancer state // assess how much FLOW was deposited into the position - let autoBalancerRecollateralizeEvent = getLastPositionDepositedEvent(Test.eventsOfType(Type())) as! FlowALPv1.Deposited + let autoBalancerRecollateralizeEvent = getLastPositionDepositedEvent(Test.eventsOfType(Type())) as! FlowALPv0.Deposited Test.assertEqual(positionID, autoBalancerRecollateralizeEvent.pid) Test.assertEqual(autoBalancerRecollateralizeEvent.amount, (autoBalancerValueAfter - autoBalancerValueBefore) / startingFlowPrice @@ -247,7 +247,7 @@ fun test_RebalanceYieldVaultSucceedsAfterYieldPriceDecrease() { amount: fundingAmount, beFailed: false ) - let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv0.Opened).pid var yieldVaultIDs = getYieldVaultIDs(address: user.address) Test.assert(yieldVaultIDs != nil, message: "Expected user's YieldVault IDs to be non-nil but encountered nil") @@ -304,7 +304,7 @@ fun test_RebalanceYieldVaultSucceedsAfterCollateralPriceIncrease() { amount: fundingAmount, beFailed: false ) - let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv0.Opened).pid var yieldVaultIDs = getYieldVaultIDs(address: user.address) Test.assert(yieldVaultIDs != nil, message: "Expected user's YieldVault IDs to be non-nil but encountered nil") diff --git a/cadence/tests/univ3_swap_overshoot_dust_test.cdc b/cadence/tests/univ3_swap_overshoot_dust_test.cdc new file mode 100644 index 00000000..0fbb5ce2 --- /dev/null +++ b/cadence/tests/univ3_swap_overshoot_dust_test.cdc @@ -0,0 +1,218 @@ +import Test +import "FlowEVMBridgeUtils" +import "EVMAmountUtils" +import "UniswapV3SwapConnectors" + +access(all) let serviceAccount = Test.serviceAccount() + +access(all) +fun setup() { + var err = Test.deployContract( + name: "DeFiActionsUtils", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/utils/DeFiActionsUtils.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "DeFiActions", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/interfaces/DeFiActions.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "SwapConnectors", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "EVMAbiHelpers", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/utils/EVMAbiHelpers.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "EVMAmountUtils", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "UniswapV3SwapConnectors", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) +} + +/* --- Helpers --- */ + +access(all) fun toEVM(_ x: UFix64, decimals: UInt8): UInt256 { + return FlowEVMBridgeUtils.ufix64ToUInt256(value: x, decimals: decimals) +} + +access(all) fun quantum(_ decimals: UInt8): UInt256 { + if decimals <= 8 { return UInt256(1) } + return FlowEVMBridgeUtils.pow(base: 10, exponent: decimals - 8) +} + +access(all) let ONE_QUANTUM: UFix64 = 0.00000001 + +/* --- Tests --- */ + +/// For any 18-decimal EVM amount the gap between toCadenceIn (ceil) and +/// toCadenceOut (floor) is at most 0.00000001 (1 UFix64 quantum). +access(all) fun test_ceil_floor_gap_capped_at_one_quantum() { + let decimals: UInt8 = 18 + let q = quantum(decimals) + + let a0: UInt256 = UInt256(1) + let a1: UInt256 = q - UInt256(1) + let a2: UInt256 = q + UInt256(1) + let a3: UInt256 = UInt256(1000) * q + UInt256(1) + let a4: UInt256 = UInt256(1000) * q + q / UInt256(2) + let a5: UInt256 = UInt256(1000) * q + q - UInt256(1) + let a6: UInt256 = UInt256(5000000002) * UInt256(1000000000) + let a7: UInt256 = UInt256(12345678) * UInt256(10000000000) + UInt256(12345678) + let a8: UInt256 = UInt256(99999999) * UInt256(10000000000) + UInt256(9999999999) + + let amounts: [UInt256] = [a0, a1, a2, a3, a4, a5, a6, a7, a8] + + for amt in amounts { + let ceiled = EVMAmountUtils.toCadenceIn(amt, decimals: decimals) + let floored = EVMAmountUtils.toCadenceOut(amt, decimals: decimals) + let gap = ceiled - floored + + assert( + gap <= ONE_QUANTUM, + message: "Gap exceeds 0.00000001 for amount " + .concat(amt.toString()) + .concat(": ceil=").concat(ceiled.toString()) + .concat(" floor=").concat(floored.toString()) + .concat(" gap=").concat(gap.toString()) + ) + } +} + +/// Quantum-aligned amounts produce zero overshoot -- ceil equals floor. +access(all) fun test_quantum_aligned_zero_overshoot() { + let decimals: UInt8 = 18 + let q = quantum(decimals) + + let a0: UInt256 = q + let a1: UInt256 = UInt256(10) * q + let a2: UInt256 = UInt256(5000000001) * q + + let aligned: [UInt256] = [a0, a1, a2] + + for amt in aligned { + let ceiled = EVMAmountUtils.toCadenceIn(amt, decimals: decimals) + let floored = EVMAmountUtils.toCadenceOut(amt, decimals: decimals) + + assert( + ceiled == floored, + message: "Quantum-aligned amount " + .concat(amt.toString()) + .concat(" should have zero gap, got ceil=") + .concat(ceiled.toString()) + .concat(" floor=").concat(floored.toString()) + ) + } +} + +/// Reproduce the exact overshoot scenario documented in +/// UniswapV3SwapConnectors._swapExactIn (lines 506-515): +/// +/// Pool price 1 FLOW = 2 USDC, want 10 USDC out. +/// 1. Quoter says need 5,000000002000000000 FLOW wei +/// 2. Ceil to UFix64: 5.00000001 FLOW (overshoot 8e9 wei) +/// 3. Extra input x 2 = 16e9 USDC wei extra output +/// 4. Actual output: 10,000000016000000000 USDC wei +/// 5. Floor to UFix64: 10.00000001 USDC (overshoot 0.00000001) +/// +access(all) fun test_documented_swap_overshoot_scenario() { + let decimals: UInt8 = 18 + let q = quantum(decimals) + + // Step 1: quoter reports exact input needed (in wei) + let quoterInputWei: UInt256 = UInt256(5000000002) * UInt256(1000000000) + + // Step 2: ceil to UFix64 + let ceiledInput = EVMAmountUtils.toCadenceIn(quoterInputWei, decimals: decimals) + Test.assertEqual(5.00000001, ceiledInput) + + // Convert back to EVM -- this is the amount actually sent to the pool + let ceiledInputEVM = toEVM(ceiledInput, decimals: decimals) + Test.assertEqual( + UInt256(5000000010) * UInt256(1000000000), + ceiledInputEVM + ) + + // Input overshoot in wei + let inputOvershoot = ceiledInputEVM - quoterInputWei + Test.assertEqual(UInt256(8000000000), inputOvershoot) + assert(inputOvershoot < q, message: "Input overshoot must be < 1 quantum") + + // Step 3-4: pool price 2 => extra output = 8e9 x 2 = 16e9 USDC wei + let tenTokens: UInt256 = UInt256(10) * UInt256(1000000000) * UInt256(1000000000) + let actualOutputWei = tenTokens + inputOvershoot * UInt256(2) + + // Step 5: floor both to UFix64 + let desiredUFix = EVMAmountUtils.toCadenceOut(tenTokens, decimals: decimals) + let actualUFix = EVMAmountUtils.toCadenceOut(actualOutputWei, decimals: decimals) + + Test.assertEqual(10.0, desiredUFix) + Test.assertEqual(10.00000001, actualUFix) + + // Overshoot is exactly 1 UFix64 quantum + Test.assertEqual(ONE_QUANTUM, actualUFix - desiredUFix) +} + +/// The round-trip ceil overshoot in EVM units is always strictly less than +/// 1 quantum, so the input sent to the pool exceeds the quoter amount by +/// less than 10^10 wei (< 0.00000001 in UFix64). +access(all) fun test_ceil_roundtrip_overshoot_below_one_quantum() { + let decimals: UInt8 = 18 + let q = quantum(decimals) + + let a0: UInt256 = UInt256(1) + let a1: UInt256 = q - UInt256(1) + let a2: UInt256 = q + UInt256(1) + let a3: UInt256 = UInt256(5000000002) * UInt256(1000000000) + let a4: UInt256 = UInt256(12345678) * UInt256(10000000000) + UInt256(12345678) + let a5: UInt256 = UInt256(99999999) * UInt256(10000000000) + UInt256(9999999999) + + let amounts: [UInt256] = [a0, a1, a2, a3, a4, a5] + + for amt in amounts { + let ceiled = EVMAmountUtils.toCadenceIn(amt, decimals: decimals) + let backToEVM = toEVM(ceiled, decimals: decimals) + + assert(backToEVM >= amt, message: "Ceiled round-trip must be >= original") + assert( + backToEVM - amt < q, + message: "EVM overshoot must be < 1 quantum for " + .concat(amt.toString()) + .concat(": overshoot=").concat((backToEVM - amt).toString()) + ) + } +} + +/// Worst-case remainder (quantum - 1) produces exactly the maximum +/// UFix64 gap of 0.00000001, and the EVM overshoot is exactly 1 wei. +access(all) fun test_worst_case_remainder_produces_max_gap() { + let decimals: UInt8 = 18 + let q = quantum(decimals) + + // remainder = q - 1 => maximum ceil padding + let amt: UInt256 = UInt256(42) * q + q - UInt256(1) + + let ceiled = EVMAmountUtils.toCadenceIn(amt, decimals: decimals) + let floored = EVMAmountUtils.toCadenceOut(amt, decimals: decimals) + + Test.assertEqual(ONE_QUANTUM, ceiled - floored) + + // EVM overshoot is exactly 1 wei -- the minimum non-zero overshoot + let backToEVM = toEVM(ceiled, decimals: decimals) + Test.assertEqual(UInt256(1), backToEVM - amt) +} diff --git a/cadence/tests/yield_vault_lifecycle_test.cdc b/cadence/tests/yield_vault_lifecycle_test.cdc index a165df04..4b4bf0bb 100644 --- a/cadence/tests/yield_vault_lifecycle_test.cdc +++ b/cadence/tests/yield_vault_lifecycle_test.cdc @@ -6,15 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "MockStrategies" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) access(all) let yieldTokenAccount = Test.getAccount(0x0000000000000010) -access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategies.TracerStrategy>().identifier +access(all) var strategyIdentifier = Type<@MockStrategies.TracerStrategy>().identifier access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier access(all) var yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier @@ -72,8 +71,8 @@ fun setup() { addStrategyComposer( signer: flowYieldVaultsAccount, strategyIdentifier: strategyIdentifier, - composerIdentifier: Type<@FlowYieldVaultsStrategies.TracerStrategyComposer>().identifier, - issuerStoragePath: FlowYieldVaultsStrategies.IssuerStoragePath, + composerIdentifier: Type<@MockStrategies.TracerStrategyComposer>().identifier, + issuerStoragePath: MockStrategies.IssuerStoragePath, beFailed: false ) diff --git a/cadence/transactions/flow-yield-vaults/admin/upsert_musdc_config.cdc b/cadence/transactions/flow-yield-vaults/admin/upsert_musdc_config.cdc deleted file mode 100644 index 4dabf0df..00000000 --- a/cadence/transactions/flow-yield-vaults/admin/upsert_musdc_config.cdc +++ /dev/null @@ -1,82 +0,0 @@ -import "FlowYieldVaultsStrategies" -import "FlowToken" -import "EVM" - -// Upserts the config for mUSDCStrategy under mUSDCStrategyComposer. -// -// Args (in order): -// 0: univ3FactoryEVMAddress (String) -// 1: univ3RouterEVMAddress (String) -// 2: univ3QuoterEVMAddress (String) -// 3: yieldTokenEVMAddress (String) -// 4: recollateralizationUniV3AddressPath ([String]) -// 5: recollateralizationUniV3FeePath ([UInt32]) -// -// Example JSON args you gave: -// [ -// "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", // factory -// "0x2Db6468229F6fB1a77d248Dbb1c386760C257804", // router -// "0xA1e0E4CCACA34a738f03cFB1EAbAb16331FA3E2c", // quoter -// "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", // yield token -// ["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", -// "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"], // recollat path -// [3000] // fee path -// ] -// -transaction( - univ3FactoryEVMAddress: String, - univ3RouterEVMAddress: String, - univ3QuoterEVMAddress: String, - yieldTokenEVMAddress: String, - recollateralizationUniV3AddressPath: [String], - recollateralizationUniV3FeePath: [UInt32] -) { - - prepare(signer: auth(BorrowValue) &Account) { - // Borrow the StrategyComposerIssuer with Configure entitlement - let issuerRef = signer.storage.borrow< - auth(FlowYieldVaultsStrategies.Configure) &FlowYieldVaultsStrategies.StrategyComposerIssuer - >(from: FlowYieldVaultsStrategies.IssuerStoragePath) - ?? panic("Could not borrow StrategyComposerIssuer from IssuerStoragePath") - - // Collateral type we’re configuring for (matches contract init) - let initialCollateralType: Type = Type<@FlowToken.Vault>() - - // Build the Uniswap V3 address path as [EVM.EVMAddress] - var swapAddressPath: [EVM.EVMAddress] = [] - for hex in recollateralizationUniV3AddressPath { - swapAddressPath.append(EVM.addressFromString(hex)) - } - - // Build the config shape: - // { Strategy Type: { Collateral Type: { String: AnyStruct } } } - // - // This mirrors what the contract does in init(...) for mUSDCStrategyComposer. - let config: {Type: {Type: {String: AnyStruct}}} = { - Type<@FlowYieldVaultsStrategies.mUSDCStrategy>(): { - initialCollateralType: { - "univ3FactoryEVMAddress": EVM.addressFromString(univ3FactoryEVMAddress), - "univ3RouterEVMAddress": EVM.addressFromString(univ3RouterEVMAddress), - "univ3QuoterEVMAddress": EVM.addressFromString(univ3QuoterEVMAddress), - "yieldTokenEVMAddress": EVM.addressFromString(yieldTokenEVMAddress), - "yieldToCollateralUniV3AddressPaths": { - initialCollateralType: swapAddressPath - }, - "yieldToCollateralUniV3FeePaths": { - initialCollateralType: recollateralizationUniV3FeePath - } - } - } - } - - // Upsert config for the mUSDCStrategyComposer - issuerRef.upsertConfigFor( - composer: Type<@FlowYieldVaultsStrategies.mUSDCStrategyComposer>(), - config: config - ) - } - - execute { - log("Updated mUSDC strategy config for FlowYieldVaultsStrategies.mUSDCStrategyComposer") - } -} diff --git a/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc b/cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc similarity index 68% rename from cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc rename to cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc index 80f22443..792c7031 100644 --- a/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc +++ b/cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc @@ -1,14 +1,20 @@ import "FungibleToken" import "EVM" -import "FlowYieldVaultsStrategiesV1_1" +import "FlowYieldVaultsStrategiesV2" -/// Admin tx to (re)configure Uniswap paths for the mUSDFStrategy +/// Admin tx to (re)configure Uniswap paths for strategies from FlowYieldVaultsStrategiesV2 /// /// NOTE: /// - Must be signed by the account that deployed FlowYieldVaultsStrategies /// - You can omit some collaterals by passing empty arrays and guarding in prepare{} transaction( + // e.g. "A.0x...FlowYieldVaultsStrategiesV2.FUSDEVStrategy" + strategyTypeIdentifier: String, + + // collateral vault type (e.g. "A.0x...FlowToken.Vault") tokenTypeIdentifier: String, + + // yield token (EVM) address yieldTokenEVMAddress: String, // collateral path/fees: [YIELD, ..., ] @@ -17,13 +23,15 @@ transaction( ) { prepare(acct: auth(Storage, Capabilities, BorrowValue) &Account) { + let strategyType = CompositeType(strategyTypeIdentifier) + ?? panic("Invalid strategyTypeIdentifier \(strategyTypeIdentifier)") let tokenType = CompositeType(tokenTypeIdentifier) ?? panic("Invalid tokenTypeIdentifier \(tokenTypeIdentifier)") // This tx must run on the same account that stores the issuer // otherwise this borrow will fail. let issuer = acct.storage.borrow< - auth(FlowYieldVaultsStrategiesV1_1.Configure) &FlowYieldVaultsStrategiesV1_1.StrategyComposerIssuer - >(from: FlowYieldVaultsStrategiesV1_1.IssuerStoragePath) + auth(FlowYieldVaultsStrategiesV2.Configure) &FlowYieldVaultsStrategiesV2.StrategyComposerIssuer + >(from: FlowYieldVaultsStrategiesV2.IssuerStoragePath) ?? panic("Missing StrategyComposerIssuer at IssuerStoragePath") let yieldEVM = EVM.addressFromString(yieldTokenEVMAddress) @@ -37,8 +45,7 @@ transaction( return out } - let composerType = Type<@FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer>() - let strategyType = Type<@FlowYieldVaultsStrategiesV1_1.mUSDFStrategy>() + let composerType = Type<@FlowYieldVaultsStrategiesV2.MorphoERC4626StrategyComposer>() if swapPath.length > 0 { issuer.addOrUpdateCollateralConfig( diff --git a/docs/rebalancing_architecture.md b/docs/rebalancing_architecture.md index 1a51d075..a0f5c9e8 100644 --- a/docs/rebalancing_architecture.md +++ b/docs/rebalancing_architecture.md @@ -7,7 +7,7 @@ - Each YieldVault wraps a **FlowYieldVaults Strategy** (e.g. `TracerStrategy`) - The YieldVault itself does **not** know about scheduling or FlowALP; it just holds a strategy resource -### FlowYieldVaultsStrategies (TracerStrategy stack) +### MockStrategies (TracerStrategy stack) - `TracerStrategyComposer` wires together: - A **DeFiActions.AutoBalancer** (manages Yield token exposure around deposits value) - A **FlowALP.Position** (borrow/lend position in the FlowALP pool) @@ -56,7 +56,7 @@ ## 2. How the Tracer Strategy Wires AutoBalancer and FlowALP Together -Inside `FlowYieldVaultsStrategies.TracerStrategyComposer.createStrategy(...)`: +Inside `MockStrategies.TracerStrategyComposer.createStrategy(...)`: ### Step 1: Create an AutoBalancer - Configured with: diff --git a/docs/scheduled_rebalancing_comprehensive_analysis.md b/docs/scheduled_rebalancing_comprehensive_analysis.md index 2c71577f..b59ace1f 100644 --- a/docs/scheduled_rebalancing_comprehensive_analysis.md +++ b/docs/scheduled_rebalancing_comprehensive_analysis.md @@ -96,8 +96,8 @@ The scheduled-rebalancing branch has been significantly refactored to address al | ID | Issue | Location | Impact | |----|-------|----------|--------| -| L1 | `innerComponents` Regression | `FlowYieldVaultsStrategies.cdc` | Reduced observability | -| L2 | mUSDCStrategyComposer Changes | `FlowYieldVaultsStrategies.cdc` | 4626 integration breakage | +| L1 | `innerComponents` Regression | `MockStrategies.cdc` | Reduced observability | +| L2 | mUSDCStrategyComposer Changes | `MockStrategies.cdc` | 4626 integration breakage | | L3 | Missing View Modifiers | Multiple files | Optimization opportunity | | L4 | `createSupervisor()` Access Level | `FlowYieldVaultsScheduler.cdc` | Could be more restrictive | @@ -533,11 +533,11 @@ borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ## 6. Code Quality and Regression Analysis -### 6.1 FlowYieldVaultsStrategies Regressions +### 6.1 MockStrategies Regressions #### Issue L1: `innerComponents` Regression -**Context**: Both `TracerStrategy` and `mUSDCStrategy` implement `getComponentInfo()` which returns a `DeFiActions.ComponentInfo` structure. +**Context**: `TracerStrategy` implements `getComponentInfo()` which returns a `DeFiActions.ComponentInfo` structure. **Current State**: Returns `innerComponents: []` (empty array) @@ -663,7 +663,7 @@ Same concerns apply. Both should be `access(self)` unless external callers legit | Priority | Action | Rationale | |----------|--------|-----------| -| 1 | Revert `FlowYieldVaultsStrategies.cdc` changes | Restore Mainnet 4626 compatibility | +| 1 | Revert `MockStrategies.cdc` changes | Restore Mainnet 4626 compatibility | | 2 | Decide architectural path (A or B) | Foundation for all other changes | | 3 | Restrict capability getter access | Security hardening | | 4 | Fix Supervisor initialization pattern | Resource efficiency | @@ -822,7 +822,7 @@ Strategy creation via StrategyComposer | `FlowYieldVaultsScheduler.cdc` | Removed wrapper, added atomic scheduling, paginated Supervisor | | `FlowYieldVaultsSchedulerRegistry.cdc` | Added pending queue, bounded iteration, restricted access | | `FlowYieldVaultsAutoBalancers.cdc` | Added `recurringConfig` param, registration calls | -| `FlowYieldVaultsStrategies.cdc` | Added `recurringConfig: nil` to AutoBalancer creation | +| `MockStrategies.cdc` | Added `recurringConfig: nil` to AutoBalancer creation | | `FlowYieldVaults.cdc` | Removed scheduler calls (moved to AutoBalancers) | | `schedule_rebalancing.cdc` | Updated to use new API, fixed priority enum | | `has_wrapper_cap_for_yield_vault.cdc` | Updated to use `getHandlerCap` | diff --git a/flow.json b/flow.json index 86aabccf..4308a2e0 100644 --- a/flow.json +++ b/flow.json @@ -58,16 +58,6 @@ "testnet": "7014dcffa1f14186" } }, - "EVMAmountUtils": { - "source": "./lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", - "aliases": { - "emulator": "045a1763c93006ca", - "mainnet": "6d888f175c158410", - "mainnet-fork": "6d888f175c158410", - "testing": "0000000000000009", - "testnet": "0b11b1848a8aa2c0" - } - }, "ERC4626SwapConnectors": { "source": "./lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc", "aliases": { @@ -102,10 +92,10 @@ "source": "./lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", "aliases": { "emulator": "045a1763c93006ca", - "mainnet": "6d888f175c158410", - "mainnet-fork": "6d888f175c158410", + "mainnet": "43c9e8bfec507db4", + "mainnet-fork": "43c9e8bfec507db4", "testing": "0000000000000009", - "testnet": "0b11b1848a8aa2c0" + "testnet": "67402f29666f7b29" } }, "EVMTokenConnectors": { @@ -118,23 +108,23 @@ "testnet": "b88ba0e976146cd1" } }, - "FlowALPv1": { - "source": "./lib/FlowALP/cadence/contracts/FlowALPv1.cdc", + "FlowALPMath": { + "source": "./lib/FlowALP/cadence/lib/FlowALPMath.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "testing": "0000000000000008", + "testing": "0000000000000007", "testnet": "426f0458ced60037" } }, - "FlowALPMath": { - "source": "./lib/FlowALP/cadence/lib/FlowALPMath.cdc", + "FlowALPv0": { + "source": "./lib/FlowALP/cadence/contracts/FlowALPv0.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "testing": "0000000000000007", + "testing": "0000000000000008", "testnet": "426f0458ced60037" } }, @@ -188,8 +178,8 @@ "testnet": "d2580caf2ef07c2f" } }, - "FlowYieldVaultsStrategies": { - "source": "cadence/contracts/FlowYieldVaultsStrategies.cdc", + "MockStrategies": { + "source": "cadence/contracts/mocks/MockStrategies.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "b1d63873c3cc9f79", @@ -198,8 +188,8 @@ "testnet": "d2580caf2ef07c2f" } }, - "FlowYieldVaultsStrategiesV1_1": { - "source": "cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc", + "FlowYieldVaultsStrategiesV2": { + "source": "cadence/contracts/FlowYieldVaultsStrategiesV2.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "b1d63873c3cc9f79", @@ -904,13 +894,6 @@ "resourceID": "projects/dl-flow-devex-production/locations/us-central1/keyRings/tidal-keyring/cryptoKeys/tidal_admin_pk/cryptoKeyVersions/1" } }, - "mainnet-fork-admin": { - "address": "b1d63873c3cc9f79", - "key": { - "type": "file", - "location": "local/emulator-account.pkey" - } - }, "mainnet-band-oracle-connectors": { "address": "e36ef556b8b5d955", "key": { @@ -927,6 +910,13 @@ "resourceID": "projects/dl-flow-devex-production/locations/us-central1/keyRings/tidal-keyring/cryptoKeys/tidal_admin_pk/cryptoKeyVersions/1" } }, + "mainnet-fork-admin": { + "address": "b1d63873c3cc9f79", + "key": { + "type": "file", + "location": "local/emulator-account.pkey" + } + }, "mock-incrementfi": { "address": "f3fcd2c1a78f5eee", "key": { @@ -984,7 +974,7 @@ "FungibleTokenConnectors", "SwapConnectors", "DummyConnectors", - "FlowALPv1", + "FlowALPv0", { "name": "YieldToken", "args": [ @@ -1019,37 +1009,9 @@ "FlowYieldVaultsClosedBeta", "FlowYieldVaults", "UniswapV3SwapConnectors", + "MockStrategies", { - "name": "FlowYieldVaultsStrategies", - "args": [ - { - "value": "0x986Cb42b0557159431d48fE0A40073296414d410", - "type": "String" - }, - { - "value": "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", - "type": "String" - }, - { - "value": "0x8dd92c8d0C3b304255fF9D98ae59c3385F88360C", - "type": "String" - }, - { - "value": "0x102A7ed67858cF757CBBeA3390eaB72fcc60237E", - "type": "String" - }, - { - "value": [], - "type": "Array" - }, - { - "value": [], - "type": "Array" - } - ] - }, - { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0x986Cb42b0557159431d48fE0A40073296414d410", @@ -1118,66 +1080,7 @@ "FlowYieldVaultsClosedBeta", "FlowYieldVaults", { - "name": "FlowYieldVaultsStrategies", - "args": [ - { - "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", - "type": "String" - }, - { - "value": "0xeEDC6Ff75e1b10B903D9013c358e446a73d35341", - "type": "String" - }, - { - "value": "0x370A8DF17742867a44e56223EC20D82092242C85", - "type": "String" - }, - { - "value": "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c", - "type": "String" - }, - { - "value": [ - { - "value": "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c", - "type": "String" - }, - { - "value": "0x213979bB8A9A86966999b3AA797C1fcf3B967ae2", - "type": "String" - }, - { - "value": "0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED", - "type": "String" - }, - { - "value": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e", - "type": "String" - } - ], - "type": "Array" - }, - { - "value": [ - { - "value": "100", - "type": "UInt32" - }, - { - "value": "100", - "type": "UInt32" - }, - { - "value": "3000", - "type": "UInt32" - } - ], - "type": "Array" - } - ] - }, - { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", @@ -1229,67 +1132,9 @@ "FlowYieldVaultsSchedulerV1", "FlowYieldVaultsClosedBeta", "FlowYieldVaults", + "MockStrategies", { - "name": "FlowYieldVaultsStrategies", - "args": [ - { - "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", - "type": "String" - }, - { - "value": "0xeEDC6Ff75e1b10B903D9013c358e446a73d35341", - "type": "String" - }, - { - "value": "0x370A8DF17742867a44e56223EC20D82092242C85", - "type": "String" - }, - { - "value": "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c", - "type": "String" - }, - { - "value": [ - { - "value": "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c", - "type": "String" - }, - { - "value": "0x213979bB8A9A86966999b3AA797C1fcf3B967ae2", - "type": "String" - }, - { - "value": "0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED", - "type": "String" - }, - { - "value": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e", - "type": "String" - } - ], - "type": "Array" - }, - { - "value": [ - { - "value": "100", - "type": "UInt32" - }, - { - "value": "100", - "type": "UInt32" - }, - { - "value": "3000", - "type": "UInt32" - } - ], - "type": "Array" - } - ] - }, - { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", @@ -1350,51 +1195,9 @@ "FlowYieldVaultsSchedulerV1", "FlowYieldVaultsClosedBeta", "FlowYieldVaults", + "MockStrategies", { - "name": "FlowYieldVaultsStrategies", - "args": [ - { - "value": "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", - "type": "String" - }, - { - "value": "0x2Db6468229F6fB1a77d248Dbb1c386760C257804", - "type": "String" - }, - { - "value": "0xA1e0E4CCACA34a738f03cFB1EAbAb16331FA3E2c", - "type": "String" - }, - { - "value": "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", - "type": "String" - }, - { - "value": [ - { - "value": "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", - "type": "String" - }, - { - "value": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e", - "type": "String" - } - ], - "type": "Array" - }, - { - "value": [ - { - "value": "3000", - "type": "UInt32" - } - ], - "type": "Array" - } - ] - }, - { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", diff --git a/lib/FlowALP b/lib/FlowALP index 8fd49d3f..d9970e3d 160000 --- a/lib/FlowALP +++ b/lib/FlowALP @@ -1 +1 @@ -Subproject commit 8fd49d3f3a2647d8ae143c0dcff5c72fa190da1a +Subproject commit d9970e3d7aedffcb15eb1f953b299173c137f718 diff --git a/local/e2e_test.sh b/local/e2e_test.sh index fd0fd375..e3dc9258 100755 --- a/local/e2e_test.sh +++ b/local/e2e_test.sh @@ -31,7 +31,7 @@ run_txn "Transfer Flow tokens" \ run_txn "Creating YieldVault[0]" \ ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ - A.045a1763c93006ca.FlowYieldVaultsStrategies.TracerStrategy \ + A.045a1763c93006ca.MockStrategies.TracerStrategy \ A.0ae53cb6e3f42a79.FlowToken.Vault \ 100.0 \ --signer test-user \ diff --git a/local/setup_emulator.sh b/local/setup_emulator.sh index e8f3a19c..730950c2 100755 --- a/local/setup_emulator.sh +++ b/local/setup_emulator.sh @@ -18,7 +18,7 @@ flow transactions send ./lib/FlowALP/cadence/transactions/moet/mint_moet.cdc 0x0 flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.0ae53cb6e3f42a79.FlowToken.Vault' 0.5 --signer emulator-flow-yield-vaults flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.045a1763c93006ca.YieldToken.Vault' 1.0 --signer emulator-flow-yield-vaults -# configure FlowALPv1 +# configure FlowALP # # create Pool with MOET as default token flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc 'A.045a1763c93006ca.MOET.Vault' --signer emulator-flow-yield-vaults @@ -39,8 +39,8 @@ flow transactions send ./cadence/transactions/mocks/swapper/set_liquidity_connec flow transactions send ./cadence/transactions/mocks/swapper/set_liquidity_connector.cdc /storage/yieldTokenVault_0x045a1763c93006ca --signer emulator-flow-yield-vaults # add TracerStrategy as supported Strategy with the ability to initialize when new YieldVaults are created flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.045a1763c93006ca.FlowYieldVaultsStrategies.TracerStrategy' \ - 'A.045a1763c93006ca.FlowYieldVaultsStrategies.TracerStrategyComposer' \ + 'A.045a1763c93006ca.MockStrategies.TracerStrategy' \ + 'A.045a1763c93006ca.MockStrategies.TracerStrategyComposer' \ /storage/FlowYieldVaultsStrategyComposerIssuer_0x045a1763c93006ca \ --signer emulator-flow-yield-vaults @@ -51,8 +51,8 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.045a1763c93006ca.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.045a1763c93006ca.FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer' \ + 'A.045a1763c93006ca.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ + 'A.045a1763c93006ca.FlowYieldVaultsStrategiesV2.MorphoERC4626StrategyComposer' \ /storage/FlowYieldVaultsStrategyV1_1ComposerIssuer_0x045a1763c93006ca \ --signer emulator-flow-yield-vaults diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index 82f55da2..cd7fe499 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -14,7 +14,7 @@ flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/onboard echo "bridge MOET to EVM" flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/onboarding/onboard_by_type_identifier.cdc "A.6b00ff876c299c61.MOET.Vault" --compute-limit 9999 --network mainnet --signer mainnet-flow-alp-deployer -# configure FlowALPv1 +# configure FlowALP # # create Pool with MOET as default token flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc 'A.6b00ff876c299c61.MOET.Vault' --network mainnet --signer mainnet-flow-alp-deployer @@ -115,41 +115,42 @@ flow transactions send ./lib/FlowALP/FlowActions/cadence/transactions/fungible-t # flow transactions send ./cadence/transactions/mocks/swapper/set_liquidity_connector.cdc /storage/EVMVMBridgedToken_4154d5b0e2931a0a1e5b733f19161aa7d2fc4b95Vault --network mainnet --signer mainnet-admin # - -# Setup UniV3 path tauUSDFv -> USDF -> WFLOW -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +# Setup UniV3 path FUSDEV -> PYUSD0 -> WFLOW +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1654653399040a61.FlowToken.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ '[100,3000]' \ --network mainnet \ --signer mainnet-admin -# Setup UniV3 path tauUSDFv -> USDF -> WBTC -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +# Setup UniV3 path FUSDEV -> PYUSD0 -> WBTC +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ '[100,3000]' \ --network mainnet \ --signer mainnet-admin -# Setup UniV3 path tauUSDFv -> USDF -> WETH -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +# Setup UniV3 path FUSDEV -> PYUSD0 -> WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ '[100,3000]' \ --network mainnet \ --signer mainnet-admin - # -# add mUSDFStrategy as supported Strategy with the ability to initialize when new YieldVaults are created + flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer' \ - /storage/FlowYieldVaultsStrategyV1_1ComposerIssuer_0xb1d63873c3cc9f79 \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.MorphoERC4626StrategyComposer' \ + /storage/FlowYieldVaultsStrategyV2ComposerIssuer_0xb1d63873c3cc9f79 \ --network mainnet \ --signer mainnet-admin @@ -223,7 +224,7 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # test FlowYieldVault strategy # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategies.mUSDCStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1654653399040a61.FlowToken.Vault \ # 1.0 \ # --compute-limit 9999 \ @@ -233,7 +234,7 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # # WBTC (BTCf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault \ # 0.0000001 \ # --compute-limit 9999 \ @@ -242,7 +243,7 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # # WETH (ETHf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault \ # 0.00001 \ # --compute-limit 9999 \ diff --git a/local/setup_testnet.sh b/local/setup_testnet.sh index 905a3e3e..e1fb2697 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -6,13 +6,13 @@ flow project deploy --network testnet --update # set mocked prices in the MockOracle contract, initialized with MOET as unitOfAccount flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.7e60df042a9c0868.FlowToken.Vault' 0.5 --network testnet --signer testnet-admin -#flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.d2580caf2ef07c2f.YieldToken.Vault' 1.0 --network testnet --signer testnet-admin +flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.d2580caf2ef07c2f.YieldToken.Vault' 1.0 --network testnet --signer testnet-admin flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.dfc20aee650fcbdf.EVMVMBridgedToken_4154d5b0e2931a0a1e5b733f19161aa7d2fc4b95.Vault' 1.0 --network testnet --signer testnet-admin echo "bridge MOET to EVM" flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/onboarding/onboard_by_type_identifier.cdc "A.426f0458ced60037.MOET.Vault" --compute-limit 9999 --network testnet --signer testnet-flow-alp-deployer -# configure FlowALPv1 +# configure FlowALP # # add MOET - USD association on Band Oracle cd ./lib/FlowALP/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "USD" "A.426f0458ced60037.MOET.Vault" --network testnet --signer testnet-band-oracle-connectors @@ -82,42 +82,50 @@ flow transactions send ./cadence/transactions/mocks/swapper/set_liquidity_connec # add TracerStrategy as supported Strategy with the ability to initialize when new YieldVaults are created flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategies.TracerStrategy' \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategies.TracerStrategyComposer' \ + 'A.d2580caf2ef07c2f.MockStrategies.TracerStrategy' \ + 'A.d2580caf2ef07c2f.MockStrategies.TracerStrategyComposer' \ /storage/FlowYieldVaultsStrategyComposerIssuer_0xd2580caf2ef07c2f \ --network testnet \ --signer testnet-admin -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +## PYUSD0 Vault +# WFLOW univ3 path and fees +# path: FUSDEV - WFLOW +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.7e60df042a9c0868.FlowToken.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ + "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ + '["0x61b44D19486EE492449E83C1201581C754e9e1E1", "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ '[3000]' \ --network testnet \ --signer testnet-admin # WETH univ3 path and fees -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +# path: FUSDEV - MOET - WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","0x02d3575e2516a515E9B91a52b294Edc80DC7987c", "0x059A77239daFa770977DD9f1E98632C3E4559848"]' \ + "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ + '["0x61b44D19486EE492449E83C1201581C754e9e1E1","0x02d3575e2516a515E9B91a52b294Edc80DC7987c", "0x059A77239daFa770977DD9f1E98632C3E4559848"]' \ '[3000,3000]' \ --network testnet \ --signer testnet-admin # WBTC univ3 path and fees -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ +# path: FUSDEV - MOET - WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","0x02d3575e2516a515E9B91a52b294Edc80DC7987c","0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6"]' \ + "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ + '["0x61b44D19486EE492449E83C1201581C754e9e1E1","0x02d3575e2516a515E9B91a52b294Edc80DC7987c","0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6"]' \ '[3000,3000]' \ --network testnet \ --signer testnet-admin flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer' \ - /storage/FlowYieldVaultsStrategyV1_1ComposerIssuer_0xd2580caf2ef07c2f \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.MorphoERC4626StrategyComposer' \ + /storage/FlowYieldVaultsStrategyV2ComposerIssuer_0xd2580caf2ef07c2f \ --network testnet \ --signer testnet-admin @@ -158,7 +166,7 @@ flow transactions send ./lib/flow-evm-bridge/cadence/transactions/flow-token/tra # # Flow # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.7e60df042a9c0868.FlowToken.Vault \ # 100.0 \ # --signer \ @@ -168,7 +176,7 @@ flow transactions send ./lib/flow-evm-bridge/cadence/transactions/flow-token/tra # # WBTC (BTCf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault \ # 0.00001 \ # --compute-limit 9999 \ @@ -177,7 +185,7 @@ flow transactions send ./lib/flow-evm-bridge/cadence/transactions/flow-token/tra # # WETH (ETHf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault \ # 0.001 \ # --compute-limit 9999 \