getGetAmplificationParameter() precision is not used, which result in accounting issue in MetaStable2TokenAuraHelper.sol and in Boosted3TokenAuraHelper.sol
getGetAmplificationParameter() precision is not used, which result in accounting issue in MetaStable2TokenAuraHelper.sol and in Boosted3TokenAuraHelper.sol\\nThis report has two part,\\npart one trace the accounting issue in MetaStable2TokenAuraHelper.sol,\\npart two trace the accounting issue in Boosted3TokenAuraHelper.sol,\\nboth issue rooted in not handling the getGetAmplificationParameter() precision\\nAccording to the Balancer documentation\\npool.getGetAmplificationParameter()\\nreturns something resembling\\nvalue : 620000 isUpdating : False precision : 1000\\nwhere the amplification parameter is 620000 / 1000 = 620\\nbut in the code, the isUpdating and precision returned is ignored and not used.\\nPart One\\nLet's trace the function reinvestReward in MetaStable2TokenAuraHelper.sol\\n```\\n    function reinvestReward(\\n        MetaStable2TokenAuraStrategyContext calldata context,\\n        ReinvestRewardParams calldata params\\n    )\\n```\\n\\nIt calls\\n```\\n// Make sure we are joining with the right proportion to minimize slippage\\n        oracleContext._validateSpotPriceAndPairPrice({\\n            poolContext: poolContext,\\n            strategyContext: strategyContext,\\n            primaryAmount: primaryAmount,\\n            secondaryAmount: secondaryAmount\\n        });\\n```\\n\\nthen it calls\\n```\\nuint256 spotPrice = _getSpotPrice(oracleContext, poolContext, 0);\\n```\\n\\nthen it calls\\nInsite the function\\n```\\n        (uint256 balanceX, uint256 balanceY) = tokenIndex == 0 ?\\n            (poolContext.primaryBalance, poolContext.secondaryBalance) :\\n            (poolContext.secondaryBalance, poolContext.primaryBalance);\\n\\n        uint256 invariant = StableMath._calculateInvariant(\\n            oracleContext.ampParam, StableMath._balances(balanceX, balanceY), true // round up\\n        );\\n\\n        spotPrice = StableMath._calcSpotPrice({\\n            amplificationParameter: oracleContext.ampParam,\\n            invariant: invariant,\\n            balanceX: balanceX,\\n            balanceY: balanceY\\n        });\\n```\\n\\nWhat's wrong with this, I believe the precision has issue for ampParam\\nBecause When we get the oracleContext.ampParam from MetaStable2TokenVaultMixin.sol\\nWe did not use the precision returned from the pool\\n```\\n      (\\n            uint256 value,\\n            /* bool isUpdating */,\\n            /* uint256 precision */\\n        ) = IMetaStablePool(address(BALANCER_POOL_TOKEN)).getAmplificationParameter();\\n```\\n\\nAccording to the Balancer documentation\\npool.getGetAmplificationParameter()\\nreturns something resembling\\nvalue : 620000 isUpdating : False precision : 1000\\nwhere the amplification parameter is 620000 / 1000 = 620\\nThe formula that calculate the spot price is\\n```\\n   /**************************************************************************************************************\\n    //                                                                                                           //\\n    //                             2.a.x.y + a.y^2 + b.y                                                         //\\n    // spot price Y/X = - dx/dy = -----------------------                                                        //\\n    //                             2.a.x.y + a.x^2 + b.x                                                         //\\n    //                                                                                                           //\\n    // n = 2                                                                                                     //\\n    // a = amp param * n                                                                                         //\\n    // b = D + a.(S - D)                                                                                         //\\n    // D = invariant                                                                                             //\\n    // S = sum of balances but x,y = 0 since x  and y are the only tokens                                        //\\n    **************************************************************************************************************/\\n```\\n\\nthe function _calcSpotPrice hardcode the amp precision to 1e3;\\n```\\n   uint256 internal constant _AMP_PRECISION = 1e3;\\n```\\n\\nand implement\\n```\\nuint256 a = (amplificationParameter * 2) / _AMP_PRECISION;\\n```\\n\\nif the pool's ampParameter is not equal to _AMP_PRECISION, the math will break.\\nPart Two\\nLet's trace the call in Boosted3TokenPoolUtils.sol\\nFirst the function reinvestReward in Boosted3TokenAuraHelper.sol is called\\n```\\n    function reinvestReward(\\n        Boosted3TokenAuraStrategyContext calldata context,\\n        ReinvestRewardParams calldata params\\n    ) \\n```\\n\\nThen we call\\n```\\n   uint256 minBPT = context.poolContext._getMinBPT(\\n      oracleContext, strategyContext, primaryAmount\\n   );\\n```\\n\\nthen we call\\n```\\n minBPT = StableMath._calcBptOutGivenExactTokensIn({\\n  amp: oracleContext.ampParam,\\n  balances: balances,\\n  amountsIn: amountsIn,\\n  bptTotalSupply: virtualSupply,\\n  swapFeePercentage: 0,\\n  currentInvariant: invariant\\n });\\n```\\n\\nthen we call\\n```\\n // Get current and new invariants, taking swap fees into account\\n uint256 newInvariant = _calculateInvariant(amp, newBalances, false);\\n uint256 invariantRatio = newInvariant.divDown(currentInvariant);\\n```\\n\\nthen we call\\n```\\n  uint256 ampTimesTotal = amplificationParameter * numTokens;\\n```\\n\\nwe just use the amplificationParameter without handling the precision.\\nThe amplificationParameter comes from BoostedTokenPoolMixin.sol\\n```\\n (\\n  uint256 value,\\n  /* bool isUpdating */,\\n  /* uint256 precision */\\n ) = pool.getAmplificationParameter();\\n```\\n\\nthe isUpdating and precision is not used,\\nhowever, according to the documentation\\nAccording to the Balancer documentation\\npool.getGetAmplificationParameter()\\nreturns something resembling\\nvalue : 620000 isUpdating : False precision : 1000\\nwhere the amplification parameter is 620000 / 1000 = 620
Issue getGetAmplificationParameter() precision is not used, which result in accounting issue in MetaStable2TokenAuraHelper.sol and in Boosted3TokenAuraHelper.sol\\nWe recommend the project use the precision returned from getGetAmplificationParameter()\\n```\\n      (\\n            uint256 value,\\n            bool isUpdating */,\\n            uint256 precision */\\n        ) = IMetaStablePool(address(BALANCER_POOL_TOKEN)).getAmplificationParameter();\\n        return value / precision;\\n```\\n
The amplificationParameter has precision, ignoring the precision will result in accounting issue.\\nIf the precision of the amplificationParameter is not equal to hardcoded 1e3, the spot price is invalid.\\nthe code\\n```\\n   uint256 ampTimesTotal = amplificationParameter * numTokens;\\n```\\n\\nwill be overvalued because we did not divide the value by the precision.
```\\n    function reinvestReward(\\n        MetaStable2TokenAuraStrategyContext calldata context,\\n        ReinvestRewardParams calldata params\\n    )\\n```\\n