@@ -16,6 +16,8 @@ import "FlowYieldVaults"
1616import " FlowYieldVaultsAutoBalancers"
1717// vm bridge
1818import " FlowEVMBridgeConfig"
19+ import " FlowEVMBridgeUtils"
20+ import " EVMAmountUtils"
1921// live oracles
2022import " ERC4626PriceOracles"
2123
@@ -73,6 +75,15 @@ access(all) contract PMStrategiesV1 {
7375 access (all ) fun availableBalance (ofToken : Type ): UFix64 {
7476 return ofToken == self .source .getSourceType () ? self .source .minimumAvailable () : 0.0
7577 }
78+ /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault
79+ access (all ) fun navBalance (ofToken : Type ): UFix64 {
80+ return PMStrategiesV1 ._navBalanceFor (
81+ strategyType : self .getType (),
82+ collateralType : self .sink .getSinkType (),
83+ ofToken : ofToken ,
84+ id : self .id ()!
85+ )
86+ }
7687 /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference
7788 access (all ) fun deposit (from : auth (FungibleToken.Withdraw ) &{FungibleToken .Vault }) {
7889 self .sink .depositCapacity (from : from )
@@ -148,6 +159,15 @@ access(all) contract PMStrategiesV1 {
148159 access (all ) fun availableBalance (ofToken : Type ): UFix64 {
149160 return ofToken == self .source .getSourceType () ? self .source .minimumAvailable () : 0.0
150161 }
162+ /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault
163+ access (all ) fun navBalance (ofToken : Type ): UFix64 {
164+ return PMStrategiesV1 ._navBalanceFor (
165+ strategyType : self .getType (),
166+ collateralType : self .sink .getSinkType (),
167+ ofToken : ofToken ,
168+ id : self .id ()!
169+ )
170+ }
151171 /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference
152172 access (all ) fun deposit (from : auth (FungibleToken.Withdraw ) &{FungibleToken .Vault }) {
153173 self .sink .depositCapacity (from : from )
@@ -223,6 +243,15 @@ access(all) contract PMStrategiesV1 {
223243 access (all ) fun availableBalance (ofToken : Type ): UFix64 {
224244 return ofToken == self .source .getSourceType () ? self .source .minimumAvailable () : 0.0
225245 }
246+ /// Returns the NAV-based balance by calling convertToAssets on the ERC-4626 vault
247+ access (all ) fun navBalance (ofToken : Type ): UFix64 {
248+ return PMStrategiesV1 ._navBalanceFor (
249+ strategyType : self .getType (),
250+ collateralType : self .sink .getSinkType (),
251+ ofToken : ofToken ,
252+ id : self .id ()!
253+ )
254+ }
226255 /// Deposits up to the inner Sink's capacity from the provided authorized Vault reference
227256 access (all ) fun deposit (from : auth (FungibleToken.Withdraw ) &{FungibleToken .Vault }) {
228257 self .sink .depositCapacity (from : from )
@@ -549,6 +578,51 @@ access(all) contract PMStrategiesV1 {
549578 }
550579 }
551580
581+ /// Looks up the EVM vault address for a given strategy + collateral pair from the on-chain StrategyComposerIssuer config
582+ access (contract ) fun _getYieldTokenEVMAddress (forStrategy : Type , collateralType : Type ): EVM .EVMAddress ? {
583+ let issuer = self .account .storage .borrow <&StrategyComposerIssuer >(from : self .IssuerStoragePath )
584+ if issuer == nil { return nil }
585+ if let composerConfig = issuer ! .configs [Type <@ERC4626VaultStrategyComposer >()] {
586+ if let strategyConfig = composerConfig [forStrategy ] {
587+ if let collateralConfig = strategyConfig [collateralType ] {
588+ // Dictionary access through references yields &EVM.EVMAddress, not EVM.EVMAddress;
589+ // cast to reference, then reconstruct via addressFromString
590+ if let addrRef = collateralConfig [" yieldTokenEVMAddress" ] as ? &EVM.EVMAddress {
591+ return EVM .addressFromString (" 0x\( addrRef .toString ()) " )
592+ }
593+ }
594+ }
595+ }
596+ return nil
597+ }
598+
599+ /// Shared NAV balance computation: reads Cadence-side share balance from AutoBalancer,
600+ /// converts to underlying asset value via ERC-4626 convertToAssets
601+ access (contract ) fun _navBalanceFor (strategyType : Type , collateralType : Type , ofToken : Type , id : UInt64 ): UFix64 {
602+ if ofToken ! = collateralType { return 0.0 }
603+
604+ let ab = FlowYieldVaultsAutoBalancers .borrowAutoBalancer (id : id )
605+ if ab == nil { return 0.0 }
606+ let sharesBalance = ab ! .vaultBalance ()
607+ if sharesBalance == 0.0 { return 0.0 }
608+
609+ let vaultAddr = self ._getYieldTokenEVMAddress (forStrategy : strategyType , collateralType : collateralType )
610+ ?? panic (" No EVM vault address configured for \( strategyType .identifier ) " )
611+
612+ let sharesWei = FlowEVMBridgeUtils .ufix64ToUInt256 (
613+ value : sharesBalance ,
614+ decimals : FlowEVMBridgeUtils .getTokenDecimals (evmContractAddress : vaultAddr )
615+ )
616+
617+ let navWei = ERC4626Utils .convertToAssets (vault : vaultAddr , shares : sharesWei )
618+ ?? panic (" convertToAssets failed for vault " .concat (vaultAddr .toString ()))
619+
620+ let assetAddr = ERC4626Utils .underlyingAssetEVMAddress (vault : vaultAddr )
621+ ?? panic (" No underlying asset EVM address found for vault \( vaultAddr .toString ()) " )
622+
623+ return EVMAmountUtils .toCadenceOutForToken (navWei , erc20Address : assetAddr )
624+ }
625+
552626 /// Returns the COA capability for this account
553627 /// TODO: this is temporary until we have a better way to pass user's COAs to inner connectors
554628 access (self )
0 commit comments