OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
Submission Details
Impact: low
Likelihood: medium
Invalid

L02-Abuse of `newDeadlineDuration` in amendSellOrder May Enable Order "Perpetuation"

Author Revealed upon completion

Abuse of newDeadlineDuration May Enable Order "Perpetuation"

Root + Impact

Description

Normally, the amendSellOrder() function allows a seller to change the terms of an active sell order — including the token amount, price, and deadline duration — as long as the order hasn't expired.

However, by repeatedly calling amendSellOrder() and passing a new _newDeadlineDuration, the seller can continuously extend the order's expiration without restriction, keeping the order in an "active but not fulfillable" state indefinitely, unless a cancellation is enforced elsewhere.

This behavior may be intended, but it opens up griefing or denial-of-cancellation edge cases in a system where orders are expected to expire naturally after a set deadline.

function amendSellOrder(
uint256 _orderId,
uint256 _newAmountToSell,
uint256 _newPriceInUSDC,
uint256 _newDeadlineDuration
) public {
// [...]
if (_newDeadlineDuration == 0 || _newDeadlineDuration > MAX_DEADLINE_DURATION) revert InvalidDeadline();
// > update deadline here
uint256 newDeadlineTimestamp = block.timestamp + _newDeadlineDuration;
IERC20 token = IERC20(order.tokenToSell);
//Rest of the code
}

Risk

Likelihood: Low

  • Occurs when a seller wants to keep an order active indefinitely by repeatedly amending it before expiration.

  • Can also be automated via bots to "game" certain off-chain systems or GUIs that rely on natural expiry for pruning.

Impact: Low to Moderate

  • Could prevent cleanup or off-chain expiry handling, especially in frontends or indexers.

  • May abuse visibility on marketplaces by always keeping an order "fresh."

  • Could result in confusion or unexpected user experience for buyers expecting finite windows for offer expiration.


Proof of Concept

  1. Seller creates a valid sell order with a 24-hour deadline.

  2. Just before the order expires (e.g., at hour 23), seller calls amendSellOrder() and keeps all values the same except _newDeadlineDuration = 86400.

  3. The deadline is extended another 24 hours.

  4. Repeat the call daily — the order remains "active" perpetually, even if the seller is not truly engaged or interested in finalizing it.


Recommended Mitigation

Enforce a maximum number of amendments

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 numberOfAmendement // Indicate the numners of amendements made to the order
}
++ uint256 public constant MAX_NUMBER_AMENDEMENT = 3 ; // Max number of amendements allowed
function amendSellOrder(
uint256 _orderId,
uint256 _newAmountToSell,
uint256 _newPriceInUSDC,
uint256 _newDeadlineDuration
) public {
Order storage order = orders[_orderId];
// Validation checks
if (order.seller == address(0)) revert OrderNotFound(); // Check if order exists
+ if (oder.numberOfAmendement > MAX_NUMBER_AMENDEMENT) revert TooManyAmendements();
[ if (order.seller != msg.sender) revert NotOrderSeller();
if (!order.isActive) revert OrderAlreadyInactive();
if (block.timestamp >= order.deadlineTimestamp) revert OrderExpired(); // Cannot amend expired order
if (_newAmountToSell == 0) revert InvalidAmount();
if (_newPriceInUSDC == 0) revert InvalidPrice();
if (_newDeadlineDuration == 0 || _newDeadlineDuration > MAX_DEADLINE_DURATION) revert InvalidDeadline();
uint256 newDeadlineTimestamp = block.timestamp + _newDeadlineDuration;
IERC20 token = IERC20(order.tokenToSell);
// Handle token amount changes
if (_newAmountToSell > order.amountToSell) {
// Increasing amount: Transfer additional tokens from seller
uint256 diff = _newAmountToSell - order.amountToSell;
token.safeTransferFrom(msg.sender, address(this), diff);
} else if (_newAmountToSell < order.amountToSell) {
// Decreasing amount: Transfer excess tokens back to seller
uint256 diff = order.amountToSell - _newAmountToSell;
token.safeTransfer(order.seller, diff);
}]
// Update order details
++ order.numberOfAmendement += 1
order.amountToSell = _newAmountToSell;
order.priceInUSDC = _newPriceInUSDC;
order.deadlineTimestamp = newDeadlineTimestamp;
emit OrderAmended(_orderId, _newAmountToSell, _newPriceInUSDC, newDeadlineTimestamp);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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