OrderBook

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

Unlimited Deadline Extension via Repeated Amendments

Root + Impact

Description

  • Normal behavior: When an order is created, its deadline should expire no later than createdAt + MAX_DEADLINE_DURATION, and once that window has passed it should not be extendable.

  • Root cause: The amendSellOrder function recomputes expiry as block.timestamp + _newDeadlineDuration without ever recording the original creation timestamp (createdAt) or enforcing a cap relative to it. This allows a seller to call amendSellOrder immediately before each expiry and push the deadline out by another full window indefinitely.

// Root cause in the codebase with @> marks to highlight the relevant section
function amendSellOrder(
uint256 _orderId,
uint256 _newAmountToSell,
uint256 _newPriceInUSDC,
uint256 _newDeadlineDuration
) public nonReentrant {
Order storage order = orders[_orderId];
// … validation omitted …
// Recomputed every time from “now” without cap vs creation:
uint256 newExpiry = block.timestamp + _newDeadlineDuration;
@> order.deadlineTimestamp = newExpiry; // ← no check against order.createdAt + MAX_DEADLINE_DURATION
emit OrderAmended(_orderId, _newAmountToSell, _newPriceInUSDC, newExpiry);
}

Risk

Likelihood:

  • A seller or automated script simply invokes amendSellOrder right before expiry to refresh the deadline, and can repeat this indefinitely.

  • Unmonitored orders remain “active” as long as the seller keeps refreshing them.

Impact:

  • Locked-up assets: Tokens committed to the order stay locked in the contract forever, preventing both the seller and buyers from reclaiming or trading them.

    • Market distortion & UX confusion: Buyers and analytics will continue to see “active” orders past their intended lifespan, undermining trust in the protocol.

Proof of Concept

Because there’s no cap tied to the original creation time, a seller can “refresh” the deadline over and over, locking funds indefinitely.

// 1) Seller creates an order with a 3-day deadline.
uint256 id = book.createSellOrder(wbtc, 1e8, 30_000e6, 3 days);
// 2) Just before it expires, seller refreshes to another 3 days:
book.amendSellOrder(id, 1e8, 30_000e6, 3 days);
// → deadline is now “now + 3 days.”
// 3) Repeat step 2 indefinitely.
// → order never expires; tokens remain locked forever.

Recommended Mitigation

Track creation time by adding a createdAt field to the Order struct and setting it in createSellOrder.

// Compute the candidate new deadline
- order.deadlineTimestamp = block.timestamp + _newDeadlineDuration;
+ uint256 newExpiry = block.timestamp + _newDeadlineDuration;
+ // Prevent total lifetime > MAX_DEADLINE_DURATION
+ if (newExpiry > order.createdAt + MAX_DEADLINE_DURATION) {
+ revert InvalidDeadline();
+ }
+ order.deadlineTimestamp = newExpiry;
Updates

Lead Judging Commences

yeahchibyke Lead Judge
4 months ago
yeahchibyke Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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