> 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/quote-based-trading.md).

# Quote-based trading

Eligible holders can trade one to one using EIP-712 signed quotes, and the RFQSettlement contract settles each fill atomically under the share class's transfer rules.

Between Liquidity Windows, eligible holders can trade bilaterally and continuously using RFQ (request for quote). The process has two halves: one side signs a quote off-chain, and the other fills it on-chain through `RFQSettlement`. That contract applies the transfer rules and exchanges shares for stablecoin within one transaction.

Companies must switch RFQ on, since it starts disabled. The switch is per share class: behind the [Console](/the-platform/issuer-console.md) control sits `setEnabled(shareToken, true)`, sent from `ISSUER_ADMIN`. A fill is a normal share token transfer, so if the class has a `TransferWindowModule`, RFQ fills are confined to its scheduled trading periods as well.

## What a quote contains

Makers produce a quote by signing EIP-712 typed data. Four fields form the domain. `verifyingContract` is the `RFQSettlement` address, the chain id identifies the network, the name is `Selcier` and the version is `1`.

{% code title="Quote.sol" %}

```solidity
struct Quote {
    address maker;       // the signer of the quote
    address shareToken;  // the Selcier Share Token being traded
    uint8   side;        // 0 = maker sells shares, 1 = maker buys shares
    uint256 quantity;    // maximum shares, in raw token units
    uint256 price;       // stablecoin per share
    address stablecoin;  // settlement asset, USDG by default
    address taker;       // a specific counterparty, or address(0) for any eligible holder
    uint256 nonce;       // unique per maker, used for cancellation
    uint64  expiry;      // unix timestamp after which the quote cannot be filled
}
```

{% endcode %}

Distribution happens off-chain: Portfolio passes quotes between holders, and venues may use channels of their own. Setting `taker` to `address(0)` opens a quote to any wallet passing the transfer rules, whereas naming a `taker` restricts filling to that one address.

## Executing a fill

Takers use this function:

```solidity
function fill(Quote calldata quote, bytes calldata signature, uint256 quantity) external;
```

Passing a `quantity` under `quote.quantity` fills part of a quote, and partial fills can continue until nothing remains. From there, `RFQSettlement` goes through these stages:

1. confirm that the share class has RFQ enabled, the quote is unexpired, its nonce is uncancelled, the caller matches any named taker, and sufficient quantity is left
2. validate the maker's signature against the EIP-712 digest given by `hashQuote(quote)`, with EIP-1271 covering smart contract wallets
3. shift shares from seller to buyer through `transferFrom`, which triggers the token's complete rule check and a revert with `TransferNotAllowed(reasonCode)` on failure
4. within that one transaction, pay stablecoin in the opposite direction
5. take fees from the stablecoin leg, with the buyer paying the rounded-up price plus the buyer fee, the seller getting the rounded-down price less the seller fee, and the fee recipient collecting the gap
6. record the result in a `QuoteFilled(quoteHash, maker, taker, quantity, price)` event

`RFQSettlement` needs an approval from each side for the shares or stablecoin it moves. Holders using Portfolio get approvals handled within the flow, along with sponsored gas.

A purchase through RFQ creates a separate lot for the buyer. Any holding period set for the class begins at the fill.

## Withdrawing a quote

Cancelling the nonce removes one quote:

```solidity
function cancelQuote(uint256 nonce) external;
```

For bulk cancellation, a maker lifts their minimum valid nonce, and quotes with a lower nonce can no longer be filled:

```solidity
function invalidateNoncesBelow(uint256 newMinNonce) external;
```

`cancelQuote` emits `QuoteCancelled(maker, nonce)`, and `invalidateNoncesBelow` emits `NoncesInvalidated(maker, minNonce)` carrying the updated minimum. Reaching `expiry` also ends a quote, so a short expiry limits exposure with no cancellation transaction at all.

## Prices and public visibility

Because two parties negotiate an RFQ price between themselves, it never becomes a Reference Valuation. Fills remain public anyway. Each `QuoteFilled` event appears in the Explorer with price and quantity, identified only by wallet address. Inside Console, companies find RFQ activity for their share classes next to Liquidity Window results.

## Testing a trade first

`canTransfer` or `POST /v1/transfers/check` will tell you in advance whether a trade can settle, so use one before you sign or fill. A seller's holding period or a buyer's ownership cap then shows up as the matching [reason code](/build-on-selcier/transfer-outcomes.md), and no gas gets spent.

## Event reference

| Event                                                   | Trigger                                                     |
| ------------------------------------------------------- | ----------------------------------------------------------- |
| `QuoteFilled(quoteHash, maker, taker, quantity, price)` | All or part of a quote gets filled                          |
| `QuoteCancelled(maker, nonce)`                          | One quote is cancelled by its maker                         |
| `NoncesInvalidated(maker, minNonce)`                    | A maker invalidates all nonces under a minimum              |
| `Transfer`                                              | The share token records shares passing from seller to buyer |

[How trades settle](/markets-and-capital/how-trades-settle.md) explains settlement and fees for all liquidity routes.


---

# 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/quote-based-trading.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.
