@@ -225,20 +225,41 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
225225 function getPrices ()
226226 public
227227 view
228- returns (uint256 oraclePrice , uint256 reservePrice , uint256 _decimals0 , uint256 _decimals1 )
228+ returns (
229+ uint256 oraclePriceNumerator ,
230+ uint256 oraclePriceDenominator ,
231+ uint256 reservePriceNumerator ,
232+ uint256 reservePriceDenominator ,
233+ uint256 priceDifference ,
234+ bool reservePriceAboveOraclePrice
235+ )
229236 {
230237 FPMMStorage storage $ = _getFPMMStorage ();
231238
232239 require ($.referenceRateFeedID != address (0 ), "FPMM: REFERENCE_RATE_NOT_SET " );
233240 require ($.reserve0 > 0 && $.reserve1 > 0 , "FPMM: RESERVES_EMPTY " );
234241
235- _decimals0 = $.decimals0;
236- _decimals1 = $.decimals1;
237-
238- (uint256 rateNumerator , uint256 rateDenominator ) = _getRateFeed ();
239-
240- oraclePrice = (rateNumerator * 1e18 ) / (rateDenominator);
241- reservePrice = ($.reserve1 * _decimals0 * 1e18 ) / ($.reserve0 * _decimals1);
242+ (oraclePriceNumerator, oraclePriceDenominator) = _getRateFeed ();
243+
244+ reservePriceNumerator = $.reserve1 * (1e18 / $.decimals1);
245+ reservePriceDenominator = $.reserve0 * (1e18 / $.decimals0);
246+
247+ uint256 oracleCrossProduct = oraclePriceNumerator * reservePriceDenominator;
248+ uint256 reserveCrossProduct = reservePriceNumerator * oraclePriceDenominator;
249+ reservePriceAboveOraclePrice = reserveCrossProduct > oracleCrossProduct;
250+
251+ uint256 absolutePriceDiff = reservePriceAboveOraclePrice
252+ ? reserveCrossProduct - oracleCrossProduct
253+ : oracleCrossProduct - reserveCrossProduct;
254+ priceDifference = (absolutePriceDiff * BASIS_POINTS_DENOMINATOR) / oracleCrossProduct;
255+ return (
256+ oraclePriceNumerator,
257+ oraclePriceDenominator,
258+ reservePriceNumerator,
259+ reservePriceDenominator,
260+ priceDifference,
261+ reservePriceAboveOraclePrice
262+ );
242263 }
243264
244265 /// @inheritdoc IFPMM
@@ -366,7 +387,7 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
366387 swapData.amount1Out = amount1Out;
367388
368389 (swapData.rateNumerator, swapData.rateDenominator) = _getRateFeed ();
369- swapData.initialReserveValue = _totalValueInToken1 (
390+ swapData.initialReserveValue = _totalValueInToken1Scaled (
370391 $.reserve0,
371392 $.reserve1,
372393 swapData.rateNumerator,
@@ -417,14 +438,21 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
417438 swapData.amount0Out = amount0Out;
418439 swapData.amount1Out = amount1Out;
419440
420- (swapData.rateNumerator, swapData.rateDenominator) = _getRateFeed ();
421- swapData.initialReserveValue = _totalValueInToken1 (
441+ (
442+ swapData.rateNumerator,
443+ swapData.rateDenominator,
444+ ,
445+ ,
446+ swapData.initialPriceDifference,
447+ swapData.reservePriceAboveOraclePrice
448+ ) = getPrices ();
449+
450+ swapData.initialReserveValue = _totalValueInToken1Scaled (
422451 $.reserve0,
423452 $.reserve1,
424453 swapData.rateNumerator,
425454 swapData.rateDenominator
426455 );
427- (swapData.initialPriceDifference, swapData.reservePriceAboveOraclePrice) = _calculatePriceDifference ();
428456
429457 uint256 threshold = swapData.reservePriceAboveOraclePrice ? $.rebalanceThresholdAbove : $.rebalanceThresholdBelow;
430458 require (swapData.initialPriceDifference >= threshold, "FPMM: PRICE_DIFFERENCE_TOO_SMALL " );
@@ -446,6 +474,9 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
446474 "FPMM: REBALANCE_DIRECTION_INVALID "
447475 );
448476
477+ swapData.amount0In = amount0In;
478+ swapData.amount1In = amount1In;
479+
449480 _update ();
450481
451482 uint256 newPriceDifference = _rebalanceCheck (swapData);
@@ -565,44 +596,31 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
565596 }
566597
567598 /**
568- * @notice Calculates total value of a given amount of tokens in terms of token1
599+ * @notice Calculates total value of a given amount of tokens in terms of token1 scaled to 18 decimals
569600 * @param amount0 Amount of token0
570601 * @param amount1 Amount of token1
571602 * @param rateNumerator Oracle rate numerator
572603 * @param rateDenominator Oracle rate denominator
573604 * @return Total value in token1
574605 */
575- function _totalValueInToken1 (
606+ function _totalValueInToken1Scaled (
576607 uint256 amount0 ,
577608 uint256 amount1 ,
578609 uint256 rateNumerator ,
579610 uint256 rateDenominator
580611 ) private view returns (uint256 ) {
581612 FPMMStorage storage $ = _getFPMMStorage ();
582613
583- uint256 token0ValueInToken1 = convertWithRate (amount0, $.decimals0, $.decimals1, rateNumerator, rateDenominator);
614+ uint256 token0ValueInToken1 = convertWithRate (amount0, $.decimals0, 1e18 , rateNumerator, rateDenominator);
615+ amount1 = amount1 * (1e18 / $.decimals1);
584616 return token0ValueInToken1 + amount1;
585617 }
586618
587- /**
588- * @notice Calculates price difference between oracle and reserves in basis points
589- * @return priceDifference Price difference in basis points
590- */
591- function _calculatePriceDifference ()
592- private
593- view
594- returns (uint256 priceDifference , bool reservePriceAboveOraclePrice )
595- {
596- (uint256 oraclePrice , uint256 reservePrice , , ) = getPrices ();
597-
598- reservePriceAboveOraclePrice = reservePrice > oraclePrice;
599- uint256 absolutePriceDiff = reservePriceAboveOraclePrice ? reservePrice - oraclePrice : oraclePrice - reservePrice;
600- priceDifference = (absolutePriceDiff * BASIS_POINTS_DENOMINATOR) / oraclePrice;
601- }
602-
603619 function _getRateFeed () private view returns (uint256 rateNumerator , uint256 rateDenominator ) {
604620 FPMMStorage storage $ = _getFPMMStorage ();
605621 (rateNumerator, rateDenominator) = $.sortedOracles.medianRate ($.referenceRateFeedID);
622+ rateNumerator = rateNumerator / 1e6 ;
623+ rateDenominator = rateDenominator / 1e6 ;
606624 if ($.revertRateFeed) {
607625 (rateNumerator, rateDenominator) = (rateDenominator, rateNumerator);
608626 }
@@ -619,7 +637,7 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
619637 FPMMStorage storage $ = _getFPMMStorage ();
620638
621639 bool reservePriceAboveOraclePrice;
622- (newPriceDifference, reservePriceAboveOraclePrice) = _calculatePriceDifference ();
640+ (, , , , newPriceDifference, reservePriceAboveOraclePrice) = getPrices ();
623641
624642 // Ensure price difference is smaller than before
625643 require (newPriceDifference < swapData.initialPriceDifference, "FPMM: PRICE_DIFFERENCE_NOT_IMPROVED " );
@@ -629,32 +647,29 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
629647 "FPMM: PRICE_DIFFERENCE_MOVED_IN_WRONG_DIRECTION "
630648 );
631649
632- // Check for excessive value loss
633- uint256 newReserveValue = _totalValueInToken1 (
634- $.reserve0,
635- $.reserve1,
636- swapData.rateNumerator,
637- swapData.rateDenominator
638- );
650+ if (swapData.amount0In > 0 ) {
651+ uint256 expectedAmount0In = convertWithRate (
652+ swapData.amount1Out,
653+ $.decimals1,
654+ 1e18 ,
655+ swapData.rateDenominator,
656+ swapData.rateNumerator
657+ );
658+ uint256 minAmount0In = expectedAmount0In - (expectedAmount0In * $.rebalanceIncentive) / BASIS_POINTS_DENOMINATOR;
639659
640- uint256 amountOutInToken1 ;
641- if (swapData.amount0Out > 0 ) {
642- amountOutInToken1 = convertWithRate (
660+ require (swapData.amount0In >= minAmount0In, " FPMM: INSUFFICIENT_AMOUNT_0_IN " ) ;
661+ } else {
662+ uint256 expectedAmount1In = convertWithRate (
643663 swapData.amount0Out,
644664 $.decimals0,
645- $.decimals1 ,
665+ 1e18 ,
646666 swapData.rateNumerator,
647667 swapData.rateDenominator
648668 );
649- } else {
650- amountOutInToken1 = swapData.amount1Out;
669+ expectedAmount1In = expectedAmount1In / (1e18 / $.decimals1);
670+ uint256 minAmount1In = expectedAmount1In - (expectedAmount1In * $.rebalanceIncentive) / BASIS_POINTS_DENOMINATOR;
671+ require (swapData.amount1In >= minAmount1In, "FPMM: INSUFFICIENT_AMOUNT_1_IN " );
651672 }
652-
653- uint256 maxRebalanceIncentiveInToken1 = (amountOutInToken1 * $.rebalanceIncentive) / BASIS_POINTS_DENOMINATOR;
654- require (
655- newReserveValue >= swapData.initialReserveValue - maxRebalanceIncentiveInToken1,
656- "FPMM: EXCESSIVE_VALUE_LOSS "
657- );
658673 }
659674
660675 /**
@@ -664,13 +679,14 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
664679 function _swapCheck (SwapData memory swapData ) private view {
665680 FPMMStorage storage $ = _getFPMMStorage ();
666681
667- uint256 newReserveValue = _totalValueInToken1 (
682+ uint256 newReserveValue = _totalValueInToken1Scaled (
668683 $.reserve0,
669684 $.reserve1,
670685 swapData.rateNumerator,
671686 swapData.rateDenominator
672687 );
673688
689+ // TODO: think about rounding here
674690 uint256 expectedAmount0In = convertWithRate (
675691 swapData.amount1Out,
676692 $.decimals1,
@@ -679,6 +695,7 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
679695 swapData.rateNumerator
680696 );
681697
698+ // TODO: think about rounding here
682699 uint256 expectedAmount1In = convertWithRate (
683700 swapData.amount0Out,
684701 $.decimals0,
@@ -702,6 +719,8 @@ contract FPMM is IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpg
702719 swapData.rateDenominator
703720 );
704721 uint256 totalFeeInToken1 = fee0InToken1 + fee1;
722+ // convert to 18 decimals
723+ totalFeeInToken1 = totalFeeInToken1 * (1e18 / $.decimals1);
705724
706725 // Check the reserve value is not decreased
707726 uint256 expectedReserveValue = swapData.initialReserveValue + totalFeeInToken1;
0 commit comments