Omniscia Evergon Labs Audit

PostPurchaseStakeFacetStorage Manual Review Findings

PostPurchaseStakeFacetStorage Manual Review Findings

PPF-01M: Inexistent Handling of Downward Rounded Fractions

TypeSeverityLocation
Mathematical OperationsPostPurchaseStakeFacetStorage.sol:
I-1: L90
I-2: L97

Description:

The PostPurchaseStakeFacetStorage::handlePostPurchasePhase function will not handle any division truncation that may occur when calculating the number of input packets for the staking campaign in the Evergon Labs staking system.

Impact:

Any rounded-down fractions will be locked in the FractionalisationDiamond as they are not transferred outward.

Example:

packages/contracts/contracts/internalFacets/purchasePhaseFacets/postPurchaseFacets/stakeFractions/PostPurchaseStakeFacetStorage.sol
71function handlePostPurchasePhase(
72 Layout storage l,
73 uint256 campaignId,
74 uint256 amountOfFractions,
75 address msg_sender,
76 bytes calldata data
77) internal {
78 uint256 nftId = abi.decode(data, (uint256)); // Staking Position NFT ID:: If 0 then is stake, if not then is restake
79
80 CampaignInfo storage campaignInfoLocal = l.campaignInfo[campaignId];
81
82 IERC1155(GeneralStorage.layout().infoForId[campaignId].fractionsContract).setApprovalForAll(
83 campaignInfoLocal.stakingContract,
84 true
85 );
86
87 if (nftId == 0) {
88 IStakingSkeleton(campaignInfoLocal.stakingContract).stakeBeneficiary(
89 campaignInfoLocal.stakingCampaignId,
90 amountOfFractions / campaignInfoLocal.amountOfFractionsPerInputPacket, // number of input packets
91 0, // timeLock period is 0 for now
92 msg_sender
93 );
94 } else {
95 IStakingSkeleton(campaignInfoLocal.stakingContract).restakeBeneficiary(
96 nftId,
97 amountOfFractions / campaignInfoLocal.amountOfFractionsPerInputPacket, // number of input packets
98 0, // timeLock period is 0 for now
99 msg_sender
100 );
101 }
102}

Recommendation:

We advise any remainder to be transferred to the user using a similar approach to the ReturnFungAndSemiFungFractionsFacet and ReturnFungAndSemiFungFractionsOmnichainFacet functions, ensuring that fraction units post-purchase are not lost.

Alleviation (71cda4ccfdcfa25fb96a4565f1f8143b350dd246):

The code was updated to mandate that the amountOfFractions defined is wholly divisible by the amountOfFractionsPerInputPacket, preventing the truncation scenario defined from manifesting.