# React

The React SDK gives you Omniston as ready-to-use hooks on top of the base SDK. In `v1beta8`, the main integration flow is:

1. prepare `settlementParams` for the settlement methods you want to allow
2. subscribe to RFQ updates and select a quote from the stream
3. branch on `quote.settlementData?.$case`
4. build and sign either a swap flow or an order flow
5. track the resulting settlement

An end-to-end open source reference implementation is also available in our example app: [examples/react-app](https://github.com/ston-fi/omniston-sdk/tree/main/examples/react-app)

Migrating an existing app from `@ston-fi/omniston-sdk-react@0.7` and Omniston API `v1beta7`? Use the [React SDK v0.7 to v0.8 migration guide](/developer-section/omniston/sdk/migration-v0.7-to-v0.8.md).

## Installation

* [Source code](https://github.com/ston-fi/omniston-sdk/tree/main/packages/omniston-sdk-react)
* [@ston-fi/omniston-sdk-react](https://www.npmjs.com/package/@ston-fi/omniston-sdk-react) NPM Package

Install the SDK in your project:

```sh
npm install @ston-fi/omniston-sdk-react
```

## Creating an instance

Create an `Omniston` instance, then provide it through `OmnistonProvider`.

```tsx
import { Omniston, OmnistonProvider } from "@ston-fi/omniston-sdk-react";

const omniston = new Omniston({
  apiUrl: "wss://omni-ws.ston.fi",
});

export function AppProviders({ children }: React.PropsWithChildren) {
  return <OmnistonProvider omniston={omniston}>{children}</OmnistonProvider>;
}
```

If you are integrating against the **sandbox** environment, use:

```tsx
const omniston = new Omniston({
  apiUrl: "wss://omni-ws-sandbox.ston.fi",
});
```

If your application already uses a TanStack Query client, you can pass it to `OmnistonProvider` to reuse the same client instead of creating a separate one:

```tsx
export function AppProviders({ children }: React.PropsWithChildren) {
  return (
    <QueryClientProvider client={queryClient}>
      <OmnistonProvider omniston={omniston} queryClient={queryClient}>
        {children}
      </OmnistonProvider>
    </QueryClientProvider>
  );
}
```

## Preparing settlement params

Before requesting a quote, decide which settlement methods you want the resolver network to consider. In `v1beta8`, this is controlled through `settlementParams`, where each item enables one settlement branch.

Use swap-only when you want classic swap execution, typically for simple TON flows. Use order-only when you want order settlement only, for example when your application is built specifically around signed orders or HTLC flows. Use both when you want Omniston to return the best available option and decide later based on the returned quote.

```ts
import {
  type SettlementParams,
  type SwapSettlementParams,
  type OrderSettlementParams,
} from "@ston-fi/omniston-sdk-react";

const swapOnlySettlementParams: SettlementParams[] = [
  {
    params: {
      $case: "swap",
      value: {
        maxPriceSlippagePips: 10_000, // 1%
        flexibleIntegratorFee: true,
      } satisfies SwapSettlementParams,
    },
  },
];

const orderOnlySettlementParams: SettlementParams[] = [
  {
    params: {
      $case: "order",
      value: {} satisfies OrderSettlementParams,
    },
  },
];

const swapAndOrderSettlementParams: SettlementParams[] = [
  ...swapOnlySettlementParams,
  ...orderOnlySettlementParams,
];
```

## Quote receiving based on parameters

After preparing settlement params, request a quote and subscribe to the RFQ stream. `useRfq()` is backed by the same RFQ stream as `requestForQuote()`, so your integration should handle it as a stream of updates rather than as a one-shot request.

```tsx
import { useRfq, type AssetId, type QuoteRequest } from "@ston-fi/omniston-sdk-react";

const inputAsset: AssetId = {
  chain: {
    $case: "ton",
    value: {
      kind: {
        $case: "jetton",
        value: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs", // example: USDT
      },
    },
  },
};

const outputAsset: AssetId = {
  chain: {
    $case: "ton",
    value: {
      kind: {
        $case: "jetton",
        value: "EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO", // example: STON
      },
    },
  },
};

const quoteRequest: QuoteRequest = {
  inputAsset,
  outputAsset,
  amount: {
    $case: "inputUnits",
    value: "1000000",
  },
  settlementParams: swapAndOrderSettlementParams,
};

function QuoteStream() {
  const { data: event, error } = useRfq(quoteRequest);

  if (error) {
    return <div>RFQ stream failed: {String(error)}</div>;
  }

  switch (event?.$case) {
    case "ack":
      return <div>RFQ id: {event.value.rfqId}</div>;
    case "quoteUpdated":
      return <div>Received quote: {event.value.quoteId}</div>;
    case "noQuote":
      return <div>No quote available for RFQ {event.rfqId}</div>;
    case "unsubscribed":
      return <div>Quote stream was closed by server</div>;
    default:
      return <div>Waiting for quote...</div>;
  }
}
```

## Settlement flows

Once you have selected a `quote` from the RFQ stream, branch on `quote.settlementData?.$case` and follow the corresponding settlement flow.

### Swap quotes

#### Transaction building and sign

Once you have selected a `quote` from the stream and it uses swap settlement, build a TON transaction with `useTonBuildSwap()`, then pass the resulting messages to the wallet or signing library you use in your application.

```tsx
import {
  useTonBuildSwap,
  type ChainAddress,
  type QuoteOfType,
} from "@ston-fi/omniston-sdk-react";

const traderAddress: ChainAddress = {
  chain: {
    $case: "ton",
    value: "EQ...",
  },
};

function SwapBuild({ quote }: { quote: QuoteOfType<"swap"> }) {
  const { data: swapTx } = useTonBuildSwap({
    quoteId: quote.quoteId,
    transferSrcAddress: traderAddress,
    refundSrcAddress: traderAddress,
    gasExcessAddress: traderAddress,
    traderDstAddress: traderAddress,
  });

  // `swapTx?.messages` should be signed and sent with the TON wallet package used by your project.
}
```

#### Tracking

After the swap transaction is sent, track the swap with `swapTrack()`. You need the `quoteId`, the trader wallet address, and an identifier that lets Omniston find the outgoing transaction.

```tsx
import { useEffect } from "react";
import { useOmniston, type ChainAddress, type Quote } from "@ston-fi/omniston-sdk-react";

function SwapTracking({
  quote,
  traderAddress,
  outgoingTxQuery,
}: {
  quote: Quote;
  traderAddress: ChainAddress;
  outgoingTxQuery: string;
}) {
  const omniston = useOmniston();

  useEffect(() => {
    let unsubscribe = () => {};

    void omniston
      .swapTrack({
        quoteId: quote.quoteId,
        traderAddress,
        outgoingTxQuery,
      })
      .then((stream) => {
        const subscription = stream.subscribe({
          next(event) {
            switch (event?.$case) {
              case "awaitingTransfer":
                console.log("Waiting for transfer");
                break;
              case "progress":
                console.log("Swap status:", event.value.status);
                break;
              case "unsubscribed":
                console.log("Swap tracking stream closed");
                break;
            }
          },
        });

        unsubscribe = () => subscription.unsubscribe();
      });

    return () => unsubscribe();
  }, [omniston, quote.quoteId, traderAddress, outgoingTxQuery]);

  return null;
}
```

### Order quotes

#### Transaction building and sign

Once you have selected a `quote` from the stream and it uses order settlement, the build-and-sign flow depends on the source chain.

For TON order settlement, build an escrow transfer and sign the resulting TON messages:

```tsx
import {
  useTonBuildEscrowTransfer,
  type QuoteOfType,
} from "@ston-fi/omniston-sdk-react";

function TonOrderBuild({ quote }: { quote: QuoteOfType<"order"> }) {
  const { data: tonOrderTx } = useTonBuildEscrowTransfer({
    quoteId: quote.quoteId,
    ownerSrcAddress: traderAddress,
    transferSrcAddress: traderAddress,
    refundSrcAddress: traderAddress,
    gasExcessAddress: traderAddress,
    traderDstAddress: traderAddress,
  });

  // `tonOrderTx?.messages` should be signed and sent with the TON wallet package used by your project.
}
```

For EVM order settlement, build the order payload, sign it with your EVM wallet, and register the signed order with Omniston:

```tsx
import {
  useEvmBuildOrderPayload,
  useOmniston,
  isHtlcOrderQuote,
  type ChainAddress,
  type HtlcSecrets,
  type QuoteOfType,
} from "@ston-fi/omniston-sdk-react";

const evmTraderAddress: ChainAddress = {
  chain: {
    $case: "base",
    value: "0x...",
  },
};

function EvmOrderBuild({ quote }: { quote: QuoteOfType<"order"> }) {
  const omniston = useOmniston();

  const htlcSecrets: HtlcSecrets | undefined = isHtlcOrderQuote(quote)
    ? {
        secretMode: {
          $case: "provided",
          value: {
            hashes: myGeneratedHashlocks,
          },
        },
      }
    : undefined;

  const { data: orderPayload } = useEvmBuildOrderPayload({
    quoteId: quote.quoteId,
    ownerSrcAddress: evmTraderAddress,
    traderDstAddress: traderAddress,
    htlcSecrets,
    traderDstDiscloseAddress: traderAddress,
  });

  async function registerSignedOrder() {
    if (!orderPayload) return;

    await omniston.orderRegisterSignedOrder({
      quoteId: quote.quoteId,
      ownerSrcAddress: evmTraderAddress,
      signedOrder: mySignedOrder,
      serializedOrderDetails: orderPayload.serializedOrderDetails,
    });
  }

  return <button onClick={registerSignedOrder}>Register signed order</button>;
}
```

#### Tracking

Once the order is submitted, use `orderTrack()` to monitor its lifecycle. For HTLC-based partial fills, the application must generate secrets on its own, pass their hashes when building the order payload, and later disclose the original secrets with `orderDiscloseHtlcSecret()` when executions reach the appropriate phase.

```tsx
import { useEffect } from "react";
import { useOmniston, type ChainAddress, type Quote } from "@ston-fi/omniston-sdk-react";

function OrderTracking({
  quote,
  traderAddress,
}: {
  quote: Quote;
  traderAddress: ChainAddress;
}) {
  const omniston = useOmniston();

  useEffect(() => {
    let unsubscribe = () => {};

    void omniston
      .orderTrack({
        quoteId: quote.quoteId,
        traderAddress,
      })
      .then((stream) => {
        const subscription = stream.subscribe({
          next(event) {
            switch (event?.$case) {
              case "order":
                console.log("Order status:", event.value.status);
                console.log("Executions:", event.value.executions.length);
                break;
              case "unsubscribed":
                console.log("Order tracking stream closed");
                break;
            }
          },
        });

        unsubscribe = () => subscription.unsubscribe();
      });

    return () => unsubscribe();
  }, [omniston, quote.quoteId, traderAddress]);

  return null;
}
```

If you are using HTLC order settlement and manage secrets yourself, disclose them once an execution is ready:

```tsx
import { useOmniston, type Quote } from "@ston-fi/omniston-sdk-react";

function DiscloseSecret({ quote }: { quote: Quote }) {
  const omniston = useOmniston();

  async function disclose() {
    await omniston.orderDiscloseHtlcSecret({
      quoteId: quote.quoteId,
      executionIndex: 0,
      secret: mySecretBytes,
    });
  }

  return <button onClick={disclose}>Disclose secret</button>;
}
```

## Active orders list

If your application needs to restore existing order state or show all active orders for a trader, call `useActiveOrders()`.

```tsx
import {
  useActiveOrders,
  type ChainAddress,
} from "@ston-fi/omniston-sdk-react";

const traderAddress: ChainAddress = {
  chain: {
    $case: "ton",
    value: "EQ...",
  },
};

function ActiveOrdersList() {
  const { data: activeOrders } = useActiveOrders({
    traderAddress,
  });

  return (
    <ul>
      {activeOrders?.activeOrders.map((activeOrder) => (
        <li key={activeOrder.quote.quoteId}>
          {activeOrder.quote.quoteId} - {activeOrder.order.status}
        </li>
      ))}
    </ul>
  );
}
```


---

# Agent Instructions: 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:

```
GET https://docs.ston.fi/developer-section/omniston/sdk/react.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
