Omniscia Evergon Labs Audit
FixedInterestBuybackAmountFacetStorage Manual Review Findings
FixedInterestBuybackAmountFacetStorage Manual Review Findings
FIA-01M: Inexistent Accommodation of Obligation Per Fraction Rounding
| Type | Severity | Location |
|---|---|---|
| Logical Fault | ![]() | FixedInterestBuybackAmountFacetStorage.sol:L97-L98, L109 |
Description:
The fixed interest buyback mechanism supported by the FixedInterestBuybackAmountFacetStorage contract will presently forfeit interest as it does not accommodate for the downward-rounding operation performed in the FixedInterestBuybackAmountFacetStorage::_getObligationAndBuybackAmount function.
Impact:
A campaign with many fractions purchased will lose a significant amount of interest per fraction due to a downward rounding operation on the obligation evaluation of each fraction.
Example:
92function _calculateBuyBackAmount(Layout storage l, uint256 campaignId) internal view returns (uint256) {93 FungibleAndSemiFungiblePurchaseStorage.IdInfo memory infoForId = FungibleAndSemiFungiblePurchaseStorage.layout().infoForId[94 campaignId95 ];96
97 uint256 fundedAmount = infoForId.totalFractionsPurchased * infoForId.pricePerFraction;98 uint256 requiredBuybackAmount = fundedAmount + ((fundedAmount * l.interestPercentageForId[campaignId]) / _ONE_MILLION);99
100 return requiredBuybackAmount;101}102
103function _getObligationAndBuybackAmount(Layout storage l, uint256 campaignId) internal view returns (uint256, uint256) {104 FungibleAndSemiFungiblePurchaseStorage.IdInfo memory infoForId = FungibleAndSemiFungiblePurchaseStorage.layout().infoForId[105 campaignId106 ];107 uint256 requiredBuybackAmount = _calculateBuyBackAmount(l, campaignId);108
109 return (requiredBuybackAmount, requiredBuybackAmount / infoForId.totalFractionsPurchased);110}Recommendation:
We advise the FixedInterestBuybackAmountFacetStorage::_calculateBuyBackAmount function to be updated so as to calculate a wholly-divisible interest increment by rounding the requiredBuybackAmount upwards, ensuring that each fraction can properly capture interest that would be ultimately repaid on the campaign.
To achieve this, the interestPercentageForId would have to be applied to the pricePerFraction itself rounding upwards which would guarantee that the required buyback amount ultimately calculated can be evenly distributed across the fractions purchased for the campaignId.
Alleviation (71cda4ccfd):
While the interestPercentageForId is now applied to the pricePerFraction, the mechanism via which it is applied will result in a downward-rounding operation rather than upward-rounding operation thus partially alleviating the exhibit outlined.
Alleviation (d7b20c134f):
The code was updated to ensure that an upward rounding operation is performed instead per our original recommendation, alleviating this exhibit in full.
