> For the complete documentation index, see [llms.txt](https://docs.v2.pod.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.v2.pod.network/guides-references/references/applications-precompiles/orderbook.md).

# Orderbook

The **Orderbook precompile** is the on-chain execution surface for native markets — both **spot** and **perpetual**. The same contract, calls, and balances are shared across both market types; a market's behavior is determined by the `MarketType` set at creation.

Use it for **placing/canceling/updating orders**, **moving funds between accounts**, **opening leveraged perpetual positions**, **arming take-profit / stop-loss triggers**, and **reading balances and order state**.

{% hint style="info" %}
**Orderbook precompile address:** `0x50d0000000000000000000000000000000000002`
{% endhint %}

{% hint style="warning" %}
**All timestamps sent to the orderbook are in microseconds**, not milliseconds or seconds. This applies to every `deadline` and `ttl` on this precompile.
{% endhint %}

{% hint style="info" %}
**Orders are identified by a computed `order_id`, not the tx hash.** A resting order is keyed by

```
order_id = keccak256(abi.encode(address signer, uint64 nonce, uint32 sequence))
```

where `signer` is the order owner, `nonce` is the `submitOrder` transaction's nonce, and `sequence` is the intent's position inside a `submitBatch` envelope (`0` for a standalone `submitOrder`). Wherever a call references an existing order — `cancel(canceledOrder, …)` and `update(updatedOrder, …)` — pass this `order_id`. You can compute it yourself with the formula above, or read it back from `ob_getOrders`, which returns it as `order_id` (the originating `submitOrder` tx hash is exposed separately as `tx_hash`).
{% endhint %}

{% hint style="warning" %}
**`deadline`** is the latest batch the intent is allowed to be included in — the intent can land in any batch up to and including the one whose end matches `deadline`. It must be aligned to the market's `auction_interval` (a multiple of it), or the validator rejects the intent with `"CLOB validation failed: Deadline is not aligned to auction interval"`. Compute it as:

```
deadline = ceil((now + LAG) / auction_interval) * auction_interval
```

`LAG` is the headroom you add to `now` so the intent reaches enough validators before its target batch. It is capped at **10 minutes**; aim for **at least 1 minute** under normal conditions, smaller when you want to target a specific upcoming batch.

The alignment rule applies to **every deadline-bearing call** on this precompile — `transfer` as much as orders, cancels, updates and triggers. All of them pass through the same validator check, so an unaligned transfer deadline is rejected just like an unaligned order deadline.

See [Batch Deadline](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/orderbook.md#batch-deadline) in the protocol reference for the full discussion of `deadline` semantics and the trade-offs around `LAG`.
{% endhint %}

### Order flags

`submitOrder` carries an order's boolean properties in a single `uint8 flags` bitfield rather than one `bool` argument per property. OR together the bits you want; `0` is a plain resting limit order.

| Bit | Value  | Flag          | Meaning                                                                                                                          |
| --- | ------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| 0   | `0x01` | `REDUCE_ONLY` | The order may only reduce the submitter's existing position. Perp markets only.                                                  |
| 1   | `0x02` | `IOC`         | Immediate-or-cancel: whatever does not match in the order's batch is cancelled at the end of it instead of resting on the book.  |
| 2   | `0x04` | `POST_ONLY`   | Add-liquidity-only: the order rests, but may not trade in the batch that admitted it. See [Post-only orders](#post-only-orders). |

Combinations are checked when the intent is validated:

* `IOC | POST_ONLY` is **rejected** (`post-only order cannot be immediate-or-cancel`) — IOC demands a fill in the admitting batch, post-only forbids one.
* `POST_ONLY` on a `Market` order is **rejected** (`post-only is not valid for a market order`) — a market order has no resting price, so it has nothing to post at.
* `REDUCE_ONLY | POST_ONLY` is fine, as is any other combination.
* Market orders must set `IOC` (`market orders must be immediate-or-cancel`).

{% hint style="warning" %}
**Bits 3–7 must be zero.** Calldata carrying a flag bit the network does not recognise is rejected, not masked off — so an intent is never executed with a property silently dropped from it. Future order properties arrive as new bits here rather than as another overload.
{% endhint %}

{% hint style="info" %}
**`submitOrder` is overloaded, and only the `flags` form is current.** Encode against the exact signature — the selector differs per overload:

| Signature                                                             | Selector     | Status                                                                                                                          |
| --------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `submitOrder(bytes32,int256,uint256,uint8,uint128,uint128,uint8)`     | `0x1e416275` | **Current.** The `flags` form; the only one that can request post-only.                                                         |
| `submitOrder(bytes32,int256,uint256,uint8,uint128,uint128,bool,bool)` | `0x435f7e71` | Deprecated. The old `reduceOnly, ioc` pair, still accepted; equivalent to setting bit 0 from `reduceOnly` and bit 1 from `ioc`. |

The `flags` overload can only be decoded by nodes that ship it, so a client that must also work against a network running an older build can keep emitting the deprecated `bool, bool` form — it is accepted unchanged, and it simply cannot request post-only.

`submitTrigger` still takes `bool reduceOnly, bool ioc` and has no `flags` argument, so a trigger's synthetic order cannot be post-only.
{% endhint %}

### Post-only orders

A post-only order is guaranteed to **add** liquidity: it rests on the book and never takes from it on the way in. Set `POST_ONLY` (`0x04`) in `flags`.

Because pod matches in discrete batch auctions rather than on arrival, "would this order cross the book right now?" is the wrong question — every intent in a batch is matched together, so two orders that arrive in the same batch and match each other are *both* takers. The guarantee is therefore expressed against the batch:

> **A post-only order may not trade in the batch that admitted it.** From the next batch onwards it is an ordinary resting maker and matches normally.

What that means in practice:

* The order enters the book immediately and is reported `active`, like any other resting order.
* If it would have traded **in that first batch**, it is removed from the book instead. The removal is terminal and never partial — a refusal never leaves a post-only order half-filled — and it is reported with the terminal status `post_only_refused`, which is distinct from `canceled` so you can tell a refusal from a cancel you sent yourself.
* If it would **not** have traded in that batch, nothing happens to it: it rests, and can be matched from the next batch on.
* If another order at the same price with better queue priority absorbs the crossing liquidity first, your post-only order simply rests — it never had the opportunity to take, so there is nothing to refuse.
* Two post-only orders admitted in the same batch that cross only each other are **both** refused. Neither took resting liquidity, but each would have taken from the other.

**Amendments re-arm the guarantee.** An `update` that re-queues the order — a price change, or a size increase — makes it a newcomer again, so it may not trade for the rest of *that* batch and can be refused in it (for example, when you reprice it onto a crossing level). An update that only *decreases* the size keeps its queue priority and its original admission batch, so it goes on matching normally.

### Transfers between accounts

`transfer` moves `amount` of `token` from the signer's balance to another account's balance. Both sides are accounts on Pod, so the funds stay on the network and the recipient can trade them immediately.

The call is **global, not orderbook-bound**: it names no `orderbookId`, because the balance it moves is shared across every market. It works standalone and as a `submitBatch` sub-intent.

**What is checked before attestation.** The transaction is rejected outright — it never lands — when:

* `amount` is zero.
* `recipient` is the signer. It would burn a nonce and move nothing.
* `recipient` is the zero address. Burning has to be deliberate, not a typo.
* `recipient` is a system precompile.
* `deadline` is unaligned to the auction interval, or points at a batch that has already executed.

The sender's balance is deliberately **not** checked there: pending fills can raise it before the batch executes. It is checked against the withdrawable balance when the batch executes, and a transfer the balance does not cover is reported as a failed outcome rather than rejected as a transaction.

{% hint style="warning" %}
**`transfer` cannot be delegated.** It is refused as the inner call of a `delegated` wrapper, and refused again when it appears inside a `delegated(submitBatch([…]))`. Pinning the recipient to the master — what makes a delegated call safe elsewhere — would force a self-transfer here, which moves nothing, so the envelope is refused instead. Allowing it would make a leaked delegate key worth as much as a leaked master key for the whole spendable balance.
{% endhint %}

**Following a transfer.** Every transfer has an id derived exactly like an `order_id`, so you can compute it before you submit:

```
transfer_id = keccak256(abi.encode(address signer, uint64 nonce, uint32 sequence))
```

`sequence` is the intent's position inside a `submitBatch` envelope, `0` for a standalone `transfer`. A transfer has no receipt of its own — it settles inside the solver's `submitSolutions` transaction — so this channel is the only place its fate appears:

| Surface                                              | Use                                                                                                                                                                                                                                                        |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eth_subscribe("pod_transfers", { account, since })` | Live outcomes, one array per tick. `account` matches **either** side, so a recipient hears the credit as readily as a sender hears the debit. Each entry carries `transfer_id`, `from`, `to`, `token`, `amount` (18 decimals), `error` and `timestamp_us`. |

`error` is absent when the funds moved, and otherwise names why they did not:

* `insufficient_balance` — the sender's withdrawable balance did not cover it when the batch executed.
* `recipient_not_resident` — the recipient's account was not resident when the tick ran, so the credit had nowhere to land.
* `not_included` — the solver left the intent out of the solution its deadline pointed at.

All three mean **nothing moved on either side**. The nonce is spent either way, so retrying means a new transaction, which gets a new `transfer_id`.

### Batch envelope

`submitBatch` packs several single-intent calls (1–64) into a single signed transaction that lands atomically in one auction tick. Each entry in `inner` is the full ABI-encoded calldata of a single-intent function on **this** precompile (`submitOrder`, `cancel`, `update`, `submitTrigger`, `transfer`, …) — encoded exactly as a standalone call, including its 4-byte selector. Every sub-intent **must carry the same `deadline`** (the uniform-deadline invariant), and nested batches are rejected. For the full rules and a worked example, see [Submit a batch order](/guides-references/guides/submit-a-batch-order.md).

### Delegation envelope

`delegated` lets a **delegate** key perform an orderbook call on behalf of a **master** account. The transaction is signed by the delegate; `signature` is the master's 65-byte `r ‖ s ‖ v` EIP-712 signature over `DelegationAuth { delegate, validUntil }` (domain `{ name: "pod delegation", version: "1", chainId }`), where `delegate` must equal the transaction's signer, and `inner` is the full ABI-encoded calldata of the wrapped call, including its 4-byte selector. The certificate is verified statelessly on every transaction — no registration, no on-chain state — and the intent is accepted only while `validUntil >= deadline` of the inner call (both in microseconds).

The inner intent is **owned by the master** (balances, resting-order owner, cancel/update target) while its `order_id` keys on the delegate (the tx signer). Any deadline-bearing call can be wrapped — single intents or a whole `submitBatch` — but `submitSolutions`, the market-lifecycle calls (`createMarket`, `disableMarket`, `settleMarket`, `updateMarketOracle`), and nested `delegated` are rejected, and so is `transfer`, both directly and inside a wrapped `submitBatch` (see [Transfers between accounts](#transfers-between-accounts)). Delegated calls are gas-exempt. For the concept and security model see [Key Delegation](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/key-delegation.md) in the protocol reference; for a worked example see [Delegate a trading key](/guides-references/guides/delegate-a-trading-key.md).

### Market lifecycle

Markets are created, halted, settled and re-pointed at their price feeds with four **admin-only** calls on this precompile. `createMarket` may be sent by any address on the network's market-admin allowlist and makes the signer the market's **owner**; the other three are accepted only from that owner. All four carry a `deadline` like every other intent, ride the solver's solutions, and are applied inside a batch, so every node moves the market through the same states at the same tick.

| Call                                                                | Effect                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createMarket(params, deadline, liveAt)`                            | Mints a market from a self-describing `MarketParams`. The orderbook id is **assigned by the protocol** (a counter) and returned as `bytes32`; nothing lets the caller pick it. The market is born `pending` at `deadline` and goes `active` at the first batch at or after `liveAt` that has seen an oracle price (spot markets flip unconditionally).                          |
| `disableMarket(orderbookId, deadline, disableAt)`                   | Schedules a halt. `disableAt` must be tick-aligned and at least the network's minimum notice past `deadline`. Until it, the book trades normally so users can exit; from that tick the market is `disabled` and **every** intent on it is refused. Resting orders and positions stay where they are, and the oracle price of the halt tick is captured as the settlement price. |
| `settleMarket(orderbookId, deadline)`                               | Closes a `disabled` market: every resting order is refunded and every position closed at the captured settlement price. The market stays listed as `settled` for history. Disable to settle is one-way; a "revived" market is a new `createMarket`.                                                                                                                             |
| `updateMarketOracle(orderbookId, deadline, oracleSpec, midSources)` | Rebinds the feeds of an `active` or `pending` market without touching orders or positions. `oracleSpec` is the comma-separated `<source>/<asset>` list with the first entry primary; empty is legal only for spot. A perp created against a feed that never served a price stays `pending` until this call points it at one.                                                    |

`ob_getMarkets` reports every market with its lifecycle `status` (`pending`, `active`, `disabled`, `settled`) plus `live_at`, `disable_at` and `settlement_price` when they apply, so a client can hide a halted book or warn users during a notice window.

{% hint style="warning" %}
**Intents due after a scheduled halt are refused up front.** Once `disable_at` is set, any order, cancel or update on that book whose `deadline` lies past the halt is rejected at submission with `market disables at …: an intent with deadline … could never execute`. Bots that stamp long deadlines should shorten them, or drop the book, as soon as `disable_at` appears, and a `submitBatch` that spans several books fails as a whole when one sub-intent trips this rule.
{% endhint %}

The lifecycle calls cannot be wrapped in `delegated` or carried inside `submitBatch`, and they pay flat gas with no exemption.

### Solidity interface (ABI)

```solidity
/**
 * @title Orderbook
 * @notice A central limit order book for trading assets.
 * @dev Handles order placement, cancellation, and fund management.
 */
contract Orderbook {

    enum Side { Buy, Sell }
    enum OrderType { Limit, Market }
    enum MarketType { Spot, Perp }

    // Trigger kind for a TP/SL trigger (perp markets only).
    enum TriggerType { TakeProfit, StopLoss }

    // Exposure-association for a trigger.
    // None: standalone — removed only by a user cancel, TTL expiry, or its own fire.
    // Asset: binds the trigger to the asset the market type implies — on perp
    //        markets the venue cancels the armed trigger (and any resting synthetic
    //        order it already produced) at the end of the batch in which the
    //        bidder's position on the pair reaches size 0; on spot markets it
    //        cancels the armed trigger when the bidder's base-asset holdings hit 0.
    //        (Renamed from `Position`; same ABI value — older nodes report it as
    //        `position` in RPC responses.)
    enum TriggerGrouping { None, Asset }

    // --- Order Management ---

    // Bits of `submitOrder`'s `flags` argument. OR together the ones you want;
    // 0 is a plain resting limit order. Bits 3-7 are unassigned and MUST be
    // zero — a node rejects calldata carrying a flag bit it does not know
    // rather than ignoring it. New order properties become a new bit here.
    uint8 constant REDUCE_ONLY = 0x01; // perp markets only
    uint8 constant IOC         = 0x02;
    uint8 constant POST_ONLY   = 0x04;

    /**
     * Submits a new order to the orderbook.
     * The direction of the trade (Bid/Ask) is determined by the sign of the size.
     * @param orderbookId The unique identifier of the specific market (e.g., ETH-USDC).
     * @param size The size of the order. Positive (+) for Buy/Bid, Negative (-) for Sell/Ask.
     * @param price The limit price for the order.
     * @param orderType The order type (Limit or Market).
     * @param deadline The timestamp limit for this order to be included in a batch in microseconds. Must be a multiple of the market's `auction_interval`.
     * @param ttl The "Time To Live" duration in microseconds; how long the order remains active in the book.
     * @param flags Bitfield of the order's properties — REDUCE_ONLY, IOC, POST_ONLY (see above).
     *        IOC | POST_ONLY is rejected, as is POST_ONLY on a Market order.
     */
    function submitOrder(
        bytes32 orderbookId,
        int256 size,
        uint256 price,
        OrderType orderType,
        uint128 deadline,
        uint128 ttl,
        uint8 flags
    ) public {}

    /**
     * @notice Deprecated: the pre-`flags` form of `submitOrder`, kept so calldata
     *         written against it still decodes. It cannot request POST_ONLY.
     *         Equivalent to the current form with bit 0 set from `reduceOnly`
     *         and bit 1 from `ioc`.
     */
    function submitOrder(
        bytes32 orderbookId,
        int256 size,
        uint256 price,
        OrderType orderType,
        uint128 deadline,
        uint128 ttl,
        bool reduceOnly,
        bool ioc
    ) public {}

    /**
     * @notice Cancels an existing open order.
     * @param orderbookId The unique identifier of the market the order belongs to.
     * @param canceledOrder The `order_id` of the order to cancel — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id` by
     *        `ob_getOrders`. This is NOT the `submitOrder` tx hash.
     * @param deadline The Unix timestamp after which this cancellation request is invalid in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function cancel(
        bytes32 orderbookId,
        bytes32 canceledOrder,
        uint128 deadline
    ) public {}

    /**
     * @notice Updates an existing open order.
     * @param orderbookId The unique identifier of the market the order belongs to.
     * @param updatedOrder The `order_id` of the order to update — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id` by
     *        `ob_getOrders`. This is NOT the `submitOrder` tx hash.
     * @param newSize The new size for the order.
     * @param newPrice The new price for the order.
     * @param token The token used to cover any additional collateral required by the update.
     * @param deadline The Unix timestamp after which this update is invalid in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function update(
        bytes32 orderbookId,
        bytes32 updatedOrder,
        uint256 newSize,
        uint256 newPrice,
        address token,
        uint128 deadline
    ) public {}

    // --- Data Retrieval ---

    /**
     * @notice Token balance for an account, as a signed integer.
     * @param token The address of the token to check.
     * @param account The address of the account to check.
     * @return Native USD: cash adjusted for unsettled funding (negative if the account is underwater).
     *         Other tokens: the raw spot balance.
     */
    function balanceOf(address token, address account) public view returns (int256) {}

    /**
     * @notice Withdrawable balance for an account.
     * @param token The address of the token to check.
     * @param account The address of the account to check.
     * @return Native USD: perps equity minus reserved initial margin (never negative).
     *         Other tokens: the raw spot balance (no margin deducted).
     */
    function withdrawableBalance(address token, address account) public view returns (uint256) {}

    // --- Fund Management ---

    /**
     * @notice Moves tokens from the caller's balance to another account's
     *         balance. Both sides are accounts on Pod.
     * @dev Global rather than orderbook-bound: the balance it moves is shared
     *      across every market, so there is no `orderbookId`. Valid standalone
     *      and as a `submitBatch` sub-intent, but **never** under `delegated` —
     *      including inside a delegated `submitBatch`. Rejected before
     *      attestation when `amount` is zero, when `recipient` is the caller,
     *      the zero address or a system precompile, or when `deadline` is
     *      unaligned or already executed. The caller's balance is checked at
     *      execution instead, so an insufficient balance arrives as a
     *      `pod_transfers` outcome rather than as a rejected transaction. See
     *      "Transfers between accounts" above.
     * @param token The address of the token to move.
     * @param recipient The account to credit, on Pod.
     * @param amount The amount to move, in Pod's 18 decimals. Must be non-zero.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function transfer(
        address token,
        address recipient,
        uint256 amount,
        uint128 deadline
    ) public {}

    // --- TP/SL triggers (perp markets only) ---

    /**
     * @notice Arms a take-profit / stop-loss trigger on a perp market.
     * @dev The trigger rests on the venue until it fires, is cancelled, or its TTL
     *      expires. It fires when the pair's mark price crosses `triggerPrice` in the
     *      direction implied by the order side (sign of `size`) and `triggerType`:
     *
     *        | Side | Type       | Fires when             |
     *        |------|------------|------------------------|
     *        | Buy  | TakeProfit | mark price <= trigger  |
     *        | Buy  | StopLoss   | mark price >= trigger  |
     *        | Sell | TakeProfit | mark price >= trigger  |
     *        | Sell | StopLoss   | mark price <= trigger  |
     *
     *      On firing the venue emits a synthetic limit order (price `limitPrice`,
     *      size `size`) that is admitted into the matching batch like any other order.
     * @param orderbookId The unique identifier of the perp market.
     * @param size The signed base amount of the order produced when the trigger fires.
     *        Positive (+) for Buy/long, negative (-) for Sell/short.
     * @param limitPrice The limit price of the synthetic order produced when the trigger fires.
     * @param triggerPrice The mark-price threshold that fires the trigger.
     * @param triggerType TakeProfit or StopLoss.
     * @param grouping Whether the trigger is bound to the bidder's exposure on the pair (see TriggerGrouping).
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     * @param ttl The "Time To Live" duration in microseconds; how long the armed trigger remains active.
     * @param reduceOnly If true, the synthetic order will only reduce an existing position.
     * @param ioc If true, the synthetic order is Immediate-Or-Cancel: any unmatched portion is cancelled at the end of the batch it fires in.
     */
    function submitTrigger(
        bytes32 orderbookId,
        int256 size,
        uint256 limitPrice,
        uint256 triggerPrice,
        TriggerType triggerType,
        TriggerGrouping grouping,
        uint128 deadline,
        uint128 ttl,
        bool reduceOnly,
        bool ioc
    ) public {}

    /**
     * @notice Cancels an armed trigger.
     * @param orderbookId The unique identifier of the market the trigger belongs to.
     * @param triggerOrder The `order_id` of the trigger to cancel — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id`
     *        by `ob_getTriggers`. This is NOT the `submitTrigger` tx hash.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function cancelTrigger(
        bytes32 orderbookId,
        bytes32 triggerOrder,
        uint128 deadline
    ) public {}

    /**
     * @notice Updates an armed trigger. The `grouping` mode is immutable and cannot be changed.
     * @param orderbookId The unique identifier of the market the trigger belongs to.
     * @param triggerOrder The `order_id` of the trigger to update — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id`
     *        by `ob_getTriggers`. This is NOT the `submitTrigger` tx hash.
     * @param newSize The new signed base amount of the order produced when the trigger fires.
     * @param newLimitPrice The new limit price of the synthetic order.
     * @param newTriggerPrice The new mark-price threshold that fires the trigger.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function updateTrigger(
        bytes32 orderbookId,
        bytes32 triggerOrder,
        int256 newSize,
        uint256 newLimitPrice,
        uint256 newTriggerPrice,
        uint128 deadline
    ) public {}

    // --- Batch envelope ---

    /**
     * @notice Carries multiple single-intent calls in one signed transaction.
     * @dev Each `inner[i]` is the full ABI-encoded calldata of one of the other
     *      single-intent functions on this contract — `submitOrder`, `cancel`,
     *      `update`, `submitTrigger`, `cancelTrigger`, `updateTrigger`, or
     *      `transfer`. The whole envelope is atomic: it lands in a
     *      single auction tick, so every sub-intent must carry the **same**
     *      `deadline`. Constraints (enforced at validation):
     *      - 1 to 64 sub-intents (the cap is configurable by the operator).
     *      - All sub-intents share one `deadline` (uniform-deadline invariant).
     *      - Nested batches are rejected — `inner[i]` may not itself be a `submitBatch`.
     * @param inner The ABI-encoded calldata of each sub-intent, in order.
     */
    function submitBatch(bytes[] calldata inner) public {}

    // --- Market lifecycle (admin-only; see "Market lifecycle" above) ---

    /**
     * @notice Full self-describing market definition for `createMarket`. The
     *         perp-only fields are ignored for `MarketType.Spot`.
     * @dev `oracleSpec` is the comma-separated `"<source>/<asset>"` list with the
     *      first entry primary; required for `Perp`, empty for `Spot`.
     *      `midSources` are external mid-price feeds and may be empty. Durations
     *      are microseconds; amounts and prices are 1e18-scaled.
     */
    struct MarketParams {
        address baseToken;
        address quoteToken;
        string baseSymbol;
        string quoteSymbol;
        string baseName;
        string quoteName;
        MarketType marketType;
        uint256 tickPrecision;
        uint256 lotSize;
        uint256 minNotional;
        uint256 maxPrice;
        uint256 maxPositionSize;
        string oracleSpec;
        string[] midSources;
        // -- perp-only --
        uint32 maxLeverage;
        int32 interestRate;
        uint32 maxFundingRate;
        uint32 maxPremium;
        uint32 markPriceClamp;
        uint64 fundingWindowMicros;
        uint64 emaWindowMicros;
        uint256 impactNotional;
    }

    /**
     * @notice Creates a market owned by the signer, who must be a market admin.
     * @dev The orderbook id is protocol-assigned and returned; it is never chosen
     *      by the caller. `deadline` is the inclusion batch (microseconds) that
     *      creates the market in `pending` status; `liveAt` (>= `deadline`,
     *      tick-aligned) is the batch from which it may go `active` — at the
     *      first executed batch at/after it that has seen an oracle price, or
     *      unconditionally for a spot market.
     */
    function createMarket(
        MarketParams calldata params,
        uint128 deadline,
        uint128 liveAt
    ) public returns (bytes32) {}

    /**
     * @notice Schedules a halt of `orderbookId`. Owner-only.
     * @dev `disableAt` must be tick-aligned and at least the network's minimum
     *      notice past `deadline`. The book trades normally until the halt; from
     *      that batch every intent on it is refused and the oracle price is
     *      captured as the settlement price.
     */
    function disableMarket(bytes32 orderbookId, uint128 deadline, uint128 disableAt) public {}

    /**
     * @notice Settles a `disabled` market: refunds every resting order and closes
     *         every position at the captured settlement price. Owner-only.
     */
    function settleMarket(bytes32 orderbookId, uint128 deadline) public {}

    /**
     * @notice Rebinds the oracle feeds of an `active` or `pending` market.
     *         Owner-only.
     * @dev `oracleSpec` is the comma-separated `"<source>/<asset>"` list, first
     *      entry primary; empty is legal only for a spot market, a perp must keep
     *      one. Orders, positions and the mark price are untouched.
     */
    function updateMarketOracle(
        bytes32 orderbookId,
        uint128 deadline,
        string calldata oracleSpec,
        string[] calldata midSources
    ) public {}

    // --- Delegation envelope ---

    /**
     * @notice Performs an orderbook call on behalf of a master account. The
     *         transaction is signed by the delegate; the master's authorization
     *         travels inside the call and is verified on every transaction.
     * @dev `signature` is the master's 65-byte `r‖s‖v` EIP-712 signature (v = 27/28)
     *      over `DelegationAuth { address delegate; uint64 validUntil; }` with domain
     *      `{ name: "pod delegation", version: "1", chainId }`, where `delegate` must
     *      equal the transaction's signer. Constraints (enforced at validation):
     *      - `validUntil` must be >= the inner call's `deadline` (both microseconds).
     *      - `inner` must be a deadline-bearing call — a single intent or a
     *        `submitBatch`. `submitSolutions`, the market-lifecycle calls
     *        (`createMarket`, `disableMarket`, `settleMarket`,
     *        `updateMarketOracle`), and nested `delegated` are rejected; view
     *        functions cannot be wrapped.
     *      - `transfer` is rejected, both as `inner` and inside a wrapped
     *        `submitBatch`: a delegate must not be able to name the recipient.
     *      The inner intent is owned by `master` (balances, resting-order owner,
     *      cancel/update target), while its `order_id` keys on the delegate
     *      (the tx signer). Delegated calls are gas-exempt.
     * @param master The account the wrapped call is performed on behalf of.
     * @param validUntil Expiry of the delegation certificate, in microseconds.
     * @param signature The master's 65-byte EIP-712 signature authorizing the delegate.
     * @param inner The full ABI-encoded calldata of the wrapped call, including its selector.
     */
    function delegated(
        address master,
        uint64 validUntil,
        bytes calldata signature,
        bytes calldata inner
    ) public {}
}
```


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.v2.pod.network/guides-references/references/applications-precompiles/orderbook.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
