Closed code423n4 closed 2 years ago
Orders with ascending/descending amount items can be easily mirrored using any method other than matchOrders
; and even when using matchOrders
they can still be fulfilled by simply adding 1 to the mirrored startAmount and endAmount for offer items fulfilling an ascending/descending consideration item, or subtracting 1 from the mirrored startAmount and endAmount for consideration items fulfilling an ascending/descending offer item.
As the sponsor has noted, orders can be mirrored using any other method, however, to utilise matchOrders()
, adding -1/+1 seems to be a plausible work around. Considering the outlined issue has no direct security risk, I think it would be fair to downgrade this to QA and merge with #203
Lines of code
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/contracts/lib/AmountDeriver.sol#L57
Vulnerability details
Impact
Existing orders with moving prices (
startAmount
andendAmount
) can match viamatchAdvancedOrders
. However the expression(startAmount * remaining) + (endAmount * elapsed) + extraCeiling
in AmountDeriver.sol#L57 makes it very unlikely thattotalBeforeDivision
is divisible byduration
whenelapsed > 0
, which is at anytimestamp > startTime
(basically all the time except the first tx). When two orders match, each side is considered the offerer when computing the offer and consideration amounts, which favors offerers by:However, because the protocol tries to favor both, orders that could match do not match anymore due to the rounding above. Example:
[10, 20)
for 10 ERC1155.[10, 20)
ERC20.This looks like it should just match, and it does at
startTime
. However, at timestampstartTime + 1
, the current sell price for Alice's ERC20 is 10, and the current buy price for the ERC20 that Bob wants is 11. This happens even though the moving prices are the same, and the orders'startTime
andendTime
are the same. For different cases, the problem is bigger and makes it almost impossible to match orders that use moving prices.Opensea documentation mentions that the way an order can be matched is by creating a mirror image of an existing order. However, this technique becomes nearly impossible to match for moving price due to rounding issues. This is why the issue has a severity of Medium.
Proof of Concept
The patch below when used with
forge test -m "testMatchOrdersMovingPrice" -vvvv
reproduces the example above:Tools Used
Manual review
Recommended Mitigation Steps
Potentially reconsider the usability of moving prices.