> For the complete documentation index, see [llms.txt](https://docs.selcier.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.selcier.xyz/markets-and-capital/scheduled-windows.md).

# Scheduled Liquidity Windows

Issuer-run batch auctions and tenders with fixed dates, in which shareholders sell to eligible buyers at one clearing price, with every fill settled atomically on-chain.

Companies control and schedule their own liquidity events through Liquidity Windows. Holders who qualify offer shares over a fixed period while qualifying buyers place bids. Then, once the period ends, the `LiquidityWindow` contract settles all matched orders together at a single price in one transaction.

Think of a window as the replacement for a traditional tender offer. Timing, participation and limits are the company's decisions, while price discovery takes place openly, and nobody places an order without being verified first.

## Setting up a window

| Setting                | Purpose                                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
| `shareToken`           | Class of shares on offer                                                                                  |
| `mode`                 | Selects `TENDER`, where the price is fixed, or `AUCTION`, a batch auction at one uniform price            |
| `opensAt` / `closesAt` | When orders are accepted                                                                                  |
| `stablecoin`           | Asset used to settle, USDG unless changed                                                                 |
| `reservePrice`         | Optional floor. Shares never trade under it                                                               |
| `tenderPrice`          | Used only in `TENDER` mode, as the set price per share                                                    |
| `maxVolume`            | Optional ceiling on shares traded across the window, in raw token units. A value of `0` removes the limit |
| `perSellerCap`         | Optional ceiling on what a single seller may offer, in raw token units. A value of `0` removes the limit  |
| `rofrHolder`           | Optional party holding a right of first refusal for this window, typically the company treasury           |
| `rofrPeriod`           | Optional length of time `rofrHolder` gets to exercise once `closesAt` passes                              |
| `sellerClaims`         | Topics required of sellers, such as `EMPLOYEE_OF` when only employees may sell                            |
| `buyerClaims`          | Topics required of buyers                                                                                 |

Holding these claims is not enough on its own. The share class's transfer rules apply to both sides too, so eligibility also depends on holding periods, vesting and region rules. To keep settlement inside one transaction, 200 orders (`MAX_ORDERS`) is the most a window accepts.

A share class may carry a `TransferWindowModule` set with `allowDuringLiquidityWindows`. In that case transfers into and out of the `LiquidityWindow` contract succeed even while the module's own trading periods are shut. Details are in [Compliance modules](/fundamentals/compliance-modules.md).

## How an auction runs

Sellers and buyers each state a price.

| Side   | Call                                               | Meaning of the limit      | What gets locked                                                            |
| ------ | -------------------------------------------------- | ------------------------- | --------------------------------------------------------------------------- |
| Seller | `placeOrder(windowId, SELL, quantity, limitPrice)` | The floor they will take  | The tokens, which enter the contract until clearing or cancellation         |
| Buyer  | `placeOrder(windowId, BUY, quantity, limitPrice)`  | The ceiling they will pay | Stablecoin equal to `quantity × limitPrice`, rounded up, plus the buyer fee |

`canTransfer` applies to each order on placement, which restricts sellers to unlocked shares and requires buyers to be able to receive them. Until `closesAt`, `cancelOrder(windowId, orderId)` withdraws an order. In the gap between close and clearing, the company may use `removeOrder` to take out one problem order and return its escrow.

### Reaching the clearing price

Once `closesAt` has passed, along with any ROFR period, any account may call `clear(windowId)`. The contract proceeds as follows:

1. identify the prices at which the most shares match, counting as supply all sell orders limited at or under a price, and as demand all buy orders limited at or over it
2. within that range, select the price nearest the class's latest [Reference Valuation](/fundamentals/valuation-publishing.md), falling back to the midpoint of best ask and best bid when no valuation exists
3. lift the result to `reservePrice` if it sits under that level
4. allocate fills by price priority, sharing pro-rata between orders with an equal limit price
5. settle all fills atomically and hand back anything unfilled

All matched buyers pay one clearing price, and all matched sellers receive it, net of fees. Stablecoin locked above the amount owed goes back to the buyer. Rounding favors the contract in every case, so buyers round up, sellers round down, and the dust reaches the fee recipient, which means a window can never pay out beyond what it holds. A bid whose buyer fails the share class rules at clearing gets refunded and is not filled.

Sometimes a token delivery fails the recipient's rules at clearing, as when a seller's claim lapses while unfilled shares sit in escrow. The window keeps running instead of reverting: it retains those tokens on the owner's behalf and emits `DeliveryDeferred`. After passing the rules again, the owner calls `claimDeferred(shareToken)`. You can call `previewClearing(windowId)` at any moment to see the price and volume `clear` would give.

### An auction with real numbers

Consider a Series B Preferred window, with the latest Reference Valuation at 20.40 USDG per share, and this book:

| Seller | Shares offered | Lowest acceptable price |
| ------ | -------------- | ----------------------- |
| A      | 4,000          | 18.00                   |
| B      | 3,000          | 20.00                   |
| C      | 5,000          | 22.00                   |
| D      | 2,000          | 25.00                   |

| Buyer | Shares wanted | Highest acceptable price |
| ----- | ------------- | ------------------------ |
| X     | 6,000         | 24.00                    |
| Y     | 4,000         | 21.00                    |
| Z     | 3,000         | 19.00                    |

Here is what would match at each candidate:

| Candidate price | 19.00  | 20.00  | 21.00  | 22.00  |
| --------------- | ------ | ------ | ------ | ------ |
| Supply          | 4,000  | 7,000  | 7,000  | 12,000 |
| Demand          | 13,000 | 10,000 | 10,000 | 6,000  |
| Shares matched  | 4,000  | 7,000  | 7,000  | 6,000  |

Matching tops out at 7,000 shares anywhere between 20.00 and 21.00. That span contains the Reference Valuation of 20.40, so **20.40 USDG** becomes the clearing price.

On the sell side, A and B place all 7,000 of their shares. On the buy side, X holds the better limit and takes a full 6,000, leaving 1,000 for Y. Z's limit sits under the clearing price, so nothing fills for Z, and C and D receive their tokens back. The result is 7,000 shares changing hands for 142,800 USDG.

## How a tender runs

A tender sets the price ahead of time through `tenderPrice`. A holder tenders with `placeOrder(windowId, SELL, quantity, 0)`. On the other side, `placeOrder(windowId, BUY, quantity, 0)` is how the company or another buyer commits. If a limit price is supplied anyway, `tenderPrice` overrides it. The oversubscribed side, whichever it turns out to be, fills pro-rata. Reach for it when a price is settled in advance, as with a structured secondary sale or a company buyback.

## ROFR holders

Naming a `rofrHolder` gives the window a ROFR period following `closesAt`, with the indicative result readable on-chain from `previewClearing(windowId)`. The right holder has one chance during `rofrPeriod` to call `exerciseRofr(windowId, quantity)`. Doing so requires a stablecoin deposit that covers the quantity at the previewed price. When the period is over, `clear` serves the right holder ahead of others at the clearing price, limited by both the clearing volume and the deposit. Volume does not grow as a result, since ROFR fills take the place of other buyers, and leftover deposit goes back to the right holder. The `exemptVenues` of a class's `ROFRModule` usually contain the `LiquidityWindow`, given that the right is exercised inside the window.

## Price floors and company buybacks

Setting a `reservePrice` shields current holders against a disorderly outcome. A selected price under the reserve is replaced by the reserve. If nothing can trade at that level, the window clears without fills and all orders are returned.

Buybacks work by the company joining as a buyer. Its treasury bids in the ordinary way, and the Explorer labels that bid as a company order. Repurchased shares arrive in the treasury wallet, which needs verification just as any holder's wallet does, and the registrar may burn them later.

## Once a window has cleared

A window that traded any volume publishes its clearing price to the `ValuationOracle` as a Reference Valuation with the source `WINDOW_CLEARING`. Shares received by a buyer make up a separate lot, which begins whatever holding period the class has configured.

## Event reference

| Event                                                        | Trigger                                                                           |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------- |
| `WindowOpened(windowId, opensAt, closesAt)`                  | A window is opened by the company                                                 |
| `OrderPlaced(windowId, orderId, side, quantity, limitPrice)` | The contract accepts an order                                                     |
| `OrderCancelled(windowId, orderId)`                          | An order is pulled ahead of close, or the company removes it ahead of clearing    |
| `WindowCleared(windowId, clearingPrice, volume)`             | All fills in the window have finished settling                                    |
| `WindowCancelled(windowId)`                                  | The company calls off the window ahead of clearing, and all orders go back        |
| `RofrExercised(windowId, holder, quantity, price)`           | Stablecoin is put up by the right holder while the ROFR period runs               |
| `DeliveryDeferred(shareToken, owner, amount)`                | Tokens fail the recipient's rules on delivery and are retained for that recipient |
| `DeferredClaimed(shareToken, owner, amount)`                 | Deferred tokens are collected by their owner                                      |

Practical walkthroughs are available in [Put a Liquidity Window on the calendar](/walkthroughs/schedule-a-window.md) and [Sell your shares in a window](/walkthroughs/sell-your-shares.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.selcier.xyz/markets-and-capital/scheduled-windows.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
