Skip to content

Latest commit

 

History

History
101 lines (67 loc) · 3.15 KB

File metadata and controls

101 lines (67 loc) · 3.15 KB

Main Honeysuckle Tarantula

Medium

user may be grossly overpaying fees in buyVotes due to incorrect calculation

Summary

Consider the buyVotes function. Specifically its internal call to _calculateBuy.

function _calculateBuy(
    Market memory market,
    bool isPositive,
    uint256 funds
  )
    private
    view
    returns (
      uint256 votesBought,
      uint256 fundsPaid,
      uint256 newVotePrice,
      uint256 protocolFee,
      uint256 donation,
      uint256 minVotePrice,
      uint256 maxVotePrice
    )
  {
    uint256 fundsAvailable;
    (fundsAvailable, protocolFee, donation) = previewFees(funds, true);
    uint256 votePrice = _calcVotePrice(market, isPositive);

    uint256 minPrice = votePrice;
    uint256 maxPrice;
    if (fundsAvailable < votePrice) {
      revert InsufficientFunds();
    }

    while (fundsAvailable >= votePrice) {
      fundsAvailable -= votePrice;
      fundsPaid += votePrice;
      votesBought++;

      market.votes[isPositive ? TRUST : DISTRUST] += 1;
      votePrice = _calcVotePrice(market, isPositive);
    }
    fundsPaid += protocolFee + donation;

    maxPrice = votePrice;

    return (votesBought, fundsPaid, votePrice, protocolFee, donation, minPrice, maxPrice);
  }

The previewFees function counts the commission that the user will pay for the purchase. However, the funds - passed to previewFees - is msg.value attached to the call.

Thus, the amount of commission the user will pay depends only on the msg.value he attaches to the message, not on the amount he spends on the purchase.

That is, either the user tries to minimise the msg.value and risks not buying the vote because of slippage, or he doesn't minimise it and overpays the commission.

Judging by the sponsor's discord message, it is important to the protocol that users do not overpay the commission, I will now show that user losses can be significant.

For simplicity, let's assume that 1 vote costs 90 ETH. The user wants to buy exactly 1 vote. Protocol commission 5%, donation 5%.

So, if msg.value is in [100; 200] - user will get exactly 1 share, but will pay different amount of fee.

msg.value = 100. ProtocolFee = 5, Donation = 5. Price = 90. TotalCost = 100

msg.value = 150. ProtocolFee = 7.5, Donation = 7.5. Price = 90. TotalCost = 105

msg.value = 200. ProtocolFee = 10, Donation = 10, Price = 90. TotalCost = 110

The user overpays up to 10% in the worst case.

Root Cause

The purchase commission depends on the msg.value attached, not the money spent. Msg.value may be inflated by the buyer due to slippage, but in this case he will overpay the protocol.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

The user loses funds through no fault of their own (if they specify an accurate msg.value, they probably won't buy because of slippage)

PoC

No response

Mitigation

Calculate fees from spend funds, not from msg.value