Order creation can run out of gas since relying on previous order matchtype
If the hint order id has been reused and the previous order type is `matched` the current code iterates from the head of the linked list under the assumption that `since the previous order has been `matched` it must have been at the top of the orderbook which would mean the new order with a similar price would also be somewhere near the top of the orderbook`.\\n```\\n    function findOrderHintId(\\n        mapping(address => mapping(uint16 => STypes.Order)) storage orders,\\n        address asset,\\n        MTypes.OrderHint[] memory orderHintArray\\n    ) internal returns (uint16 hintId) {\\n\\n          // more code\\n\\n          // @audit if a reused order's prevOrderType is matched, returns HEAD\\n\\n          if (hintOrderType == O.Cancelled || hintOrderType == O.Matched) {\\n                emit Events.FindOrderHintId(0);\\n                continue;\\n            } else if (\\n                orders[asset][orderHint.hintId].creationTime == orderHint.creationTime\\n            ) {\\n                emit Events.FindOrderHintId(1);\\n                return orderHint.hintId;\\n            } else if (orders[asset][orderHint.hintId].prevOrderType == O.Matched) {\\n                //@dev If hint was prev matched, it means that the hint was close to HEAD and therefore is reasonable to use HEAD\\n                emit Events.FindOrderHintId(2);\\n                return Constants.HEAD;\\n            }\\n```\\n\\nhttps://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/libraries/LibOrders.sol#L927-L947\\nBut it is possible that the initial order was cancelled and the id reused multiple times with the previous order being close to the market price resulting in a match. This can lead to a possible exhaustion of gas if the user's order has a price far from the top of the orderbook.\\nExample scenario\\nCurrent state of bids in orderbook:\\nTop bid 2000\\nTotal bids 1000\\nBids ids are from 100 to 999. No order is cancelled and reusable.\\nA user wants to bid at 1700 which would be the 800th order pricewise.\\nUser calls `createBid` passing in `[799,798]` for the orderHintArray.\\nThe following tx's occur in the same block before the user's `createBid` call in the following order.\\nOrder id `799` gets cancelled.\\nAnother user creates a limit order at `2001` which now has order id `799` since it is reused.\\nA market/new limit ask order fills the bid.\\nAnother user creates a limit order at price `1800`.\\nIn `createBid` when finding the hint id, the condition `prevOrderType == O.Matched` will pass and the hintId returned will be the `HEAD`.\\nThe loop starts to check for the price match from `HEAD` and exhausts gas before iterating over 800 bids.
I think the probability of the above scenario is higher than that of multiple user's cancelling their orders. Hence moving to the next hint order as soon as the current hint order has been found to be reused could be better and will cost less gas on error.
Order creation can run out-of-gas on particular flow\\nTest Code\\nAdd the following change in test/AskSellOrders.t.sol and run\\n```\\ndiff // Remove the line below\\n// Remove the line below\\ngit a/test/AskSellOrders.t.sol b/test/AskSellOrders.t.sol\\nindex 4e8a4a9..264ea32 100644\\n// Remove the line below\\n// Remove the line below\\n// Remove the line below\\n a/test/AskSellOrders.t.sol\\n// Add the line below\\n// Add the line below\\n// Add the line below\\n b/test/AskSellOrders.t.sol\\n@@ // Remove the line below\\n8,7 // Add the line below\\n8,7 @@ import {Errors} from "contracts/libraries/Errors.sol";\\n import {STypes, MTypes, O} from "contracts/libraries/DataTypes.sol";\\n \\n import {OBFixture} from "test/utils/OBFixture.sol";\\n// Remove the line below\\n// import {console} from "contracts/libraries/console.sol";\\n// Add the line below\\nimport {console} from "contracts/libraries/console.sol";\\n \\n contract SellOrdersTest is OBFixture {\\n     using U256 for uint256;\\n@@ // Remove the line below\\n59,6 // Add the line below\\n59,49 @@ contract SellOrdersTest is OBFixture {\\n         assertEq(asks[0].price, DEFAULT_PRICE);\\n     }\\n \\n// Add the line below\\n    function testPossibleOutOfGasInLoopDueToHighIterations() public {\\n// Add the line below\\n        for (uint256 i = 0; i < 1000; i// Add the line below\\n// Add the line below\\n) {\\n// Add the line below\\n            fundLimitAskOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, sender);\\n// Add the line below\\n        }\\n// Add the line below\\n\\n// Add the line below\\n        // a new order at the bottom of the order book\\n// Add the line below\\n        fundLimitAskOpt(HIGHER_PRICE, DEFAULT_AMOUNT, sender);\\n// Add the line below\\n        assertTrue(getAsks()[1000].price == HIGHER_PRICE);\\n// Add the line below\\n        assertTrue(getAsks()[1000].ercAmount == DEFAULT_AMOUNT);\\n// Add the line below\\n\\n// Add the line below\\n        // user wants to create an order at HIGHER_PRICE\\n// Add the line below\\n        MTypes.OrderHint[] memory orderHintArray =\\n// Add the line below\\n            diamond.getHintArray(asset, HIGHER_PRICE, O.LimitAsk);\\n// Add the line below\\n        uint16 targetOrderId = orderHintArray[0].hintId;\\n// Add the line below\\n        assertTrue(targetOrderId == getAsks()[1000].id);\\n// Add the line below\\n\\n// Add the line below\\n        // the target order gets cancelled\\n// Add the line below\\n        vm.prank(sender);\\n// Add the line below\\n        cancelAsk(targetOrderId);\\n// Add the line below\\n\\n// Add the line below\\n        // a person creates a limit ask which reuses the cancelled order id\\n// Add the line below\\n        fundLimitAskOpt(LOWER_PRICE, DEFAULT_AMOUNT, sender);\\n// Add the line below\\n        assertTrue(getAsks()[0].id == targetOrderId);\\n// Add the line below\\n\\n// Add the line below\\n        // a bid matches the targetId\\n// Add the line below\\n        fundLimitBid(LOWER_PRICE, DEFAULT_AMOUNT, receiver);\\n// Add the line below\\n\\n// Add the line below\\n        // another person creates a limit ask which reuses the matched order id\\n// Add the line below\\n        fundLimitAskOpt(LOWER_PRICE, DEFAULT_AMOUNT, sender);\\n// Add the line below\\n        assertTrue(getAsks()[0].id == targetOrderId);\\n// Add the line below\\n\\n// Add the line below\\n        // the tx of the user goes through\\n// Add the line below\\n        depositUsd(sender, DEFAULT_AMOUNT);\\n// Add the line below\\n        vm.prank(sender);\\n// Add the line below\\n        uint256 gasStart = gasleft();\\n// Add the line below\\n        diamond.createAsk(\\n// Add the line below\\n            asset, HIGHER_PRICE, DEFAULT_AMOUNT, Constants.LIMIT_ORDER, orderHintArray\\n// Add the line below\\n        );\\n// Add the line below\\n        uint256 gasUsed = gasStart // Remove the line below\\n gasleft();\\n// Add the line below\\n        assertGt(gasUsed, 2_000_000);\\n// Add the line below\\n        console.log(gasUsed);\\n// Add the line below\\n    }\\n// Add the line below\\n\\n     function testAddingLimitSellAskUsdGreaterThanBidUsd() public {\\n         fundLimitBidOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, receiver);\\n         fundLimitAskOpt(DEFAULT_PRICE, DEFAULT_AMOUNT * 2, sender);\\n```\\n
```\\n    function findOrderHintId(\\n        mapping(address => mapping(uint16 => STypes.Order)) storage orders,\\n        address asset,\\n        MTypes.OrderHint[] memory orderHintArray\\n    ) internal returns (uint16 hintId) {\\n\\n          // more code\\n\\n          // @audit if a reused order's prevOrderType is matched, returns HEAD\\n\\n          if (hintOrderType == O.Cancelled || hintOrderType == O.Matched) {\\n                emit Events.FindOrderHintId(0);\\n                continue;\\n            } else if (\\n                orders[asset][orderHint.hintId].creationTime == orderHint.creationTime\\n            ) {\\n                emit Events.FindOrderHintId(1);\\n                return orderHint.hintId;\\n            } else if (orders[asset][orderHint.hintId].prevOrderType == O.Matched) {\\n                //@dev If hint was prev matched, it means that the hint was close to HEAD and therefore is reasonable to use HEAD\\n                emit Events.FindOrderHintId(2);\\n                return Constants.HEAD;\\n            }\\n```\\n