diff --git a/cadence/contracts/FlowYieldVaults.cdc b/cadence/contracts/FlowYieldVaults.cdc index e9e9589f..f61033e5 100644 --- a/cadence/contracts/FlowYieldVaults.cdc +++ b/cadence/contracts/FlowYieldVaults.cdc @@ -91,10 +91,10 @@ access(all) contract FlowYieldVaults { /// Returns the balance of the given token available for withdrawal. Note that this may be an estimate due to /// the lack of guarantees inherent to DeFiActions Sources access(all) fun availableBalance(ofToken: Type): UFix64 - /// Returns the NAV-based balance of the given token. Defaults to availableBalance(); strategies backed by - /// ERC-4626 vaults should override to return convertToAssets(shares) instead of an AMM quote. - access(all) fun navBalance(ofToken: Type): UFix64 { - return self.availableBalance(ofToken: ofToken) + /// Returns the NAV-based balance of the given token, if available for this strategy. + /// Strategies that cannot provide a NAV measurement should return `nil`. + access(all) fun navBalance(ofToken: Type): UFix64? { + return nil } /// Deposits up to the balance of the referenced Vault into this Strategy access(all) fun deposit(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) { @@ -264,8 +264,8 @@ access(all) contract FlowYieldVaults { access(all) fun getYieldVaultBalance(): UFix64 { return self._borrowStrategy().availableBalance(ofToken: self.vaultType) } - /// Returns the NAV-based balance of the YieldVault's position via convertToAssets on the underlying ERC-4626 vault - access(all) fun getNAVBalance(): UFix64 { + /// Returns the NAV-based balance of the YieldVault's position when supported by the inner strategy. + access(all) fun getNAVBalance(): UFix64? { return self._borrowStrategy().navBalance(ofToken: self.vaultType) } /// Burner.Burnable conformance - emits the BurnedYieldVault event when burned diff --git a/cadence/contracts/PMStrategiesV1.cdc b/cadence/contracts/PMStrategiesV1.cdc index 2ebb73af..5d9e6039 100644 --- a/cadence/contracts/PMStrategiesV1.cdc +++ b/cadence/contracts/PMStrategiesV1.cdc @@ -76,7 +76,7 @@ access(all) contract PMStrategiesV1 { return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 } /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault - access(all) fun navBalance(ofToken: Type): UFix64 { + access(all) fun navBalance(ofToken: Type): UFix64? { return PMStrategiesV1._navBalanceFor( strategyType: self.getType(), collateralType: self.sink.getSinkType(), @@ -150,7 +150,7 @@ access(all) contract PMStrategiesV1 { return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 } /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault - access(all) fun navBalance(ofToken: Type): UFix64 { + access(all) fun navBalance(ofToken: Type): UFix64? { return PMStrategiesV1._navBalanceFor( strategyType: self.getType(), collateralType: self.sink.getSinkType(), @@ -224,7 +224,7 @@ access(all) contract PMStrategiesV1 { return ofToken == self.source.getSourceType() ? self.source.minimumAvailable() : 0.0 } /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault - access(all) fun navBalance(ofToken: Type): UFix64 { + access(all) fun navBalance(ofToken: Type): UFix64? { return PMStrategiesV1._navBalanceFor( strategyType: self.getType(), collateralType: self.sink.getSinkType(), @@ -568,29 +568,35 @@ access(all) contract PMStrategiesV1 { /// Shared NAV balance computation: reads Cadence-side share balance from AutoBalancer, /// converts to underlying asset value via ERC-4626 convertToAssets - access(contract) fun _navBalanceFor(strategyType: Type, collateralType: Type, ofToken: Type, id: UInt64): UFix64 { - if ofToken != collateralType { return 0.0 } + access(contract) fun _navBalanceFor(strategyType: Type, collateralType: Type, ofToken: Type, id: UInt64): UFix64? { + if ofToken != collateralType { return nil } let ab = FlowYieldVaultsAutoBalancers.borrowAutoBalancer(id: id) - if ab == nil { return 0.0 } + if ab == nil { return nil } let sharesBalance = ab!.vaultBalance() if sharesBalance == 0.0 { return 0.0 } let vaultAddr = self._getYieldTokenEVMAddress(forStrategy: strategyType, collateralType: collateralType) - ?? panic("No EVM vault address configured for \(strategyType.identifier)") + if vaultAddr == nil { + return nil + } let sharesWei = FlowEVMBridgeUtils.ufix64ToUInt256( value: sharesBalance, - decimals: FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: vaultAddr) + decimals: FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: vaultAddr!) ) - let navWei = ERC4626Utils.convertToAssets(vault: vaultAddr, shares: sharesWei) - ?? panic("convertToAssets failed for vault ".concat(vaultAddr.toString())) + let navWei = ERC4626Utils.convertToAssets(vault: vaultAddr!, shares: sharesWei) + if navWei == nil { + return nil + } - let assetAddr = ERC4626Utils.underlyingAssetEVMAddress(vault: vaultAddr) - ?? panic("No underlying asset EVM address found for vault \(vaultAddr.toString())") + let assetAddr = ERC4626Utils.underlyingAssetEVMAddress(vault: vaultAddr!) + if assetAddr == nil { + return nil + } - return EVMAmountUtils.toCadenceOutForToken(navWei, erc20Address: assetAddr) + return EVMAmountUtils.toCadenceOutForToken(navWei!, erc20Address: assetAddr!) } /// Returns the COA capability for this account