# Node.js

The Node.js SDK gives you direct access to the Omniston API surface. 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)

## Installation

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

Install the SDK in your project:

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

## Creating an instance

Create an `Omniston` instance pointing to the desired API endpoint.

```ts
import { Omniston } from "@ston-fi/omniston-sdk";

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

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

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

## 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";

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. `requestForQuote()` is a live stream and may emit multiple `quoteUpdated` events over time, so your integration should handle it as an ongoing subscription rather than as a one-shot request.

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

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,
};

omniston.requestForQuote(quoteRequest).subscribe({
  next(event) {
    switch (event?.$case) {
      case "ack":
        console.log("RFQ id:", event.value.rfqId);
        break;
      case "quoteUpdated":
        console.log("Received quote:", event.value.quoteId);
        break;
      case "noQuote":
        console.log(`No quote available for RFQ ${event.rfqId}`);
        break;
      case "unsubscribed":
        console.log("Quote stream was closed by server");
        break;
    }
  },
  error(error) {
    console.error("RFQ stream failed", error);
  },
});
```

## 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 `tonBuildSwap()`, then pass the resulting messages to the wallet or signing library you use in your application.

```ts
import { isSwapQuote, type ChainAddress } from "@ston-fi/omniston-sdk";

if (!isSwapQuote(quote)) {
  throw new Error("Expected a swap quote");
}

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

const swapTx = await omniston.tonBuildSwap({
  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.

```ts
const swapTrackStream = await omniston.swapTrack({
  quoteId: quote.quoteId,
  traderAddress,
  outgoingTxQuery, // tx hash, message hash, or outgoing message body
});

swapTrackStream.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;
    }
  },
});
```

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

```ts
import {
  isHtlcOrderQuote,
  isOrderQuote,
  type HtlcSecrets,
} from "@ston-fi/omniston-sdk";

if (!isOrderQuote(quote)) {
  throw new Error("Expected an order quote");
}

const tonOrderTx = await omniston.tonBuildEscrowTransfer({
  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:

```ts
if (!isOrderQuote(quote)) {
  throw new Error("Expected an order quote");
}

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

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

const orderPayload = await omniston.evmBuildOrderPayload({
  quoteId: quote.quoteId,
  ownerSrcAddress: evmTraderAddress,
  traderDstAddress: traderAddress,
  htlcSecrets,
  traderDstDiscloseAddress: traderAddress,
});

const signedOrder = await buildSignedOrderSomehow(orderPayload);

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

#### 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.

```ts
const orderTrackStream = await omniston.orderTrack({
  quoteId: quote.quoteId,
  traderAddress,
});

orderTrackStream.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;
    }
  },
});
```

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

```ts
await omniston.orderDiscloseHtlcSecret({
  quoteId: quote.quoteId,
  executionIndex: 0,
  secret: mySecretBytes,
});
```

## Active orders list

If your application needs to restore existing order state or show all active orders for a trader, call `orderGetActive()`. Unlike `requestForQuote()`, this is a regular request-response method, so you should call it on demand or poll it from your application if you need periodic refresh.

```ts
import type { ChainAddress } from "@ston-fi/omniston-sdk";

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

const activeOrders = await omniston.orderGetActive({
  traderAddress,
});

for (const activeOrder of activeOrders.activeOrders) {
  console.log("Order quote id:", activeOrder.quote.quoteId);
  console.log("Order status:", activeOrder.order.status);
}
```


---

# 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/nodejs.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.
