From 63dcad8189413fa200acefc506a09bde85aed279 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 15 Jan 2026 21:32:11 -0500 Subject: [PATCH 01/24] pyusd strategy --- .../FlowYieldVaultsStrategiesV1_1.cdc | 86 +++++++++++++++++-- 1 file changed, 79 insertions(+), 7 deletions(-) diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc index 7cfe055b..231f9a5a 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc @@ -131,6 +131,65 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } } + 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: FlowCreditMarket.Position + access(self) var sink: {DeFiActions.Sink} + access(self) var source: {DeFiActions.Source} + + init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: FlowCreditMarket.Position) { + self.uniqueID = id + self.position = position + self.sink = position.createSink(type: collateralType) + self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) + } + + // 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 + } + } + access(all) struct TokenBundle { access(all) let moetTokenType: Type access(all) let moetTokenEVMAddress: EVM.EVMAddress @@ -306,11 +365,22 @@ 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<@mUSDFStrategy>(): + return <-create mUSDFStrategy( + id: uniqueID, + collateralType: collateralType, + position: position + ) + case Type<@FUSDEVStrategy>(): + return <-create FUSDEVStrategy( + id: uniqueID, + collateralType: collateralType, + position: position + ) + default: + panic("Unsupported strategy type \(type.identifier)") + } } /* =========================== @@ -671,7 +741,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { access(Configure) fun purgeConfig() { self.configs = { Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} + Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}, + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} } } } @@ -757,7 +828,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { let configs = { Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): ({} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}) + Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}, + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} } } self.account.storage.save(<-create StrategyComposerIssuer(configs: configs), to: self.IssuerStoragePath) From dc00223c8846c0981731d37c3347df41e2a72a28 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:09:46 -0500 Subject: [PATCH 02/24] config transaction scripts --- .../admin/upsert_musdf_config.cdc | 9 +++- local/setup_mainnet.sh | 41 +++++++++++++++++ local/setup_testnet.sh | 45 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc b/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc index 80f22443..1a5414c7 100644 --- a/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc +++ b/cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc @@ -8,7 +8,13 @@ import "FlowYieldVaultsStrategiesV1_1" /// - 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...FlowYieldVaultsStrategiesV1_1.mUSDFStrategy" + strategyTypeIdentifier: String, + + // collateral vault type (e.g. "A.0x...FlowToken.Vault") tokenTypeIdentifier: String, + + // yield token (EVM) address yieldTokenEVMAddress: String, // collateral path/fees: [YIELD, ..., ] @@ -17,6 +23,8 @@ 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 @@ -38,7 +46,6 @@ transaction( } let composerType = Type<@FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer>() - let strategyType = Type<@FlowYieldVaultsStrategiesV1_1.mUSDFStrategy>() if swapPath.length > 0 { issuer.addOrUpdateCollateralConfig( diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index 5982c6d5..4de0b4fa 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -118,6 +118,7 @@ flow transactions send ./lib/FlowCreditMarket/FlowActions/cadence/transactions/f # Setup UniV3 path tauUSDFv -> USDF -> WFLOW flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.1654653399040a61.FlowToken.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -128,6 +129,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path tauUSDFv -> USDF -> WBTC flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ @@ -137,6 +139,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path tauUSDFv -> USDF -> WETH flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ @@ -144,6 +147,37 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus --network mainnet \ --signer mainnet-admin + +# Setup UniV3 path FUSDEV -> PYUSD0 -> WFLOW +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.1654653399040a61.FlowToken.Vault' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ + '[100,3000]' \ + --network mainnet \ + --signer mainnet-admin + + +# Setup UniV3 path FUSDEV -> PYUSD0 -> WBTC +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ + '[100,3000]' \ + --network mainnet \ + --signer mainnet-admin + +# Setup UniV3 path FUSDEV -> PYUSD0 -> WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ + "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 \ @@ -153,6 +187,13 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate --network mainnet \ --signer mainnet-admin +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer' \ + /storage/FlowYieldVaultsStrategyV1_1ComposerIssuer_0xb1d63873c3cc9f79 \ + --network mainnet \ + --signer mainnet-admin + # configure PMStrategies strategy configs flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc \ 'A.b1d63873c3cc9f79.PMStrategiesV1.syWFLOWvStrategy' \ diff --git a/local/setup_testnet.sh b/local/setup_testnet.sh index c8cfb0f9..aeec38e2 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -89,6 +89,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate --signer testnet-admin flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.7e60df042a9c0868.FlowToken.Vault' \ "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -98,6 +99,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # WETH univ3 path and fees flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","0x02d3575e2516a515E9B91a52b294Edc80DC7987c", "0x059A77239daFa770977DD9f1E98632C3E4559848"]' \ @@ -107,6 +109,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # WBTC univ3 path and fees flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","0x02d3575e2516a515E9B91a52b294Edc80DC7987c","0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6"]' \ @@ -114,6 +117,41 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus --network testnet \ --signer testnet-admin + +## PYUSD0 Vault +# WFLOW univ3 path and fees +# path: FUSDEV - WFLOW +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.7e60df042a9c0868.FlowToken.Vault' \ + "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ + '["0x61b44D19486EE492449E83C1201581C754e9e1E1", "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ + '[3000]' \ + --network testnet \ + --signer testnet-admin + +# WETH univ3 path and fees +# path: FUSDEV - MOET - WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ + "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ + '["0x61b44D19486EE492449E83C1201581C754e9e1E1","0x02d3575e2516a515E9B91a52b294Edc80DC7987c", "0x059A77239daFa770977DD9f1E98632C3E4559848"]' \ + '[3000,3000]' \ + --network testnet \ + --signer testnet-admin + +# WBTC univ3 path and fees +# path: FUSDEV - MOET - WETH +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ + "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' \ @@ -121,6 +159,13 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate --network testnet \ --signer testnet-admin +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer' \ + /storage/FlowYieldVaultsStrategyV1_1ComposerIssuer_0xd2580caf2ef07c2f \ + --network testnet \ + --signer testnet-admin + # PYUSD0 Vault flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc \ 'A.d2580caf2ef07c2f.PMStrategiesV1.FUSDEVStrategy' \ From 4dc9664bbb8fdbe443b14962a51f2e20686c3680 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:23:58 -0500 Subject: [PATCH 03/24] mainnet setup script fixes --- local/setup_mainnet.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index 4de0b4fa..6ffffc8c 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -118,7 +118,7 @@ flow transactions send ./lib/FlowCreditMarket/FlowActions/cadence/transactions/f # Setup UniV3 path tauUSDFv -> USDF -> WFLOW flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ 'A.1654653399040a61.FlowToken.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -129,7 +129,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path tauUSDFv -> USDF -> WBTC flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ @@ -139,7 +139,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path tauUSDFv -> USDF -> WETH flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ @@ -150,7 +150,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path FUSDEV -> PYUSD0 -> WFLOW flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ 'A.1654653399040a61.FlowToken.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -161,7 +161,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path FUSDEV -> PYUSD0 -> WBTC flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ @@ -171,7 +171,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path FUSDEV -> PYUSD0 -> WETH flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ @@ -264,7 +264,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # test FlowYieldVault strategy # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategies.mUSDCStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ # A.1654653399040a61.FlowToken.Vault \ # 1.0 \ # --compute-limit 9999 \ @@ -274,7 +274,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # # WBTC (BTCf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ # A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault \ # 0.0000001 \ # --compute-limit 9999 \ @@ -283,7 +283,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # # WETH (ETHf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ # A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault \ # 0.00001 \ # --compute-limit 9999 \ From f8859573da7bcfb3bf1ef4090a66991b57f63f69 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:04:48 -0500 Subject: [PATCH 04/24] add readme addresses --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b98d7a2b..1fa311a5 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,14 @@ Mock FungibleToken implementations representing: | FlowActions | 0xd27920b6384e2a78 | DeFiActions | TBD | | FlowCreditMarket | 0xd27920b6384e2a78 | FlowALP | TBD | | FlowYieldVaults | 0xd27920b6384e2a78 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategies | 0xd27920b6384e2a78 | FlowYieldVaultsStrategies | TBD | +| FlowYieldVaultsStrategiesV1_1 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV1_1 | 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 | @@ -78,13 +80,15 @@ Mock FungibleToken implementations representing: | FlowActions | 0x6d888f175c158410 | DeFiActions | TBD | | FlowCreditMarket | 0x6b00ff876c299c61 | FlowALP | TBD | | FlowYieldVaults | 0xb1d63873c3cc9f79 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategies | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategies | TBD | +| FlowYieldVaultsStrategiesV1_1 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV1_1 | 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 From 98141020a60662a729f46de7a6c45e686f0d82d6 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:47:46 -0500 Subject: [PATCH 05/24] add morpho swapper to PMStrategiesV1 --- cadence/contracts/PMStrategiesV1.cdc | 40 +++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/cadence/contracts/PMStrategiesV1.cdc b/cadence/contracts/PMStrategiesV1.cdc index ba0ff9e9..27097081 100644 --- a/cadence/contracts/PMStrategiesV1.cdc +++ b/cadence/contracts/PMStrategiesV1.cdc @@ -8,7 +8,7 @@ import "SwapConnectors" import "FungibleTokenConnectors" // amm integration import "UniswapV3SwapConnectors" -import "ERC4626SwapConnectors" +import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // FlowYieldVaults platform import "FlowYieldVaults" @@ -346,24 +346,32 @@ access(all) contract PMStrategiesV1 { uniqueID: uniqueID ) // Swap Collateral -> YieldToken via ERC4626 Vault - let collateralTo4626Swapper = ERC4626SwapConnectors.Swapper( + let collateralToYieldMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swapper( asset: collateralType, vault: yieldTokenEVMAddress, coa: PMStrategiesV1._getCOACapability(), feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), - uniqueID: uniqueID + uniqueID: uniqueID, + isReversed: false ) // Finally, add the two Collateral -> YieldToken swappers into an aggregate MultiSwapper let collateralToYieldSwapper = SwapConnectors.MultiSwapper( inVault: collateralType, outVault: yieldTokenType, - swappers: [collateralToYieldAMMSwapper, collateralTo4626Swapper], + swappers: [collateralToYieldAMMSwapper, collateralToYieldMorphoERC4626Swapper], uniqueID: uniqueID ) - // YieldToken -> Collateral - // - Targets the Collateral <-> YieldToken pool as the only route since withdraws from the ERC4626 Vault are async - let yieldToCollateralSwapper = UniswapV3SwapConnectors.Swapper( + // create YieldToken <-> Collateral swappers + // + // YieldToken -> Collateral - can swap via two primary routes: + // - via AMM swap pairing YieldToken <-> Collateral + // - via ERC4626 vault deposit + // YieldToken -> Collateral high-level Swapper contains: + // - MultiSwapper aggregates across two sub-swappers + // - YieldToken -> Collateral (UniV3 Swapper) + // - YieldToken -> Collateral (ERC4626 Swapper) + let yieldToCollateralAMMSwapper = UniswapV3SwapConnectors.Swapper( factoryAddress: PMStrategiesV1.univ3FactoryEVMAddress, routerAddress: PMStrategiesV1.univ3RouterEVMAddress, quoterAddress: PMStrategiesV1.univ3QuoterEVMAddress, @@ -375,6 +383,24 @@ access(all) contract PMStrategiesV1 { uniqueID: uniqueID ) + // Swap (redeem) YieldToken -> Collateral via MorphoERC4626 Vault + let yieldToCollateralMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swaper( + asset: collateralType, + vault: yieldTokenEVMAddress, + coa: PMStrategiesV1._getCOACapability(), + feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: true + ) + + // Finally, add the two YieldToken <-> Collateral swappers into an aggregate MultiSwapper + let yieldToCollateralSwapper = SwapConnectors.MultiSwapper( + inVault: yieldTokenType, + outVault: collateralType, + swappers: [yieldToCollateralAMMSwapper, yieldToCollateralMorphoERC4626Swapper], + uniqueID: uniqueID + ) + // init SwapSink directing swapped funds to AutoBalancer // // Swaps provided Collateral to YieldToken & deposits to the AutoBalancer From f29da304b903f9a5f387786233c94cd72a7cc879 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:57:11 -0500 Subject: [PATCH 06/24] FYVStrategy v2 --- README.md | 4 +- ..._1.cdc => FlowYieldVaultsStrategiesV2.cdc} | 212 +++++------ cadence/contracts/PMStrategies.cdc | 358 ++++++++++++++++++ cadence/contracts/PMStrategiesV1.cdc | 6 +- cadence/tests/test_helpers.cdc | 4 +- ..._config.cdc => upsert_strategy_config.cdc} | 12 +- flow.json | 10 +- local/setup_emulator.sh | 4 +- local/setup_mainnet.sh | 64 +--- local/setup_testnet.sh | 63 +-- 10 files changed, 495 insertions(+), 242 deletions(-) rename cadence/contracts/{FlowYieldVaultsStrategiesV1_1.cdc => FlowYieldVaultsStrategiesV2.cdc} (83%) create mode 100644 cadence/contracts/PMStrategies.cdc rename cadence/transactions/flow-yield-vaults/admin/{upsert_musdf_config.cdc => upsert_strategy_config.cdc} (80%) diff --git a/README.md b/README.md index 1fa311a5..37328b2a 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Mock FungibleToken implementations representing: | FlowActions | 0xd27920b6384e2a78 | DeFiActions | TBD | | FlowCreditMarket | 0xd27920b6384e2a78 | FlowALP | TBD | | FlowYieldVaults | 0xd27920b6384e2a78 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategiesV1_1 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV1_1 | TBD | +| FlowYieldVaultsStrategiesV2 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xd27920b6384e2a78 | PMStrategiesV1 | TBD | | MOET | 0xd27920b6384e2a78 | MOET | 0x51f5cc5f50afb81e8f23c926080fa38c3024b238 | | USDC | 0xdfc20aee650fcbdf | EVMVMBridgedToken_d431955d55a99ef69beb96ba34718d0f9fbc91b1 | 0xd431955D55a99EF69BEb96BA34718d0f9fBc91b1 | @@ -80,7 +80,7 @@ Mock FungibleToken implementations representing: | FlowActions | 0x6d888f175c158410 | DeFiActions | TBD | | FlowCreditMarket | 0x6b00ff876c299c61 | FlowALP | TBD | | FlowYieldVaults | 0xb1d63873c3cc9f79 | FlowYieldVaults | TBD | -| FlowYieldVaultsStrategiesV1_1 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV1_1 | TBD | +| FlowYieldVaultsStrategiesV2 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xb1d63873c3cc9f79 | PMStrategiesV1 | TBD | | MOET | 0x6b00ff876c299c61 | MOET | 0x213979bB8A9A86966999b3AA797C1fcf3B967ae2 | | USDC | 0x1e4aa0b87d10b141 | EVMVMBridgedToken_f1815bd50389c46847f0bda824ec8da914045d14 | 0xF1815bd50389c46847f0Bda824eC8da914045D14 | diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc similarity index 83% rename from cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc rename to cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index 231f9a5a..b752d3f2 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -8,7 +8,7 @@ import "SwapConnectors" import "FungibleTokenConnectors" // amm integration import "UniswapV3SwapConnectors" -import "ERC4626SwapConnectors" +import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol import "FlowCreditMarket" @@ -24,7 +24,7 @@ import "FlowEVMBridgeConfig" // live oracles import "ERC4626PriceOracles" -/// FlowYieldVaultsStrategiesV1_1 +/// FlowYieldVaultsStrategiesV2 /// /// This contract defines Strategies used in the FlowYieldVaults platform. /// @@ -35,7 +35,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,66 +71,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } } - /// This strategy uses mUSDF vaults - access(all) resource mUSDFStrategy : 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: FlowCreditMarket.Position - access(self) var sink: {DeFiActions.Sink} - access(self) var source: {DeFiActions.Source} - - init(id: DeFiActions.UniqueIdentifier, collateralType: Type, position: FlowCreditMarket.Position) { - self.uniqueID = id - self.position = position - self.sink = position.createSink(type: collateralType) - self.source = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true) - } - - // 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 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 @@ -237,12 +178,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 } @@ -258,7 +199,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 } @@ -287,6 +228,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( @@ -304,7 +248,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( @@ -317,13 +261,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { // Swappers: MOET <-> YIELD (YIELD is ERC4626 vault token) let moetToYieldSwapper = self._createMoetToYieldSwapper(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(tokens: tokens, uniqueID: uniqueID) // AutoBalancer-directed swap IO let abaSwapSink = SwapConnectors.SwapSink( @@ -366,12 +304,6 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { balancerIO.autoBalancer.setSink(positionSwapSink, updateSinkID: true) switch type { - case Type<@mUSDFStrategy>(): - return <-create mUSDFStrategy( - id: uniqueID, - collateralType: collateralType, - position: position - ) case Type<@FUSDEVStrategy>(): return <-create FUSDEVStrategy( id: uniqueID, @@ -390,7 +322,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)" @@ -403,8 +335,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) @@ -427,7 +359,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, @@ -457,20 +389,20 @@ 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, + tokens: FlowYieldVaultsStrategiesV2.TokenBundle, uniqueID: DeFiActions.UniqueIdentifier ): SwapConnectors.MultiSwapper { // Direct MOET -> YIELD via AMM @@ -492,12 +424,12 @@ 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 + let underlyingTo4626 = MorphoERC4626SwapConnectors.Swapper( + vaultEVMAddress: tokens.yieldTokenEVMAddress, + coa: FlowYieldVaultsStrategiesV2._getCOACapability(), + feeSource: FlowYieldVaultsStrategiesV2._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: false ) let seq = SwapConnectors.SequentialSwapper( @@ -513,12 +445,56 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { ) } + access(self) fun _createYieldToMoetSwapper( + 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 + ) + + // 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 + ) + } + 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( @@ -537,7 +513,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 @@ -549,7 +525,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { issuanceSink: {DeFiActions.Sink}, repaymentSource: {DeFiActions.Source} ): FlowCreditMarket.Position { - let poolCap = FlowYieldVaultsStrategiesV1_1.account.storage.copy< + let poolCap = FlowYieldVaultsStrategiesV2.account.storage.copy< Capability >(from: FlowCreditMarket.PoolCapStoragePath) ?? panic("Missing or invalid pool capability") @@ -567,7 +543,7 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } access(self) fun _createYieldToCollateralSwapper( - collateralConfig: FlowYieldVaultsStrategiesV1_1.CollateralConfig, + collateralConfig: FlowYieldVaultsStrategiesV2.CollateralConfig, yieldTokenEVMAddress: EVM.EVMAddress, yieldTokenType: Type, collateralType: Type, @@ -623,10 +599,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 } @@ -645,12 +621,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 { @@ -660,8 +636,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") } @@ -670,7 +646,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: @@ -694,7 +670,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]! @@ -723,7 +699,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 @@ -740,9 +716,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } access(Configure) fun purgeConfig() { self.configs = { - Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}, - Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig} + Type<@MorphoERC4626StrategyComposer>(): { + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} } } } @@ -818,7 +793,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>() @@ -827,9 +802,8 @@ access(all) contract FlowYieldVaultsStrategiesV1_1 { } let configs = { - Type<@mUSDFStrategyComposer>(): { - Type<@mUSDFStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV1_1.CollateralConfig}, - Type<@FUSDEVStrategy>(): {} 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/PMStrategies.cdc b/cadence/contracts/PMStrategies.cdc new file mode 100644 index 00000000..817c4137 --- /dev/null +++ b/cadence/contracts/PMStrategies.cdc @@ -0,0 +1,358 @@ +// standards +import "FungibleToken" +import "FlowToken" +import "EVM" +// DeFiActions +import "DeFiActionsUtils" +import "DeFiActions" +import "SwapConnectors" +import "FungibleTokenConnectors" +// amm integration +import "UniswapV3SwapConnectors" +import "ERC4626SwapConnectors" +import "ERC4626Utils" +// FlowYieldVaults platform +import "FlowYieldVaults" +import "FlowYieldVaultsAutoBalancers" +// vm bridge +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" +import "FlowEVMBridge" +// live oracles +import "ERC4626PriceOracles" + +/// PMStrategies +/// +/// 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 PMStrategies { + + access(all) var univ3FactoryEVMAddress: EVM.EVMAddress + access(all) var univ3RouterEVMAddress: EVM.EVMAddress + access(all) var univ3QuoterEVMAddress: EVM.EVMAddress + + access(all) var yieldTokenEVMAddress: EVM.EVMAddress + access(all) var swapFeeTier: UInt32 + + /// Canonical StoragePath where the StrategyComposerIssuer should be stored + access(all) let IssuerStoragePath: StoragePath + + /// This strategy uses syWFLOWv vaults + access(all) resource syWFLOWvStrategy : 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? + + /// User-facing deposit connector + access(self) var sink: {DeFiActions.Sink} + /// User-facing withdrawal connector + access(self) var source: {DeFiActions.Source} + + init( + id: DeFiActions.UniqueIdentifier, + sink: {DeFiActions.Sink}, + source: {DeFiActions.Source} + ) { + self.uniqueID = id + self.sink = sink + self.source = source + } + + // 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 syWFLOWvStrategy + access(all) resource syWFLOWvStrategyComposer : FlowYieldVaults.StrategyComposer { + init() {} + + /// Returns the Types of Strategies composed by this StrategyComposer + access(all) view fun getComposedStrategyTypes(): {Type: Bool} { + return { + Type<@syWFLOWvStrategy>(): 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} { + 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 + access(all) fun createStrategy( + _ type: Type, + uniqueID: DeFiActions.UniqueIdentifier, + withFunds: @{FungibleToken.Vault} + ): @{FlowYieldVaults.Strategy} { + let flowTokenType = Type<@FlowToken.Vault>() + + // assign token types & associated EVM Addresses + let wflowTokenEVMAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) + ?? panic("Token Vault type \(flowTokenType.identifier) has not yet been registered with the VMbridge") + let yieldTokenType = FlowEVMBridgeConfig.getTypeAssociated(with: PMStrategies.yieldTokenEVMAddress) + ?? panic("Could not retrieve the VM Bridge associated Type for the yield token address \(PMStrategies.yieldTokenEVMAddress.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: PMStrategies.yieldTokenEVMAddress, + asset: flowTokenType, + uniqueID: uniqueID + ) + + // configure and AutoBalancer for this stack + 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 Strategy + recurringConfig: nil, // disables native AutoBalancer self-scheduling, no rebalancing required after init + 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 WFLOW <-> YIELD swappers + // + // WFLOW -> YIELD - WFLOW can swap to YieldToken via two primary routes + // - via AMM swap pairing WFLOW <-> YIELD + // - via 4626 vault, swapping first to underlying asset then depositing to the 4626 vault + // WFLOW -> YIELD high-level Swapper then contains + // - MultiSwapper aggregates across two sub-swappers + // - WFLOW -> YIELD (UniV3 Swapper) + let wflowToYieldAMMSwapper = UniswapV3SwapConnectors.Swapper( + factoryAddress: PMStrategies.univ3FactoryEVMAddress, + routerAddress: PMStrategies.univ3RouterEVMAddress, + quoterAddress: PMStrategies.univ3QuoterEVMAddress, + tokenPath: [wflowTokenEVMAddress, PMStrategies.yieldTokenEVMAddress], + feePath: [PMStrategies.swapFeeTier], + inVault: flowTokenType, + outVault: yieldTokenType, + coaCapability: PMStrategies._getCOACapability(), + uniqueID: uniqueID + ) + // Swap UNDERLYING -> YIELD via ERC4626 Vault + let wflowTo4626Swapper = ERC4626SwapConnectors.Swapper( + asset: flowTokenType, + vault: PMStrategies.yieldTokenEVMAddress, + coa: PMStrategies._getCOACapability(), + feeSource: PMStrategies._createFeeSource(withID: uniqueID), + uniqueID: uniqueID + ) + // Finally, add the two WFLOW -> YIELD swappers into an aggregate MultiSwapper + let wflowToYieldSwapper = SwapConnectors.MultiSwapper( + inVault: flowTokenType, + outVault: yieldTokenType, + swappers: [wflowToYieldAMMSwapper, wflowTo4626Swapper], + uniqueID: uniqueID + ) + + // YIELD -> WFLOW + // - Targets the WFLOW <-> YIELD pool as the only route since withdraws from the ERC4626 Vault are async + let yieldToWFLOWSwapper = UniswapV3SwapConnectors.Swapper( + factoryAddress: PMStrategies.univ3FactoryEVMAddress, + routerAddress: PMStrategies.univ3RouterEVMAddress, + quoterAddress: PMStrategies.univ3QuoterEVMAddress, + tokenPath: [PMStrategies.yieldTokenEVMAddress, wflowTokenEVMAddress], + feePath: [PMStrategies.swapFeeTier], + inVault: yieldTokenType, + outVault: flowTokenType, + coaCapability: PMStrategies._getCOACapability(), + uniqueID: uniqueID + ) + + // init SwapSink directing swapped funds to AutoBalancer + // + // Swaps provided WFLOW to YIELD & deposits to the AutoBalancer + let abaSwapSink = SwapConnectors.SwapSink(swapper: wflowToYieldSwapper, sink: abaSink, uniqueID: uniqueID) + // Swaps YIELD & provides swapped WFLOW, sourcing YIELD from the AutoBalancer + let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToWFLOWSwapper, source: abaSource, uniqueID: uniqueID) + + abaSwapSink.depositCapacity(from: &withFunds as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) + + assert(withFunds.balance == 0.0, message: "Vault should be empty after depositing") + destroy withFunds + + // Use the same uniqueID passed to createStrategy so Strategy.burnCallback + // calls _cleanupAutoBalancer with the correct ID + return <-create syWFLOWvStrategy( + id: uniqueID, + sink: abaSwapSink, + source: abaSwapSource + ) + } + } + + 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 Strategy creation consumes account storage + /// via configured AutoBalancers + access(all) resource StrategyComposerIssuer : FlowYieldVaults.StrategyComposerIssuer { + init() {} + + access(all) view fun getSupportedComposers(): {Type: Bool} { + return { + Type<@syWFLOWvStrategyComposer>(): true + } + } + access(all) fun issueComposer(_ type: Type): @{FlowYieldVaults.StrategyComposer} { + pre { + self.getSupportedComposers()[type] == true: + "Unsupported StrategyComposer \(type.identifier) requested" + } + switch type { + case Type<@syWFLOWvStrategyComposer>(): + return <- create syWFLOWvStrategyComposer() + default: + panic("Unsupported StrategyComposer \(type.identifier) requested") + } + } + access(Configure) + fun updateEVMAddresses( + factory: String, + router: String, + quoter: String, + yieldToken: String, + swapFeeTier: UInt32 + ) { + PMStrategies.univ3FactoryEVMAddress = EVM.addressFromString(factory) + PMStrategies.univ3RouterEVMAddress = EVM.addressFromString(router) + PMStrategies.univ3QuoterEVMAddress = EVM.addressFromString(quoter) + PMStrategies.yieldTokenEVMAddress = EVM.addressFromString(yieldToken) + PMStrategies.swapFeeTier = swapFeeTier + } + } + + /// 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 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, + swapFeeTier: UInt32 + ) { + self.univ3FactoryEVMAddress = EVM.addressFromString(univ3FactoryEVMAddress) + self.univ3RouterEVMAddress = EVM.addressFromString(univ3RouterEVMAddress) + self.univ3QuoterEVMAddress = EVM.addressFromString(univ3QuoterEVMAddress) + self.yieldTokenEVMAddress = EVM.addressFromString(yieldTokenEVMAddress) + self.swapFeeTier = swapFeeTier + + self.IssuerStoragePath = StoragePath(identifier: "PMStrategiesComposerIssuer_\(self.account.address)")! + + self.account.storage.save(<-create StrategyComposerIssuer(), 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/PMStrategiesV1.cdc b/cadence/contracts/PMStrategiesV1.cdc index 27097081..0d0b061f 100644 --- a/cadence/contracts/PMStrategiesV1.cdc +++ b/cadence/contracts/PMStrategiesV1.cdc @@ -347,8 +347,7 @@ access(all) contract PMStrategiesV1 { ) // Swap Collateral -> YieldToken via ERC4626 Vault let collateralToYieldMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swapper( - asset: collateralType, - vault: yieldTokenEVMAddress, + vaultEVMAddress: yieldTokenEVMAddress, coa: PMStrategiesV1._getCOACapability(), feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), uniqueID: uniqueID, @@ -385,8 +384,7 @@ access(all) contract PMStrategiesV1 { // Swap (redeem) YieldToken -> Collateral via MorphoERC4626 Vault let yieldToCollateralMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swaper( - asset: collateralType, - vault: yieldTokenEVMAddress, + vaultEVMAddress: yieldTokenEVMAddress, coa: PMStrategiesV1._getCOACapability(), feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), uniqueID: uniqueID, diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 1155e843..c4f46951 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -330,8 +330,8 @@ access(all) fun deployContracts() { 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", 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 80% 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 1a5414c7..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,14 @@ 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...FlowYieldVaultsStrategiesV1_1.mUSDFStrategy" + // e.g. "A.0x...FlowYieldVaultsStrategiesV2.FUSDEVStrategy" strategyTypeIdentifier: String, // collateral vault type (e.g. "A.0x...FlowToken.Vault") @@ -30,8 +30,8 @@ transaction( // 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) @@ -45,7 +45,7 @@ transaction( return out } - let composerType = Type<@FlowYieldVaultsStrategiesV1_1.mUSDFStrategyComposer>() + let composerType = Type<@FlowYieldVaultsStrategiesV2.MorphoERC4626StrategyComposer>() if swapPath.length > 0 { issuer.addOrUpdateCollateralConfig( diff --git a/flow.json b/flow.json index 0914fc34..e65a9ba1 100644 --- a/flow.json +++ b/flow.json @@ -161,8 +161,8 @@ "testnet": "d2580caf2ef07c2f" } }, - "FlowYieldVaultsStrategiesV1_1": { - "source": "cadence/contracts/FlowYieldVaultsStrategiesV1_1.cdc", + "FlowYieldVaultsStrategiesV2": { + "source": "cadence/contracts/FlowYieldVaultsStrategiesV2.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "b1d63873c3cc9f79", @@ -873,7 +873,7 @@ ] }, { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0x986Cb42b0557159431d48fE0A40073296414d410", @@ -1001,7 +1001,7 @@ ] }, { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", @@ -1106,7 +1106,7 @@ ] }, { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0x92657b195e22b69E4779BBD09Fa3CD46F0CF8e39", diff --git a/local/setup_emulator.sh b/local/setup_emulator.sh index c726fb5d..6110c5fe 100755 --- a/local/setup_emulator.sh +++ b/local/setup_emulator.sh @@ -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 6ffffc8c..3794db1a 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -115,42 +115,9 @@ flow transactions send ./lib/FlowCreditMarket/FlowActions/cadence/transactions/f # 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 \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.1654653399040a61.FlowToken.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","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 \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","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 \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' \ - 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ - "0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c" \ - '["0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c","0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ - '[100,3000]' \ - --network mainnet \ - --signer mainnet-admin - - # Setup UniV3 path FUSDEV -> PYUSD0 -> WFLOW -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1654653399040a61.FlowToken.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -160,8 +127,8 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # Setup UniV3 path FUSDEV -> PYUSD0 -> WBTC -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x717DAE2BaF7656BE9a9B01deE31d571a9d4c9579"]' \ @@ -170,8 +137,8 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus --signer mainnet-admin # Setup UniV3 path FUSDEV -> PYUSD0 -> WETH -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750","0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590"]' \ @@ -179,18 +146,11 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus --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 \ - --network mainnet \ - --signer mainnet-admin flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ - '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 @@ -264,7 +224,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # test FlowYieldVault strategy # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1654653399040a61.FlowToken.Vault \ # 1.0 \ # --compute-limit 9999 \ @@ -274,7 +234,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # # WBTC (BTCf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault \ # 0.0000001 \ # --compute-limit 9999 \ @@ -283,7 +243,7 @@ flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-cr # # WETH (ETHf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ -# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy \ +# 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 aeec38e2..a1d90e15 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -6,7 +6,7 @@ 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" @@ -88,41 +88,11 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate --network testnet \ --signer testnet-admin -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' - 'A.7e60df042a9c0868.FlowToken.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95", "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 \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' - 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","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 \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.mUSDFStrategy' - 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ - "0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95" \ - '["0x4154d5B0E2931a0A1E5b733f19161aa7D2fc4b95","0x02d3575e2516a515E9B91a52b294Edc80DC7987c","0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6"]' \ - '[3000,3000]' \ - --network testnet \ - --signer testnet-admin - - ## PYUSD0 Vault # WFLOW univ3 path and fees # path: FUSDEV - WFLOW -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.7e60df042a9c0868.FlowToken.Vault' \ "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ '["0x61b44D19486EE492449E83C1201581C754e9e1E1", "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"]' \ @@ -132,8 +102,8 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # WETH univ3 path and fees # path: FUSDEV - MOET - WETH -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ '["0x61b44D19486EE492449E83C1201581C754e9e1E1","0x02d3575e2516a515E9B91a52b294Edc80DC7987c", "0x059A77239daFa770977DD9f1E98632C3E4559848"]' \ @@ -143,8 +113,8 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus # WBTC univ3 path and fees # path: FUSDEV - MOET - WETH -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_musdf_config.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ "0x61b44D19486EE492449E83C1201581C754e9e1E1" \ '["0x61b44D19486EE492449E83C1201581C754e9e1E1","0x02d3575e2516a515E9B91a52b294Edc80DC7987c","0x208d09d2a6Dd176e3e95b3F0DE172A7471C5B2d6"]' \ @@ -153,16 +123,9 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_mus --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 \ - --network testnet \ - --signer testnet-admin - -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ - 'A.d2580caf2ef07c2f.FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy' \ - '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 @@ -203,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 \ @@ -213,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 \ @@ -222,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 \ From 428ba29731078a45301c05230e47e6d7f626f1f1 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:59:29 -0500 Subject: [PATCH 07/24] remove old PMStrategies --- cadence/contracts/PMStrategies.cdc | 358 ----------------------------- 1 file changed, 358 deletions(-) delete mode 100644 cadence/contracts/PMStrategies.cdc diff --git a/cadence/contracts/PMStrategies.cdc b/cadence/contracts/PMStrategies.cdc deleted file mode 100644 index 817c4137..00000000 --- a/cadence/contracts/PMStrategies.cdc +++ /dev/null @@ -1,358 +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" -// FlowYieldVaults platform -import "FlowYieldVaults" -import "FlowYieldVaultsAutoBalancers" -// vm bridge -import "FlowEVMBridgeConfig" -import "FlowEVMBridgeUtils" -import "FlowEVMBridge" -// live oracles -import "ERC4626PriceOracles" - -/// PMStrategies -/// -/// 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 PMStrategies { - - access(all) var univ3FactoryEVMAddress: EVM.EVMAddress - access(all) var univ3RouterEVMAddress: EVM.EVMAddress - access(all) var univ3QuoterEVMAddress: EVM.EVMAddress - - access(all) var yieldTokenEVMAddress: EVM.EVMAddress - access(all) var swapFeeTier: UInt32 - - /// Canonical StoragePath where the StrategyComposerIssuer should be stored - access(all) let IssuerStoragePath: StoragePath - - /// This strategy uses syWFLOWv vaults - access(all) resource syWFLOWvStrategy : 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? - - /// User-facing deposit connector - access(self) var sink: {DeFiActions.Sink} - /// User-facing withdrawal connector - access(self) var source: {DeFiActions.Source} - - init( - id: DeFiActions.UniqueIdentifier, - sink: {DeFiActions.Sink}, - source: {DeFiActions.Source} - ) { - self.uniqueID = id - self.sink = sink - self.source = source - } - - // 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 syWFLOWvStrategy - access(all) resource syWFLOWvStrategyComposer : FlowYieldVaults.StrategyComposer { - init() {} - - /// Returns the Types of Strategies composed by this StrategyComposer - access(all) view fun getComposedStrategyTypes(): {Type: Bool} { - return { - Type<@syWFLOWvStrategy>(): 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} { - 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 - access(all) fun createStrategy( - _ type: Type, - uniqueID: DeFiActions.UniqueIdentifier, - withFunds: @{FungibleToken.Vault} - ): @{FlowYieldVaults.Strategy} { - let flowTokenType = Type<@FlowToken.Vault>() - - // assign token types & associated EVM Addresses - let wflowTokenEVMAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) - ?? panic("Token Vault type \(flowTokenType.identifier) has not yet been registered with the VMbridge") - let yieldTokenType = FlowEVMBridgeConfig.getTypeAssociated(with: PMStrategies.yieldTokenEVMAddress) - ?? panic("Could not retrieve the VM Bridge associated Type for the yield token address \(PMStrategies.yieldTokenEVMAddress.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: PMStrategies.yieldTokenEVMAddress, - asset: flowTokenType, - uniqueID: uniqueID - ) - - // configure and AutoBalancer for this stack - 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 Strategy - recurringConfig: nil, // disables native AutoBalancer self-scheduling, no rebalancing required after init - 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 WFLOW <-> YIELD swappers - // - // WFLOW -> YIELD - WFLOW can swap to YieldToken via two primary routes - // - via AMM swap pairing WFLOW <-> YIELD - // - via 4626 vault, swapping first to underlying asset then depositing to the 4626 vault - // WFLOW -> YIELD high-level Swapper then contains - // - MultiSwapper aggregates across two sub-swappers - // - WFLOW -> YIELD (UniV3 Swapper) - let wflowToYieldAMMSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: PMStrategies.univ3FactoryEVMAddress, - routerAddress: PMStrategies.univ3RouterEVMAddress, - quoterAddress: PMStrategies.univ3QuoterEVMAddress, - tokenPath: [wflowTokenEVMAddress, PMStrategies.yieldTokenEVMAddress], - feePath: [PMStrategies.swapFeeTier], - inVault: flowTokenType, - outVault: yieldTokenType, - coaCapability: PMStrategies._getCOACapability(), - uniqueID: uniqueID - ) - // Swap UNDERLYING -> YIELD via ERC4626 Vault - let wflowTo4626Swapper = ERC4626SwapConnectors.Swapper( - asset: flowTokenType, - vault: PMStrategies.yieldTokenEVMAddress, - coa: PMStrategies._getCOACapability(), - feeSource: PMStrategies._createFeeSource(withID: uniqueID), - uniqueID: uniqueID - ) - // Finally, add the two WFLOW -> YIELD swappers into an aggregate MultiSwapper - let wflowToYieldSwapper = SwapConnectors.MultiSwapper( - inVault: flowTokenType, - outVault: yieldTokenType, - swappers: [wflowToYieldAMMSwapper, wflowTo4626Swapper], - uniqueID: uniqueID - ) - - // YIELD -> WFLOW - // - Targets the WFLOW <-> YIELD pool as the only route since withdraws from the ERC4626 Vault are async - let yieldToWFLOWSwapper = UniswapV3SwapConnectors.Swapper( - factoryAddress: PMStrategies.univ3FactoryEVMAddress, - routerAddress: PMStrategies.univ3RouterEVMAddress, - quoterAddress: PMStrategies.univ3QuoterEVMAddress, - tokenPath: [PMStrategies.yieldTokenEVMAddress, wflowTokenEVMAddress], - feePath: [PMStrategies.swapFeeTier], - inVault: yieldTokenType, - outVault: flowTokenType, - coaCapability: PMStrategies._getCOACapability(), - uniqueID: uniqueID - ) - - // init SwapSink directing swapped funds to AutoBalancer - // - // Swaps provided WFLOW to YIELD & deposits to the AutoBalancer - let abaSwapSink = SwapConnectors.SwapSink(swapper: wflowToYieldSwapper, sink: abaSink, uniqueID: uniqueID) - // Swaps YIELD & provides swapped WFLOW, sourcing YIELD from the AutoBalancer - let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToWFLOWSwapper, source: abaSource, uniqueID: uniqueID) - - abaSwapSink.depositCapacity(from: &withFunds as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) - - assert(withFunds.balance == 0.0, message: "Vault should be empty after depositing") - destroy withFunds - - // Use the same uniqueID passed to createStrategy so Strategy.burnCallback - // calls _cleanupAutoBalancer with the correct ID - return <-create syWFLOWvStrategy( - id: uniqueID, - sink: abaSwapSink, - source: abaSwapSource - ) - } - } - - 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 Strategy creation consumes account storage - /// via configured AutoBalancers - access(all) resource StrategyComposerIssuer : FlowYieldVaults.StrategyComposerIssuer { - init() {} - - access(all) view fun getSupportedComposers(): {Type: Bool} { - return { - Type<@syWFLOWvStrategyComposer>(): true - } - } - access(all) fun issueComposer(_ type: Type): @{FlowYieldVaults.StrategyComposer} { - pre { - self.getSupportedComposers()[type] == true: - "Unsupported StrategyComposer \(type.identifier) requested" - } - switch type { - case Type<@syWFLOWvStrategyComposer>(): - return <- create syWFLOWvStrategyComposer() - default: - panic("Unsupported StrategyComposer \(type.identifier) requested") - } - } - access(Configure) - fun updateEVMAddresses( - factory: String, - router: String, - quoter: String, - yieldToken: String, - swapFeeTier: UInt32 - ) { - PMStrategies.univ3FactoryEVMAddress = EVM.addressFromString(factory) - PMStrategies.univ3RouterEVMAddress = EVM.addressFromString(router) - PMStrategies.univ3QuoterEVMAddress = EVM.addressFromString(quoter) - PMStrategies.yieldTokenEVMAddress = EVM.addressFromString(yieldToken) - PMStrategies.swapFeeTier = swapFeeTier - } - } - - /// 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 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, - swapFeeTier: UInt32 - ) { - self.univ3FactoryEVMAddress = EVM.addressFromString(univ3FactoryEVMAddress) - self.univ3RouterEVMAddress = EVM.addressFromString(univ3RouterEVMAddress) - self.univ3QuoterEVMAddress = EVM.addressFromString(univ3QuoterEVMAddress) - self.yieldTokenEVMAddress = EVM.addressFromString(yieldTokenEVMAddress) - self.swapFeeTier = swapFeeTier - - self.IssuerStoragePath = StoragePath(identifier: "PMStrategiesComposerIssuer_\(self.account.address)")! - - self.account.storage.save(<-create StrategyComposerIssuer(), 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) - } - } -} From 2168f686bc2791b2c1db2af234be4cfded2ba4fd Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:41:21 -0500 Subject: [PATCH 08/24] tests --- cadence/contracts/FlowYieldVaults.cdc | 2 +- .../contracts/FlowYieldVaultsStrategiesV2.cdc | 99 +++-- cadence/contracts/PMStrategiesV1.cdc | 92 +++-- cadence/tests/PMStrategiesV1_test.cdc | 364 ++++++++++++++++++ cadence/tests/test_helpers.cdc | 20 + .../transactions/swap_flow_to_pyusd0.cdc | 159 ++++++++ flow.json | 28 ++ 7 files changed, 694 insertions(+), 70 deletions(-) create mode 100644 cadence/tests/PMStrategiesV1_test.cdc create mode 100644 cadence/tests/transactions/swap_flow_to_pyusd0.cdc diff --git a/cadence/contracts/FlowYieldVaults.cdc b/cadence/contracts/FlowYieldVaults.cdc index ccf618ea..8449f990 100644 --- a/cadence/contracts/FlowYieldVaults.cdc +++ b/cadence/contracts/FlowYieldVaults.cdc @@ -317,7 +317,7 @@ access(all) contract FlowYieldVaults { /// Withdraws the requested amount from the Strategy access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { post { - result.balance == amount: + result.balance >= amount && result.balance <= amount + 0.00000001: "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/FlowYieldVaultsStrategiesV2.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index cd176e96..6d66b4a9 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -8,6 +8,7 @@ import "SwapConnectors" import "FungibleTokenConnectors" // amm integration import "UniswapV3SwapConnectors" +import "ERC4626SwapConnectors" import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol @@ -259,9 +260,9 @@ access(all) contract FlowYieldVaultsStrategiesV2 { ) // 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._createYieldToMoetSwapper(tokens: tokens, uniqueID: uniqueID) + let yieldToMoetSwapper = self._createYieldToMoetSwapper(strategyType: type, tokens: tokens, uniqueID: uniqueID) // AutoBalancer-directed swap IO let abaSwapSink = SwapConnectors.SwapSink( @@ -402,6 +403,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { } access(self) fun _createMoetToYieldSwapper( + strategyType: Type, tokens: FlowYieldVaultsStrategiesV2.TokenBundle, uniqueID: DeFiActions.UniqueIdentifier ): SwapConnectors.MultiSwapper { @@ -424,16 +426,28 @@ access(all) contract FlowYieldVaultsStrategiesV2 { ) // UNDERLYING -> YIELD via ERC4626 vault - let underlyingTo4626 = MorphoERC4626SwapConnectors.Swapper( - vaultEVMAddress: tokens.yieldTokenEVMAddress, - coa: FlowYieldVaultsStrategiesV2._getCOACapability(), - feeSource: FlowYieldVaultsStrategiesV2._createFeeSource(withID: uniqueID), - uniqueID: uniqueID, - isReversed: false - ) + // 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 ) @@ -446,6 +460,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { } access(self) fun _createYieldToMoetSwapper( + strategyType: Type, tokens: FlowYieldVaultsStrategiesV2.TokenBundle, uniqueID: DeFiActions.UniqueIdentifier ): SwapConnectors.MultiSwapper { @@ -458,35 +473,45 @@ access(all) contract FlowYieldVaultsStrategiesV2 { uniqueID: uniqueID ) - // 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 - ) - + // 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 - ) + let seq = SwapConnectors.SequentialSwapper( + swappers: [yieldToUnderlying, underlyingToMoet], + uniqueID: uniqueID + ) - return SwapConnectors.MultiSwapper( - inVault: tokens.yieldTokenType, - outVault: tokens.moetTokenType, - swappers: [yieldToMoetAMM, seq], - 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( diff --git a/cadence/contracts/PMStrategiesV1.cdc b/cadence/contracts/PMStrategiesV1.cdc index 0d0b061f..366e5878 100644 --- a/cadence/contracts/PMStrategiesV1.cdc +++ b/cadence/contracts/PMStrategiesV1.cdc @@ -8,6 +8,7 @@ import "SwapConnectors" import "FungibleTokenConnectors" // amm integration import "UniswapV3SwapConnectors" +import "ERC4626SwapConnectors" import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // FlowYieldVaults platform @@ -346,20 +347,37 @@ access(all) contract PMStrategiesV1 { uniqueID: uniqueID ) // Swap Collateral -> YieldToken via ERC4626 Vault - let collateralToYieldMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swapper( - vaultEVMAddress: yieldTokenEVMAddress, - coa: PMStrategiesV1._getCOACapability(), - feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), - uniqueID: uniqueID, - isReversed: false - ) - // Finally, add the two Collateral -> YieldToken swappers into an aggregate MultiSwapper - let collateralToYieldSwapper = SwapConnectors.MultiSwapper( - inVault: collateralType, - outVault: yieldTokenType, - swappers: [collateralToYieldAMMSwapper, collateralToYieldMorphoERC4626Swapper], - uniqueID: uniqueID - ) + // Morpho vaults use MorphoERC4626SwapConnectors; standard ERC4626 vaults use ERC4626SwapConnectors + var collateralToYieldSwapper: SwapConnectors.MultiSwapper? = nil + if type == Type<@FUSDEVStrategy>() { + let collateralToYieldMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swapper( + vaultEVMAddress: yieldTokenEVMAddress, + coa: PMStrategiesV1._getCOACapability(), + feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: false + ) + collateralToYieldSwapper = SwapConnectors.MultiSwapper( + inVault: collateralType, + outVault: yieldTokenType, + swappers: [collateralToYieldAMMSwapper, collateralToYieldMorphoERC4626Swapper], + uniqueID: uniqueID + ) + } else { + let collateralToYieldERC4626Swapper = ERC4626SwapConnectors.Swapper( + asset: collateralType, + vault: yieldTokenEVMAddress, + coa: PMStrategiesV1._getCOACapability(), + feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), + uniqueID: uniqueID + ) + collateralToYieldSwapper = SwapConnectors.MultiSwapper( + inVault: collateralType, + outVault: yieldTokenType, + swappers: [collateralToYieldAMMSwapper, collateralToYieldERC4626Swapper], + uniqueID: uniqueID + ) + } // create YieldToken <-> Collateral swappers // @@ -382,29 +400,39 @@ access(all) contract PMStrategiesV1 { uniqueID: uniqueID ) - // Swap (redeem) YieldToken -> Collateral via MorphoERC4626 Vault - let yieldToCollateralMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swaper( - vaultEVMAddress: yieldTokenEVMAddress, - coa: PMStrategiesV1._getCOACapability(), - feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), - uniqueID: uniqueID, - isReversed: true - ) - - // Finally, add the two YieldToken <-> Collateral swappers into an aggregate MultiSwapper - let yieldToCollateralSwapper = SwapConnectors.MultiSwapper( - inVault: yieldTokenType, - outVault: collateralType, - swappers: [yieldToCollateralAMMSwapper, yieldToCollateralMorphoERC4626Swapper], - uniqueID: uniqueID - ) + // Reverse path: YieldToken -> Collateral + // Morpho vaults support direct redeem; standard ERC4626 vaults use AMM-only path + var yieldToCollateralSwapper: SwapConnectors.MultiSwapper? = nil + if type == Type<@FUSDEVStrategy>() { + let yieldToCollateralMorphoERC4626Swapper = MorphoERC4626SwapConnectors.Swapper( + vaultEVMAddress: yieldTokenEVMAddress, + coa: PMStrategiesV1._getCOACapability(), + feeSource: PMStrategiesV1._createFeeSource(withID: uniqueID), + uniqueID: uniqueID, + isReversed: true + ) + yieldToCollateralSwapper = SwapConnectors.MultiSwapper( + inVault: yieldTokenType, + outVault: collateralType, + swappers: [yieldToCollateralAMMSwapper, yieldToCollateralMorphoERC4626Swapper], + uniqueID: uniqueID + ) + } else { + // Standard ERC4626: AMM-only reverse (no synchronous redeem support) + yieldToCollateralSwapper = SwapConnectors.MultiSwapper( + inVault: yieldTokenType, + outVault: collateralType, + swappers: [yieldToCollateralAMMSwapper], + uniqueID: uniqueID + ) + } // init SwapSink directing swapped funds to AutoBalancer // // Swaps provided Collateral to YieldToken & deposits to the AutoBalancer - let abaSwapSink = SwapConnectors.SwapSink(swapper: collateralToYieldSwapper, sink: abaSink, uniqueID: uniqueID) + let abaSwapSink = SwapConnectors.SwapSink(swapper: collateralToYieldSwapper!, sink: abaSink, uniqueID: uniqueID) // Swaps YieldToken & provides swapped Collateral, sourcing YieldToken from the AutoBalancer - let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToCollateralSwapper, source: abaSource, uniqueID: uniqueID) + let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToCollateralSwapper!, source: abaSource, uniqueID: uniqueID) abaSwapSink.depositCapacity(from: &withFunds as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) diff --git a/cadence/tests/PMStrategiesV1_test.cdc b/cadence/tests/PMStrategiesV1_test.cdc new file mode 100644 index 00000000..65849fac --- /dev/null +++ b/cadence/tests/PMStrategiesV1_test.cdc @@ -0,0 +1,364 @@ +#test_fork(network: "mainnet", height: nil) + +import Test + +import "EVM" +import "FlowToken" +import "FlowYieldVaults" +import "PMStrategiesV1" +import "FlowYieldVaultsClosedBeta" + +/// Fork test for PMStrategiesV1 — validates the full YieldVault lifecycle (create, deposit, withdraw, close) +/// against real mainnet state using Morpho ERC4626 connectors. +/// +/// This test: +/// - Forks Flow mainnet to access real EVM state (Morpho vaults, UniswapV3 pools) +/// - Configures PMStrategiesV1 strategies for both syWFLOWv (FLOW collateral) and FUSDEV (PYUSD0 collateral) +/// - Tests the complete yield vault lifecycle through the strategy factory +/// - Validates Morpho ERC4626 swap connectors work with real vault contracts +/// +/// Mainnet addresses: +/// - Admin (FlowYieldVaults deployer): 0xb1d63873c3cc9f79 +/// - UniV3 Factory: 0xca6d7Bb03334bBf135902e1d919a5feccb461632 +/// - UniV3 Router: 0xeEDC6Ff75e1b10B903D9013c358e446a73d35341 +/// - UniV3 Quoter: 0x370A8DF17742867a44e56223EC20D82092242C85 +/// - WFLOW: 0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e +/// - syWFLOWv (More vault): 0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597 +/// - PYUSD0: 0x99aF3EeA856556646C98c8B9b2548Fe815240750 +/// - FUSDEV (Morpho vault): 0xd069d989e2F44B70c65347d1853C0c67e10a9F8D + +// --- Accounts --- + +/// Mainnet admin account — deployer of PMStrategiesV1, FlowYieldVaults, FlowYieldVaultsClosedBeta +access(all) let adminAccount = Test.getAccount(0xb1d63873c3cc9f79) + +/// Mainnet user account — used to test yield vault operations (has 5 PYUSD0) +access(all) let userAccount = Test.getAccount(0x443472749ebdaac8) + +// --- Strategy Config Constants --- + +/// syWFLOWvStrategy: FLOW collateral -> syWFLOWv Morpho ERC4626 vault +access(all) let syWFLOWvStrategyIdentifier = "A.b1d63873c3cc9f79.PMStrategiesV1.syWFLOWvStrategy" +access(all) let flowVaultIdentifier = "A.1654653399040a61.FlowToken.Vault" +access(all) let syWFLOWvEVMAddress = "0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597" + +/// FUSDEVStrategy: PYUSD0 collateral -> FUSDEV Morpho ERC4626 vault +access(all) let fusdEvStrategyIdentifier = "A.b1d63873c3cc9f79.PMStrategiesV1.FUSDEVStrategy" +access(all) let pyusd0VaultIdentifier = "A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault" +access(all) let fusdEvEVMAddress = "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" + +/// ERC4626VaultStrategyComposer type and issuer path +access(all) let composerIdentifier = "A.b1d63873c3cc9f79.PMStrategiesV1.ERC4626VaultStrategyComposer" +access(all) let issuerStoragePath: StoragePath = /storage/PMStrategiesV1ComposerIssuer_0xb1d63873c3cc9f79 + +/// Swap fee tier for Morpho vault <-> underlying asset UniV3 pools +access(all) let swapFeeTier: UInt32 = 100 + +// --- Test State --- + +access(all) var syWFLOWvYieldVaultID: UInt64 = 0 +access(all) var fusdEvYieldVaultID: UInt64 = 0 + +/* --- Test Helpers --- */ + +access(all) +fun _executeScript(_ path: String, _ args: [AnyStruct]): Test.ScriptResult { + return Test.executeScript(Test.readFile(path), args) +} + +access(all) +fun _executeTransactionFile(_ path: String, _ args: [AnyStruct], _ signers: [Test.TestAccount]): Test.TransactionResult { + let txn = Test.Transaction( + code: Test.readFile(path), + authorizers: signers.map(fun (s: Test.TestAccount): Address { return s.address }), + signers: signers, + arguments: args + ) + return Test.executeTransaction(txn) +} + +/* --- Setup --- */ + +access(all) fun setup() { + log("==== PMStrategiesV1 Fork Test Setup ====") + + log("Deploying EVMAmountUtils contract ...") + var err = Test.deployContract( + name: "EVMAmountUtils", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + log("Deploying UniswapV3SwapConnectors contract ...") + err = Test.deployContract( + name: "UniswapV3SwapConnectors", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + // Deploy Morpho contracts (latest local code) to the forked environment + log("Deploying Morpho contracts...") + err = Test.deployContract( + name: "ERC4626Utils", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/utils/ERC4626Utils.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + err = Test.deployContract( + name: "ERC4626SwapConnectors", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + err = Test.deployContract( + name: "MorphoERC4626SinkConnectors", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + err = Test.deployContract( + name: "MorphoERC4626SwapConnectors", + path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + log("Deploying FlowYieldVaults contract ...") + err = Test.deployContract( + name: "FlowYieldVaults", + path: "../../../cadence/contracts/FlowYieldVaults.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + // Redeploy PMStrategiesV1 with latest local code to override mainnet version + log("Deploying PMStrategiesV1...") + err = Test.deployContract( + name: "PMStrategiesV1", + path: "../../../cadence/contracts/PMStrategiesV1.cdc", + arguments: [ + "0xca6d7Bb03334bBf135902e1d919a5feccb461632", + "0xeEDC6Ff75e1b10B903D9013c358e446a73d35341", + "0x370A8DF17742867a44e56223EC20D82092242C85" + ] + ) + Test.expect(err, Test.beNil()) + + // // 1. Configure syWFLOWvStrategy with FlowToken collateral + // log("Configuring syWFLOWvStrategy...") + // var result = _executeTransactionFile( + // "../../transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc", + // [syWFLOWvStrategyIdentifier, flowVaultIdentifier, syWFLOWvEVMAddress, swapFeeTier], + // [adminAccount] + // ) + // Test.expect(result, Test.beSucceeded()) + // + // // 2. Configure FUSDEVStrategy with PYUSD0 collateral + // log("Configuring FUSDEVStrategy...") + // result = _executeTransactionFile( + // "../../transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc", + // [fusdEvStrategyIdentifier, pyusd0VaultIdentifier, fusdEvEVMAddress, swapFeeTier], + // [adminAccount] + // ) + // Test.expect(result, Test.beSucceeded()) + // + // // 3. Register syWFLOWvStrategy with the StrategyFactory + // log("Adding syWFLOWvStrategy composer...") + // result = _executeTransactionFile( + // "../../transactions/flow-yield-vaults/admin/add_strategy_composer.cdc", + // [syWFLOWvStrategyIdentifier, composerIdentifier, issuerStoragePath], + // [adminAccount] + // ) + // Test.expect(result, Test.beSucceeded()) + // + // // 4. Register FUSDEVStrategy with the StrategyFactory + // log("Adding FUSDEVStrategy composer...") + // result = _executeTransactionFile( + // "../../transactions/flow-yield-vaults/admin/add_strategy_composer.cdc", + // [fusdEvStrategyIdentifier, composerIdentifier, issuerStoragePath], + // [adminAccount] + // ) + // Test.expect(result, Test.beSucceeded()) + // + // 5. Grant beta access to user account for testing yield vault operations + log("Granting beta access to user...") + var result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/admin/grant_beta.cdc", + [], + [adminAccount, userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + log("==== Setup Complete ====") +} + +/* --- syWFLOWvStrategy Tests (FLOW collateral, Morpho syWFLOWv vault) --- */ + +access(all) fun testCreateSyWFLOWvYieldVault() { + log("Creating syWFLOWvStrategy yield vault with 1.0 FLOW...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/create_yield_vault.cdc", + [syWFLOWvStrategyIdentifier, flowVaultIdentifier, 1.0], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + // Retrieve the vault IDs + let idsResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", + [userAccount.address] + ) + Test.expect(idsResult, Test.beSucceeded()) + let ids = idsResult.returnValue! as! [UInt64]? + Test.assert(ids != nil && ids!.length > 0, message: "Expected at least one yield vault") + syWFLOWvYieldVaultID = ids![ids!.length - 1] + log("Created syWFLOWv yield vault ID: ".concat(syWFLOWvYieldVaultID.toString())) + + // Verify initial balance + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, syWFLOWvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil, message: "Expected balance to be available") + Test.assert(balance! > 0.0, message: "Expected positive balance after deposit") + log("syWFLOWv vault balance: ".concat(balance!.toString())) +} + +access(all) fun testDepositToSyWFLOWvYieldVault() { + log("Depositing 0.5 FLOW to syWFLOWv yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", + [syWFLOWvYieldVaultID, 0.5], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, syWFLOWvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil && balance! > 0.0, message: "Expected positive balance after additional deposit") + log("syWFLOWv vault balance after deposit: ".concat(balance!.toString())) +} + +access(all) fun testWithdrawFromSyWFLOWvYieldVault() { + log("Withdrawing 0.3 FLOW from syWFLOWv yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", + [syWFLOWvYieldVaultID, 0.3], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, syWFLOWvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil && balance! > 0.0, message: "Expected positive balance after withdrawal") + log("syWFLOWv vault balance after withdrawal: ".concat(balance!.toString())) +} + +access(all) fun testCloseSyWFLOWvYieldVault() { + log("Closing syWFLOWv yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/close_yield_vault.cdc", + [syWFLOWvYieldVaultID], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + log("syWFLOWv yield vault closed successfully") +} + +/* --- FUSDEVStrategy Tests (PYUSD0 collateral, Morpho FUSDEV vault) --- */ + +access(all) fun testCreateFUSDEVYieldVault() { + log("Creating FUSDEVStrategy yield vault with 1.0 PYUSD0...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/create_yield_vault.cdc", + [fusdEvStrategyIdentifier, pyusd0VaultIdentifier, 1.0], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + // Retrieve the vault IDs + let idsResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", + [userAccount.address] + ) + Test.expect(idsResult, Test.beSucceeded()) + let ids = idsResult.returnValue! as! [UInt64]? + Test.assert(ids != nil && ids!.length > 0, message: "Expected at least one yield vault") + fusdEvYieldVaultID = ids![ids!.length - 1] + log("Created FUSDEV yield vault ID: ".concat(fusdEvYieldVaultID.toString())) + + // Verify initial balance + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, fusdEvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil, message: "Expected balance to be available") + Test.assert(balance! > 0.0, message: "Expected positive balance after deposit") + log("FUSDEV vault balance: ".concat(balance!.toString())) +} + +access(all) fun testDepositToFUSDEVYieldVault() { + log("Depositing 0.5 PYUSD0 to FUSDEV yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", + [fusdEvYieldVaultID, 0.5], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, fusdEvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil && balance! > 0.0, message: "Expected positive balance after additional deposit") + log("FUSDEV vault balance after deposit: ".concat(balance!.toString())) +} + +access(all) fun testWithdrawFromFUSDEVYieldVault() { + log("Withdrawing 0.3 PYUSD0 from FUSDEV yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", + [fusdEvYieldVaultID, 0.3], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + + let balResult = _executeScript( + "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + [userAccount.address, fusdEvYieldVaultID] + ) + Test.expect(balResult, Test.beSucceeded()) + let balance = balResult.returnValue! as! UFix64? + Test.assert(balance != nil && balance! > 0.0, message: "Expected positive balance after withdrawal") + log("FUSDEV vault balance after withdrawal: ".concat(balance!.toString())) +} + +access(all) fun testCloseFUSDEVYieldVault() { + log("Closing FUSDEV yield vault...") + let result = _executeTransactionFile( + "../../transactions/flow-yield-vaults/close_yield_vault.cdc", + [fusdEvYieldVaultID], + [userAccount] + ) + Test.expect(result, Test.beSucceeded()) + log("FUSDEV yield vault closed successfully") +} diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 02f08050..73407035 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -262,6 +262,12 @@ access(all) fun deployContracts() { arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "EVMAmountUtils", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) err = Test.deployContract( name: "UniswapV3SwapConnectors", path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc", @@ -304,6 +310,20 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "MorphoERC4626SinkConnectors", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) + + err = Test.deployContract( + name: "MorphoERC4626SwapConnectors", + path: "../../lib/FlowCreditMarket/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( diff --git a/cadence/tests/transactions/swap_flow_to_pyusd0.cdc b/cadence/tests/transactions/swap_flow_to_pyusd0.cdc new file mode 100644 index 00000000..8637a277 --- /dev/null +++ b/cadence/tests/transactions/swap_flow_to_pyusd0.cdc @@ -0,0 +1,159 @@ +import "FungibleToken" +import "FungibleTokenMetadataViews" +import "ViewResolver" +import "FlowToken" +import "EVM" +import "FlowEVMBridgeUtils" +import "FlowEVMBridgeConfig" +import "ScopedFTProviders" + +/// Funds the signer with PYUSD0 by swapping FLOW on EVM via UniswapV3, then bridging to Cadence. +/// +/// Steps: +/// 1. Deposit FLOW to the signer's COA +/// 2. Wrap FLOW to WFLOW +/// 3. Swap WFLOW -> PYUSD0 via UniswapV3 exactInput +/// 4. Bridge PYUSD0 from EVM to Cadence +/// +/// @param flowAmount: Amount of FLOW to swap for PYUSD0 +/// +transaction(flowAmount: UFix64) { + + let coa: auth(EVM.Owner, EVM.Call, EVM.Bridge) &EVM.CadenceOwnedAccount + let scopedProvider: @ScopedFTProviders.ScopedFTProvider + let receiver: &{FungibleToken.Vault} + + prepare(signer: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability, CopyValue) &Account) { + // Borrow COA + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("No COA at /storage/evm") + + // Withdraw FLOW and deposit to COA + let flowVault = signer.storage.borrow(from: /storage/flowTokenVault) + ?? panic("No FlowToken vault") + let deposit <- flowVault.withdraw(amount: flowAmount) as! @FlowToken.Vault + self.coa.deposit(from: <-deposit) + + // Set up scoped fee provider for bridging + let approxFee = FlowEVMBridgeUtils.calculateBridgeFee(bytes: 400_000) + if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil { + let providerCap = signer.capabilities.storage.issue( + /storage/flowTokenVault + ) + signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath) + } + let providerCapCopy = signer.storage.copy>( + from: FlowEVMBridgeConfig.providerCapabilityStoragePath + ) ?? panic("Invalid provider capability") + self.scopedProvider <- ScopedFTProviders.createScopedFTProvider( + provider: providerCapCopy, + filters: [ScopedFTProviders.AllowanceFilter(approxFee)], + expiration: getCurrentBlock().timestamp + 1000.0 + ) + + // Set up PYUSD0 vault if needed + let pyusd0Type = CompositeType("A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault")! + let tokenContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: pyusd0Type) + ?? panic("Could not get PYUSD0 contract address") + let tokenContractName = FlowEVMBridgeUtils.getContractName(fromType: pyusd0Type) + ?? panic("Could not get PYUSD0 contract name") + let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName) + ?? panic("Could not borrow ViewResolver for PYUSD0") + let vaultData = viewResolver.resolveContractView( + resourceType: pyusd0Type, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("Could not resolve FTVaultData for PYUSD0") + if signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) == nil { + signer.storage.save(<-vaultData.createEmptyVault(), to: vaultData.storagePath) + signer.capabilities.unpublish(vaultData.receiverPath) + signer.capabilities.unpublish(vaultData.metadataPath) + let receiverCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath) + let metadataCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath) + signer.capabilities.publish(receiverCap, at: vaultData.receiverPath) + signer.capabilities.publish(metadataCap, at: vaultData.metadataPath) + } + self.receiver = signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) + ?? panic("Could not borrow PYUSD0 vault") + } + + execute { + let wflowAddr = EVM.addressFromString("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e") + let pyusd0Addr = EVM.addressFromString("0x99aF3EeA856556646C98c8B9b2548Fe815240750") + let routerAddr = EVM.addressFromString("0xeEDC6Ff75e1b10B903D9013c358e446a73d35341") + let zeroValue = EVM.Balance(attoflow: 0) + + // 1. Wrap FLOW -> WFLOW + let flowBalance = EVM.Balance(attoflow: 0) + flowBalance.setFLOW(flow: flowAmount) + let wrapRes = self.coa.call( + to: wflowAddr, + data: EVM.encodeABIWithSignature("deposit()", []), + gasLimit: 100_000, + value: flowBalance + ) + assert(wrapRes.status == EVM.Status.successful, message: "WFLOW wrap failed: ".concat(wrapRes.errorMessage)) + + // 2. Approve UniV3 Router to spend WFLOW + let amountEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(flowAmount, erc20Address: wflowAddr) + let approveRes = self.coa.call( + to: wflowAddr, + data: EVM.encodeABIWithSignature("approve(address,uint256)", [routerAddr, amountEVM]), + gasLimit: 100_000, + value: zeroValue + ) + assert(approveRes.status == EVM.Status.successful, message: "WFLOW approve failed: ".concat(approveRes.errorMessage)) + + // 3. Swap WFLOW -> PYUSD0 via UniV3 exactInput + // Path encoding: tokenIn(20) | fee(3 bytes big-endian) | tokenOut(20) + var pathBytes: [UInt8] = [] + let wflowFixed: [UInt8; 20] = wflowAddr.bytes + let pyusd0Fixed: [UInt8; 20] = pyusd0Addr.bytes + var i = 0 + while i < 20 { pathBytes.append(wflowFixed[i]); i = i + 1 } + // fee 3000 = 0x000BB8 big-endian + pathBytes.append(0x00) + pathBytes.append(0x0B) + pathBytes.append(0xB8) + i = 0 + while i < 20 { pathBytes.append(pyusd0Fixed[i]); i = i + 1 } + + let swapRes = self.coa.call( + to: routerAddr, + data: EVM.encodeABIWithSignature( + "exactInput((bytes,address,uint256,uint256))", + [EVM.EVMBytes(value: pathBytes), self.coa.address(), amountEVM, UInt256(0)] + ), + gasLimit: 1_000_000, + value: zeroValue + ) + assert(swapRes.status == EVM.Status.successful, message: "UniV3 swap failed: ".concat(swapRes.errorMessage)) + + // 4. Check PYUSD0 balance in COA + let balRes = self.coa.call( + to: pyusd0Addr, + data: EVM.encodeABIWithSignature("balanceOf(address)", [self.coa.address()]), + gasLimit: 100_000, + value: zeroValue + ) + assert(balRes.status == EVM.Status.successful, message: "balanceOf failed") + let decoded = EVM.decodeABI(types: [Type()], data: balRes.data) + let pyusd0Balance = decoded[0] as! UInt256 + assert(pyusd0Balance > UInt256(0), message: "No PYUSD0 received from swap") + + // 5. Bridge PYUSD0 from EVM to Cadence + let pyusd0Type = CompositeType("A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault")! + let bridgedVault <- self.coa.withdrawTokens( + type: pyusd0Type, + amount: pyusd0Balance, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + assert(bridgedVault.balance > 0.0, message: "Bridged PYUSD0 vault is empty") + log("Bridged PYUSD0 amount: ".concat(bridgedVault.balance.toString())) + + // Deposit bridged PYUSD0 into the signer's Cadence vault + self.receiver.deposit(from: <-bridgedVault) + + destroy self.scopedProvider + } +} diff --git a/flow.json b/flow.json index 821d0734..9a8fd739 100644 --- a/flow.json +++ b/flow.json @@ -53,6 +53,15 @@ "testnet": "7014dcffa1f14186" } }, + "EVMAmountUtils": { + "source": "./lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + "aliases": { + "emulator": "045a1763c93006ca", + "mainnet": "6d888f175c158410", + "testing": "0000000000000009", + "testnet": "0b11b1848a8aa2c0" + } + }, "ERC4626SwapConnectors": { "source": "./lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc", "aliases": { @@ -199,6 +208,7 @@ "source": "cadence/contracts/mocks/MockOracle.cdc", "aliases": { "emulator": "045a1763c93006ca", + "mainnet": "b1d63873c3cc9f79", "testing": "0000000000000009", "testnet": "d2580caf2ef07c2f" } @@ -215,14 +225,32 @@ "source": "cadence/contracts/mocks/MockSwapper.cdc", "aliases": { "emulator": "045a1763c93006ca", + "mainnet": "b1d63873c3cc9f79", "testing": "0000000000000009", "testnet": "d2580caf2ef07c2f" } }, + "MorphoERC4626SinkConnectors": { + "source": "./lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + "aliases": { + "emulator": "045a1763c93006ca", + "mainnet": "251032a66e9700ef", + "testing": "0000000000000009" + } + }, + "MorphoERC4626SwapConnectors": { + "source": "./lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", + "aliases": { + "emulator": "045a1763c93006ca", + "mainnet": "251032a66e9700ef", + "testing": "0000000000000009" + } + }, "PMStrategiesV1": { "source": "cadence/contracts/PMStrategiesV1.cdc", "aliases": { "emulator": "045a1763c93006ca", + "mainnet": "b1d63873c3cc9f79", "testing": "0000000000000009" } }, From 4a3845285f45c3831144d1c9326836d498a6a03f Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:48:36 -0500 Subject: [PATCH 09/24] update ref --- lib/FlowCreditMarket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlowCreditMarket b/lib/FlowCreditMarket index 81635182..3eaa1bad 160000 --- a/lib/FlowCreditMarket +++ b/lib/FlowCreditMarket @@ -1 +1 @@ -Subproject commit 816351826a9deb86033469d8dea9cc847104ecbd +Subproject commit 3eaa1badcb17d45aff6bbe50bba330458828a045 From 94258991f93bfd5ed6f0fa062445f1ebd463afcf Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:38:24 -0500 Subject: [PATCH 10/24] fix renamed reference --- README.md | 44 ++++----- .../contracts/FlowYieldVaultsStrategies.cdc | 26 +++--- .../contracts/FlowYieldVaultsStrategiesV2.cdc | 14 +-- ...Consumer.cdc => MockFlowALPv1Consumer.cdc} | 22 ++--- cadence/contracts/mocks/MockSwapper.cdc | 6 +- .../get_complete_user_position_info.cdc | 18 ++-- cadence/tests/PMStrategiesV1_test.cdc | 90 ++++++------------- cadence/tests/atomic_registration_gc_test.cdc | 8 +- cadence/tests/rebalance_scenario1_test.cdc | 4 +- cadence/tests/rebalance_scenario2_test.cdc | 6 +- cadence/tests/rebalance_scenario3a_test.cdc | 12 +-- cadence/tests/rebalance_scenario3b_test.cdc | 8 +- cadence/tests/rebalance_scenario3c_test.cdc | 10 +-- cadence/tests/rebalance_scenario3d_test.cdc | 10 +-- cadence/tests/rebalance_yield_test.cdc | 4 +- .../scheduled_rebalance_integration_test.cdc | 6 +- .../scheduled_rebalance_scenario_test.cdc | 6 +- cadence/tests/scheduled_supervisor_test.cdc | 4 +- cadence/tests/scheduler_edge_cases_test.cdc | 4 +- cadence/tests/test_helpers.cdc | 44 ++++----- cadence/tests/tracer_strategy_test.cdc | 14 +-- cadence/tests/yield_vault_lifecycle_test.cdc | 6 +- .../position/create_wrapped_position.cdc | 10 +-- ...autobalancer-restart-recurring-proposal.md | 2 +- docs/rebalancing_architecture.md | 58 ++++++------ flow.json | 18 ++-- local/setup_emulator.sh | 6 +- local/setup_mainnet.sh | 38 ++++---- local/setup_testnet.sh | 28 +++--- 29 files changed, 245 insertions(+), 281 deletions(-) rename cadence/contracts/mocks/{MockFlowCreditMarketConsumer.cdc => MockFlowALPv1Consumer.cdc} (66%) diff --git a/README.md b/README.md index 37328b2a..abe74e5e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # FlowYieldVaults Smart Contracts -FlowYieldVaults is a yield farming platform built on the Flow blockchain using [Cadence](https://cadence-lang.org). The platform enables users to deposit tokens to supported DeFi strategies such as collateralized borrowing via FlowCreditMarket's Active Lending Platform. FlowYieldVaults aims to support yield-generating strategies, automatically optimizing returns through [DeFi Actions](https://developers.flow.com/blockchain-development-tutorials/forte/flow-actions) components and auto-balancing mechanisms. +FlowYieldVaults is a yield farming platform built on the Flow blockchain using [Cadence](https://cadence-lang.org). The platform enables users to deposit tokens to supported DeFi strategies such as collateralized borrowing via FlowALPv1's Active Lending Platform. FlowYieldVaults aims to support yield-generating strategies, automatically optimizing returns through [DeFi Actions](https://developers.flow.com/blockchain-development-tutorials/forte/flow-actions) components and auto-balancing mechanisms. ## System Architecture @@ -22,7 +22,7 @@ The main contract that orchestrates the entire yield farming system: Implements specific yield strategies: -- **TracerStrategy**: A strategy that uses FlowCreditMarket lending positions with auto-balancing +- **TracerStrategy**: A strategy that uses FlowALPv1 lending positions with auto-balancing - **TracerStrategyComposer**: Creates TracerStrategy instances with complex DeFi Actions stacking - **StrategyComposerIssuer**: Controls access to strategy composer creation @@ -41,7 +41,7 @@ Manages automated rebalancing of positions: Mock FungibleToken implementations representing: - **YieldToken**: Receipt tokens for yield-bearing positions -- **MOET**: FlowCreditMarket's synthetic stablecoin +- **MOET**: FlowALPv1's synthetic stablecoin ### Mock Infrastructure @@ -63,7 +63,7 @@ Mock FungibleToken implementations representing: | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0xd27920b6384e2a78 | DeFiActions | TBD | -| FlowCreditMarket | 0xd27920b6384e2a78 | FlowALP | TBD | +| FlowALPv1 | 0xd27920b6384e2a78 | FlowALPv1 | TBD | | FlowYieldVaults | 0xd27920b6384e2a78 | FlowYieldVaults | TBD | | FlowYieldVaultsStrategiesV2 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xd27920b6384e2a78 | PMStrategiesV1 | TBD | @@ -78,7 +78,7 @@ Mock FungibleToken implementations representing: | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0x6d888f175c158410 | DeFiActions | TBD | -| FlowCreditMarket | 0x6b00ff876c299c61 | FlowALP | TBD | +| FlowALPv1 | 0x6b00ff876c299c61 | FlowALPv1 | TBD | | FlowYieldVaults | 0xb1d63873c3cc9f79 | FlowYieldVaults | TBD | | FlowYieldVaultsStrategiesV2 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xb1d63873c3cc9f79 | PMStrategiesV1 | TBD | @@ -92,14 +92,14 @@ Mock FungibleToken implementations representing: ## How the System Works -Below is an overview of the initial prototype Tracer Strategy in the broader context of FlowCreditMarket and the FlowYieldVaults platform. +Below is an overview of the initial prototype Tracer Strategy in the broader context of FlowALPv1 and the FlowYieldVaults platform. ### 1. Strategy Architecture The TracerStrategy demonstrates the power of DeFi Actions composition: ``` -User Deposit (FLOW) → FlowCreditMarket Position → MOET Issuance → Swap to YieldToken → AutoBalancer +User Deposit (FLOW) → FlowALPv1 Position → MOET Issuance → Swap to YieldToken → AutoBalancer ↑ YieldToken → Swap to FLOW → Recollateralize Position ``` @@ -188,7 +188,7 @@ The FlowYieldVaults platform implements sophisticated automatic rebalancing and **Important Distinction:** The system has TWO different rebalancing mechanisms: 1. **AutoBalancer Rebalancing** (DFB): Maintains optimal ratio between YieldToken holdings and expected deposit value -2. **Position Rebalancing** (FlowCreditMarket): Maintains healthy collateralization ratios for lending positions +2. **Position Rebalancing** (FlowALPv1): Maintains healthy collateralization ratios for lending positions These work together but serve different purposes and can trigger independently based on market conditions. @@ -210,12 +210,12 @@ The AutoBalancer continuously monitors the **value ratio** between: **When:** Current YieldToken value > 105% historical value of deposits **Cause:** YieldToken price has increased OR position became over-collateralized leading to excess token holdings -**Action:** AutoBalancer deposits excess YieldToken to the rebalanceSink, swapping to FLOW and recollateralizing the FlowCreditMarket position. +**Action:** AutoBalancer deposits excess YieldToken to the rebalanceSink, swapping to FLOW and recollateralizing the FlowALPv1 position. **Automated Flow:** ``` -YieldToken (excess) → Swap to FLOW → Deposit to FlowCreditMarket Position (recollateralization) +YieldToken (excess) → Swap to FLOW → Deposit to FlowALPv1 Position (recollateralization) ``` **Result:** @@ -264,7 +264,7 @@ The system creates a sophisticated token flow: 1. **Initial Position Opening:** - - User deposits FLOW → FlowCreditMarket Position + - User deposits FLOW → FlowALPv1 Position - Position issues MOET → Swaps to YieldToken - YieldToken held in AutoBalancer @@ -335,7 +335,7 @@ This creates a fully automated yield farming system that adapts to market condit ## Interest Rate System -The FlowCreditMarket implements a sophisticated interest rate system that governs borrowing costs and lending yields. This system is fundamental to the protocol's economics and affects all lending positions. +The FlowALPv1 implements a sophisticated interest rate system that governs borrowing costs and lending yields. This system is fundamental to the protocol's economics and affects all lending positions. ### How Interest Rates Work @@ -520,15 +520,15 @@ The interest rate system is designed to: 3. **Manage Risk**: Insurance reserves and dynamic adjustments protect the protocol 4. **Enable Automation**: Continuous compounding without manual intervention -This interest system is what enables the FlowCreditMarket to function as a sustainable lending platform while providing the foundation for complex yield farming strategies built on top. +This interest system is what enables the FlowALPv1 to function as a sustainable lending platform while providing the foundation for complex yield farming strategies built on top. -## FlowCreditMarket Loan Health Mechanism +## FlowALPv1 Loan Health Mechanism -The FlowCreditMarket implements a sophisticated loan health system that determines borrowing capacity, monitors position safety, and prevents liquidations. This system is fundamental to how the TracerStrategy calculates how much can be borrowed against a user's initial collateral position. +The FlowALPv1 implements a sophisticated loan health system that determines borrowing capacity, monitors position safety, and prevents liquidations. This system is fundamental to how the TracerStrategy calculates how much can be borrowed against a user's initial collateral position. ### Key Definitions -Before diving into the mechanics, it's important to understand the core terminology used throughout the FlowCreditMarket loan system: +Before diving into the mechanics, it's important to understand the core terminology used throughout the FlowALPv1 loan system: #### Position-Related Terms @@ -577,7 +577,7 @@ Position Health = Effective Collateral / Effective Debt #### Health Computation Function ```cadence -// From FlowCreditMarket.cdc +// From FlowALPv1.cdc access(all) fun healthComputation(effectiveCollateral: UFix64, effectiveDebt: UFix64): UFix64 { if effectiveCollateral == 0.0 { return 0.0 @@ -866,7 +866,7 @@ let value = tokenPrice * trueBalance - Cross-collateralization enables complex strategies - Unified health calculation across all assets -This comprehensive loan health system enables the FlowCreditMarket to safely support leveraged yield farming strategies while maintaining strict risk management and protecting user funds from liquidation through automated rebalancing mechanisms. +This comprehensive loan health system enables the FlowALPv1 to safely support leveraged yield farming strategies while maintaining strict risk management and protecting user funds from liquidation through automated rebalancing mechanisms. ## Testing Rebalancing @@ -1020,7 +1020,7 @@ flow transactions send cadence/transactions/flow-yield-vaults/admin/rebalance_au $YIELD_VAULT_ID true \ --signer test-account -flow transactions send cadence/transactions/flow-credit-market/pool-management/rebalance_position.cdc \ +flow transactions send cadence/transactions/flow-alp/pool-management/rebalance_position.cdc \ $YIELD_VAULT_ID true \ --signer test-account @@ -1512,10 +1512,10 @@ scripts/flow-yield-vaults/get_auto_balancer_balance_by_id.cdc ```bash # Overall position health (collateralization ratio) -scripts/flow-credit-market/position_health.cdc +scripts/flow-alp/position_health.cdc # Available balance for withdrawal from position -scripts/flow-credit-market/get_available_balance.cdc +scripts/flow-alp/get_available_balance.cdc ``` #### User Balance @@ -1557,7 +1557,7 @@ scripts/tokens/get_balance.cdc 1. **"Could not borrow AutoBalancer"** - Ensure YieldVault ID is correct 2. **"No price set for token"** - Set initial prices for all tokens before testing 3. **"Insufficient liquidity"** - Fund MockSwapper with adequate token reserves -4. **"Position not found"** - Verify FlowCreditMarket position ID (different from YieldVault ID) +4. **"Position not found"** - Verify FlowALPv1 position ID (different from YieldVault ID) #### Debugging Commands: diff --git a/cadence/contracts/FlowYieldVaultsStrategies.cdc b/cadence/contracts/FlowYieldVaultsStrategies.cdc index d7f7f46a..a5d4d1ff 100644 --- a/cadence/contracts/FlowYieldVaultsStrategies.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategies.cdc @@ -12,7 +12,7 @@ import "UniswapV3SwapConnectors" import "ERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol -import "FlowCreditMarket" +import "FlowALPv1" // FlowYieldVaults platform import "FlowYieldVaultsClosedBeta" import "FlowYieldVaults" @@ -57,7 +57,7 @@ access(all) contract FlowYieldVaultsStrategies { /// Canonical StoragePath where the StrategyComposerIssuer should be stored access(all) let IssuerStoragePath: StoragePath - /// This is the first Strategy implementation, wrapping a @FlowCreditMarket.Position along with its related Sink & + /// 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. @@ -65,11 +65,11 @@ access(all) contract FlowYieldVaultsStrategies { /// 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: @FlowCreditMarket.Position + 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: @FlowCreditMarket.Position) { + 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) @@ -193,9 +193,9 @@ access(all) contract FlowYieldVaultsStrategies { // Swaps YieldToken & provides swapped Stable, sourcing YieldToken from the AutoBalancer let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToStableSwapper, source: abaSource, uniqueID: uniqueID) - // open a FlowCreditMarket position - let poolCap = FlowYieldVaultsStrategies.account.storage.load>( - from: FlowCreditMarket.PoolCapStoragePath + // open a FlowALPv1 position + let poolCap = FlowYieldVaultsStrategies.account.storage.load>( + from: FlowALPv1.PoolCapStoragePath ) ?? panic("Missing pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") @@ -206,7 +206,7 @@ access(all) contract FlowYieldVaultsStrategies { repaymentSource: abaSwapSource, pushToDrawDownSink: true ) - FlowYieldVaultsStrategies.account.storage.save(poolCap, to: FlowCreditMarket.PoolCapStoragePath) + 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) @@ -240,11 +240,11 @@ access(all) contract FlowYieldVaultsStrategies { /// 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: @FlowCreditMarket.Position + 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: @FlowCreditMarket.Position) { + 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) @@ -469,9 +469,9 @@ access(all) contract FlowYieldVaultsStrategies { // Swaps YIELD & provides swapped MOET, sourcing YIELD from the AutoBalancer let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToMOETSwapper, source: abaSource, uniqueID: uniqueID) - // open a FlowCreditMarket position - let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( - from: FlowCreditMarket.PoolCapStoragePath + // open a FlowALPv1 position + let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( + from: FlowALPv1.PoolCapStoragePath ) ?? panic("Missing or invalid pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index 6d66b4a9..1712e924 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -12,7 +12,7 @@ import "ERC4626SwapConnectors" import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol -import "FlowCreditMarket" +import "FlowALPv1" // FlowYieldVaults platform import "FlowYieldVaults" import "FlowYieldVaultsAutoBalancers" @@ -77,11 +77,11 @@ access(all) contract FlowYieldVaultsStrategiesV2 { /// 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: @FlowCreditMarket.Position + 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: @FlowCreditMarket.Position) { + 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) @@ -276,7 +276,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { uniqueID: uniqueID ) - // Open FlowCreditMarket position + // Open FlowALPv1 position let position <- self._openCreditPosition( funds: <-withFunds, issuanceSink: abaSwapSink, @@ -549,10 +549,10 @@ access(all) contract FlowYieldVaultsStrategiesV2 { funds: @{FungibleToken.Vault}, issuanceSink: {DeFiActions.Sink}, repaymentSource: {DeFiActions.Source} - ): @FlowCreditMarket.Position { + ): @FlowALPv1.Position { let poolCap = FlowYieldVaultsStrategiesV2.account.storage.copy< - Capability - >(from: FlowCreditMarket.PoolCapStoragePath) + Capability + >(from: FlowALPv1.PoolCapStoragePath) ?? panic("Missing or invalid pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") diff --git a/cadence/contracts/mocks/MockFlowCreditMarketConsumer.cdc b/cadence/contracts/mocks/MockFlowALPv1Consumer.cdc similarity index 66% rename from cadence/contracts/mocks/MockFlowCreditMarketConsumer.cdc rename to cadence/contracts/mocks/MockFlowALPv1Consumer.cdc index da5719b6..ec8225ef 100644 --- a/cadence/contracts/mocks/MockFlowCreditMarketConsumer.cdc +++ b/cadence/contracts/mocks/MockFlowALPv1Consumer.cdc @@ -1,20 +1,20 @@ import "FungibleToken" import "DeFiActions" -import "FlowCreditMarket" +import "FlowALPv1" /// THIS CONTRACT IS NOT SAFE FOR PRODUCTION - FOR TEST USE ONLY /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /// /// A simple contract enabling the persistent storage of a Position similar to a pattern expected for platforms -/// building on top of FlowCreditMarket's lending protocol +/// building on top of FlowALPv1's lending protocol /// -access(all) contract MockFlowCreditMarketConsumer { +access(all) contract MockFlowALPv1Consumer { /// Canonical path for where the wrapper is to be stored access(all) let WrapperStoragePath: StoragePath - /// Opens a FlowCreditMarket Position and returns a PositionWrapper containing that new position + /// Opens a FlowALPv1 Position and returns a PositionWrapper containing that new position /// access(all) fun createPositionWrapper( @@ -24,7 +24,7 @@ access(all) contract MockFlowCreditMarketConsumer { pushToDrawDownSink: Bool ): @PositionWrapper { return <- create PositionWrapper( - position: FlowCreditMarket.openPosition( + position: FlowALPv1.openPosition( collateral: <-collateral, issuanceSink: issuanceSink, repaymentSource: repaymentSource, @@ -33,28 +33,28 @@ access(all) contract MockFlowCreditMarketConsumer { ) } - /// A simple resource encapsulating a FlowCreditMarket Position + /// A simple resource encapsulating a FlowALPv1 Position access(all) resource PositionWrapper { - access(self) let position: FlowCreditMarket.Position + access(self) let position: FlowALPv1.Position - init(position: FlowCreditMarket.Position) { + init(position: FlowALPv1.Position) { self.position = position } /// NOT SAFE FOR PRODUCTION /// /// Returns a reference to the wrapped Position - access(all) fun borrowPosition(): &FlowCreditMarket.Position { + access(all) fun borrowPosition(): &FlowALPv1.Position { return &self.position } - access(all) fun borrowPositionForWithdraw(): auth(FungibleToken.Withdraw) &FlowCreditMarket.Position { + access(all) fun borrowPositionForWithdraw(): auth(FungibleToken.Withdraw) &FlowALPv1.Position { return &self.position } } init() { - self.WrapperStoragePath = /storage/flowCreditMarketPositionWrapper + self.WrapperStoragePath = /storage/flowALPv1PositionWrapper } } diff --git a/cadence/contracts/mocks/MockSwapper.cdc b/cadence/contracts/mocks/MockSwapper.cdc index 1d7f3944..99ed06d4 100644 --- a/cadence/contracts/mocks/MockSwapper.cdc +++ b/cadence/contracts/mocks/MockSwapper.cdc @@ -5,7 +5,7 @@ import "MockOracle" import "DeFiActions" import "SwapConnectors" -import "FlowCreditMarketMath" +import "FlowALPMath" /// /// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION @@ -114,8 +114,8 @@ access(all) contract MockSwapper { let uintInAmount = out ? uintAmount : (uintAmount / uintPrice) let uintOutAmount = out ? uintAmount * uintPrice : uintAmount - let inAmount = FlowCreditMarketMath.toUFix64Round(uintInAmount) - let outAmount = FlowCreditMarketMath.toUFix64Round(uintOutAmount) + let inAmount = FlowALPMath.toUFix64Round(uintInAmount) + let outAmount = FlowALPMath.toUFix64Round(uintOutAmount) return SwapConnectors.BasicQuote( inType: reverse ? self.outVault : self.inVault, 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 8458e3d0..e14e617e 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 "FlowCreditMarket" +import "FlowALPv1" import "MockOracle" import "YieldToken" import "MOET" @@ -181,8 +181,8 @@ fun main(address: Address): CompleteUserSummary { let moetPrice = oracle.price(ofToken: Type<@MOET.Vault>()) ?? 1.0 let flowPrice = oracle.price(ofToken: Type<@FlowToken.Vault>()) ?? 1.0 - // Note: FlowCreditMarket positions and FlowYieldVaults yield vaults use different ID systems - // We'll calculate health manually since yield vault IDs don't correspond to FlowCreditMarket position IDs + // Note: FlowALPv1 positions and FlowYieldVaults yield vaults use different ID systems + // We'll calculate health manually since yield vault IDs don't correspond to FlowALPv1 position IDs var totalCollateralValue = 0.0 var totalYieldTokenValue = 0.0 @@ -196,7 +196,7 @@ fun main(address: Address): CompleteUserSummary { let yieldTokenBalance = autoBalancer?.vaultBalance() ?? 0.0 // Use the AutoBalancer's balance as the primary balance source - // This bypasses the FlowCreditMarket overflow issue + // This bypasses the FlowALPv1 overflow issue let realAvailableBalance = yieldTokenBalance let yieldTokenIdentifier = Type<@YieldToken.Vault>().identifier @@ -231,13 +231,13 @@ fun main(address: Address): CompleteUserSummary { let netWorth = estimatedCollateralValue + yieldTokenValue - estimatedDebtValue - // Get the actual position health from FlowCreditMarket.Pool - // FlowCreditMarket positions use sequential IDs (0, 1, 2, ...) while yield vault IDs are different + // Get the actual position health from FlowALPv1.Pool + // FlowALPv1 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 FlowCreditMarket.Pool using sequential position IDs - let protocolAddress = Type<@FlowCreditMarket.Pool>().address! - if let pool = getAccount(protocolAddress).capabilities.borrow<&FlowCreditMarket.Pool>(FlowCreditMarket.PoolPublicPath) { + // 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) { // 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/PMStrategiesV1_test.cdc b/cadence/tests/PMStrategiesV1_test.cdc index 65849fac..bc469010 100644 --- a/cadence/tests/PMStrategiesV1_test.cdc +++ b/cadence/tests/PMStrategiesV1_test.cdc @@ -1,4 +1,4 @@ -#test_fork(network: "mainnet", height: nil) +#test_fork(network: "mainnet", height: 141935000) import Test @@ -85,7 +85,7 @@ access(all) fun setup() { log("Deploying EVMAmountUtils contract ...") var err = Test.deployContract( name: "EVMAmountUtils", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -93,7 +93,7 @@ access(all) fun setup() { log("Deploying UniswapV3SwapConnectors contract ...") err = Test.deployContract( name: "UniswapV3SwapConnectors", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -102,28 +102,28 @@ access(all) fun setup() { log("Deploying Morpho contracts...") err = Test.deployContract( name: "ERC4626Utils", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/utils/ERC4626Utils.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/utils/ERC4626Utils.cdc", arguments: [] ) Test.expect(err, Test.beNil()) err = Test.deployContract( name: "ERC4626SwapConnectors", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) err = Test.deployContract( name: "MorphoERC4626SinkConnectors", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) err = Test.deployContract( name: "MorphoERC4626SwapConnectors", - path: "../../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", + path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -131,7 +131,7 @@ access(all) fun setup() { log("Deploying FlowYieldVaults contract ...") err = Test.deployContract( name: "FlowYieldVaults", - path: "../../../cadence/contracts/FlowYieldVaults.cdc", + path: "../../cadence/contracts/FlowYieldVaults.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -140,7 +140,7 @@ access(all) fun setup() { log("Deploying PMStrategiesV1...") err = Test.deployContract( name: "PMStrategiesV1", - path: "../../../cadence/contracts/PMStrategiesV1.cdc", + path: "../../cadence/contracts/PMStrategiesV1.cdc", arguments: [ "0xca6d7Bb03334bBf135902e1d919a5feccb461632", "0xeEDC6Ff75e1b10B903D9013c358e446a73d35341", @@ -149,46 +149,10 @@ access(all) fun setup() { ) Test.expect(err, Test.beNil()) - // // 1. Configure syWFLOWvStrategy with FlowToken collateral - // log("Configuring syWFLOWvStrategy...") - // var result = _executeTransactionFile( - // "../../transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc", - // [syWFLOWvStrategyIdentifier, flowVaultIdentifier, syWFLOWvEVMAddress, swapFeeTier], - // [adminAccount] - // ) - // Test.expect(result, Test.beSucceeded()) - // - // // 2. Configure FUSDEVStrategy with PYUSD0 collateral - // log("Configuring FUSDEVStrategy...") - // result = _executeTransactionFile( - // "../../transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc", - // [fusdEvStrategyIdentifier, pyusd0VaultIdentifier, fusdEvEVMAddress, swapFeeTier], - // [adminAccount] - // ) - // Test.expect(result, Test.beSucceeded()) - // - // // 3. Register syWFLOWvStrategy with the StrategyFactory - // log("Adding syWFLOWvStrategy composer...") - // result = _executeTransactionFile( - // "../../transactions/flow-yield-vaults/admin/add_strategy_composer.cdc", - // [syWFLOWvStrategyIdentifier, composerIdentifier, issuerStoragePath], - // [adminAccount] - // ) - // Test.expect(result, Test.beSucceeded()) - // - // // 4. Register FUSDEVStrategy with the StrategyFactory - // log("Adding FUSDEVStrategy composer...") - // result = _executeTransactionFile( - // "../../transactions/flow-yield-vaults/admin/add_strategy_composer.cdc", - // [fusdEvStrategyIdentifier, composerIdentifier, issuerStoragePath], - // [adminAccount] - // ) - // Test.expect(result, Test.beSucceeded()) - // - // 5. Grant beta access to user account for testing yield vault operations + // Grant beta access to user account for testing yield vault operations log("Granting beta access to user...") var result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/admin/grant_beta.cdc", + "../transactions/flow-yield-vaults/admin/grant_beta.cdc", [], [adminAccount, userAccount] ) @@ -202,7 +166,7 @@ access(all) fun setup() { access(all) fun testCreateSyWFLOWvYieldVault() { log("Creating syWFLOWvStrategy yield vault with 1.0 FLOW...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/create_yield_vault.cdc", + "../transactions/flow-yield-vaults/create_yield_vault.cdc", [syWFLOWvStrategyIdentifier, flowVaultIdentifier, 1.0], [userAccount] ) @@ -210,7 +174,7 @@ access(all) fun testCreateSyWFLOWvYieldVault() { // Retrieve the vault IDs let idsResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", [userAccount.address] ) Test.expect(idsResult, Test.beSucceeded()) @@ -221,7 +185,7 @@ access(all) fun testCreateSyWFLOWvYieldVault() { // Verify initial balance let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, syWFLOWvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -234,14 +198,14 @@ access(all) fun testCreateSyWFLOWvYieldVault() { access(all) fun testDepositToSyWFLOWvYieldVault() { log("Depositing 0.5 FLOW to syWFLOWv yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", + "../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", [syWFLOWvYieldVaultID, 0.5], [userAccount] ) Test.expect(result, Test.beSucceeded()) let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, syWFLOWvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -253,14 +217,14 @@ access(all) fun testDepositToSyWFLOWvYieldVault() { access(all) fun testWithdrawFromSyWFLOWvYieldVault() { log("Withdrawing 0.3 FLOW from syWFLOWv yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", + "../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", [syWFLOWvYieldVaultID, 0.3], [userAccount] ) Test.expect(result, Test.beSucceeded()) let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, syWFLOWvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -272,7 +236,7 @@ access(all) fun testWithdrawFromSyWFLOWvYieldVault() { access(all) fun testCloseSyWFLOWvYieldVault() { log("Closing syWFLOWv yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/close_yield_vault.cdc", + "../transactions/flow-yield-vaults/close_yield_vault.cdc", [syWFLOWvYieldVaultID], [userAccount] ) @@ -285,7 +249,7 @@ access(all) fun testCloseSyWFLOWvYieldVault() { access(all) fun testCreateFUSDEVYieldVault() { log("Creating FUSDEVStrategy yield vault with 1.0 PYUSD0...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/create_yield_vault.cdc", + "../transactions/flow-yield-vaults/create_yield_vault.cdc", [fusdEvStrategyIdentifier, pyusd0VaultIdentifier, 1.0], [userAccount] ) @@ -293,7 +257,7 @@ access(all) fun testCreateFUSDEVYieldVault() { // Retrieve the vault IDs let idsResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_ids.cdc", [userAccount.address] ) Test.expect(idsResult, Test.beSucceeded()) @@ -304,7 +268,7 @@ access(all) fun testCreateFUSDEVYieldVault() { // Verify initial balance let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, fusdEvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -317,14 +281,14 @@ access(all) fun testCreateFUSDEVYieldVault() { access(all) fun testDepositToFUSDEVYieldVault() { log("Depositing 0.5 PYUSD0 to FUSDEV yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", + "../transactions/flow-yield-vaults/deposit_to_yield_vault.cdc", [fusdEvYieldVaultID, 0.5], [userAccount] ) Test.expect(result, Test.beSucceeded()) let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, fusdEvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -336,14 +300,14 @@ access(all) fun testDepositToFUSDEVYieldVault() { access(all) fun testWithdrawFromFUSDEVYieldVault() { log("Withdrawing 0.3 PYUSD0 from FUSDEV yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", + "../transactions/flow-yield-vaults/withdraw_from_yield_vault.cdc", [fusdEvYieldVaultID, 0.3], [userAccount] ) Test.expect(result, Test.beSucceeded()) let balResult = _executeScript( - "../../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", + "../scripts/flow-yield-vaults/get_yield_vault_balance.cdc", [userAccount.address, fusdEvYieldVaultID] ) Test.expect(balResult, Test.beSucceeded()) @@ -355,7 +319,7 @@ access(all) fun testWithdrawFromFUSDEVYieldVault() { access(all) fun testCloseFUSDEVYieldVault() { log("Closing FUSDEV yield vault...") let result = _executeTransactionFile( - "../../transactions/flow-yield-vaults/close_yield_vault.cdc", + "../transactions/flow-yield-vaults/close_yield_vault.cdc", [fusdEvYieldVaultID], [userAccount] ) diff --git a/cadence/tests/atomic_registration_gc_test.cdc b/cadence/tests/atomic_registration_gc_test.cdc index 18280862..95ad31d1 100644 --- a/cadence/tests/atomic_registration_gc_test.cdc +++ b/cadence/tests/atomic_registration_gc_test.cdc @@ -7,7 +7,7 @@ import "FlowYieldVaultsSchedulerRegistry" import "FlowToken" import "MOET" import "YieldToken" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -39,7 +39,7 @@ access(all) fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // Setup FlowCreditMarket with a pool & add FLOW as a supported token. + // Setup FlowALPv1 with a pool & add FLOW as a supported token. createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -51,9 +51,9 @@ access(all) fun setup() { depositCapacityCap: 1_000_000.0 ) - // Open a wrapped FlowCreditMarket position so strategies have an underlying position to work with. + // Open a wrapped FlowALPv1 position so strategies have an underlying position to work with. let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/rebalance_scenario1_test.cdc b/cadence/tests/rebalance_scenario1_test.cdc index 80adf99e..5ac7072f 100644 --- a/cadence/tests/rebalance_scenario1_test.cdc +++ b/cadence/tests/rebalance_scenario1_test.cdc @@ -42,7 +42,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -57,7 +57,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/rebalance_scenario2_test.cdc b/cadence/tests/rebalance_scenario2_test.cdc index b92f3554..dd97774d 100644 --- a/cadence/tests/rebalance_scenario2_test.cdc +++ b/cadence/tests/rebalance_scenario2_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) @@ -128,7 +128,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -143,7 +143,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/rebalance_scenario3a_test.cdc b/cadence/tests/rebalance_scenario3a_test.cdc index 6baf54ae..3d5b865b 100644 --- a/cadence/tests/rebalance_scenario3a_test.cdc +++ b/cadence/tests/rebalance_scenario3a_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 == FlowCreditMarket.BalanceDirection.Credit { + if balance.direction == FlowALPv1.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 == FlowCreditMarket.BalanceDirection.Debit { + if balance.direction == FlowALPv1.BalanceDirection.Debit { return balance.balance } } @@ -71,7 +71,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -86,7 +86,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) @@ -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 == FlowCreditMarket.BalanceDirection.Credit { + if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv1.BalanceDirection.Credit { positionFlowBalance = balance.balance break } diff --git a/cadence/tests/rebalance_scenario3b_test.cdc b/cadence/tests/rebalance_scenario3b_test.cdc index 6100651a..98186c5f 100644 --- a/cadence/tests/rebalance_scenario3b_test.cdc +++ b/cadence/tests/rebalance_scenario3b_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -71,7 +71,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -86,7 +86,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) @@ -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 == FlowCreditMarket.BalanceDirection.Credit { + if balance.vaultType == Type<@FlowToken.Vault>() && balance.direction == FlowALPv1.BalanceDirection.Credit { positionFlowBalance = balance.balance break } diff --git a/cadence/tests/rebalance_scenario3c_test.cdc b/cadence/tests/rebalance_scenario3c_test.cdc index 330c4944..de62ea0f 100644 --- a/cadence/tests/rebalance_scenario3c_test.cdc +++ b/cadence/tests/rebalance_scenario3c_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 == FlowCreditMarket.BalanceDirection.Credit { + if balance.direction == FlowALPv1.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 == FlowCreditMarket.BalanceDirection.Debit { + if balance.direction == FlowALPv1.BalanceDirection.Debit { return balance.balance } } @@ -71,7 +71,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -86,7 +86,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/rebalance_scenario3d_test.cdc b/cadence/tests/rebalance_scenario3d_test.cdc index 1f467ae0..74534a96 100644 --- a/cadence/tests/rebalance_scenario3d_test.cdc +++ b/cadence/tests/rebalance_scenario3d_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 == FlowCreditMarket.BalanceDirection.Credit { + if balance.direction == FlowALPv1.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 == FlowCreditMarket.BalanceDirection.Debit { + if balance.direction == FlowALPv1.BalanceDirection.Debit { return balance.balance } } @@ -71,7 +71,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -86,7 +86,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/rebalance_yield_test.cdc b/cadence/tests/rebalance_yield_test.cdc index c0c90108..f3c20c83 100644 --- a/cadence/tests/rebalance_yield_test.cdc +++ b/cadence/tests/rebalance_yield_test.cdc @@ -41,7 +41,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -56,7 +56,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/scheduled_rebalance_integration_test.cdc b/cadence/tests/scheduled_rebalance_integration_test.cdc index b5e8ec92..4550e57d 100644 --- a/cadence/tests/scheduled_rebalance_integration_test.cdc +++ b/cadence/tests/scheduled_rebalance_integration_test.cdc @@ -56,7 +56,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) log("Token liquidity setup") - // Setup FlowCreditMarket with a Pool & add FLOW as supported token + // Setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -67,11 +67,11 @@ fun setup() { depositRate: 1_000_000.0, depositCapacityCap: 1_000_000.0 ) - log("FlowCreditMarket pool configured") + log("FlowALPv1 pool configured") // Open wrapped position let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/scheduled_rebalance_scenario_test.cdc b/cadence/tests/scheduled_rebalance_scenario_test.cdc index 8dda29bd..102d32bb 100644 --- a/cadence/tests/scheduled_rebalance_scenario_test.cdc +++ b/cadence/tests/scheduled_rebalance_scenario_test.cdc @@ -32,7 +32,7 @@ access(all) var snapshot: UInt64 = 0 // 5. The Supervisor is for recovery only - picks up yield vaults from pending queue // // PRICE SEMANTICS: -// - flowTokenIdentifier (FLOW): The COLLATERAL token deposited into FlowCreditMarket +// - flowTokenIdentifier (FLOW): The COLLATERAL token deposited into FlowALPv1 // - yieldTokenIdentifier (YieldToken): The YIELD-BEARING token the strategy produces // // TEST ISOLATION: @@ -63,7 +63,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // Setup FlowCreditMarket with a Pool + // Setup FlowALPv1 with a Pool createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -77,7 +77,7 @@ fun setup() { // Open wrapped position let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/scheduled_supervisor_test.cdc b/cadence/tests/scheduled_supervisor_test.cdc index 9ba8b7b9..bdf56261 100644 --- a/cadence/tests/scheduled_supervisor_test.cdc +++ b/cadence/tests/scheduled_supervisor_test.cdc @@ -49,7 +49,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // FlowCreditMarket + // FlowALPv1 createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -63,7 +63,7 @@ fun setup() { // Wrapped Position let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/scheduler_edge_cases_test.cdc b/cadence/tests/scheduler_edge_cases_test.cdc index 86c62889..c1df43c7 100644 --- a/cadence/tests/scheduler_edge_cases_test.cdc +++ b/cadence/tests/scheduler_edge_cases_test.cdc @@ -45,7 +45,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // Setup FlowCreditMarket + // Setup FlowALPv1 createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -59,7 +59,7 @@ fun setup() { // Open wrapped position let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 73407035..b5b5280c 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 "FlowCreditMarket" +import "FlowALPv1" access(all) let serviceAccount = Test.serviceAccount() @@ -37,7 +37,7 @@ access(all) fun grantProtocolBeta(_ admin: Test.TestAccount, _ grantee: Test.TestAccount): Test.TransactionResult { let signers = admin.address == grantee.address ? [admin] : [admin, grantee] let betaTxn = Test.Transaction( - code: Test.readFile("../../lib/FlowCreditMarket/cadence/tests/transactions/flow-credit-market/pool-management/03_grant_beta.cdc"), + code: Test.readFile("../../lib/FlowCreditMarket/cadence/tests/transactions/flow-alp/pool-management/03_grant_beta.cdc"), authorizers: [admin.address, grantee.address], signers: signers, arguments: [] @@ -157,8 +157,8 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) err = Test.deployContract( - name: "FlowCreditMarketMath", - path: "../../lib/FlowCreditMarket/cadence/lib/FlowCreditMarketMath.cdc", + name: "FlowALPMath", + path: "../../lib/FlowCreditMarket/cadence/lib/FlowALPMath.cdc", arguments: [] ) err = Test.deployContract( @@ -180,7 +180,7 @@ access(all) fun deployContracts() { ) Test.expect(err, Test.beNil()) - // FlowCreditMarket contracts + // FlowALPv1 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: "FlowCreditMarket", - path: "../../lib/FlowCreditMarket/cadence/contracts/FlowCreditMarket.cdc", + name: "FlowALPv1", + path: "../../lib/FlowCreditMarket/cadence/contracts/FlowALPv1.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -387,8 +387,8 @@ access(all) fun deployContracts() { } access(all) -fun setupFlowCreditMarket(signer: Test.TestAccount) { - let res = _executeTransaction("../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/create_and_store_pool.cdc", +fun setupFlowALPv1(signer: Test.TestAccount) { + let res = _executeTransaction("../../lib/FlowCreditMarket/cadence/transactions/flow-alp/create_and_store_pool.cdc", [], signer ) @@ -432,19 +432,19 @@ fun getAutoBalancerCurrentValue(id: UInt64): UFix64? { } access(all) -fun getPositionDetails(pid: UInt64, beFailed: Bool): FlowCreditMarket.PositionDetails { - let res = _executeScript("../../lib/FlowCreditMarket/cadence/scripts/flow-credit-market/position_details.cdc", +fun getPositionDetails(pid: UInt64, beFailed: Bool): FlowALPv1.PositionDetails { + let res = _executeScript("../../lib/FlowCreditMarket/cadence/scripts/flow-alp/position_details.cdc", [pid] ) Test.expect(res, beFailed ? Test.beFailed() : Test.beSucceeded()) - return res.returnValue as! FlowCreditMarket.PositionDetails + return res.returnValue as! FlowALPv1.PositionDetails } access(all) fun getReserveBalanceForType(vaultIdentifier: String): UFix64 { let res = _executeScript( - "../../lib/FlowCreditMarket/cadence/scripts/flow-credit-market/get_reserve_balance_for_type.cdc", + "../../lib/FlowCreditMarket/cadence/scripts/flow-alp/get_reserve_balance_for_type.cdc", [vaultIdentifier] ) Test.expect(res, Test.beSucceeded()) @@ -460,7 +460,7 @@ fun positionAvailableBalance( beFailed: Bool ): UFix64 { let res = _executeScript( - "../../lib/FlowCreditMarket/cadence/scripts/flow-credit-market/get_available_balance.cdc", + "../../lib/FlowCreditMarket/cadence/scripts/flow-alp/get_available_balance.cdc", [pid, type, pullFromSource] ) Test.expect(res, beFailed ? Test.beFailed() : Test.beSucceeded()) @@ -473,7 +473,7 @@ fun positionAvailableBalance( access(all) fun createAndStorePool(signer: Test.TestAccount, defaultTokenIdentifier: String, beFailed: Bool) { let createRes = _executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-factory/create_and_store_pool.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc", [defaultTokenIdentifier], signer ) @@ -491,7 +491,7 @@ fun addSupportedTokenFixedRateInterestCurve( depositCapacityCap: UFix64 ) { let additionRes = _executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_fixed_rate_curve.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_fixed_rate_curve.cdc", [ tokenTypeIdentifier, collateralFactor, borrowFactor, yearlyRate, depositRate, depositCapacityCap ], signer ) @@ -501,7 +501,7 @@ fun addSupportedTokenFixedRateInterestCurve( access(all) fun rebalancePosition(signer: Test.TestAccount, pid: UInt64, force: Bool, beFailed: Bool) { let rebalanceRes = _executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-management/rebalance_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-management/rebalance_position.cdc", [ pid, force ], signer ) @@ -584,14 +584,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 FlowCreditMarket.Opened event but found none") - return evts[evts.length - 1] as! FlowCreditMarket.Opened + Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv1.Opened event but found none") + return evts[evts.length - 1] as! FlowALPv1.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 FlowCreditMarket.Deposited event but found none") - return evts[evts.length - 1] as! FlowCreditMarket.Deposited + Test.assert(evts.length > 0, message: "Expected at least 1 FlowALPv1.Deposited event but found none") + return evts[evts.length - 1] as! FlowALPv1.Deposited } /* --- Mock helpers --- */ @@ -671,7 +671,7 @@ access(all) fun setupBetaAccess(): Void { // Returns the balance for a given Vault 'Type' if present, otherwise nil. access(all) fun findBalance( - details: FlowCreditMarket.PositionDetails, + details: FlowALPv1.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 2c2949af..27ae2f7a 100644 --- a/cadence/tests/tracer_strategy_test.cdc +++ b/cadence/tests/tracer_strategy_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -47,7 +47,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -62,7 +62,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) @@ -162,7 +162,7 @@ fun test_RebalanceYieldVaultSucceeds() { amount: fundingAmount, beFailed: false ) - let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowCreditMarket.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.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! FlowCreditMarket.Deposited + let autoBalancerRecollateralizeEvent = getLastPositionDepositedEvent(Test.eventsOfType(Type())) as! FlowALPv1.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! FlowCreditMarket.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.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! FlowCreditMarket.Opened).pid + let positionID = (getLastPositionOpenedEvent(Test.eventsOfType(Type())) as! FlowALPv1.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/yield_vault_lifecycle_test.cdc b/cadence/tests/yield_vault_lifecycle_test.cdc index 0e1ad05e..b515b554 100644 --- a/cadence/tests/yield_vault_lifecycle_test.cdc +++ b/cadence/tests/yield_vault_lifecycle_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowCreditMarket" +import "FlowALPv1" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) @@ -47,7 +47,7 @@ fun setup() { setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: YieldToken.VaultStoragePath) setMockSwapperLiquidityConnector(signer: protocolAccount, vaultStoragePath: /storage/flowTokenVault) - // setup FlowCreditMarket with a Pool & add FLOW as supported token + // setup FlowALPv1 with a Pool & add FLOW as supported token createAndStorePool(signer: protocolAccount, defaultTokenIdentifier: moetTokenIdentifier, beFailed: false) addSupportedTokenFixedRateInterestCurve( signer: protocolAccount, @@ -62,7 +62,7 @@ fun setup() { // open wrapped position (pushToDrawDownSink) // the equivalent of depositing reserves let openRes = executeTransaction( - "../../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/position/create_position.cdc", + "../../lib/FlowCreditMarket/cadence/transactions/flow-alp/position/create_position.cdc", [reserveAmount/2.0, /storage/flowTokenVault, true], protocolAccount ) diff --git a/cadence/transactions/mocks/position/create_wrapped_position.cdc b/cadence/transactions/mocks/position/create_wrapped_position.cdc index c6edbefb..01b64aca 100644 --- a/cadence/transactions/mocks/position/create_wrapped_position.cdc +++ b/cadence/transactions/mocks/position/create_wrapped_position.cdc @@ -4,16 +4,16 @@ import "DeFiActions" import "FungibleTokenConnectors" import "MOET" -import "MockFlowCreditMarketConsumer" +import "MockFlowALPv1Consumer" /// TEST TRANSACTION - DO NOT USE IN PRODUCTION /// /// Opens a Position with the amount of funds source from the Vault at the provided StoragePath and wraps it in a -/// MockFlowCreditMarketConsumer PositionWrapper +/// MockFlowALPv1Consumer PositionWrapper /// transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: Bool) { - // the funds that will be used as collateral for a FlowCreditMarket loan + // the funds that will be used as collateral for a FlowALPv1 loan let collateral: @{FungibleToken.Vault} // this DeFiActions Sink that will receive the loaned funds let sink: {DeFiActions.Sink} @@ -63,13 +63,13 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B execute { // open a position & save in the Wrapper - let wrapper <- MockFlowCreditMarketConsumer.createPositionWrapper( + let wrapper <- MockFlowALPv1Consumer.createPositionWrapper( collateral: <-self.collateral, issuanceSink: self.sink, repaymentSource: self.source, pushToDrawDownSink: pushToDrawDownSink ) // save the wrapper into the signer's account - reverts on storage collision - self.account.storage.save(<-wrapper, to: MockFlowCreditMarketConsumer.WrapperStoragePath) + self.account.storage.save(<-wrapper, to: MockFlowALPv1Consumer.WrapperStoragePath) } } diff --git a/docs/autobalancer-restart-recurring-proposal.md b/docs/autobalancer-restart-recurring-proposal.md index f7858487..cde18b69 100644 --- a/docs/autobalancer-restart-recurring-proposal.md +++ b/docs/autobalancer-restart-recurring-proposal.md @@ -174,7 +174,7 @@ let autoBalancerRef = scheduleCap!.borrow()! let scheduleError = autoBalancerRef.scheduleNextRebalance(whileExecuting: nil) ``` -### DeFiActions (FlowCreditMarket/FlowActions) +### DeFiActions (FlowALPv1/FlowActions) Only the fee buffer fix (5% margin) was kept. No `restartRecurring` flag was added. diff --git a/docs/rebalancing_architecture.md b/docs/rebalancing_architecture.md index 919a4817..1aa587b9 100644 --- a/docs/rebalancing_architecture.md +++ b/docs/rebalancing_architecture.md @@ -1,18 +1,18 @@ -# Rebalancing Architecture: AutoBalancer, FlowCreditMarket Position, and Scheduled Transactions +# Rebalancing Architecture: AutoBalancer, FlowALPv1 Position, and Scheduled Transactions ## 1. Main Components and Their Responsibilities ### FlowYieldVaults (YieldVaults) - Owns `YieldVault` and `YieldVaultManager` - Each YieldVault wraps a **FlowYieldVaults Strategy** (e.g. `TracerStrategy`) -- The YieldVault itself does **not** know about scheduling or FlowCreditMarket; it just holds a strategy resource +- The YieldVault itself does **not** know about scheduling or FlowALPv1; it just holds a strategy resource ### FlowYieldVaultsStrategies (TracerStrategy stack) - `TracerStrategyComposer` wires together: - A **DeFiActions.AutoBalancer** (manages Yield token exposure around deposits value) - - A **FlowCreditMarket.Position** (borrow/lend position in the FlowCreditMarket pool) - - Swappers and connectors that shuttle value between AutoBalancer and FlowCreditMarket -- This is where the **YieldVault -> AutoBalancer -> FlowCreditMarket** wiring is defined + - A **FlowALPv1.Position** (borrow/lend position in the FlowALPv1 pool) + - Swappers and connectors that shuttle value between AutoBalancer and FlowALPv1 +- This is where the **YieldVault -> AutoBalancer -> FlowALPv1** wiring is defined ### FlowYieldVaultsAutoBalancers - Utility contract for: @@ -34,7 +34,7 @@ - `executeTransaction(id, data)`: entrypoint for **FlowTransactionScheduler** - `scheduleNextRebalance()`: self-schedules next execution (when configured with recurringConfig) -### FlowCreditMarket.Pool + Position +### FlowALPv1.Pool + Position - Maintains positions, collateral, MOET debt, health - Key function: `rebalancePosition(pid: UInt64, force: Bool)`: - If undercollateralized and there is a `topUpSource`, pulls extra collateral @@ -54,7 +54,7 @@ --- -## 2. How the Tracer Strategy Wires AutoBalancer and FlowCreditMarket Together +## 2. How the Tracer Strategy Wires AutoBalancer and FlowALPv1 Together Inside `FlowYieldVaultsStrategies.TracerStrategyComposer.createStrategy(...)`: @@ -75,21 +75,21 @@ Inside `FlowYieldVaultsStrategies.TracerStrategyComposer.createStrategy(...)`: - Attach swappers (MockSwapper or UniswapV3) for MOET <-> Yield - Direct MOET -> Yield into `abaSink`, Yield -> MOET from `abaSource` -### Step 3: Open a FlowCreditMarket position +### Step 3: Open a FlowALPv1 position - Call `poolRef.createPosition(funds, issuanceSink: abaSwapSink, repaymentSource: abaSwapSource, pushToDrawDownSink: true)` -- Initial user Flow goes through `abaSwapSink` to become Yield, deposited into AutoBalancer, then into FlowCreditMarket position +- Initial user Flow goes through `abaSwapSink` to become Yield, deposited into AutoBalancer, then into FlowALPv1 position -### Step 4: Create FlowCreditMarket position-level sink/source +### Step 4: Create FlowALPv1 position-level sink/source - `positionSink = position.createSinkWithOptions(type: collateralType, pushToDrawDownSink: true)` - `positionSource = position.createSourceWithOptions(type: collateralType, pullFromTopUpSource: true)` -### Step 5: Wire AutoBalancer's rebalance sink into FlowCreditMarket position +### Step 5: Wire AutoBalancer's rebalance sink into FlowALPv1 position - Create `positionSwapSink` to swap Yield -> Flow and deposit into `positionSink` - Call `autoBalancer.setSink(positionSwapSink, updateSinkID: true)` -- When AutoBalancer rebalances, it withdraws Yield, swaps to Flow, deposits into FlowCreditMarket position +- When AutoBalancer rebalances, it withdraws Yield, swaps to Flow, deposits into FlowALPv1 position -### Step 6: FlowCreditMarket's `pushToDrawDownSink` triggers position rebalancing -- In FlowCreditMarket's `depositAndPush` logic with `pushToDrawDownSink: true`: +### Step 6: FlowALPv1's `pushToDrawDownSink` triggers position rebalancing +- In FlowALPv1's `depositAndPush` logic with `pushToDrawDownSink: true`: ```cadence if pushToDrawDownSink { self.rebalancePosition(pid: pid, force: true) @@ -98,8 +98,8 @@ Inside `FlowYieldVaultsStrategies.TracerStrategyComposer.createStrategy(...)`: - Any deposit via that sink automatically triggers `rebalancePosition(pid, force: true)` **Conclusion:** When AutoBalancer performs a rebalance that moves value through its sink, it indirectly causes: -- An update in the FlowCreditMarket position via deposits/withdrawals -- A call to `FlowCreditMarket.Pool.rebalancePosition(pid, force: true)` +- An update in the FlowALPv1 position via deposits/withdrawals +- A call to `FlowALPv1.Pool.rebalancePosition(pid, force: true)` --- @@ -185,22 +185,22 @@ fun executeTransaction(id: UInt64, data: AnyStruct?) { ## 4. Behavior in Different Price Scenarios ### Only Flow collateral price changes (Yield price constant) -- FlowCreditMarket position's **health** changes (Flow is collateral) +- FlowALPv1 position's **health** changes (Flow is collateral) - AutoBalancer's asset (YieldToken) oracle price unchanged - `currentValue == valueOfDeposits` -> `valueDiff == 0` -> **rebalance is no-op** -- **Only `rebalancePosition` (FlowCreditMarket) will actually move collateral** +- **Only `rebalancePosition` (FlowALPv1) will actually move collateral** ### Only Yield token price changes (Flow price constant) - AutoBalancer's `currentValue` changes versus `valueOfDeposits` - If difference exceeds threshold (or `force == true`): - AutoBalancer rebalances via sink (`positionSwapSink`) - - Yield -> Flow deposited into FlowCreditMarket position with `pushToDrawDownSink == true` - - Triggers `FlowCreditMarket.Pool.rebalancePosition(pid, force: true)` -- **Both AutoBalancer and FlowCreditMarket position are adjusted** + - Yield -> Flow deposited into FlowALPv1 position with `pushToDrawDownSink == true` + - Triggers `FlowALPv1.Pool.rebalancePosition(pid, force: true)` +- **Both AutoBalancer and FlowALPv1 position are adjusted** ### Both Flow and Yield move - If Yield changes enough, AutoBalancer rebalances -- FlowCreditMarket position's health also changes from Flow's move +- FlowALPv1 position's health also changes from Flow's move - AutoBalancer-induced deposit triggers `rebalancePosition(pid, force: true)` - **Scheduled executions become effective when Yield-side value moves** @@ -212,15 +212,15 @@ fun executeTransaction(id: UInt64, data: AnyStruct?) { - Semantically equivalent to manual `rebalanceYieldVault` 2. **`rebalanceYieldVault` does NOT directly call `rebalancePosition`** - - Position rebalancing happens **indirectly** via connector graph and FlowCreditMarket's `pushToDrawDownSink` logic + - Position rebalancing happens **indirectly** via connector graph and FlowALPv1's `pushToDrawDownSink` logic 3. **Flow-only price changes do NOT trigger AutoBalancer rebalance** - AutoBalancer's `valueDiff` only sensitive to Yield side - - Scheduled executions won't touch FlowCreditMarket position in this case + - Scheduled executions won't touch FlowALPv1 position in this case -4. **For FlowCreditMarket position rebalancing on collateral moves** - - Would need separate scheduling in FlowCreditMarket - - Belongs in FlowCreditMarket/FlowActions, not FlowYieldVaults +4. **For FlowALPv1 position rebalancing on collateral moves** + - Would need separate scheduling in FlowALPv1 + - Belongs in FlowALPv1/FlowActions, not FlowYieldVaults --- @@ -229,9 +229,9 @@ fun executeTransaction(id: UInt64, data: AnyStruct?) { | Component | Responsibility | |-----------|---------------| | FlowYieldVaults YieldVault | Holds strategy, user-facing | -| TracerStrategy | Wires AutoBalancer <-> FlowCreditMarket | +| TracerStrategy | Wires AutoBalancer <-> FlowALPv1 | | AutoBalancer | Manages Yield exposure, executes rebalance | -| FlowCreditMarket Position | Manages collateral/debt health | +| FlowALPv1 Position | Manages collateral/debt health | | FlowYieldVaultsScheduler | Registration, atomic initial scheduling | | FlowYieldVaultsSchedulerRegistry | Stores registry, pending queue | | Supervisor | Recovery for failed schedules (bounded) | diff --git a/flow.json b/flow.json index 9a8fd739..471fe51f 100644 --- a/flow.json +++ b/flow.json @@ -98,8 +98,8 @@ "testnet": "b88ba0e976146cd1" } }, - "FlowCreditMarket": { - "source": "./lib/FlowCreditMarket/cadence/contracts/FlowCreditMarket.cdc", + "FlowALPv1": { + "source": "./lib/FlowCreditMarket/cadence/contracts/FlowALPv1.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", @@ -107,8 +107,8 @@ "testnet": "426f0458ced60037" } }, - "FlowCreditMarketMath": { - "source": "./lib/FlowCreditMarket/cadence/lib/FlowCreditMarketMath.cdc", + "FlowALPMath": { + "source": "./lib/FlowCreditMarket/cadence/lib/FlowALPMath.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", @@ -819,7 +819,7 @@ "resourceID": "projects/flow-foundation-admin/locations/global/keyRings/defi-actions/cryptoKeys/mainnet-defi-actions/cryptoKeyVersions/1" } }, - "mainnet-flow-credit-market-deployer": { + "mainnet-flow-alp-deployer": { "address": "6b00ff876c299c61", "key": { "type": "google-kms", @@ -856,7 +856,7 @@ "resourceID": "projects/dl-flow-devex-staging/locations/us-central1/keyRings/tidal-keyring/cryptoKeys/tidal_admin_pk/cryptoKeyVersions/1" } }, - "testnet-flow-credit-market-deployer": { + "testnet-flow-alp-deployer": { "address": "426f0458ced60037", "key": { "type": "google-kms", @@ -879,11 +879,11 @@ }, "DeFiActionsUtils", "DeFiActions", - "FlowCreditMarketMath", + "FlowALPMath", "FungibleTokenConnectors", "SwapConnectors", "DummyConnectors", - "FlowCreditMarket", + "FlowALPv1", { "name": "YieldToken", "args": [ @@ -1217,4 +1217,4 @@ ] } } -} \ No newline at end of file +} diff --git a/local/setup_emulator.sh b/local/setup_emulator.sh index 5fddabbf..70126259 100755 --- a/local/setup_emulator.sh +++ b/local/setup_emulator.sh @@ -21,9 +21,9 @@ flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.045a # configure FlowCreditMarket # # create Pool with MOET as default token -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-factory/create_and_store_pool.cdc 'A.045a1763c93006ca.MOET.Vault' --signer emulator-flow-yield-vaults +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc 'A.045a1763c93006ca.MOET.Vault' --signer emulator-flow-yield-vaults # add FLOW as supported token - params: collateralFactor, borrowFactor, depositRate, depositCapacityCap -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_zero_rate_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_zero_rate_curve.cdc \ 'A.0ae53cb6e3f42a79.FlowToken.Vault' \ 0.8 \ 1.0 \ @@ -58,7 +58,7 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate # grant PoolBeta cap echo "Grant Protocol Beta access to FlowYieldVaults" -flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-credit-market/pool-management/03_grant_beta.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-alp/pool-management/03_grant_beta.cdc \ --authorizer emulator-flow-yield-vaults,emulator-flow-yield-vaults \ --proposer emulator-flow-yield-vaults \ --payer emulator-flow-yield-vaults diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index 3cd923f3..b4be0348 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -12,24 +12,24 @@ flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.1654 echo "bridge YieldToken to Cadence" flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc 0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c --network mainnet --signer mainnet-admin 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-credit-market-deployer +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 FlowCreditMarket +# configure FlowALPv1 # # create Pool with MOET as default token -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-factory/create_and_store_pool.cdc 'A.6b00ff876c299c61.MOET.Vault' --network mainnet --signer mainnet-flow-credit-market-deployer +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc 'A.6b00ff876c299c61.MOET.Vault' --network mainnet --signer mainnet-flow-alp-deployer # update Pool with Band Oracle instead of Mock Oracle -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/update_oracle.cdc --network mainnet --signer mainnet-flow-credit-market-deployer +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/update_oracle.cdc --network mainnet --signer mainnet-flow-alp-deployer # add FLOW as supported token - params: collateralFactor, borrowFactor, depositRate, depositCapacityCap -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.1654653399040a61.FlowToken.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network mainnet \ - --signer mainnet-flow-credit-market-deployer + --signer mainnet-flow-alp-deployer # add WBTC to band oracle cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "BTC" "A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault" --network mainnet --signer mainnet-band-oracle-connectors && cd ../../.. @@ -38,30 +38,30 @@ cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transa cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "ETH" "A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault" --network mainnet --signer mainnet-band-oracle-connectors && cd ../../.. # WBTC simple curve -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network mainnet \ - --signer mainnet-flow-credit-market-deployer + --signer mainnet-flow-alp-deployer # WETH simple curve -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network mainnet \ - --signer mainnet-flow-credit-market-deployer + --signer mainnet-flow-alp-deployer # kink interest curve setup # enable when FCM_V1 is deployed # # # add WBTC as supported token -# flow transactions send ../lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_kink_curve.cdc \ +# flow transactions send ../lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_kink_curve.cdc \ # 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ # 0.8 \ # 1.0 \ @@ -72,10 +72,10 @@ flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-m # 1_000_000.0 \ # 1_000_000.0 \ # --network mainnet \ -# --signer mainnet-flow-credit-market-deployer +# --signer mainnet-flow-alp-deployer # # # add WETH as supported token -# flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_kink_curve.cdc \ +# flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_kink_curve.cdc \ # 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ # 0.8 \ # 1.0 \ @@ -86,17 +86,17 @@ flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-m # 1_000_000.0 \ # 1_000_000.0 \ # --network mainnet \ -# --signer mainnet-flow-credit-market-deployer +# --signer mainnet-flow-alp-deployer # TODO # swap # echo "swap Flow to MOET" -# flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/create_position.cdc 100000.0 --network mainnet --signer mainnet-flow-credit-market-deployer +# flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/create_position.cdc 100000.0 --network mainnet --signer mainnet-flow-alp-deployer # TODO # flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/tokens/bridge_tokens_to_any_evm_address.cdc \ # "A.6b00ff876c299c61.MOET.Vault" 100000.0 "0xOWNER" \ -# --network mainnet --signer mainnet-flow-credit-market-deployer +# --network mainnet --signer mainnet-flow-alp-deployer # create pool # add liquidity to pool @@ -202,9 +202,9 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate # grant PoolBeta cap echo "Grant Protocol Beta access to FlowYieldVaults" -flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-credit-market/pool-management/03_grant_beta.cdc \ - --authorizer mainnet-flow-credit-market-deployer,mainnet-admin \ - --proposer mainnet-flow-credit-market-deployer \ +flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-alp/pool-management/03_grant_beta.cdc \ + --authorizer mainnet-flow-alp-deployer,mainnet-admin \ + --proposer mainnet-flow-alp-deployer \ --payer mainnet-admin \ --network mainnet diff --git a/local/setup_testnet.sh b/local/setup_testnet.sh index a1d90e15..ec5f73a5 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -10,7 +10,7 @@ flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.d258 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-credit-market-deployer +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 FlowCreditMarket # @@ -18,18 +18,18 @@ flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/onboard cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "USD" "A.426f0458ced60037.MOET.Vault" --network testnet --signer testnet-band-oracle-connectors # create Pool with MOET as default token with Mock Oracle -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-factory/create_and_store_pool.cdc 'A.426f0458ced60037.MOET.Vault' --network testnet --signer testnet-flow-credit-market-deployer +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-factory/create_and_store_pool.cdc 'A.426f0458ced60037.MOET.Vault' --network testnet --signer testnet-flow-alp-deployer # update Pool with Band Oracle instead of Mock Oracle -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/update_oracle.cdc --network testnet --signer testnet-flow-credit-market-deployer +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/update_oracle.cdc --network testnet --signer testnet-flow-alp-deployer # add FLOW as supported token - params: collateralFactor, borrowFactor, depositRate, depositCapacityCap -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.7e60df042a9c0868.FlowToken.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network testnet \ - --signer testnet-flow-credit-market-deployer + --signer testnet-flow-alp-deployer # add WBTC to band oracle cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "BTC" "A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault" --network testnet --signer testnet-band-oracle-connectors && cd ../../.. @@ -38,32 +38,32 @@ cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transa cd ./lib/FlowCreditMarket/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "ETH" "A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault" --network testnet --signer testnet-band-oracle-connectors && cd ../../.. # add WBTC as supported token -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_208d09d2a6dd176e3e95b3f0de172a7471c5b2d6.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network testnet \ - --signer testnet-flow-credit-market-deployer + --signer testnet-flow-alp-deployer # add WETH as supported token -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ 'A.dfc20aee650fcbdf.EVMVMBridgedToken_059a77239dafa770977dd9f1e98632c3e4559848.Vault' \ 0.8 \ 1.0 \ 1_000_000.0 \ 1_000_000.0 \ --network testnet \ - --signer testnet-flow-credit-market-deployer + --signer testnet-flow-alp-deployer echo "swap Flow to MOET" -flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-credit-market/create_position.cdc 100000.0 --network testnet --signer testnet-flow-credit-market-deployer +flow transactions send ./lib/FlowCreditMarket/cadence/transactions/flow-alp/create_position.cdc 100000.0 --network testnet --signer testnet-flow-alp-deployer # TODO: # flow transactions send ./lib/flow-evm-bridge/cadence/transactions/bridge/tokens/bridge_tokens_to_any_evm_address.cdc \ # "A.426f0458ced60037.MOET.Vault" 100000.0 "0xOWNER" \ -# --network testnet --signer testnet-flow-credit-market-deployer +# --network testnet --signer testnet-flow-alp-deployer # create pool # add liquidity to pool @@ -147,9 +147,9 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strate # grant PoolBeta cap echo "Grant Protocol Beta access to FlowYieldVaults" -flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-credit-market/pool-management/03_grant_beta.cdc \ - --authorizer testnet-flow-credit-market-deployer,testnet-admin \ - --proposer testnet-flow-credit-market-deployer \ +flow transactions send ./lib/FlowCreditMarket/cadence/tests/transactions/flow-alp/pool-management/03_grant_beta.cdc \ + --authorizer testnet-flow-alp-deployer,testnet-admin \ + --proposer testnet-flow-alp-deployer \ --payer testnet-admin \ --network testnet From 58779754f281e25d3a814f6d1979cf1dc6f86706 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:29:22 -0500 Subject: [PATCH 11/24] update ref --- lib/FlowCreditMarket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlowCreditMarket b/lib/FlowCreditMarket index 3eaa1bad..cdb155cd 160000 --- a/lib/FlowCreditMarket +++ b/lib/FlowCreditMarket @@ -1 +1 @@ -Subproject commit 3eaa1badcb17d45aff6bbe50bba330458828a045 +Subproject commit cdb155cdda36658b424760b9c1fa7a5db6487624 From f495d102dc44e5de9ce72716269b94ed0bfe18fc Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:18:01 -0500 Subject: [PATCH 12/24] update ref --- lib/FlowCreditMarket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlowCreditMarket b/lib/FlowCreditMarket index cdb155cd..6ef4a6e0 160000 --- a/lib/FlowCreditMarket +++ b/lib/FlowCreditMarket @@ -1 +1 @@ -Subproject commit cdb155cdda36658b424760b9c1fa7a5db6487624 +Subproject commit 6ef4a6e0d63b396332a219fa5a89f9440a251f68 From 12288bd57bc9af634ad3483a9343f0e588bede12 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:49:00 -0500 Subject: [PATCH 13/24] tweak fork height --- cadence/tests/PMStrategiesV1_test.cdc | 2 +- lib/FlowCreditMarket | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cadence/tests/PMStrategiesV1_test.cdc b/cadence/tests/PMStrategiesV1_test.cdc index bc469010..0db49416 100644 --- a/cadence/tests/PMStrategiesV1_test.cdc +++ b/cadence/tests/PMStrategiesV1_test.cdc @@ -1,4 +1,4 @@ -#test_fork(network: "mainnet", height: 141935000) +#test_fork(network: "mainnet", height: 141994362) import Test diff --git a/lib/FlowCreditMarket b/lib/FlowCreditMarket index 6ef4a6e0..74f939bc 160000 --- a/lib/FlowCreditMarket +++ b/lib/FlowCreditMarket @@ -1 +1 @@ -Subproject commit 6ef4a6e0d63b396332a219fa5a89f9440a251f68 +Subproject commit 74f939bcb795b03c733758d74c76f9eaa72455f5 From fab9f20f80db6598009548714c3c1a542e6f4812 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Thu, 12 Feb 2026 12:20:06 -0500 Subject: [PATCH 14/24] fix emulator deployment --- flow.json | 1 + 1 file changed, 1 insertion(+) diff --git a/flow.json b/flow.json index 471fe51f..d57b0ba3 100644 --- a/flow.json +++ b/flow.json @@ -879,6 +879,7 @@ }, "DeFiActionsUtils", "DeFiActions", + "EVMAmountUtils", "FlowALPMath", "FungibleTokenConnectors", "SwapConnectors", From e96ad5b59c291a273f3b2500adcca7701f93f406 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:16:16 -0500 Subject: [PATCH 15/24] revert unnecessary changes --- cadence/contracts/FlowYieldVaultsStrategies.cdc | 4 ++-- cadence/contracts/mocks/MockFlowALPConsumer.cdc | 2 +- cadence/tests/scheduled_rebalance_integration_test.cdc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cadence/contracts/FlowYieldVaultsStrategies.cdc b/cadence/contracts/FlowYieldVaultsStrategies.cdc index a5d4d1ff..70b398ed 100644 --- a/cadence/contracts/FlowYieldVaultsStrategies.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategies.cdc @@ -193,7 +193,7 @@ access(all) contract FlowYieldVaultsStrategies { // Swaps YieldToken & provides swapped Stable, sourcing YieldToken from the AutoBalancer let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToStableSwapper, source: abaSource, uniqueID: uniqueID) - // open a FlowALPv1 position + // open a FlowALP position let poolCap = FlowYieldVaultsStrategies.account.storage.load>( from: FlowALPv1.PoolCapStoragePath ) ?? panic("Missing pool capability") @@ -469,7 +469,7 @@ access(all) contract FlowYieldVaultsStrategies { // Swaps YIELD & provides swapped MOET, sourcing YIELD from the AutoBalancer let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToMOETSwapper, source: abaSource, uniqueID: uniqueID) - // open a FlowALPv1 position + // open a FlowALP position let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( from: FlowALPv1.PoolCapStoragePath ) ?? panic("Missing or invalid pool capability") diff --git a/cadence/contracts/mocks/MockFlowALPConsumer.cdc b/cadence/contracts/mocks/MockFlowALPConsumer.cdc index 1b01695f..e08fdcdd 100644 --- a/cadence/contracts/mocks/MockFlowALPConsumer.cdc +++ b/cadence/contracts/mocks/MockFlowALPConsumer.cdc @@ -55,6 +55,6 @@ access(all) contract MockFlowALPConsumer { } init() { - self.WrapperStoragePath = /storage/flowALPv1PositionWrapper + self.WrapperStoragePath = /storage/flowALPPositionWrapper } } diff --git a/cadence/tests/scheduled_rebalance_integration_test.cdc b/cadence/tests/scheduled_rebalance_integration_test.cdc index dd53c346..9ceeae26 100644 --- a/cadence/tests/scheduled_rebalance_integration_test.cdc +++ b/cadence/tests/scheduled_rebalance_integration_test.cdc @@ -67,7 +67,7 @@ fun setup() { depositRate: 1_000_000.0, depositCapacityCap: 1_000_000.0 ) - log("FlowALPv1 pool configured") + log("FlowALP pool configured") // Open wrapped position let openRes = executeTransaction( From ff6327033321d2c9970afb79435727bb142799a2 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:23:23 -0500 Subject: [PATCH 16/24] fix contract name --- flow.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow.json b/flow.json index 6008217e..115afc72 100644 --- a/flow.json +++ b/flow.json @@ -1289,7 +1289,7 @@ ] }, { - "name": "FlowYieldVaultsStrategiesV1_1", + "name": "FlowYieldVaultsStrategiesV2", "args": [ { "value": "0xca6d7Bb03334bBf135902e1d919a5feccb461632", From 276e9d2d0c1c758e65e7f8e1809a9d00f11d9a7e Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:36:05 -0500 Subject: [PATCH 17/24] fix path --- cadence/tests/test_helpers.cdc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 5cd07bfe..4a22054c 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -270,7 +270,7 @@ access(all) fun deployContracts() { Test.expect(err, Test.beNil()) err = Test.deployContract( name: "EVMAmountUtils", - path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/EVMAmountUtils.cdc", arguments: [] ) Test.expect(err, Test.beNil()) @@ -318,14 +318,14 @@ access(all) fun deployContracts() { err = Test.deployContract( name: "MorphoERC4626SinkConnectors", - path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SinkConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) err = Test.deployContract( name: "MorphoERC4626SwapConnectors", - path: "../../lib/FlowCreditMarket/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", + path: "../../lib/FlowALP/FlowActions/cadence/contracts/connectors/evm/morpho/MorphoERC4626SwapConnectors.cdc", arguments: [] ) Test.expect(err, Test.beNil()) From 7b5481c20e299ce1052789c948b1f171a2f2f625 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Tue, 17 Feb 2026 12:13:13 -0500 Subject: [PATCH 18/24] add explanation --- cadence/contracts/FlowYieldVaults.cdc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cadence/contracts/FlowYieldVaults.cdc b/cadence/contracts/FlowYieldVaults.cdc index 8449f990..dcf8e972 100644 --- a/cadence/contracts/FlowYieldVaults.cdc +++ b/cadence/contracts/FlowYieldVaults.cdc @@ -317,8 +317,22 @@ access(all) contract FlowYieldVaults { /// Withdraws the requested amount from the Strategy access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { post { + /// Quoting exact output then swapping exact input can overshoot by 0.00000001 (1 UFix64 quantum). + /// + /// UFix64 has 8 decimals; EVM tokens have 18. One UFix64 step = 10^10 wei. + /// + /// Example (pool price 1 USDC = 2 FLOW, want 10 FLOW out): + /// 1. Quoter says need 5,000000002000000000 USDC wei + /// 2. Ceil to UFix64: 5,000000010000000000 (overshoot: 8e9 wei) + /// 3. exactInput swaps the ceiled amount; extra 8e9 FLOW wei × 2 = 16e9 FLOW wei extra + /// 4. Actual output: 10,000000016000000000 FLOW wei + /// 5. Floor to UFix64: 10.00000001 FLOW (quoted 10.00000000) + /// + /// The overshoot is always non-negative (ceiled input >= what pool needs). + /// It surfaces when the extra output crosses a 10^10 wei quantum boundary. result.balance >= amount && result.balance <= amount + 0.00000001: "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)" } From f31e729b94637207b0f523f9aaa39b905923b1d8 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:02:29 -0500 Subject: [PATCH 19/24] update ref --- cadence/contracts/FlowYieldVaults.cdc | 15 +---------- flow.json | 38 ++++++++++----------------- lib/FlowALP | 2 +- 3 files changed, 16 insertions(+), 39 deletions(-) diff --git a/cadence/contracts/FlowYieldVaults.cdc b/cadence/contracts/FlowYieldVaults.cdc index dcf8e972..a3e3ae95 100644 --- a/cadence/contracts/FlowYieldVaults.cdc +++ b/cadence/contracts/FlowYieldVaults.cdc @@ -317,20 +317,7 @@ access(all) contract FlowYieldVaults { /// Withdraws the requested amount from the Strategy access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { post { - /// Quoting exact output then swapping exact input can overshoot by 0.00000001 (1 UFix64 quantum). - /// - /// UFix64 has 8 decimals; EVM tokens have 18. One UFix64 step = 10^10 wei. - /// - /// Example (pool price 1 USDC = 2 FLOW, want 10 FLOW out): - /// 1. Quoter says need 5,000000002000000000 USDC wei - /// 2. Ceil to UFix64: 5,000000010000000000 (overshoot: 8e9 wei) - /// 3. exactInput swaps the ceiled amount; extra 8e9 FLOW wei × 2 = 16e9 FLOW wei extra - /// 4. Actual output: 10,000000016000000000 FLOW wei - /// 5. Floor to UFix64: 10.00000001 FLOW (quoted 10.00000000) - /// - /// The overshoot is always non-negative (ceiled input >= what pool needs). - /// It surfaces when the extra output crosses a 10^10 wei quantum boundary. - result.balance >= amount && result.balance <= amount + 0.00000001: + result.balance == amount: "Invalid Vault balance returned - requested \(amount) but returned \(result.balance)" self.vaultType == result.getType(): diff --git a/flow.json b/flow.json index 115afc72..af8f8272 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": { @@ -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", + "FlowALPv1": { + "source": "./lib/FlowALP/cadence/contracts/FlowALPv1.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "testing": "0000000000000007", + "testing": "0000000000000008", "testnet": "426f0458ced60037" } }, @@ -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": { @@ -1430,4 +1420,4 @@ ] } } -} +} \ No newline at end of file diff --git a/lib/FlowALP b/lib/FlowALP index 8fd49d3f..760b53d0 160000 --- a/lib/FlowALP +++ b/lib/FlowALP @@ -1 +1 @@ -Subproject commit 8fd49d3f3a2647d8ae143c0dcff5c72fa190da1a +Subproject commit 760b53d01d968180c404b9cdae0f290af8e42676 From 898f5e2f65e52e2fc51866bea4d3f2b04199e237 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:16:39 -0500 Subject: [PATCH 20/24] catch up with renaming --- README.md | 14 +- .../contracts/FlowYieldVaultsStrategies.cdc | 22 +- .../contracts/FlowYieldVaultsStrategiesV2.cdc | 14 +- .../contracts/mocks/MockFlowALPConsumer.cdc | 12 +- cadence/scripts/diag_bridge_associations.cdc | 31 +++ cadence/scripts/diag_check_pool.cdc | 26 +++ cadence/scripts/diag_evm_vault_state.cdc | 35 +++ cadence/scripts/diag_get_moet_evm.cdc | 9 + cadence/scripts/diag_sywflowv.cdc | 50 ++++ cadence/scripts/diag_univ3_dust.cdc | 134 +++++++++++ .../get_complete_user_position_info.cdc | 10 +- cadence/tests/atomic_registration_gc_test.cdc | 1 - cadence/tests/diag_sywflowv_test.cdc | 47 ++++ cadence/tests/rebalance_scenario2_test.cdc | 1 - cadence/tests/rebalance_scenario3a_test.cdc | 8 +- cadence/tests/rebalance_scenario3b_test.cdc | 4 +- cadence/tests/rebalance_scenario3c_test.cdc | 6 +- cadence/tests/rebalance_scenario3d_test.cdc | 6 +- cadence/tests/test_helpers.cdc | 28 +-- cadence/tests/tracer_strategy_test.cdc | 10 +- .../tests/univ3_swap_overshoot_dust_test.cdc | 218 ++++++++++++++++++ cadence/tests/yield_vault_lifecycle_test.cdc | 1 - flow.json | 14 +- lib/FlowALP | 2 +- local/setup_emulator.sh | 2 +- local/setup_mainnet.sh | 2 +- local/setup_testnet.sh | 2 +- 27 files changed, 625 insertions(+), 84 deletions(-) create mode 100644 cadence/scripts/diag_bridge_associations.cdc create mode 100644 cadence/scripts/diag_check_pool.cdc create mode 100644 cadence/scripts/diag_evm_vault_state.cdc create mode 100644 cadence/scripts/diag_get_moet_evm.cdc create mode 100644 cadence/scripts/diag_sywflowv.cdc create mode 100644 cadence/scripts/diag_univ3_dust.cdc create mode 100644 cadence/tests/diag_sywflowv_test.cdc create mode 100644 cadence/tests/univ3_swap_overshoot_dust_test.cdc diff --git a/README.md b/README.md index 85c2b3ba..9aef5ebb 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Mock FungibleToken implementations representing: | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0xd27920b6384e2a78 | DeFiActions | TBD | -| FlowALPv1 | 0xd27920b6384e2a78 | FlowALPv1 | TBD | +| FlowALPv0 | 0xd27920b6384e2a78 | FlowALPv0 | TBD | | FlowYieldVaults | 0xd27920b6384e2a78 | FlowYieldVaults | TBD | | FlowYieldVaultsStrategiesV2 | 0xd27920b6384e2a78 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xd27920b6384e2a78 | PMStrategiesV1 | TBD | @@ -78,7 +78,7 @@ Mock FungibleToken implementations representing: | Asset Name | Cadence Address | Cadence Contract Name | EVM | |---|---|---|---| | FlowActions | 0x6d888f175c158410 | DeFiActions | TBD | -| FlowALPv1 | 0x6b00ff876c299c61 | FlowALPv1 | TBD | +| FlowALPv0 | 0x6b00ff876c299c61 | FlowALPv0 | TBD | | FlowYieldVaults | 0xb1d63873c3cc9f79 | FlowYieldVaults | TBD | | FlowYieldVaultsStrategiesV2 | 0xb1d63873c3cc9f79 | FlowYieldVaultsStrategiesV2 | TBD | | PMStrategiesV1 | 0xb1d63873c3cc9f79 | PMStrategiesV1 | TBD | @@ -99,7 +99,7 @@ Below is an overview of the initial prototype Tracer Strategy in the broader con The TracerStrategy demonstrates the power of DeFi Actions composition: ``` -User Deposit (FLOW) → FlowALPv1 Position → MOET Issuance → Swap to YieldToken → AutoBalancer +User Deposit (FLOW) → FlowALP Position → MOET Issuance → Swap to YieldToken → AutoBalancer ↑ YieldToken → Swap to FLOW → Recollateralize Position ``` @@ -210,12 +210,12 @@ The AutoBalancer continuously monitors the **value ratio** between: **When:** Current YieldToken value > 105% historical value of deposits **Cause:** YieldToken price has increased OR position became over-collateralized leading to excess token holdings -**Action:** AutoBalancer deposits excess YieldToken to the rebalanceSink, swapping to FLOW and recollateralizing the FlowALPv1 position. +**Action:** AutoBalancer deposits excess YieldToken to the rebalanceSink, swapping to FLOW and recollateralizing the FlowALP position. **Automated Flow:** ``` -YieldToken (excess) → Swap to FLOW → Deposit to FlowALPv1 Position (recollateralization) +YieldToken (excess) → Swap to FLOW → Deposit to FlowALP Position (recollateralization) ``` **Result:** @@ -264,7 +264,7 @@ The system creates a sophisticated token flow: 1. **Initial Position Opening:** - - User deposits FLOW → FlowALPv1 Position + - User deposits FLOW → FlowALP Position - Position issues MOET → Swaps to YieldToken - YieldToken held in AutoBalancer @@ -577,7 +577,7 @@ Position Health = Effective Collateral / Effective Debt #### Health Computation Function ```cadence -// From FlowALPv1.cdc +// From FlowALPv0.cdc access(all) fun healthComputation(effectiveCollateral: UFix64, effectiveDebt: UFix64): UFix64 { if effectiveCollateral == 0.0 { return 0.0 diff --git a/cadence/contracts/FlowYieldVaultsStrategies.cdc b/cadence/contracts/FlowYieldVaultsStrategies.cdc index 70b398ed..a14fc378 100644 --- a/cadence/contracts/FlowYieldVaultsStrategies.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategies.cdc @@ -12,7 +12,7 @@ import "UniswapV3SwapConnectors" import "ERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol -import "FlowALPv1" +import "FlowALPv0" // FlowYieldVaults platform import "FlowYieldVaultsClosedBeta" import "FlowYieldVaults" @@ -57,7 +57,7 @@ access(all) contract FlowYieldVaultsStrategies { /// 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 & + /// 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. @@ -65,11 +65,11 @@ access(all) contract FlowYieldVaultsStrategies { /// 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) @@ -194,8 +194,8 @@ access(all) contract FlowYieldVaultsStrategies { let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToStableSwapper, source: abaSource, uniqueID: uniqueID) // open a FlowALP position - let poolCap = FlowYieldVaultsStrategies.account.storage.load>( - from: FlowALPv1.PoolCapStoragePath + let poolCap = FlowYieldVaultsStrategies.account.storage.load>( + from: FlowALPv0.PoolCapStoragePath ) ?? panic("Missing pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") @@ -206,7 +206,7 @@ access(all) contract FlowYieldVaultsStrategies { repaymentSource: abaSwapSource, pushToDrawDownSink: true ) - FlowYieldVaultsStrategies.account.storage.save(poolCap, to: FlowALPv1.PoolCapStoragePath) + FlowYieldVaultsStrategies.account.storage.save(poolCap, to: FlowALPv0.PoolCapStoragePath) // get Sink & Source connectors relating to the new Position let positionSink = position.createSinkWithOptions(type: collateralType, pushToDrawDownSink: true) @@ -240,11 +240,11 @@ access(all) contract FlowYieldVaultsStrategies { /// 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) @@ -470,8 +470,8 @@ access(all) contract FlowYieldVaultsStrategies { let abaSwapSource = SwapConnectors.SwapSource(swapper: yieldToMOETSwapper, source: abaSource, uniqueID: uniqueID) // open a FlowALP position - let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( - from: FlowALPv1.PoolCapStoragePath + let poolCap = FlowYieldVaultsStrategies.account.storage.copy>( + from: FlowALPv0.PoolCapStoragePath ) ?? panic("Missing or invalid pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index 1712e924..05f61355 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -12,7 +12,7 @@ import "ERC4626SwapConnectors" import "MorphoERC4626SwapConnectors" import "ERC4626Utils" // Lending protocol -import "FlowALPv1" +import "FlowALPv0" // FlowYieldVaults platform import "FlowYieldVaults" import "FlowYieldVaultsAutoBalancers" @@ -77,11 +77,11 @@ access(all) contract FlowYieldVaultsStrategiesV2 { /// 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) @@ -276,7 +276,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { uniqueID: uniqueID ) - // Open FlowALPv1 position + // Open FlowALPv0 position let position <- self._openCreditPosition( funds: <-withFunds, issuanceSink: abaSwapSink, @@ -549,10 +549,10 @@ access(all) contract FlowYieldVaultsStrategiesV2 { funds: @{FungibleToken.Vault}, issuanceSink: {DeFiActions.Sink}, repaymentSource: {DeFiActions.Source} - ): @FlowALPv1.Position { + ): @FlowALPv0.Position { let poolCap = FlowYieldVaultsStrategiesV2.account.storage.copy< - Capability - >(from: FlowALPv1.PoolCapStoragePath) + Capability + >(from: FlowALPv0.PoolCapStoragePath) ?? panic("Missing or invalid pool capability") let poolRef = poolCap.borrow() ?? panic("Invalid Pool Cap") 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/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..87739251 100644 --- a/cadence/tests/atomic_registration_gc_test.cdc +++ b/cadence/tests/atomic_registration_gc_test.cdc @@ -7,7 +7,6 @@ import "FlowYieldVaultsSchedulerRegistry" import "FlowToken" import "MOET" import "YieldToken" -import "FlowALPv1" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) diff --git a/cadence/tests/diag_sywflowv_test.cdc b/cadence/tests/diag_sywflowv_test.cdc new file mode 100644 index 00000000..51068dce --- /dev/null +++ b/cadence/tests/diag_sywflowv_test.cdc @@ -0,0 +1,47 @@ +#test_fork(network: "mainnet-fork", height: 142046400) + +import Test + +import "EVM" +import "FlowToken" +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" +import "ERC4626Utils" + +access(all) fun testDiagnoseSyWFLOWv() { + let syWFLOWvAddr = EVM.addressFromString("0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597") + let fusdEvAddr = EVM.addressFromString("0xd069d989e2F44B70c65347d1853C0c67e10a9F8D") + + // Check bridge type associations + let syWFLOWvType = FlowEVMBridgeConfig.getTypeAssociated(with: syWFLOWvAddr) + log("syWFLOWv type association: ".concat(syWFLOWvType?.identifier ?? "nil")) + + let fusdEvType = FlowEVMBridgeConfig.getTypeAssociated(with: fusdEvAddr) + log("FUSDEV type association: ".concat(fusdEvType?.identifier ?? "nil")) + + // Check underlying asset + let syWFLOWvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: syWFLOWvAddr) + log("syWFLOWv underlying: ".concat(syWFLOWvUnderlying?.toString() ?? "nil")) + + let fusdEvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: fusdEvAddr) + log("FUSDEV underlying: ".concat(fusdEvUnderlying?.toString() ?? "nil")) + + // Check FlowToken EVM address association + let flowTokenType = Type<@FlowToken.Vault>() + let flowEVMAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) + log("FlowToken.Vault EVM address: ".concat(flowEVMAddr?.toString() ?? "nil")) + + // Check totalAssets and totalSupply for syWFLOWv + let syWFLOWvTotalAssets = ERC4626Utils.totalAssets(vault: syWFLOWvAddr) + log("syWFLOWv totalAssets: ".concat(syWFLOWvTotalAssets?.toString() ?? "nil")) + + let syWFLOWvTotalShares = ERC4626Utils.totalShares(vault: syWFLOWvAddr) + log("syWFLOWv totalShares: ".concat(syWFLOWvTotalShares?.toString() ?? "nil")) + + // Check totalAssets and totalSupply for FUSDEV (working reference) + let fusdEvTotalAssets = ERC4626Utils.totalAssets(vault: fusdEvAddr) + log("FUSDEV totalAssets: ".concat(fusdEvTotalAssets?.toString() ?? "nil")) + + let fusdEvTotalShares = ERC4626Utils.totalShares(vault: fusdEvAddr) + log("FUSDEV totalShares: ".concat(fusdEvTotalShares?.toString() ?? "nil")) +} diff --git a/cadence/tests/rebalance_scenario2_test.cdc b/cadence/tests/rebalance_scenario2_test.cdc index dfac8324..bb17adc5 100644 --- a/cadence/tests/rebalance_scenario2_test.cdc +++ b/cadence/tests/rebalance_scenario2_test.cdc @@ -7,7 +7,6 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) diff --git a/cadence/tests/rebalance_scenario3a_test.cdc b/cadence/tests/rebalance_scenario3a_test.cdc index 73ba3754..0f10bd29 100644 --- a/cadence/tests/rebalance_scenario3a_test.cdc +++ b/cadence/tests/rebalance_scenario3a_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 } } @@ -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..22adb4a3 100644 --- a/cadence/tests/rebalance_scenario3b_test.cdc +++ b/cadence/tests/rebalance_scenario3b_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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..9ff168d0 100644 --- a/cadence/tests/rebalance_scenario3c_test.cdc +++ b/cadence/tests/rebalance_scenario3c_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 } } diff --git a/cadence/tests/rebalance_scenario3d_test.cdc b/cadence/tests/rebalance_scenario3d_test.cdc index a9eb2f48..8933d739 100644 --- a/cadence/tests/rebalance_scenario3d_test.cdc +++ b/cadence/tests/rebalance_scenario3d_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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 } } diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 4a22054c..0c7f0d8f 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()) @@ -268,12 +268,6 @@ access(all) fun deployContracts() { 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", @@ -469,13 +463,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) @@ -621,14 +615,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 --- */ @@ -708,7 +702,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..a7b84ca7 100644 --- a/cadence/tests/tracer_strategy_test.cdc +++ b/cadence/tests/tracer_strategy_test.cdc @@ -7,7 +7,7 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" +import "FlowALPv0" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) @@ -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..cf8b67fd 100644 --- a/cadence/tests/yield_vault_lifecycle_test.cdc +++ b/cadence/tests/yield_vault_lifecycle_test.cdc @@ -7,7 +7,6 @@ import "FlowToken" import "MOET" import "YieldToken" import "FlowYieldVaultsStrategies" -import "FlowALPv1" import "FlowYieldVaults" access(all) let protocolAccount = Test.getAccount(0x0000000000000008) diff --git a/flow.json b/flow.json index af8f8272..c93f0658 100644 --- a/flow.json +++ b/flow.json @@ -92,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,8 +118,8 @@ "testnet": "426f0458ced60037" } }, - "FlowALPv1": { - "source": "./lib/FlowALP/cadence/contracts/FlowALPv1.cdc", + "FlowALPv0": { + "source": "./lib/FlowALP/cadence/contracts/FlowALPv0.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "6b00ff876c299c61", @@ -974,7 +974,7 @@ "FungibleTokenConnectors", "SwapConnectors", "DummyConnectors", - "FlowALPv1", + "FlowALPv0", { "name": "YieldToken", "args": [ @@ -1420,4 +1420,4 @@ ] } } -} \ No newline at end of file +} diff --git a/lib/FlowALP b/lib/FlowALP index 760b53d0..015a9d8d 160000 --- a/lib/FlowALP +++ b/lib/FlowALP @@ -1 +1 @@ -Subproject commit 760b53d01d968180c404b9cdae0f290af8e42676 +Subproject commit 015a9d8d02da71cf757c717072c9672919473897 diff --git a/local/setup_emulator.sh b/local/setup_emulator.sh index 55520edf..14fff173 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 diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index dcdfa36f..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 diff --git a/local/setup_testnet.sh b/local/setup_testnet.sh index c844f257..daa8f760 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -12,7 +12,7 @@ flow transactions send ./cadence/transactions/mocks/oracle/set_price.cdc 'A.dfc2 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 From 80b57b6faa87391aceb200372133853b8c4b663a Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:11:07 -0500 Subject: [PATCH 21/24] update ref --- lib/FlowALP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlowALP b/lib/FlowALP index 015a9d8d..972ac4c3 160000 --- a/lib/FlowALP +++ b/lib/FlowALP @@ -1 +1 @@ -Subproject commit 015a9d8d02da71cf757c717072c9672919473897 +Subproject commit 972ac4c3e07f7074089e22751761d4c040c026c2 From bcd6fbd3204f0108bdbfdae86b1e4efde8e8f436 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:01:09 -0500 Subject: [PATCH 22/24] update ref --- lib/FlowALP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlowALP b/lib/FlowALP index 972ac4c3..d9970e3d 160000 --- a/lib/FlowALP +++ b/lib/FlowALP @@ -1 +1 @@ -Subproject commit 972ac4c3e07f7074089e22751761d4c040c026c2 +Subproject commit d9970e3d7aedffcb15eb1f953b299173c137f718 From cf35f7d1d03e8b351e3329dc70de2d3b2dd61789 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:50:53 -0500 Subject: [PATCH 23/24] remove diag tests --- cadence/tests/diag_sywflowv_test.cdc | 47 ---------------------------- 1 file changed, 47 deletions(-) delete mode 100644 cadence/tests/diag_sywflowv_test.cdc diff --git a/cadence/tests/diag_sywflowv_test.cdc b/cadence/tests/diag_sywflowv_test.cdc deleted file mode 100644 index 51068dce..00000000 --- a/cadence/tests/diag_sywflowv_test.cdc +++ /dev/null @@ -1,47 +0,0 @@ -#test_fork(network: "mainnet-fork", height: 142046400) - -import Test - -import "EVM" -import "FlowToken" -import "FlowEVMBridgeConfig" -import "FlowEVMBridgeUtils" -import "ERC4626Utils" - -access(all) fun testDiagnoseSyWFLOWv() { - let syWFLOWvAddr = EVM.addressFromString("0xCBf9a7753F9D2d0e8141ebB36d99f87AcEf98597") - let fusdEvAddr = EVM.addressFromString("0xd069d989e2F44B70c65347d1853C0c67e10a9F8D") - - // Check bridge type associations - let syWFLOWvType = FlowEVMBridgeConfig.getTypeAssociated(with: syWFLOWvAddr) - log("syWFLOWv type association: ".concat(syWFLOWvType?.identifier ?? "nil")) - - let fusdEvType = FlowEVMBridgeConfig.getTypeAssociated(with: fusdEvAddr) - log("FUSDEV type association: ".concat(fusdEvType?.identifier ?? "nil")) - - // Check underlying asset - let syWFLOWvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: syWFLOWvAddr) - log("syWFLOWv underlying: ".concat(syWFLOWvUnderlying?.toString() ?? "nil")) - - let fusdEvUnderlying = ERC4626Utils.underlyingAssetEVMAddress(vault: fusdEvAddr) - log("FUSDEV underlying: ".concat(fusdEvUnderlying?.toString() ?? "nil")) - - // Check FlowToken EVM address association - let flowTokenType = Type<@FlowToken.Vault>() - let flowEVMAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: flowTokenType) - log("FlowToken.Vault EVM address: ".concat(flowEVMAddr?.toString() ?? "nil")) - - // Check totalAssets and totalSupply for syWFLOWv - let syWFLOWvTotalAssets = ERC4626Utils.totalAssets(vault: syWFLOWvAddr) - log("syWFLOWv totalAssets: ".concat(syWFLOWvTotalAssets?.toString() ?? "nil")) - - let syWFLOWvTotalShares = ERC4626Utils.totalShares(vault: syWFLOWvAddr) - log("syWFLOWv totalShares: ".concat(syWFLOWvTotalShares?.toString() ?? "nil")) - - // Check totalAssets and totalSupply for FUSDEV (working reference) - let fusdEvTotalAssets = ERC4626Utils.totalAssets(vault: fusdEvAddr) - log("FUSDEV totalAssets: ".concat(fusdEvTotalAssets?.toString() ?? "nil")) - - let fusdEvTotalShares = ERC4626Utils.totalShares(vault: fusdEvAddr) - log("FUSDEV totalShares: ".concat(fusdEvTotalShares?.toString() ?? "nil")) -} From ac690f4b987f71531359c5fa7746e940c23c5fe6 Mon Sep 17 00:00:00 2001 From: Alex <12097569+nialexsan@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:06:37 -0500 Subject: [PATCH 24/24] rename tracer strategy --- README.md | 4 +- .../contracts/FlowYieldVaultsStrategies.cdc | 703 ------------------ cadence/contracts/mocks/MockStrategies.cdc | 352 +++++++++ cadence/tests/atomic_registration_gc_test.cdc | 8 +- cadence/tests/rebalance_scenario1_test.cdc | 8 +- cadence/tests/rebalance_scenario2_test.cdc | 8 +- cadence/tests/rebalance_scenario3a_test.cdc | 8 +- cadence/tests/rebalance_scenario3b_test.cdc | 8 +- cadence/tests/rebalance_scenario3c_test.cdc | 8 +- cadence/tests/rebalance_scenario3d_test.cdc | 8 +- cadence/tests/rebalance_yield_test.cdc | 8 +- .../scheduled_rebalance_integration_test.cdc | 8 +- .../scheduled_rebalance_scenario_test.cdc | 8 +- cadence/tests/scheduled_supervisor_test.cdc | 8 +- cadence/tests/scheduler_edge_cases_test.cdc | 8 +- cadence/tests/test_helpers.cdc | 13 +- cadence/tests/tracer_strategy_test.cdc | 8 +- cadence/tests/yield_vault_lifecycle_test.cdc | 8 +- .../admin/upsert_musdc_config.cdc | 82 -- docs/rebalancing_architecture.md | 4 +- ...uled_rebalancing_comprehensive_analysis.md | 12 +- flow.json | 197 +---- local/e2e_test.sh | 2 +- local/setup_emulator.sh | 4 +- local/setup_testnet.sh | 4 +- 25 files changed, 431 insertions(+), 1058 deletions(-) delete mode 100644 cadence/contracts/FlowYieldVaultsStrategies.cdc create mode 100644 cadence/contracts/mocks/MockStrategies.cdc delete mode 100644 cadence/transactions/flow-yield-vaults/admin/upsert_musdc_config.cdc diff --git a/README.md b/README.md index 9aef5ebb..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: @@ -973,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/FlowYieldVaultsStrategies.cdc b/cadence/contracts/FlowYieldVaultsStrategies.cdc deleted file mode 100644 index a14fc378..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 "FlowALPv0" -// 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 @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 - // 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: 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 - ) - FlowYieldVaultsStrategies.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 - ) - } - } - - /// 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: @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: [ - 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: FlowALPv0.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/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/tests/atomic_registration_gc_test.cdc b/cadence/tests/atomic_registration_gc_test.cdc index 87739251..f4a7b89a 100644 --- a/cadence/tests/atomic_registration_gc_test.cdc +++ b/cadence/tests/atomic_registration_gc_test.cdc @@ -2,7 +2,7 @@ import Test import BlockchainHelpers import "test_helpers.cdc" -import "FlowYieldVaultsStrategies" +import "MockStrategies" import "FlowYieldVaultsSchedulerRegistry" import "FlowToken" import "MOET" @@ -12,7 +12,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 @@ -62,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 bb17adc5..4beb8734 100644 --- a/cadence/tests/rebalance_scenario2_test.cdc +++ b/cadence/tests/rebalance_scenario2_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +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 @@ -152,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 0f10bd29..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 "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 ) diff --git a/cadence/tests/rebalance_scenario3b_test.cdc b/cadence/tests/rebalance_scenario3b_test.cdc index 22adb4a3..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 "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 ) diff --git a/cadence/tests/rebalance_scenario3c_test.cdc b/cadence/tests/rebalance_scenario3c_test.cdc index 9ff168d0..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 "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 ) diff --git a/cadence/tests/rebalance_scenario3d_test.cdc b/cadence/tests/rebalance_scenario3d_test.cdc index 8933d739..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 "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 ) 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 0c7f0d8f..87aedce0 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -334,16 +334,9 @@ 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()) diff --git a/cadence/tests/tracer_strategy_test.cdc b/cadence/tests/tracer_strategy_test.cdc index a7b84ca7..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 "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 ) diff --git a/cadence/tests/yield_vault_lifecycle_test.cdc b/cadence/tests/yield_vault_lifecycle_test.cdc index cf8b67fd..4b4bf0bb 100644 --- a/cadence/tests/yield_vault_lifecycle_test.cdc +++ b/cadence/tests/yield_vault_lifecycle_test.cdc @@ -6,14 +6,14 @@ import "test_helpers.cdc" import "FlowToken" import "MOET" import "YieldToken" -import "FlowYieldVaultsStrategies" +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 @@ -71,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/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 c93f0658..4308a2e0 100644 --- a/flow.json +++ b/flow.json @@ -178,8 +178,8 @@ "testnet": "d2580caf2ef07c2f" } }, - "FlowYieldVaultsStrategies": { - "source": "cadence/contracts/FlowYieldVaultsStrategies.cdc", + "MockStrategies": { + "source": "cadence/contracts/mocks/MockStrategies.cdc", "aliases": { "emulator": "045a1763c93006ca", "mainnet": "b1d63873c3cc9f79", @@ -1009,35 +1009,7 @@ "FlowYieldVaultsClosedBeta", "FlowYieldVaults", "UniswapV3SwapConnectors", - { - "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" - } - ] - }, + "MockStrategies", { "name": "FlowYieldVaultsStrategiesV2", "args": [ @@ -1107,65 +1079,6 @@ "FlowYieldVaultsSchedulerV1", "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": "FlowYieldVaultsStrategiesV2", "args": [ @@ -1219,65 +1132,7 @@ "FlowYieldVaultsSchedulerV1", "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" - } - ] - }, + "MockStrategies", { "name": "FlowYieldVaultsStrategiesV2", "args": [ @@ -1340,49 +1195,7 @@ "FlowYieldVaultsSchedulerV1", "FlowYieldVaultsClosedBeta", "FlowYieldVaults", - { - "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" - } - ] - }, + "MockStrategies", { "name": "FlowYieldVaultsStrategiesV2", "args": [ 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 14fff173..730950c2 100755 --- a/local/setup_emulator.sh +++ b/local/setup_emulator.sh @@ -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 diff --git a/local/setup_testnet.sh b/local/setup_testnet.sh index daa8f760..e1fb2697 100755 --- a/local/setup_testnet.sh +++ b/local/setup_testnet.sh @@ -82,8 +82,8 @@ 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