Pieces Protocol

First Flight #32
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

The way `sellerFee` is calculated inside `TokenDivider::buyOrder` leads to possible truncation.

Description

The variables fee and sellerFee are calculated using division, which may lead to truncation issues.

Impact

If truncation happens when calculating the sellerFee, the protocol will be losing money.

Proof of Concepts

  • A seller creates a sellOrder with 0 wei < price < 200 wei.

  • A user buys the order

  • Both fee and sellerFee get truncated, resulting in a value of zero

Tools Used

  • Foundry, Manual analysis

Recommended mitigation

Add the following code to the contract, in order to ensure that protocol receives ceil(sellerFee) and doesn't lose any ETH:

function buyOrder(uint256 orderIndex, address seller) external payable {
if (seller == address(0)) {
revert TokenDivider__InvalidSeller();
}
SellOrder memory order = s_userToSellOrders[seller][orderIndex];
if (msg.value < order.price) {
revert TokenDivider__IncorrectEtherAmount();
}
- uint256 fee = order.price / 100;
- uint256 sellerFee = fee / 2;
+ uint256 SCALE = 1e18; // Define SCALE inside the function for precision
+ uint256 fee = (order.price * SCALE + (100 * SCALE - 1)) / (100 * SCALE);
+ uint256 sellerFee = (fee + 1) / 2; // Rounding up sellerFee
if (msg.value < order.price + sellerFee) {
revert TokenDivider__InsuficientEtherForFees();
}
balances[msg.sender][order.erc20Address] += order.amount;
s_userToSellOrders[seller][orderIndex] = s_userToSellOrders[seller][s_userToSellOrders[seller].length - 1];
s_userToSellOrders[seller].pop();
emit OrderSelled(msg.sender, order.price);
// Transfer Ether to the seller
(bool success, ) = payable(order.seller).call{value: (order.price - sellerFee)}("");
if (!success) {
revert TokenDivider__TransferFailed();
}
// Transfer the correct sellerFee to the contract owner
(bool taxSuccess, ) = payable(owner()).call{value: sellerFee}("");
if (!taxSuccess) {
revert TokenDivider__TransferFailed();
}
IERC20(order.erc20Address).transfer(msg.sender, order.amount);
}
Updates

Lead Judging Commences

fishy Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Precision loss

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.