Implementing a percentage-based fee for NFT sales in a marketplace

Hey everyone, I’m stuck on a problem with my NFT marketplace project. I’ve got the basic stuff working like listing, buying, and selling. But now I’m trying to add a 2.5% fee on every sale instead of the fixed 0.1 ether fee I used to have.

Here’s what I’ve done so far:

function processSale(address nftAddr, uint256 itemNum, uint256 feeAmount) public payable {
    uint256 cost = itemToSaleInfo[itemNum].cost;
    uint256 nftId = itemToSaleInfo[itemNum].nftId;
    require(msg.value == cost, 'Please pay the full amount');
    itemToSaleInfo[itemNum].seller.transfer(msg.value);
    IERC721(nftAddr).transferFrom(address(this), msg.sender, nftId);
    itemToSaleInfo[itemNum].newOwner = payable(msg.sender);
    itemToSaleInfo[itemNum].isSold = true;
    soldItems.increment();
    payable(owner).transfer(feeAmount);
}

And in my frontend:

async function purchaseNFT() {
    const modal = new Web3Modal();
    const conn = await modal.connect();
    const ethProvider = new ethers.providers.Web3Provider(conn);
    const signedContract = new ethers.Contract(marketplaceAddress, MarketABI.abi, ethProvider.getSigner());
    const nftPrice = ethers.utils.parseUnits(nft.price.toString(), 'ether');
    const feePercent = +((2.5 / 100) * nft.price);
    const feeAmount = feePercent.toString();
    const tx = await signedContract.processSale(nftAddress, nft.itemNum, feeAmount, {value: nftPrice});
    await tx.wait();
    window.location.replace('/profile');
}

However, I keep getting an error saying ‘Transaction reverted: function call failed to execute’ when trying to transfer the fee. Any suggestions on what might be going wrong? Thanks!

yo leapingfox, i think i see the issue. ur calculating the fee in eth on the frontend, but the contract expects it in wei. try converting feeAmount to wei before passing it:

const feeAmountWei = ethers.utils.parseUnits(feeAmount, 'ether');

also, make sure ur contract has enough balance to cover the fee transfer. gl with ur project bro!

I’ve encountered a similar issue in my own NFT marketplace project. The problem likely stems from how you’re handling the fee calculation and transfer. Instead of calculating the fee on the frontend and passing it as an argument, you should perform this calculation within the smart contract itself.

Try modifying your ‘processSale’ function like this:

function processSale(address nftAddr, uint256 itemNum) public payable {
    uint256 cost = itemToSaleInfo[itemNum].cost;
    uint256 nftId = itemToSaleInfo[itemNum].nftId;
    require(msg.value == cost, 'Please pay the full amount');
    
    uint256 feeAmount = (cost * 25) / 1000; // 2.5% fee
    uint256 sellerAmount = cost - feeAmount;
    
    itemToSaleInfo[itemNum].seller.transfer(sellerAmount);
    payable(owner).transfer(feeAmount);
    
    IERC721(nftAddr).transferFrom(address(this), msg.sender, nftId);
    itemToSaleInfo[itemNum].newOwner = payable(msg.sender);
    itemToSaleInfo[itemNum].isSold = true;
    soldItems.increment();
}

This approach ensures the fee calculation is consistent and removes the need to pass the fee as an argument. Remember to update your frontend code accordingly. Hope this helps!

hey there leapingfox! i’ve been playin around with nft marketplaces too and ran into some similar headaches :sweat_smile: have you considered using SafeMath for your calculations? it can help prevent those pesky overflow errors that sometimes pop up with fee calculations.

also, im kinda curious - are you planning to implement any dynamic fee structures in the future? like maybe lower fees for high-volume sellers or special promotions? that could be a cool feature to set your marketplace apart!

oh, and one more thing - have you thought about how gas fees might impact the overall cost for buyers? might be worth factoring that in somehow to make sure the total cost isn’t a surprise for users.

keep us posted on how it goes! I’d love to hear more about your project as it develops :blush: