OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Sellers bear full protocol fee while buyers pay only listed price

Sellers bear full protocol fee while buyers pay only listed price meaning unfair pricing discourages sellers to use the protocol hence threatening protocol viability and liquidity.

Description

  • The protocol puts the entire burden of the protocol fee on the seller, while the buyer is only required to pay the listed price.

  • Such unfair fee distribution may discourage sellers from participating in the protocol, leading to reduced listings and declining liquidity.

    // Root cause in the codebase with @> marks to highlight the relevant section
    uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;
    @> uint256 sellerReceives = order.priceInUSDC - protocolFee;
    iUSDC.safeTransferFrom(msg.sender, address(this), protocolFee);
    iUSDC.safeTransferFrom(msg.sender, order.seller, sellerReceives);
    IERC20(order.tokenToSell).safeTransfer(msg.sender, order.amountToSell);

Risk

Likelihood:

  • This occurs whenever an order is filled and the protocol fee is deducted from the seller’s amount.

Impact:

  • This can cause adoption barrier for sellers and can greatly impact the sustainability of the protocol. Making the protocol non-functional without liquidity.

Proof of Concept

Seller is expected to receive less than expected while the buyer pays nothing for using the platform.

function test_seller_at_loss_than_buyer() external {
vm.startPrank(alice);
wbtc.approve(address(book), 2e8);
uint256 aliceId = book.createSellOrder(address(wbtc), 2e8, 180_000e6, 2 days);
uint256 orderInUSDC = book.getOrder(aliceId).priceInUSDC;
uint256 protocolFee = (orderInUSDC * book.FEE()) / book.PRECISION();
vm.stopPrank();
assertEq(wbtc.balanceOf(alice), 0);
vm.startPrank(dan);
usdc.approve(address(book), 180_000e6);
book.buyOrder(aliceId);
vm.stopPrank();
assertEq(wbtc.balanceOf(dan), 2e8);
assert(usdc.balanceOf(alice) == 174_600e6);
assert(usdc.balanceOf(address(book)) == protocolFee);
}

Recommended Mitigation

Option 1: Buyer pays the fee (most common in P2P trading)
Option 2: Split fees (balanced approach)

+ //Option 1
+ //total amount paid by buyer
+ uint256 totalBuyerPayment = order.priceInUSDC + protocolFee;
- iUSDC.safeTransferFrom(msg.sender, order.seller, sellerReceives);
+ iUSDC.safeTransferFrom(msg.sender, order.seller, order.priceInUSDC);
+//Option 2
+ uint256 buyerFee = protocolFee / 2;
+ uint256 sellerFee = protocolFee - buyerFee;
+ uint256 totalBuyerPayment = order.priceInUSDC + buyerFee;
+ //seller pays half of the fee
- uint256 sellerReceives = order.priceInUSDC - protocolFee;
+ uint256 sellerReceives = order.priceInUSDC - sellerFee;
+ // buyer pays half of the fee
- iUSDC.safeTransferFrom(msg.sender, address(this), protocolFee);
+ iUSDC.safeTransferFrom(msg.sender, address(this), buyerFee);
+ iUSDC.safeTransferFrom(msg.sender, order.seller, sellerReceives);
Updates

Lead Judging Commences

yeahchibyke Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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