Omniscia Evergon Labs Audit

PurchaseSkeleton Manual Review Findings

PurchaseSkeleton Manual Review Findings

PSN-01M: Incompatible Integration of Fractionalized EIP-1155 ODC Implementation

Description:

The PurchaseSkeleton::purchase function integrates with the Evergon Labs ODC fractionalized EIP-1155 implementation to permit a mint-on-purchase approach.

This approach is inherently insecure as the first purchaser of a campaign will be able to directly interact with the FractionERC1155DataManager::fullyUnlockWrappedAssets to acquire the underlying assets, effectively stealing all wrapped funds of a campaign for the price of a single fraction.

Impact:

It is possible to fully unwrap the underlying assets of a fractionalized EIP-1155 implementation by directly interacting with the FractionERC1155DataManager, effectively acquiring all wrapped funds for the price of a single fraction.

Example:

packages/contracts/contracts/skeletonFacets/PurchaseSkeleton.sol
38function purchase(
39 uint256 campaignId,
40 uint256 amountOfFractions,
41 bytes calldata discountOperationData,
42 bytes calldata postPurchaseData,
43 uint32 chainId
44) external payable onlyExternalDelegateCall {
45 IPurchaseStateFacet(address(this)).checkPurchaseState(campaignId);
46 IPurchaseTimeFacet(address(this)).checkPurchaseTimes(campaignId);
47
48 address account = ERC2771RecipientStorage.layout()._msgSender();
49 IPurchaseEligibilityFacet(address(this)).checkPurchaserEligibility(campaignId, account, amountOfFractions);
50 IPurchaseAmountFacet(address(this)).checkPurchaseAmounts(campaignId, amountOfFractions, account);
51 uint256 discountPercentage = IPurchaseDiscountFacet(address(this)).getDiscount(
52 campaignId,
53 amountOfFractions,
54 account,
55 discountOperationData
56 );
57 IDoPurchaseFacet(address(this)).doPurchase(campaignId, account, amountOfFractions, discountPercentage);
58 if (GeneralStorage.layout().infoForId[campaignId].isMinting) {
59 // Mint to the diamond and then transfers etc will be handled by postPurchase
60 // Always mint id 0 if semi fungible. All other ids are used only for vesting in current version.
61 ISemiFungibleAndFungibleFractionTransferFacet(address(this)).mintFractions(campaignId, address(this), 0, amountOfFractions);
62 }
63 IPostPurchaseFacet(address(this)).handlePostPurchasePhase{value: msg.value}(
64 campaignId,
65 amountOfFractions,
66 chainId,
67 account,
68 postPurchaseData
69 );
70
71 emit FractionsPurchased(campaignId, account, amountOfFractions);
72}

Recommendation:

We advise the system's integration to be revised, potentially by updating either the FractionERC1155DataManager itself in the ODC repository or removing support for mint-on-purchase configurations.

Alleviation (71cda4ccfdcfa25fb96a4565f1f8143b350dd246):

The Evergon Labs team evaluated this exhibit and proceeded to update the ODC implementations to permit the deployment of an EIP-1155 fraction to define whether user unlocks are enabled.

This mechanism permits user unlocks to be disabled and thus the system to be compatible with a mint-on-purchase approach as the callback will not be able to extract funds at will.