Description: In amendSellOrder
if (_newDeadlineDuration == 0 || _newDeadlineDuration > MAX_DEADLINE_DURATION)
revert InvalidDeadline();
only checks that the new duration is non-zero and ≤ 'MAX_DEADLINE_DURATION'. It neither enforces that the resulting deadline is in the future nor prevents repeated extensions up to the maximum.
Impact: Sellers can repeatedly reset or extend their order's deadline right up to the maximum, effectively preventing orders from ever expiring and locking counter-party funds indefinitely.
Proof of Concept: Include the following test in the TestOrderBook.t.sol file:
function testUnlimitedDuration() public {
vm.startPrank(alice);
wbtc.approve(address(book), 2e8);
uint256 orderId = book.createSellOrder(address(wbtc), 2e8, 1000e6, 3 days);
vm.stopPrank();
vm.warp(block.timestamp + 2 days);
vm.prank(alice);
book.amendSellOrder(orderId, 2e8, 1000e6, 3 days);
vm.warp(block.timestamp + 2 days);
vm.prank(alice);
book.amendSellOrder(orderId, 2e8, 1000e6, 3 days);
vm.startPrank(dan);
usdc.approve(address(book), 1000e6);
book.buyOrder(orderId);
vm.stopPrank();
}
Mitigation:
– Optionally limit the number of extensions per order.
– Enforce an absolute upper bound.
struct Order {
uint256 id;
address seller;
address tokenToSell; // Address of wETH, wBTC, or wSOL
uint256 amountToSell; // Amount of tokenToSell
uint256 priceInUSDC; // Total USDC price for the entire amountToSell
uint256 deadlineTimestamp; // Block timestamp after which the order expires
bool isActive; // Flag indicating if the order is available to be bought
+ uint256 deadlineUpperBound; // Upper bound for deadline extension
}
+ uint256 public constant MAX_DEADLINE_UPPER_BOUND = 5 days;
function createSellOrder(
address _tokenToSell,
uint256 _amountToSell,
uint256 _priceInUSDC,
uint256 _deadlineDuration
) public returns (uint256) {
// ...
+ orders[orderId] = Order({
id: orderId,
seller: msg.sender,
tokenToSell: _tokenToSell,
amountToSell: _amountToSell,
priceInUSDC: _priceInUSDC,
deadlineTimestamp: deadlineTimestamp,
isActive: true,
+ deadlineUpperBound: block.timestamp + MAX_DEADLINE_UPPER_BOUND
});
// ...
}
function amendSellOrder(
uint256 _orderId,
uint256 _newAmountToSell,
uint256 _newPriceInUSDC,
uint256 _newDeadlineDuration
) public {
// ...
+ require(block.timestamp + _newDeadlineDuration <= order.deadlineUpperBound, "New deadline exceeds upper bound");
// ...
}