Incorrect StablePool BPT price calculation
Incorrect StablePool BPT price calculation as rate's are not considered\\nThe price of a stable pool BPT is computed as:\\nminimum price among the pool tokens obtained via feeds * return value of `getRate()`\\nThis method is used referring to an old documentation of Balancer\\n```\\n    function getStablePoolTokenPrice(\\n        address,\\n        uint8 outputDecimals_,\\n        bytes calldata params_\\n    ) external view returns (uint256) {\\n        // Prevent overflow\\n        if (outputDecimals_ > BASE_10_MAX_EXPONENT)\\n            revert Balancer_OutputDecimalsOutOfBounds(outputDecimals_, BASE_10_MAX_EXPONENT);\\n\\n\\n        address[] memory tokens;\\n        uint256 poolRate; // pool decimals\\n        uint8 poolDecimals;\\n        bytes32 poolId;\\n        {\\n\\n        // rest of code// rest of code\\n\\n            // Get tokens in the pool from vault\\n            (address[] memory tokens_, , ) = balVault.getPoolTokens(poolId);\\n            tokens = tokens_;\\n\\n            // Get rate\\n            try pool.getRate() returns (uint256 rate_) {\\n                if (rate_ == 0) {\\n                    revert Balancer_PoolStableRateInvalid(poolId, 0);\\n                }\\n\\n\\n                poolRate = rate_;\\n\\n        // rest of code// rest of code\\n\\n        uint256 minimumPrice; // outputDecimals_\\n        {\\n            /**\\n             * The Balancer docs do not currently state this, but a historical version noted\\n             * that getRate() should be multiplied by the minimum price of the tokens in the\\n             * pool in order to get a valuation. This is the same approach as used by Curve stable pools.\\n             */\\n            for (uint256 i; i < len; i++) {\\n                address token = tokens[i];\\n                if (token == address(0)) revert Balancer_PoolTokenInvalid(poolId, i, token);\\n\\n                (uint256 price_, ) = _PRICE().getPrice(token, PRICEv2.Variant.CURRENT); // outputDecimals_\\n\\n\\n                if (minimumPrice == 0) {\\n                    minimumPrice = price_;\\n                } else if (price_ < minimumPrice) {\\n                    minimumPrice = price_;\\n                }\\n            }\\n        }\\n\\n        uint256 poolValue = poolRate.mulDiv(minimumPrice, 10 ** poolDecimals); // outputDecimals_\\n```\\n\\nThe `getRate()` function returns the exchange `rate` of a BPT to the underlying base asset of the pool which can be different from the minimum market priced asset for pools with `rateProviders`. To consider this, the price obtained from feeds must be divided by the `rate` provided by `rateProviders` before choosing the minimum as mentioned in the previous version of Balancer's documentation.\\n1. Get market price for each constituent token\\nGet market price of wstETH and WETH in terms of USD, using chainlink oracles.\\n2. Get RateProvider price for each constituent token\\nSince wstETH - WETH pool is a MetaStablePool and not a ComposableStablePool, it does not have `getTokenRate()` function. Therefore, it`s needed to get the RateProvider price manually for wstETH, using the rate providers of the pool. The rate provider will return the wstETH token in terms of stETH.\\nNote that WETH does not have a rate provider for this pool. In that case, assume a value of `1e18` (it means, market price of WETH won't be divided by any value, and it's used purely in the minPrice formula).\\n3. Get minimum price\\n$$ minPrice = min({P_{M_{wstETH}} \\over P_{RP_{wstETH}}}, P_{M_{WETH}}) $$\\n4. Calculates the BPT price\\n$$ P_{BPT_{wstETH-WETH}} = minPrice * rate_{pool_{wstETH-WETH}} $$\\nwhere `rate_pool_wstETH-WETH` is `pool.getRate()` of wstETH-WETH pool.\\nExample\\nAt block 18821323: cbeth : 2317.48812 wstEth : 2526.84 pool total supply : 0.273259897168240633 getRate() : 1.022627523581711856 wstRateprovider rate : 1.150725009180224306 cbEthRateProvider rate : 1.058783029570983377 wstEth balance : 0.133842314907166538 cbeth balance : 0.119822100236557012 tvl : (0.133842314907166538 * 2526.84 + 0.119822100236557012 * 2317.48812) == 615.884408812\\naccording to current implementation: bpt price = 2317.48812 * 1.022627523581711856 == 2369.927137086 calculated tvl = bpt price * total supply = 647.606045776\\ncorrect calculation: rate_provided_adjusted_cbeth = (2317.48812 / 1.058783029570983377) == 2188.822502132 rate_provided_adjusted_wsteth = (2526.84 / 1.150725009180224306) == 2195.867804942 bpt price = 2188.822502132 * 1.022627523581711856 == 2238.350134915 calculated tvl = bpt price * total supply = (2238.350134915 * 0.273259897168240633) == 611.651327693
For pools having rate providers, divide prices by rate before choosing the minimum
Incorrect calculation of bpt price. Has possibility to be over and under valued.
```\\n    function getStablePoolTokenPrice(\\n        address,\\n        uint8 outputDecimals_,\\n        bytes calldata params_\\n    ) external view returns (uint256) {\\n        // Prevent overflow\\n        if (outputDecimals_ > BASE_10_MAX_EXPONENT)\\n            revert Balancer_OutputDecimalsOutOfBounds(outputDecimals_, BASE_10_MAX_EXPONENT);\\n\\n\\n        address[] memory tokens;\\n        uint256 poolRate; // pool decimals\\n        uint8 poolDecimals;\\n        bytes32 poolId;\\n        {\\n\\n        // rest of code// rest of code\\n\\n            // Get tokens in the pool from vault\\n            (address[] memory tokens_, , ) = balVault.getPoolTokens(poolId);\\n            tokens = tokens_;\\n\\n            // Get rate\\n            try pool.getRate() returns (uint256 rate_) {\\n                if (rate_ == 0) {\\n                    revert Balancer_PoolStableRateInvalid(poolId, 0);\\n                }\\n\\n\\n                poolRate = rate_;\\n\\n        // rest of code// rest of code\\n\\n        uint256 minimumPrice; // outputDecimals_\\n        {\\n            /**\\n             * The Balancer docs do not currently state this, but a historical version noted\\n             * that getRate() should be multiplied by the minimum price of the tokens in the\\n             * pool in order to get a valuation. This is the same approach as used by Curve stable pools.\\n             */\\n            for (uint256 i; i < len; i++) {\\n                address token = tokens[i];\\n                if (token == address(0)) revert Balancer_PoolTokenInvalid(poolId, i, token);\\n\\n                (uint256 price_, ) = _PRICE().getPrice(token, PRICEv2.Variant.CURRENT); // outputDecimals_\\n\\n\\n                if (minimumPrice == 0) {\\n                    minimumPrice = price_;\\n                } else if (price_ < minimumPrice) {\\n                    minimumPrice = price_;\\n                }\\n            }\\n        }\\n\\n        uint256 poolValue = poolRate.mulDiv(minimumPrice, 10 ** poolDecimals); // outputDecimals_\\n```\\n