Skip to content

Commit

Permalink
Fix rolling tick orders
Browse files Browse the repository at this point in the history
  • Loading branch information
0xSamWitch committed Jan 29, 2024
1 parent e82b276 commit 3ed5a44
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 3 deletions.
11 changes: 8 additions & 3 deletions contracts/SamWitchOrderBook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {BokkyPooBahsRedBlackTreeLibrary} from "./BokkyPooBahsRedBlackTreeLibrary
import {IBrushToken} from "./interfaces/IBrushToken.sol";
import {ISamWitchOrderBook} from "./interfaces/ISamWitchOrderBook.sol";

import "hardhat/console.sol";

/// @title SamWitchOrderBook (SWOB)
/// @author Sam Witch (PaintSwap & Estfor Kingdom)
/// @author 0xDoubleSharp
Expand Down Expand Up @@ -804,18 +806,21 @@ contract SamWitchOrderBook is ISamWitchOrderBook, ERC1155Holder, UUPSUpgradeable
// Loop until we find a suitable place to put this
while (true) {
price_ = uint72(uint128(int72(price_) + _tickIncrement));
console.log(price_);
if (!_tree.exists(price_)) {
_tree.insert(price_);
break;
} else if (
(_packedOrdersPriceMap[price_].length.sub(tombstoneOffset)).mul(NUM_ORDERS_PER_SEGMENT) >=
maxOrdersPerPrice &&
(_packedOrdersPriceMap[price_].length.sub(tombstoneOffset)).mul(NUM_ORDERS_PER_SEGMENT) <
maxOrdersPerPrice ||
uint(
_packedOrdersPriceMap[price_][_packedOrdersPriceMap[price_].length.dec()] >>
NUM_ORDERS_PER_SEGMENT.dec().mul(64)
) !=
) ==
0
) {
// There are orders left or the last segment is not filled yet
console.log("WHAT");
break;
}
}
Expand Down
115 changes: 115 additions & 0 deletions test/SamWitchOrderBook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,121 @@ describe("SamWitchOrderBook", function () {
expect(orders.length).to.eq(1);
});

it("Max number of orders for a price should increment it by the tick, where the price level exists already and has spare segments", async function () {
const {orderBook, alice, tokenId, maxOrdersPerPrice, tick} = await loadFixture(deployContractsFixture);

// Set up order book
const price = 100;
const quantity = 1;

const limitOrder: ISamWitchOrderBook.LimitOrderStruct = {
side: OrderSide.Buy,
tokenId,
price,
quantity,
};

const limitOrders = new Array<ISamWitchOrderBook.LimitOrderStruct>(maxOrdersPerPrice).fill(limitOrder);
await orderBook.limitOrders(limitOrders);

await orderBook.connect(alice).limitOrders([
{
side: OrderSide.Buy,
tokenId,
price: price - tick,
quantity,
},
]);

// Try to add one more and it will be added to the next tick price
await orderBook.connect(alice).limitOrders([limitOrder]);

let orders = await orderBook.allOrdersAtPrice(OrderSide.Buy, tokenId, price);
expect(orders.length).to.eq(maxOrdersPerPrice);

orders = await orderBook.allOrdersAtPrice(OrderSide.Buy, tokenId, price - tick);
expect(orders.length).to.eq(2);
});

it("Multiple ticks iterated when there are the max number of orders and no spare orders in the last segment", async function () {
const {orderBook, alice, tokenId, maxOrdersPerPrice, erc1155, tick} = await loadFixture(deployContractsFixture);

// Set up order book
const price = 100;
const quantity = 1;
await erc1155.mintSpecificId(tokenId, 10000);

const limitOrder: ISamWitchOrderBook.LimitOrderStruct = {
side: OrderSide.Sell,
tokenId,
price,
quantity,
};

let limitOrders = new Array<ISamWitchOrderBook.LimitOrderStruct>(maxOrdersPerPrice).fill(limitOrder);
await orderBook.limitOrders(limitOrders);

const limitOrderNextTick: ISamWitchOrderBook.LimitOrderStruct = {
side: OrderSide.Sell,
tokenId,
price: price + tick,
quantity,
};

let limitOrdersNextTick = new Array<ISamWitchOrderBook.LimitOrderStruct>(maxOrdersPerPrice).fill(
limitOrderNextTick,
);
await orderBook.limitOrders(limitOrdersNextTick);

// Try to add one more and it will be added to the tick * 2 price
await orderBook.connect(alice).limitOrders([limitOrder]);

let orders = await orderBook.allOrdersAtPrice(OrderSide.Sell, tokenId, price + 2 * tick);
expect(orders.length).to.eq(1);
});

it("Multiple ticks iterated, space at the end of the segment for it", async function () {
const {orderBook, alice, tokenId, maxOrdersPerPrice, erc1155, tick} = await loadFixture(deployContractsFixture);

// Set up order book
const price = 100;
const quantity = 1;
await erc1155.mintSpecificId(tokenId, 10000);

const limitOrder: ISamWitchOrderBook.LimitOrderStruct = {
side: OrderSide.Sell,
tokenId,
price,
quantity,
};

let limitOrders = new Array<ISamWitchOrderBook.LimitOrderStruct>(maxOrdersPerPrice).fill(limitOrder);
await orderBook.limitOrders(limitOrders);

const limitOrderNextTick: ISamWitchOrderBook.LimitOrderStruct = {
side: OrderSide.Sell,
tokenId,
price: price + tick,
quantity,
};

let limitOrdersNextTick = new Array<ISamWitchOrderBook.LimitOrderStruct>(maxOrdersPerPrice).fill(
limitOrderNextTick,
);
await orderBook.limitOrders(limitOrdersNextTick);

await orderBook.cancelOrders([maxOrdersPerPrice * 2 - 2], [{side: OrderSide.Sell, tokenId, price: price + tick}]);

// Try to add one more and it will be added to the tick * 2 price
await orderBook.connect(alice).limitOrders([limitOrder]);

let orders = await orderBook.allOrdersAtPrice(OrderSide.Sell, tokenId, price + tick);
expect(orders.length).to.eq(100);

orders = await orderBook.allOrdersAtPrice(OrderSide.Sell, tokenId, price + 2 * tick);
expect(orders.length).to.eq(0);
});

it("Price must be modulus of tick quantity must be > min quantity, sell", async function () {
const {orderBook, erc1155, tokenId} = await loadFixture(deployContractsFixture);

Expand Down

0 comments on commit 3ed5a44

Please sign in to comment.