diff --git a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc index 05f6135..f763672 100644 --- a/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc +++ b/cadence/contracts/FlowYieldVaultsStrategiesV2.cdc @@ -72,7 +72,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { } } - /// This strategy uses FUSDEV vault + /// This strategy uses FUSDEV vault (Morpho ERC4626) 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 @@ -132,6 +132,66 @@ access(all) contract FlowYieldVaultsStrategiesV2 { } } + /// This strategy uses syWFLOWv vault (Standard ERC4626) + 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? + 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 + } + } + access(all) struct TokenBundle { access(all) let moetTokenType: Type access(all) let moetTokenEVMAddress: EVM.EVMAddress @@ -179,7 +239,7 @@ access(all) contract FlowYieldVaultsStrategiesV2 { } } - /// This StrategyComposer builds a Strategy that uses MorphoERC4626 vault + /// This StrategyComposer builds a Strategy that uses ERC4626 and MorphoERC4626 vaults access(all) resource MorphoERC4626StrategyComposer : FlowYieldVaults.StrategyComposer { /// { Strategy Type: { Collateral Type: FlowYieldVaultsStrategiesV2.CollateralConfig } } access(self) let config: {Type: {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}} @@ -311,6 +371,12 @@ access(all) contract FlowYieldVaultsStrategiesV2 { collateralType: collateralType, position: <-position ) + case Type<@syWFLOWvStrategy>(): + return <-create syWFLOWvStrategy( + id: uniqueID, + collateralType: collateralType, + position: <-position + ) default: panic("Unsupported strategy type \(type.identifier)") } @@ -742,7 +808,8 @@ access(all) contract FlowYieldVaultsStrategiesV2 { access(Configure) fun purgeConfig() { self.configs = { Type<@MorphoERC4626StrategyComposer>(): { - Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}, + Type<@syWFLOWvStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} } } } @@ -828,7 +895,8 @@ access(all) contract FlowYieldVaultsStrategiesV2 { let configs = { Type<@MorphoERC4626StrategyComposer>(): { - Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} + Type<@FUSDEVStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig}, + Type<@syWFLOWvStrategy>(): {} as {Type: FlowYieldVaultsStrategiesV2.CollateralConfig} } } self.account.storage.save(<-create StrategyComposerIssuer(configs: configs), to: self.IssuerStoragePath) diff --git a/cadence/contracts/mocks/MockStrategies.cdc b/cadence/contracts/mocks/MockStrategies.cdc index 84fbdcc..e073780 100644 --- a/cadence/contracts/mocks/MockStrategies.cdc +++ b/cadence/contracts/mocks/MockStrategies.cdc @@ -330,7 +330,7 @@ access(all) contract MockStrategies { } init() { - self.IssuerStoragePath = StoragePath(identifier: "FlowYieldVaultsStrategyComposerIssuer_\(self.account.address)")! + self.IssuerStoragePath = StoragePath(identifier: "MockStrategyComposerIssuer_\(self.account.address)")! let initialCollateralType = Type<@FlowToken.Vault>() diff --git a/cadence/scripts/band-oracle/get_pyusd_price.cdc b/cadence/scripts/band-oracle/get_pyusd_price.cdc new file mode 100644 index 0000000..8c74120 --- /dev/null +++ b/cadence/scripts/band-oracle/get_pyusd_price.cdc @@ -0,0 +1,37 @@ +import "FungibleToken" +import "FlowToken" +import "BandOracle" + +/// Retrieves the PYUSD/USD price from the Band Protocol oracle on Flow. +/// +/// BandOracle stores rates as symbol/USD values and computes cross-rates on demand. +/// Querying PYUSD/USD returns the USD price of one PYUSD token (~1.0 for a healthy peg). +/// +/// NOTE: BandOracle.getReferenceData requires a FLOW fee payment. This script creates an +/// empty vault and succeeds only when BandOracle.getFee() == 0.0. If the fee is non-zero, +/// use the get_pyusd_price transaction instead, which withdraws from the signer's FLOW vault. +/// +/// @return A struct with: +/// - fixedPointRate: UFix64 — PYUSD/USD price as a decimal (e.g. 0.99980000) +/// - integerE18Rate: UInt256 — rate multiplied by 10^18 +/// - baseTimestamp: UInt64 — UNIX epoch of the last PYUSD data update on BandChain +/// - quoteTimestamp: UInt64 — UNIX epoch of the last USD data update on BandChain +/// +access(all) +fun main(): BandOracle.ReferenceData { + let fee = BandOracle.getFee() + assert(fee == 0.0, message: "BandOracle fee is non-zero (\(fee) FLOW). Use the get_pyusd_price transaction to pay the fee.") + + // Create an empty vault satisfying the payment parameter (fee == 0.0 is already asserted above) + let payment <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + + // PYUSD is the base symbol; USD is the implicit quote for all Band oracle rates. + // The returned fixedPointRate = PYUSD price in USD. + let priceData = BandOracle.getReferenceData( + baseSymbol: "PYUSD", + quoteSymbol: "USD", + payment: <-payment + ) + + return priceData +} diff --git a/cadence/transactions/band-oracle/get_pyusd_price.cdc b/cadence/transactions/band-oracle/get_pyusd_price.cdc new file mode 100644 index 0000000..2f0ec4b --- /dev/null +++ b/cadence/transactions/band-oracle/get_pyusd_price.cdc @@ -0,0 +1,36 @@ +import "FungibleToken" +import "FlowToken" +import "BandOracle" + +/// Retrieves the PYUSD/USD price from the Band Protocol oracle, paying the oracle fee from +/// the signer's FLOW vault. Use this transaction when BandOracle.getFee() > 0.0. +/// +/// The price is emitted to the transaction log. Band oracle rates are USD-denominated, so +/// PYUSD/USD returns the USD value of one PYUSD token (~1.0 for a healthy peg). +/// +/// Excess FLOW (payment beyond the required fee) is returned to the signer's vault. +/// +transaction { + + prepare(signer: auth(BorrowValue) &Account) { + let fee = BandOracle.getFee() + + // Borrow the signer's FLOW vault and withdraw the exact oracle fee + let flowVault = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("Could not borrow signer's FlowToken vault") + + let payment <- flowVault.withdraw(amount: fee) as! @FlowToken.Vault + + let priceData = BandOracle.getReferenceData( + baseSymbol: "PYUSD", + quoteSymbol: "USD", + payment: <-payment + ) + + log("PYUSD/USD price (UFix64): ".concat(priceData.fixedPointRate.toString())) + log("PYUSD/USD rate (e18 integer): ".concat(priceData.integerE18Rate.toString())) + log("Base timestamp (UNIX): ".concat(priceData.baseTimestamp.toString())) + log("Quote timestamp (UNIX): ".concat(priceData.quoteTimestamp.toString())) + } +} diff --git a/local/setup_mainnet.sh b/local/setup_mainnet.sh index cd7fe49..a092a62 100755 --- a/local/setup_mainnet.sh +++ b/local/setup_mainnet.sh @@ -22,7 +22,7 @@ flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-factory/ flow transactions send ./lib/FlowALP/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/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_zero_rate_curve.cdc \ 'A.1654653399040a61.FlowToken.Vault' \ 0.8 \ 1.0 \ @@ -34,11 +34,8 @@ flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governan # add WBTC to band oracle cd ./lib/FlowALP/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 ../../.. -# add WETH to band oracle -cd ./lib/FlowALP/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/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_zero_rate_curve.cdc \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ 0.8 \ 1.0 \ @@ -47,8 +44,18 @@ flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governan --network mainnet \ --signer mainnet-flow-alp-deployer +# set minimum deposit for WBTC ~ 0.005 USD +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/set_minimum_token_balance_per_position.cdc \ + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_717dae2baf7656be9a9b01dee31d571a9d4c9579.Vault' \ + 0.0000001 \ + --network mainnet \ + --signer mainnet-flow-alp-deployer + +# add WETH to band oracle +cd ./lib/FlowALP/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 ../../.. + # WETH simple curve -flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_simple_interest_curve.cdc \ +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_zero_rate_curve.cdc \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ 0.8 \ 1.0 \ @@ -57,6 +64,33 @@ flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governan --network mainnet \ --signer mainnet-flow-alp-deployer +# set minimum deposit for WETH ~ 0.01 USD +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/set_minimum_token_balance_per_position.cdc \ + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2f6f07cdcf3588944bf4c42ac74ff24bf56e7590.Vault' \ + 0.00001 \ + --network mainnet \ + --signer mainnet-flow-alp-deployer + +# add PYUSD0 to band oracle +cd ./lib/FlowALP/FlowActions && flow transactions send ./cadence/transactions/band-oracle-connector/add_symbol.cdc "PYUSD" "A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault" --network mainnet --signer mainnet-band-oracle-connectors && cd ../../.. + +# PYUSD0 simple curve +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/add_supported_token_zero_rate_curve.cdc \ + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault' \ + 0.8 \ + 1.0 \ + 1_000_000.0 \ + 1_000_000.0 \ + --network mainnet \ + --signer mainnet-flow-alp-deployer + +# set minimum deposit for PYUSD0 ~ 0.01 USD +flow transactions send ./lib/FlowALP/cadence/transactions/flow-alp/pool-governance/set_minimum_token_balance_per_position.cdc \ + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault' \ + 0.01 \ + --network mainnet \ + --signer mainnet-flow-alp-deployer + # kink interest curve setup # enable when FCM_V1 is deployed # @@ -146,6 +180,15 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_str --network mainnet \ --signer mainnet-admin # +# Setup UniV3 path FUSDEV -> PYUSD0 +flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert_strategy_config.cdc \ + 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ + 'A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault' \ + "0xd069d989e2F44B70c65347d1853C0c67e10a9F8D" \ + '["0xd069d989e2F44B70c65347d1853C0c67e10a9F8D","0x99aF3EeA856556646C98c8B9b2548Fe815240750"]' \ + '[100]' \ + --network mainnet \ + --signer mainnet-admin flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ 'A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy' \ @@ -163,14 +206,6 @@ flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert-pm- --network mainnet \ --signer mainnet-admin -flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc \ - 'A.b1d63873c3cc9f79.PMStrategiesV1.tauUSDFvStrategy' \ - 'A.1e4aa0b87d10b141.EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabed.Vault' \ - '0xc52E820d2D6207D18667a97e2c6Ac22eB26E803c' \ - 100 \ - --network mainnet \ - --signer mainnet-admin - flow transactions send ./cadence/transactions/flow-yield-vaults/admin/upsert-pm-strategy-config.cdc \ 'A.b1d63873c3cc9f79.PMStrategiesV1.FUSDEVStrategy' \ 'A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault' \ @@ -186,13 +221,6 @@ 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.PMStrategiesV1.tauUSDFvStrategy' \ - 'A.b1d63873c3cc9f79.PMStrategiesV1.ERC4626VaultStrategyComposer' \ - /storage/PMStrategiesV1ComposerIssuer_0xb1d63873c3cc9f79 \ - --network mainnet \ - --signer mainnet-admin - flow transactions send ./cadence/transactions/flow-yield-vaults/admin/add_strategy_composer.cdc \ 'A.b1d63873c3cc9f79.PMStrategiesV1.FUSDEVStrategy' \ 'A.b1d63873c3cc9f79.PMStrategiesV1.ERC4626VaultStrategyComposer' \ @@ -222,7 +250,8 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # --proposer # test FlowYieldVault strategy - +# +# WFLOW (FLOW) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ # A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ # A.1654653399040a61.FlowToken.Vault \ @@ -231,7 +260,6 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # --network mainnet \ # --signer # -# # WBTC (BTCf) # flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ # A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ @@ -250,6 +278,14 @@ flow transactions send ./lib/FlowALP/cadence/tests/transactions/flow-alp/pool-ma # --network mainnet \ # --signer # +# PYUSD0 +# flow transactions send ./cadence/transactions/flow-yield-vaults/create_yield_vault.cdc \ +# A.b1d63873c3cc9f79.FlowYieldVaultsStrategiesV2.FUSDEVStrategy \ +# A.1e4aa0b87d10b141.EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750.Vault \ +# 0.01 \ +# --compute-limit 9999 \ +# --network mainnet \ +# --signer # # test PEAK MONEY strategy #