The sellErc20 function lacks input validation for the price parameter, allowing users to create sell orders with zero price. This leads to fee calculation issues and enables free token acquisitions.
**Lines of code**
https://github.com/Cyfrin/2025-01-pieces-protocol/blob/4ef5e96fced27334f2a62e388a8a377f97a7f8cb/src/TokenDivider.sol#L221 
```solidity
//Vulnerable Code Section
function sellErc20(address nftPegged, uint256 price, uint256 amount) external {
    // ❌ No validation for price == 0
    
    if(nftPegged == address(0)) {
        revert TokenDivider__NftAddressIsZero();
    }
    
    if( amount == 0) {
        revert TokenDivider__AmountCantBeZero();
    }
    // ... rest of function
}
```
**In buyOrder function:**
https://github.com/Cyfrin/2025-01-pieces-protocol/blob/4ef5e96fced27334f2a62e388a8a377f97a7f8cb/src/TokenDivider.sol#L274
```solidity
uint256 fee = order.price / 100;  // ❌ Zero price leads to zero fees
```
## Vulnerability Details
Here's the sequence that demonstrates the problem:
**User lists tokens for sale with zero price:**
```solidity
divider.sellErc20(nftAddress, 0, amount);
```
**Buyer can purchase tokens for free:**
**Calculations in buyOrder:**
```solidity
fee = price/100 = 0/100 = 0
sellerFee = fee/2 = 0/2 = 0
//price + sellerFee = 0 + 0 = 0
if(msg.value <  order.price + sellerFee ) {
    revert TokenDivider__InsuficientEtherForFees();
}
```
## Coded POC
- create a file in the test folder in the project repo, paste this code and run the test.
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {Test, console} from "forge-std/Test.sol";
import {TokenDivider} from "../src/TokenDivider.sol";
import {ERC721Mock} from './mocks/ERC721Mock.sol';
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract TokenDividerTest is Test {
    TokenDivider public tokenDivider;
    ERC721Mock public mockNFT;
    address public owner;
    address public user1;
    address public user2;
    uint256 constant NFT_ID = 0; //first nft id will be 0
    uint256 constant INITIAL_AMOUNT = 1000;
    function setUp() public {
        owner = makeAddr("owner");
        user1 = makeAddr("user1");
        user2 = makeAddr("user2");
        
        vm.startPrank(owner);
        tokenDivider = new TokenDivider();
        mockNFT = new ERC721Mock();
        vm.stopPrank();
        vm.startPrank(owner);
        mockNFT.mint(user1); // minted tokenId 0 to user1
        vm.stopPrank();
    }
    function testZeroPriceExploit() public {
        // Step 1: User1 divides their NFT into fractions
        vm.startPrank(user1);
        mockNFT.approve(address(tokenDivider), 0);
        tokenDivider.divideNft(address(mockNFT), 0, INITIAL_AMOUNT);
        // Get the ERC20 token address
        TokenDivider.ERC20Info memory info = tokenDivider.getErc20InfoFromNft(address(mockNFT));
        address erc20Address = info.erc20Address;
        
        // Approve tokens for selling
        IERC20(erc20Address).approve(address(tokenDivider), INITIAL_AMOUNT);
        
        // Step 2: Create a sell order with price = 0
        uint256 sellAmount = 500;
        uint256 price = 0; // Zero price!
        tokenDivider.sellErc20(address(mockNFT), price, sellAmount);
        vm.stopPrank();
        // Step 3: User2 buys the tokens
        vm.startPrank(user2);
        
        // sent 0 ETH to buy the tokens
        // Fee calculation: fee = price/100 = 0/100 = 0
        // sellerFee = fee/2 = 0/2 = 0
        // Total required = price + sellerFee = 0 + 0 = 0
        tokenDivider.buyOrder{value: 0}(0, user1);
        
        // Verify user2 received the tokens
        uint256 user2Balance = tokenDivider.getBalanceOf(user2, erc20Address);
        assertEq(user2Balance, sellAmount, "User2 should receive the tokens");
        
        // Verify no ETH was transferred (since price and fees are 0)
        assertEq(user1.balance, 0, "Seller should receive no ETH");
        assertEq(owner.balance, 0, "Owner should receive no fees");
        vm.stopPrank();
    }
}
```
## Impact:
**Free Token Acquisition:** Buyers can obtain tokens without payment
**Lost Protocol Fees:** Platform receives no fees *(fee = price/100 = 0)*
**Lost Seller Revenue:** Sellers receive no payment  *(price - sellerFee = 0 - 0 = 0)*
**Economic Implications:**
- Undermines the entire trading mechanism
- Protocol loses revenue from fees
- Creates unfair market dynamics
## Tools Used
Manual Review
## Fix Recommendation:
Add price validation in the sellErc20 function:
```solidity
// Correct Implementation
function sellErc20(address nftPegged, uint256 price, uint256 amount) external {
    if(price == 0) {
        revert TokenDivider__InvalidPrice();
    }
    if(nftPegged == address(0)) {
        revert TokenDivider__NftAddressIsZero();
    }
    // ... rest of the function
}
```
The fix ensures that all sell orders must have a non-zero price, maintaining the economic integrity of the platform and ensuring proper fee collection.