sherlock-audit / 2024-04-titles-judging

6 stars 6 forks source link

Varun_05 - collectionReferrerShare is not given to the right referrer when tokenId is minted. #290

Closed sherlock-admin3 closed 2 months ago

sherlock-admin3 commented 3 months ago

Varun_05

high

collectionReferrerShare is not given to the right referrer when tokenId is minted.

Summary

collectionReferrerShare is given to wrong referrer which denies the correct referrer from receiving correct fees.

Vulnerability Detail

When tokenId is minted for a particular work from the edition contract then collectFee function is called in the fee manager contract.Collect fee function is executed before minting the tokens to the right user. Collect fees function is as follows

function _collectMintFee(
        IEdition edition_,
        uint256 tokenId_,
        uint256 amount_,
        address payer_,
        address referrer_,
        Fee memory fee_
    ) internal {
        if (fee_.amount == 0) return;

        // For free mints:
        // - Protocol Share = 1/3 of flat fee
        // - Edition Share = 2/3 of flat fee
        //
        // For priced mints:
        // - Protocol Share = 100% of flat fee, shared as follows:
        // - Edition Share = 100% of creator-specified mint cost, 0% of flat fee
        //
        // In both cases, the protocol and edition shares may be split as follows:
        // - Protocol Share
        //   - If a referred mint, mint referrer gets 50% of the protocol share
        //   - If a referred collection, collection referrer gets 25% of the protcol share
        //   - Protocol fee receiver gets the remainder of the protocol share
        // - Edition Share
        //   - Attributions equally split 25% of the edition share, if applicable
        //   - Creator gets the remainder of the edition share

        uint256 protocolFee = protocolFlatFee * amount_;
        uint256 protocolShare;
        if (fee_.amount == protocolFee) {
            protocolShare = protocolFee * protocolFeeshareBps / MAX_BPS;
        } else {
            protocolShare = protocolFee;
        }

        _route(
            Fee({asset: fee_.asset, amount: fee_.amount - protocolShare}),
            _feeReceivers[getRouteId(edition_, tokenId_)],
            payer_
        );

        uint256 referrerShare =
            _splitProtocolFee(edition_, fee_.asset, protocolShare, payer_, referrer_);
        emit FeeCollected(address(edition_), tokenId_, fee_.asset, fee_.amount, referrerShare);
    }

    function _splitProtocolFee(
        IEdition edition_,
        address asset_,
        uint256 amount_,
        address payer_,
        address referrer_
    ) internal returns (uint256 referrerShare) {
        // The creation and mint referrers earn 25% and 50% of the protocol's share respectively, if applicable
        uint256 mintReferrerShare = getMintReferrerShare(amount_, referrer_);
        uint256 collectionReferrerShare = getCollectionReferrerShare(amount_, referrers[edition_]);
        referrerShare = mintReferrerShare + collectionReferrerShare;

        _route(
            Fee({asset: asset_, amount: amount_ - referrerShare}),
            Target({target: protocolFeeReceiver, chainId: block.chainid}),
            payer_
        );

        _route(
            Fee({asset: asset_, amount: mintReferrerShare}),
            Target({target: referrer_, chainId: block.chainid}),
            payer_
        );

        _route(
            Fee({asset: asset_, amount: collectionReferrerShare}),
            Target({target: referrer_, chainId: block.chainid}),
            payer_
        );
    }

Issue lies in the _splitProtocolFee function and particularly in the following line

_route(
            Fee({asset: asset_, amount: collectionReferrerShare}),
            Target({target: referrer_, chainId: block.chainid}),
            payer_
        );

Above can be seen that the collectionReferrerShare is given to the wrong referrer because collectionReferrerShare belong to the referrers[edition_] as can be seen from the following line

uint256 collectionReferrerShare = getCollectionReferrerShare(amount_, referrers[edition_]);

Impact

Loss of funds for the collectionReferrer

Code Snippet

https://github.com/sherlock-audit/2024-04-titles/blob/d7f60952df22da00b772db5d3a8272a988546089/wallflower-contract-v2/src/fees/FeeManager.sol#L438

Tool used

Manual Review

Recommendation

make the following change

---_route(
            Fee({asset: asset_, amount: collectionReferrerShare}),
            Target({target: referrer_, chainId: block.chainid}),
            payer_
        );
+++ _route(
            Fee({asset: asset_, amount: collectionReferrerShare}),
            Target({target: referrers[edition_], chainId: block.chainid}),
            payer_
        );

Duplicate of #267