<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan “Crypto Vazima” Zimanov</title>
    <description>The latest articles on DEV Community by Ivan “Crypto Vazima” Zimanov (@ivan_cryptovazimazima).</description>
    <link>https://dev.to/ivan_cryptovazimazima</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4024371%2F6e866acb-b8c0-409e-b2aa-a23fdcc6668e.jpg</url>
      <title>DEV Community: Ivan “Crypto Vazima” Zimanov</title>
      <link>https://dev.to/ivan_cryptovazimazima</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivan_cryptovazimazima"/>
    <language>en</language>
    <item>
      <title>How to Reuse an Existing TON Connect Instance with Omniston Widget Integrated Mode</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Mon, 28 Sep 2026 05:04:20 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-reuse-an-existing-ton-connect-instance-with-omniston-widget-integrated-mode-1p6m</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-reuse-an-existing-ton-connect-instance-with-omniston-widget-integrated-mode-1p6m</guid>
      <description>&lt;p&gt;If your TON dApp already has wallet connectivity, you should not create another TON Connect instance just for the Omniston Widget. Instead, configure the widget in &lt;code&gt;integrated&lt;/code&gt; mode and pass it the same initialized instance that the rest of your application already uses.&lt;/p&gt;

&lt;p&gt;The result is one shared wallet session across your interface. A wallet connected through your navigation, account panel, or another TON feature can also be used by the embedded Omniston swap interface. More importantly, this follows the architecture required by the current STON.fi widget integration, which warns against running multiple TON Connect instances inside the same application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why reuse the connection instead of creating another one?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6cuxmfini2m2gc0ci1mq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6cuxmfini2m2gc0ci1mq.png" alt="Why reuse the connection instead of creating another one" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine a TON dashboard that already has a wallet button in its header.&lt;/p&gt;

&lt;p&gt;A visitor connects Tonkeeper or another compatible wallet, and your application uses that connection to display the wallet address, account state, or transaction controls. You later decide to add token swaps through the Omniston Widget.&lt;/p&gt;

&lt;p&gt;At first, it may seem reasonable to give the widget its own TON Connect configuration. That would create two separate wallet connection layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the TON Connect instance owned by your application&lt;/li&gt;
&lt;li&gt;another TON Connect instance initialized for the widget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly the situation integrated mode is designed to avoid.&lt;/p&gt;

&lt;p&gt;STON.fi's current widget documentation states that an application with an existing TON Connect instance should reuse it with the widget. The documentation also warns that multiple instances can cause the application to fail because of TON Connect SDK limitations.&lt;/p&gt;

&lt;p&gt;Integrated mode changes the ownership model. Your application continues to own TON Connect. Omniston simply receives access to that existing connection.&lt;/p&gt;

&lt;p&gt;The architecture becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
    |
    +-- Existing TON Connect instance
    |       |
    |       +-- Header wallet UI
    |       +-- Account features
    |       +-- Other TON actions
    |       +-- Omniston Widget
    |
    +-- Application state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one wallet session rather than parallel wallet systems competing inside the same page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What integrated mode actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs46wn7ud6s09a3f9zvhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs46wn7ud6s09a3f9zvhw.png" alt="What integrated mode actually does" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Omniston Widget currently supports two TON Connect modes: &lt;code&gt;standalone&lt;/code&gt; and &lt;code&gt;integrated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;standalone&lt;/code&gt; is intended for applications where the widget itself can own the wallet integration. You provide a TON Connect manifest URL, and the widget creates the connection layer internally.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;integrated&lt;/code&gt; assumes that your application has already done that work.&lt;/p&gt;

&lt;p&gt;The configuration is deliberately small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;instance&lt;/code&gt; is the important part.&lt;/p&gt;

&lt;p&gt;According to the current STON.fi reference, it can be an initialized &lt;code&gt;TonConnect&lt;/code&gt; instance from &lt;code&gt;@tonconnect/sdk&lt;/code&gt; or a &lt;code&gt;TonConnectUI&lt;/code&gt; instance from the TON Connect UI tooling.&lt;/p&gt;

&lt;p&gt;That lets Omniston participate in the wallet architecture you already maintain instead of introducing another one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The practical difference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Who owns TON Connect?&lt;/th&gt;
&lt;th&gt;What the widget receives&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;standalone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Omniston Widget&lt;/td&gt;
&lt;td&gt;TON Connect manifest configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;integrated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your application&lt;/td&gt;
&lt;td&gt;Existing TON Connect instance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For an established dApp, the second model is usually the relevant one because wallet connectivity often belongs to the application as a whole, not to one swap component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reuse a &lt;code&gt;TonConnect&lt;/code&gt; SDK instance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgafh8xlx4bbcqbf2n5ju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgafh8xlx4bbcqbf2n5ju.png" alt="Reuse a  raw `TonConnect` endraw  SDK instance" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start with the simplest case: your application already uses the headless &lt;code&gt;@tonconnect/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TON describes &lt;code&gt;TonConnect&lt;/code&gt; as the connector responsible for wallet connections and transaction signing. The SDK also exposes &lt;code&gt;restoreConnection()&lt;/code&gt;, which can restore an existing session when the application loads.&lt;/p&gt;

&lt;p&gt;A simplified application setup might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TonConnect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tonconnect/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TonConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restoreConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important architectural decision happens here. Create the connector once and export or otherwise provide access to that same object wherever wallet functionality is needed.&lt;/p&gt;

&lt;p&gt;Now install the Omniston widget loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your project already depends on &lt;code&gt;@tonconnect/sdk&lt;/code&gt;, you do not need another TON Connect installation specifically for the widget. STON.fi's widget guide explicitly notes this case for integrated applications.&lt;/p&gt;

&lt;p&gt;Load the widget constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then pass the existing connector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, mount it into a real DOM element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No second &lt;code&gt;new TonConnect()&lt;/code&gt; appears in the widget integration.&lt;/p&gt;

&lt;p&gt;That absence is the core of the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the instance at the application level
&lt;/h2&gt;

&lt;p&gt;Integrated mode works best when TON Connect already has a clear owner in your codebase.&lt;/p&gt;

&lt;p&gt;Avoid creating the connector inside the component that renders the Omniston Widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SwapPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TonConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A component can rerender, unmount, or mount again. Depending on the framework and component lifecycle, putting connection infrastructure directly inside the rendering path can make ownership harder to reason about.&lt;/p&gt;

&lt;p&gt;A cleaner pattern is to initialize the wallet layer at application level and reuse the reference.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tonconnect.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TonConnect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tonconnect/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TonConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restoreConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// omniston.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./tonconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mountOmniston&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the same object can serve your wallet button, account logic, and Omniston integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  One useful rule
&lt;/h3&gt;

&lt;p&gt;When reviewing your project, ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where is TON Connect instantiated?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ideally, there should be one clear answer.&lt;/p&gt;

&lt;p&gt;If you find one initialization in your navigation code and another near the Omniston Widget, you probably have an architectural problem to fix before adding more wallet-dependent features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about &lt;code&gt;TonConnectUI&lt;/code&gt; and React?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4smpsqj1rop0zjafwrq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4smpsqj1rop0zjafwrq.png" alt="Keep the instance at the application level" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many TON applications do not interact with the headless SDK directly. React applications commonly use &lt;code&gt;@tonconnect/ui-react&lt;/code&gt;, which provides &lt;code&gt;TonConnectUIProvider&lt;/code&gt;, &lt;code&gt;TonConnectButton&lt;/code&gt;, and hooks such as &lt;code&gt;useTonConnectUI()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TON's current React documentation says &lt;code&gt;useTonConnectUI()&lt;/code&gt; returns the active &lt;code&gt;TonConnectUI&lt;/code&gt; instance. That instance exposes wallet and transaction functionality and can be shared with other components that need TON Connect access.&lt;/p&gt;

&lt;p&gt;A React component can therefore retrieve the existing instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useTonConnectUI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tonconnect/ui-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SwapSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tonConnectUI&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonConnectUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// tonConnectUI is the existing application instance&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would then use that &lt;code&gt;tonConnectUI&lt;/code&gt; object as the widget's integrated instance rather than constructing another wallet layer.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonConnectUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi's widget configuration currently accepts &lt;code&gt;TonConnectUI&lt;/code&gt; for the integrated &lt;code&gt;tonconnect.instance&lt;/code&gt; field, while TON's React API exposes the shared UI instance through its provider and hook model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remember the client lifecycle
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftwg8jux5xm90j7nxiu1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftwg8jux5xm90j7nxiu1m.png" alt="Remember the client lifecycle" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TON Connect UI is browser-facing infrastructure. Current TON documentation describes &lt;code&gt;@tonconnect/ui-react&lt;/code&gt; as client-only and notes that Next.js integrations should keep the provider on the client side.&lt;/p&gt;

&lt;p&gt;The Omniston Widget also needs a real DOM node for mounting.&lt;/p&gt;

&lt;p&gt;So in a React or Next.js application, avoid treating widget construction as server rendering logic. Wait until the client has mounted and the container exists.&lt;/p&gt;

&lt;p&gt;A typical sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let the application establish its TON Connect provider.&lt;/li&gt;
&lt;li&gt;Obtain the existing &lt;code&gt;TonConnectUI&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Wait until the widget container exists in the DOM.&lt;/li&gt;
&lt;li&gt;Load the Omniston widget constructor.&lt;/li&gt;
&lt;li&gt;Create the widget in &lt;code&gt;integrated&lt;/code&gt; mode.&lt;/li&gt;
&lt;li&gt;Pass the existing instance.&lt;/li&gt;
&lt;li&gt;Mount the widget.&lt;/li&gt;
&lt;li&gt;Clean up appropriately if your application destroys or replaces the view.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The exact component code depends on your framework lifecycle, but the ownership rule does not change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens to an already connected wallet?
&lt;/h2&gt;

&lt;p&gt;This is where integrated mode becomes especially useful.&lt;/p&gt;

&lt;p&gt;Suppose the visitor connects a wallet from your global navigation before opening the swap page.&lt;/p&gt;

&lt;p&gt;Your application already knows about that connection through its existing TON Connect infrastructure. The Omniston Widget receives the same TON Connect object, so it works with the shared wallet context rather than starting an unrelated wallet session.&lt;/p&gt;

&lt;p&gt;TON Connect itself supports connection restoration. The headless SDK exposes &lt;code&gt;restoreConnection()&lt;/code&gt;, while TON Connect UI has restoration support enabled by default unless the application configures it differently.&lt;/p&gt;

&lt;p&gt;You should therefore let the application-level wallet system remain responsible for connection restoration.&lt;/p&gt;

&lt;p&gt;Do not interpret integrated mode as an instruction to manually synchronize two TON Connect instances. There should not be two instances to synchronize in the first place.&lt;/p&gt;

&lt;p&gt;The flow should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App starts
   |
Existing TON Connect restores or establishes wallet session
   |
User opens swap interface
   |
Omniston Widget receives the same instance
   |
Widget uses that wallet context for swap interaction
   |
Wallet asks the user to approve the transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integrated mode shares infrastructure. It does not bypass wallet authorization.&lt;/p&gt;

&lt;h2&gt;
  
  
  A complete integrated example
&lt;/h2&gt;

&lt;p&gt;Here is the core setup in one place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TonConnect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tonconnect/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TonConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restoreConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;defaultBidAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Omniston widget container not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The widget settings are independent of the connection ownership decision. You can configure default assets, custom assets, referral parameters, and supported widget styling without creating another TON Connect instance.&lt;/p&gt;

&lt;p&gt;Keep those concerns separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TON Connect configuration answers which wallet session the widget uses.&lt;/li&gt;
&lt;li&gt;Widget configuration controls the swap experience.&lt;/li&gt;
&lt;li&gt;Application lifecycle controls when the widget is created and mounted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That separation makes the integration easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes when switching to integrated mode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvq6l8pg7mmu47ja97bf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvq6l8pg7mmu47ja97bf6.png" alt="Common mistakes when switching to integrated mode" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most common error is leaving standalone configuration in place after the rest of the application gains TON Connect support.&lt;/p&gt;

&lt;p&gt;For example, do not keep this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if another part of the same application already initializes TON Connect.&lt;/p&gt;

&lt;p&gt;Instead, pass the existing instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also watch for these problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creating the instance twice in different modules.&lt;/strong&gt; Two files can both look correct individually while producing the wrong application architecture together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructing TON Connect inside a frequently recreated component.&lt;/strong&gt; Move wallet infrastructure to a stable application-level owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Passing a different connector than the rest of the UI uses.&lt;/strong&gt; Integrated mode is useful because the instance is shared.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mounting before the DOM container exists.&lt;/strong&gt; Wait for the relevant client lifecycle stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reimplementing connection restoration for the widget.&lt;/strong&gt; Let your established TON Connect setup own session restoration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming a connected wallet removes transaction approval.&lt;/strong&gt; The wallet still controls authorization for requested transactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before shipping, test the application as one connected system rather than testing only whether the widget appears.&lt;/p&gt;

&lt;p&gt;Connect from the global wallet button, navigate to the swap interface, disconnect, reconnect, reload the page, and repeat the flow on the environments you actually support.&lt;/p&gt;

&lt;p&gt;Practical takeaway: if your application already owns TON Connect, keep it that way. Create or obtain one stable &lt;code&gt;TonConnect&lt;/code&gt; or &lt;code&gt;TonConnectUI&lt;/code&gt; instance, let the rest of the app manage its connection lifecycle, and give Omniston that exact instance through &lt;code&gt;tonconnect.type: 'integrated'&lt;/code&gt;. The goal is not merely fewer lines of code. It is one coherent wallet session shared by every TON-enabled part of your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is integrated TON Connect mode in the Omniston Widget?
&lt;/h3&gt;

&lt;p&gt;Integrated mode tells the Omniston Widget to use a TON Connect instance that your application has already initialized. Instead of receiving a manifest URL and constructing its own connection layer, the widget receives the existing &lt;code&gt;TonConnect&lt;/code&gt; or supported &lt;code&gt;TonConnectUI&lt;/code&gt; instance and participates in the wallet session already managed by your dApp.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I use integrated instead of standalone mode?
&lt;/h3&gt;

&lt;p&gt;Use integrated mode when your application already manages TON Connect outside the widget. A common example is a dApp with a global connect button, account page, and several wallet-enabled features. Standalone mode is more appropriate when the Omniston Widget is effectively the only part of the application that needs TON Connect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I create one TON Connect instance for my app and another for Omniston?
&lt;/h3&gt;

&lt;p&gt;You should not. STON.fi's current widget documentation explicitly warns that only one TON Connect instance should exist in the application because of TON Connect SDK limitations. If an instance already exists, configure Omniston in integrated mode and reuse that same instance instead of creating a second one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Omniston integrated mode use &lt;code&gt;TonConnectUI&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Yes. The current STON.fi widget configuration lists both &lt;code&gt;TonConnect&lt;/code&gt; from &lt;code&gt;@tonconnect/sdk&lt;/code&gt; and &lt;code&gt;TonConnectUI&lt;/code&gt; from the TON Connect UI stack as supported values for the integrated &lt;code&gt;tonconnect.instance&lt;/code&gt; option. This allows applications that already use the higher-level wallet UI tooling to share that connection with Omniston.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should Omniston call &lt;code&gt;restoreConnection()&lt;/code&gt; itself?
&lt;/h3&gt;

&lt;p&gt;Your application should continue owning the connection lifecycle when using integrated mode. If you use the headless SDK, TON documents &lt;code&gt;restoreConnection()&lt;/code&gt; as the method for restoring an earlier session. If you use TON Connect UI, restoration behavior is managed through its configuration. Omniston receives the resulting shared instance rather than requiring a separate restoration system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the TON Connect manifest still matter in integrated mode?
&lt;/h3&gt;

&lt;p&gt;Yes, but it normally belongs to the application-level TON Connect initialization rather than the Omniston configuration. TON Connect uses the manifest to provide dApp information to wallets. Your existing connector or UI setup should already reference the appropriate manifest, while the Omniston Widget receives the initialized instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use integrated mode in Next.js?
&lt;/h3&gt;

&lt;p&gt;Yes, but TON Connect UI and widget mounting need to happen on the client side. TON's current React documentation describes &lt;code&gt;@tonconnect/ui-react&lt;/code&gt; as client-only and recommends client components or disabled server-side rendering for the provider in Next.js. Mount Omniston only after its DOM container and TON Connect instance are available.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I verify before shipping an Omniston integrated-mode integration?
&lt;/h3&gt;

&lt;p&gt;Verify that your application creates only one TON Connect instance, that Omniston receives exactly that instance, and that connection restoration works after a reload. Then test connecting and disconnecting from your main wallet UI, navigating to the widget, initiating a swap, and reviewing the wallet approval request. The important test is whether the whole application behaves as one wallet-connected system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Full Guide and Reference - Official Omniston Widget installation, TON Connect modes, integrated instance configuration, and the warning about multiple instances&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Widget - Official overview of widget capabilities and the distinction between standalone and integrated TON Connect modes&lt;/li&gt;
&lt;li&gt;STON.fi Help Center - Official explanation of embedding the swap widget and choosing between standalone and integrated wallet connectivity&lt;/li&gt;
&lt;li&gt;TON Connect SDK Reference - Official &lt;code&gt;@tonconnect/sdk&lt;/code&gt; reference covering &lt;code&gt;TonConnect&lt;/code&gt;, &lt;code&gt;restoreConnection()&lt;/code&gt;, and transaction methods&lt;/li&gt;
&lt;li&gt;TON Connect UI React Reference - Official React API reference for &lt;code&gt;TonConnectUIProvider&lt;/code&gt;, &lt;code&gt;useTonConnectUI()&lt;/code&gt;, and shared connector instances&lt;/li&gt;
&lt;li&gt;TON Connect UI Reference - Official UI configuration reference covering connection restoration, manifest configuration, and the underlying connector model&lt;/li&gt;
&lt;li&gt;TON Connect Get Started - Official TON documentation explaining headless SDK usage and application-level wallet integration&lt;/li&gt;
&lt;li&gt;TON Connect Protocol Specification - The protocol-level definition of the wallet connection request and the role of &lt;code&gt;manifestUrl&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>blockchain</category>
      <category>frontend</category>
      <category>web3</category>
    </item>
    <item>
      <title>How to Configure Standalone TON Connect Mode in the Omniston Widget</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Tue, 22 Sep 2026 06:20:43 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-configure-standalone-ton-connect-mode-in-the-omniston-widget-1kd7</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-configure-standalone-ton-connect-mode-in-the-omniston-widget-1kd7</guid>
      <description>&lt;p&gt;&lt;em&gt;Use the STON.fi swap widget with wallet connectivity built in, without creating or managing a separate TON Connect instance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Standalone TON Connect mode is the simplest way to give an embedded Omniston Widget its own wallet connection flow. You provide the widget with the URL of your TON Connect manifest, mount the widget on the page, and the widget initializes TON Connect internally. You do not need to install or configure a separate TON Connect package just to make the swap widget work.&lt;/p&gt;

&lt;p&gt;That makes standalone mode a good fit for landing pages, lightweight dApps, dashboards, and websites where the Omniston Widget is the main feature that needs wallet access. The important limitation is just as simple: if your application already has its own TON Connect instance, standalone mode is no longer the right choice. In that case, the widget should reuse the existing connection through integrated mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  What standalone mode actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2sccwvxep2z53sc4efz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2sccwvxep2z53sc4efz.png" alt="What standalone mode actually does" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Omniston Widget supports two TON Connect configurations: &lt;code&gt;standalone&lt;/code&gt; and &lt;code&gt;integrated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With standalone mode, the responsibility boundary is clear. Your application provides the TON Connect manifest and a DOM element where the widget should appear. The widget handles its own TON Connect initialization and uses that connection when a user needs to connect a wallet and approve a swap.&lt;/p&gt;

&lt;p&gt;The minimal structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are not passing an existing &lt;code&gt;TonConnect&lt;/code&gt; or &lt;code&gt;TonConnectUI&lt;/code&gt; instance into the widget. The widget creates the TON Connect layer it needs internally. STON.fi documents this mode specifically for smaller applications or sites that only need the swap flow supplied by the widget.&lt;/p&gt;

&lt;p&gt;The practical split looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app hosts the TON Connect manifest.&lt;/li&gt;
&lt;li&gt;Your app loads and mounts the Omniston Widget.&lt;/li&gt;
&lt;li&gt;The widget manages its TON Connect instance.&lt;/li&gt;
&lt;li&gt;The wallet still presents connection and transaction requests to the user.&lt;/li&gt;
&lt;li&gt;The user remains responsible for approving or rejecting the wallet action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Standalone does not remove wallet approval. It removes the need for your application to build the wallet connection layer separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the TON Connect manifest first
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkosrafqj5qtwqycthod5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkosrafqj5qtwqycthod5.png" alt="Prepare the TON Connect manifest first" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before initializing the widget, create a &lt;code&gt;tonconnect-manifest.json&lt;/code&gt; file for your application.&lt;/p&gt;

&lt;p&gt;The manifest tells compatible wallets which application is asking for a connection. TON Connect defines required fields for the application URL, application name, and icon, while terms of use and privacy policy URLs are optional.&lt;/p&gt;

&lt;p&gt;A minimal manifest could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Omniston App"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iconUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com/icon-180.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more complete version might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Omniston App"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iconUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com/icon-180.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"termsOfUseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com/terms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"privacyPolicyUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com/privacy"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manifest needs to be publicly reachable. TON Connect documentation says wallets must be able to fetch it without authentication, restrictive CORS rules, or proxy challenges that block automated requests. HTTPS should be used, and the application icon should use a compatible raster format such as PNG or ICO rather than SVG.&lt;/p&gt;

&lt;p&gt;STON.fi's widget guide specifically instructs integrators to create and host their own manifest and says the manifest URL should be hosted on the same domain as the application. For an Omniston Widget integration, following that stricter integration guidance is the safest approach.&lt;/p&gt;

&lt;p&gt;Before writing any widget code, check these four things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://myapp.com/tonconnect-manifest.json&lt;/code&gt; opens without authentication.&lt;/li&gt;
&lt;li&gt;The response is valid JSON.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;iconUrl&lt;/code&gt; contain real production values.&lt;/li&gt;
&lt;li&gt;The icon URL itself can be opened publicly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A surprising number of wallet connection problems start here rather than inside the widget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load the Omniston Widget
&lt;/h2&gt;

&lt;p&gt;STON.fi currently provides the widget as a CDN-hosted bundle. You can either use the small npm loader package to fetch that bundle at runtime or include the CDN script directly. Both approaches expose the same &lt;code&gt;OmnistonWidget&lt;/code&gt; constructor.&lt;/p&gt;

&lt;p&gt;For a bundled JavaScript or TypeScript project, install the loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then load the widget constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loader is useful when your application should control when the widget bundle is fetched and mounted.&lt;/p&gt;

&lt;p&gt;For a static page, you can skip npm completely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://widget.ston.fi/v0/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor then becomes available as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi uses major-versioned CDN paths such as &lt;code&gt;/v0/&lt;/code&gt;. Non-breaking updates can be delivered inside that major version without requiring you to change the script URL. A future breaking release can use another major-version path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure standalone TON Connect mode
&lt;/h2&gt;

&lt;p&gt;Once the manifest and widget loader are ready, the actual standalone configuration is small.&lt;/p&gt;

&lt;p&gt;Create a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize and mount the widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is enough for the basic standalone wallet setup. According to the STON.fi reference, &lt;code&gt;tonconnect.options.manifestUrl&lt;/code&gt; is required for standalone mode, while a separately initialized TON Connect instance is not.&lt;/p&gt;

&lt;p&gt;You can then add normal widget configuration without changing the wallet architecture. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;defaultBidAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="na"&gt;defaultAskAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the TON Connect configuration still answers only one question: who owns wallet connectivity? The answer remains the widget itself.&lt;/p&gt;

&lt;p&gt;Options such as default assets, custom assets, styling, and integrator fee configuration belong to the swap experience and can be changed independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CDN version is even smaller
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsrspqhpvosjdjdgcu1ik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsrspqhpvosjdjdgcu1ik.png" alt="The CDN version is even smaller" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Standalone mode is especially convenient when you want a swap interface on a page without maintaining a JavaScript build pipeline.&lt;/p&gt;

&lt;p&gt;A compact CDN implementation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Omniston Swap&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://widget.ston.fi/v0/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myapp.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no separate &lt;code&gt;@tonconnect/ui&lt;/code&gt;, &lt;code&gt;@tonconnect/ui-react&lt;/code&gt;, or &lt;code&gt;@tonconnect/sdk&lt;/code&gt; setup in this version. That is the main value of standalone mode: wallet connectivity is part of the widget integration rather than another application-level dependency you need to wire together yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When standalone becomes the wrong mode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk9bdiuzimvnkpmckfgve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk9bdiuzimvnkpmckfgve.png" alt="When standalone becomes the wrong mode" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The simplicity of standalone mode can become a problem if your application already uses TON Connect elsewhere.&lt;/p&gt;

&lt;p&gt;Imagine a dashboard with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a wallet button in the global navigation&lt;/li&gt;
&lt;li&gt;account information in a profile panel&lt;/li&gt;
&lt;li&gt;several TON-powered features&lt;/li&gt;
&lt;li&gt;the Omniston Widget on one page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the application already initializes TON Connect for the global wallet experience, the Omniston Widget should not initialize another independent instance.&lt;/p&gt;

&lt;p&gt;STON.fi explicitly warns that only one TON Connect instance should exist in the application and instructs developers to use &lt;code&gt;integrated&lt;/code&gt; mode when an instance already exists. The widget can then reuse that connection instead of creating its own.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Recommended mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Widget is the only feature that needs a TON wallet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;standalone&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple static website with an embedded swap&lt;/td&gt;
&lt;td&gt;&lt;code&gt;standalone&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Landing page with no existing wallet architecture&lt;/td&gt;
&lt;td&gt;&lt;code&gt;standalone&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App already initializes TON Connect&lt;/td&gt;
&lt;td&gt;&lt;code&gt;integrated&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global wallet state is shared across multiple features&lt;/td&gt;
&lt;td&gt;&lt;code&gt;integrated&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React app already uses &lt;code&gt;TonConnectUIProvider&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Usually &lt;code&gt;integrated&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A useful rule is to decide who owns the wallet session.&lt;/p&gt;

&lt;p&gt;If the Omniston Widget owns it, use standalone. If your application owns it, use integrated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one standalone swap from page load to signing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7t89gabw4sfu06qex0nc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7t89gabw4sfu06qex0nc.png" alt="Following one standalone swap from page load to signing" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider a simple site that only wants to offer Omniston-powered swaps.&lt;/p&gt;

&lt;p&gt;When the page loads, your code fetches the widget bundle and constructs &lt;code&gt;OmnistonWidget&lt;/code&gt; with &lt;code&gt;type: 'standalone'&lt;/code&gt;. The configuration points to your public TON Connect manifest. The widget then mounts into the selected DOM container.&lt;/p&gt;

&lt;p&gt;The visitor can browse the swap interface without your page creating a separate TON Connect UI layer.&lt;/p&gt;

&lt;p&gt;When wallet access becomes necessary, TON Connect handles the connection request using the manifest metadata that identifies your application. At the protocol level, the wallet receives a connect request that contains the manifest URL and the requested connection data.&lt;/p&gt;

&lt;p&gt;After the wallet is connected, the swap flow can proceed through the widget. Transaction authorization still happens in the wallet. Standalone mode changes the integration architecture, not the basic self-custodial principle that a wallet action needs the wallet holder's approval.&lt;/p&gt;

&lt;p&gt;For a developer, the resulting flow is compact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Host the manifest.&lt;/li&gt;
&lt;li&gt;Load the widget.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;tonconnect.type&lt;/code&gt; to &lt;code&gt;standalone&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pass &lt;code&gt;manifestUrl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mount the widget.&lt;/li&gt;
&lt;li&gt;Test connecting a wallet and initiating a swap.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You are not reproducing Omniston's swap UI or manually building a TON Connect wallet picker. You are giving the widget enough information to manage those parts of its own workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to test before shipping
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2epu0gimcof7f7ou0nf9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2epu0gimcof7f7ou0nf9.png" alt="What to test before shipping" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A widget appearing correctly on the page does not prove that the wallet flow is configured correctly. Test the connection itself.&lt;/p&gt;

&lt;p&gt;Start with the manifest in a normal browser window and then test the full flow from the production-like domain.&lt;/p&gt;

&lt;p&gt;A useful release checklist is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the exact &lt;code&gt;manifestUrl&lt;/code&gt; configured in the widget.&lt;/li&gt;
&lt;li&gt;Confirm that it returns JSON without login or access challenges.&lt;/li&gt;
&lt;li&gt;Confirm that the application URL in the manifest is correct.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;iconUrl&lt;/code&gt; independently.&lt;/li&gt;
&lt;li&gt;Test wallet connection from the deployed application.&lt;/li&gt;
&lt;li&gt;Confirm that reconnecting does not create duplicate wallet systems.&lt;/li&gt;
&lt;li&gt;Initiate a small test swap and inspect the wallet request before approval.&lt;/li&gt;
&lt;li&gt;Test both desktop and mobile connection paths relevant to your audience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the wallet reports that the manifest cannot be loaded, check the URL, deployment state, CORS behavior, HTTPS configuration, and any CDN or security layer in front of the file. TON documentation identifies unavailable manifests and invalid manifest content as explicit connection errors.&lt;/p&gt;

&lt;p&gt;For local or preview environments, remember that the wallet must still be able to reach the manifest URL. A file that exists inside your repository but is not publicly served does not satisfy the connection flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; use standalone mode when the Omniston Widget can legitimately own the wallet connection for the page. Keep the configuration small, treat the manifest as part of the production integration rather than a placeholder file, and switch to integrated mode as soon as TON Connect becomes shared application infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is standalone TON Connect mode in the Omniston Widget?
&lt;/h3&gt;

&lt;p&gt;Standalone mode tells the Omniston Widget to initialize and manage TON Connect internally. You supply a public &lt;code&gt;manifestUrl&lt;/code&gt;, while the widget handles the wallet connection layer it needs for its swap flow. You do not need to create a separate &lt;code&gt;TonConnect&lt;/code&gt; instance only for the widget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to install &lt;code&gt;@tonconnect/sdk&lt;/code&gt; for standalone mode?
&lt;/h3&gt;

&lt;p&gt;No. STON.fi states that standalone mode works with the manifest URL and does not require additional TON Connect packages. You still need a valid TON Connect manifest, but the Omniston Widget manages its own connection internally.&lt;/p&gt;

&lt;h3&gt;
  
  
  What fields does the TON Connect manifest need?
&lt;/h3&gt;

&lt;p&gt;The current TON Connect specification requires &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;iconUrl&lt;/code&gt;. &lt;code&gt;termsOfUseUrl&lt;/code&gt; and &lt;code&gt;privacyPolicyUrl&lt;/code&gt; are optional. The manifest must be valid JSON and publicly reachable so wallets can fetch it when processing a connection request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use standalone mode in a React application?
&lt;/h3&gt;

&lt;p&gt;Yes. Standalone mode is about who controls TON Connect, not which frontend framework you use. If your React application does not already initialize TON Connect elsewhere, the widget can run standalone. If you already use &lt;code&gt;TonConnectUIProvider&lt;/code&gt; or another shared TON Connect instance, integrated mode is generally the appropriate architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can standalone mode and another TON Connect instance run together?
&lt;/h3&gt;

&lt;p&gt;They should not. STON.fi warns that an application should not create multiple TON Connect instances. If your application already manages TON Connect, configure the Omniston Widget with &lt;code&gt;type: 'integrated'&lt;/code&gt; and provide the existing instance instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does standalone mode mean users do not need to approve swaps?
&lt;/h3&gt;

&lt;p&gt;No. Standalone describes how the application integrates TON Connect. It does not bypass the wallet. TON Connect still provides the communication flow between the dApp and wallet, and transaction requests remain subject to the wallet holder's authorization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use standalone mode without npm?
&lt;/h3&gt;

&lt;p&gt;Yes. Load &lt;code&gt;https://widget.ston.fi/v0/index.js&lt;/code&gt; directly in the browser, create &lt;code&gt;new window.OmnistonWidget(...)&lt;/code&gt;, provide the standalone TON Connect descriptor, and mount it into your chosen DOM element. STON.fi documents the CDN approach as the no-bundler option.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I check first if the Omniston Widget cannot connect a TON wallet?
&lt;/h3&gt;

&lt;p&gt;Check the manifest before debugging the swap logic. Confirm that the configured URL is correct, publicly accessible over HTTPS, valid JSON, and reachable without authentication, restrictive CORS, or proxy challenges. Then verify the application and icon URLs inside the manifest and retest the connection from your deployed domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Widget - official overview of the swap widget, distribution options, TON Connect modes, and basic standalone configuration&lt;/li&gt;
&lt;li&gt;STON.fi Widget Full Guide &amp;amp; Reference - detailed configuration reference for standalone and integrated TON Connect modes, CDN usage, assets, styling, and widget lifecycle&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Widget GitHub Repository - official widget repository with distribution and loader information&lt;/li&gt;
&lt;li&gt;TON Connect Get Started - official TON documentation covering manifests, SDK choices, wallet connection, and transaction flows&lt;/li&gt;
&lt;li&gt;TON Connect App Manifest Specification - normative reference for manifest fields, hosting requirements, caching, and icon requirements&lt;/li&gt;
&lt;li&gt;TON Connect Connection Specification - normative description of the connection request and manifest URL used during wallet connection&lt;/li&gt;
&lt;li&gt;TON Connect Bridge Specification - normative description of communication between dApps and wallets through HTTP and JavaScript bridges&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>web3</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Load the Omniston Widget with @ston-fi/omniston-widget-loader</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sat, 19 Sep 2026 04:45:45 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-load-the-omniston-widget-with-ston-fiomniston-widget-loader-47i7</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-load-the-omniston-widget-with-ston-fiomniston-widget-loader-47i7</guid>
      <description>&lt;p&gt;&lt;em&gt;Use the npm loader to fetch the current Omniston Widget bundle at runtime, connect TON Connect, and mount a complete swap interface inside your application.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are building a modern JavaScript application, &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt; gives you programmatic control over when the Omniston Widget enters the page. You install a small npm package, call its &lt;code&gt;load()&lt;/code&gt; method, receive the &lt;code&gt;OmnistonWidget&lt;/code&gt; constructor, create an instance, and mount that instance into a DOM element.&lt;/p&gt;

&lt;p&gt;The important detail is that the npm package is a loader, not a packaged copy of the complete widget. The actual widget remains CDN-hosted. That distribution model lets STON.fi deliver compatible updates inside a major version without requiring every integrator to reinstall the full widget package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does Omniston use a loader package?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5lheb78c4dqou70acjj1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5lheb78c4dqou70acjj1.png" alt="Why does Omniston use a loader package" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A normal npm integration usually installs the complete library into your project. Your package manager resolves a particular version, your bundler includes it in the application, and that exact copy stays there until you update the dependency.&lt;/p&gt;

&lt;p&gt;Omniston takes a different approach.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt; package gives your application the code needed to load the widget, while the widget itself is distributed through STON.fi's CDN. According to the official documentation, CDN paths are major-versioned. Within one major version, integrators can receive compatible fixes and improvements without changing the integration every time the widget receives an update.&lt;/p&gt;

&lt;p&gt;That creates a useful separation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm manages the loader&lt;/strong&gt; inside your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The loader fetches the widget bundle&lt;/strong&gt; when your code requests it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The widget constructor is returned to your code&lt;/strong&gt; after loading succeeds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your application decides when and where to mount it.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is particularly useful in React, Vue, Svelte, Angular, and other bundled applications where a developer may not want a global &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag running immediately when the page loads.&lt;/p&gt;

&lt;p&gt;It also means you should not assume that installing &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt; places the complete Omniston Widget inside your JavaScript bundle. The runtime loading step is part of the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happens when you call &lt;code&gt;load()&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyvhlxet6ehxtc4copk3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyvhlxet6ehxtc4copk3.png" alt="What actually happens when you call  raw `load()` endraw " width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the application level, the flow is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your application
      |
      v
@ston-fi/omniston-widget-loader
      |
      | load()
      v
STON.fi widget CDN
      |
      v
OmnistonWidget constructor
      |
      v
new OmnistonWidget(config)
      |
      v
widget.mount(container)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package exposes a loader with a &lt;code&gt;load()&lt;/code&gt; function. When the promise resolves, you receive the constructor that you use to create the widget instance.&lt;/p&gt;

&lt;p&gt;A minimal pattern looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// configuration&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Loading and creating are therefore two different operations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;load()&lt;/code&gt; obtains the widget constructor. &lt;code&gt;new OmnistonWidget(...)&lt;/code&gt; creates your configured widget instance. &lt;code&gt;mount(...)&lt;/code&gt; finally attaches that instance to a real element on the page.&lt;/p&gt;

&lt;p&gt;The widget also brings its own styles, so the official guide does not require a separate CSS package import.&lt;/p&gt;

&lt;p&gt;That separation matters when you integrate it into an application lifecycle. You can wait until a component exists, lazy-load the widget only where swaps are needed, and clean up the mounted instance when the surrounding page changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the loader and mount your first widget
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5khsvuvmcmbjovsoeizc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5khsvuvmcmbjovsoeizc.png" alt="Install the loader and mount your first widget" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install the package with your preferred package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add a container to your page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then load, configure, and mount the widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-app.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are four operations worth noticing here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import the loader.&lt;/li&gt;
&lt;li&gt;Await &lt;code&gt;OmnistonWidgetLoader.load()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create the widget with its configuration.&lt;/li&gt;
&lt;li&gt;Mount it into an existing DOM node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The container check is not cosmetic. &lt;code&gt;mount()&lt;/code&gt; needs an element that actually exists, so your framework's rendering lifecycle matters. In a React component, for example, you normally wait until the component has mounted and the container ref is available.&lt;/p&gt;

&lt;p&gt;You also need TON Connect configuration before the swap experience can connect to a wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the right TON Connect mode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujrpmkicsx2mjyae3n8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujrpmkicsx2mjyae3n8u.png" alt="Choose the right TON Connect mode" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Omniston Widget supports two TON Connect patterns: &lt;code&gt;standalone&lt;/code&gt; and &lt;code&gt;integrated&lt;/code&gt;. They solve different application problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Wallet connection&lt;/th&gt;
&lt;th&gt;Good fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;standalone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The widget manages its own TON Connect setup from your manifest&lt;/td&gt;
&lt;td&gt;A site where the widget is the main wallet-enabled feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;integrated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The widget receives an existing TON Connect instance&lt;/td&gt;
&lt;td&gt;A larger dApp that already manages wallet state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Standalone mode
&lt;/h3&gt;

&lt;p&gt;Standalone mode keeps the integration compact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-app.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You provide the TON Connect manifest and let the widget handle the connection flow it needs.&lt;/p&gt;

&lt;p&gt;This works well when you are adding a swap module to a landing page, product page, dashboard, or another application that does not already maintain a separate TON Connect session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrated mode
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvosqki8nip2zcfy5y8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvosqki8nip2zcfy5y8g.png" alt="Integrated mode" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your dApp already has TON Connect, creating an independent connection just for the widget is usually unnecessary. Instead, pass the initialized instance to Omniston:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TonConnect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tonconnect/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TonConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-app.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The widget can then share the wallet connection already used by the rest of your application.&lt;/p&gt;

&lt;p&gt;Your TON Connect manifest must also be publicly reachable. TON documentation specifies HTTPS access, no authentication requirement, and no blocking proxy challenge. STON.fi's widget guide additionally instructs integrators to host their own manifest on their application domain. Following the widget guide's deployment pattern is the safer choice for this particular integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one loader-based STON.fi integration
&lt;/h2&gt;

&lt;p&gt;Imagine you already have a dashboard built with a modern frontend framework. Users can connect their TON wallet elsewhere in the application, but there is no swap interface yet.&lt;/p&gt;

&lt;p&gt;You want to add Omniston without implementing token selectors, swap UI, routing integration, and transaction interaction from scratch.&lt;/p&gt;

&lt;p&gt;First, install the loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/omniston-widget-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your application already maintains a TON Connect instance, so the widget should use &lt;code&gt;integrated&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;After the swap component appears, load the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create the instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;defaultBidAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;defaultAskAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above preselects TON as the asset to sell and STON as the asset to receive, using the addresses shown in STON.fi's current widget documentation. These defaults are optional.&lt;/p&gt;

&lt;p&gt;Finally, mount the interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At that point, the loader's job is effectively finished. It got the constructor into your application. The configured &lt;code&gt;OmnistonWidget&lt;/code&gt; instance now owns the widget lifecycle.&lt;/p&gt;

&lt;p&gt;This distinction is useful when debugging. If &lt;code&gt;load()&lt;/code&gt; fails, investigate the runtime loading stage. If construction succeeds but wallet interaction fails, inspect TON Connect configuration. If the instance exists but nothing appears, check the DOM container and mount timing.&lt;/p&gt;

&lt;h3&gt;
  
  
  A compact debugging checklist
&lt;/h3&gt;

&lt;p&gt;When a loader-based integration does not behave as expected, check these areas separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did &lt;code&gt;OmnistonWidgetLoader.load()&lt;/code&gt; resolve successfully?&lt;/li&gt;
&lt;li&gt;Does the mount container exist at the moment &lt;code&gt;mount()&lt;/code&gt; runs?&lt;/li&gt;
&lt;li&gt;Is the TON Connect manifest publicly accessible?&lt;/li&gt;
&lt;li&gt;Are you using the intended &lt;code&gt;standalone&lt;/code&gt; or &lt;code&gt;integrated&lt;/code&gt; mode?&lt;/li&gt;
&lt;li&gt;If using integrated mode, are you passing the initialized TON Connect instance?&lt;/li&gt;
&lt;li&gt;Does your application remove or recreate the container during navigation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separating loading, configuration, and mounting usually makes the source of a problem much easier to identify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control mounting, unmounting, and runtime behavior
&lt;/h2&gt;

&lt;p&gt;Loading a widget once does not mean it must remain mounted forever.&lt;/p&gt;

&lt;p&gt;The official guide exposes &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;unmount&lt;/code&gt; lifecycle methods, along with events for &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;unmount&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Omniston Widget mounted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unmount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Omniston Widget unmounted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Omniston Widget error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can explicitly remove the widget when it is no longer needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unmount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes important in single-page applications. A route change can remove the original DOM node while your JavaScript still holds a reference to the widget instance.&lt;/p&gt;

&lt;p&gt;A React component, for example, can load the widget inside an effect and unmount it during cleanup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;containerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;integrated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;unmount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;active&lt;/code&gt; guard prevents asynchronous loading from mounting into a component that disappeared before the promise resolved.&lt;/p&gt;

&lt;p&gt;That is one of the practical advantages of the loader approach. Widget loading can participate in the same lifecycle logic as the rest of your application instead of depending on a permanently declared global script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loader or direct CDN script?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5q09rih2tf7dpao4ur2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5q09rih2tf7dpao4ur2.png" alt="Loader or Direct CDN" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi supports both approaches. They eventually give you access to the same widget constructor, but they fit different environments.&lt;/p&gt;

&lt;p&gt;With the npm loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-widget-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OmnistonWidgetLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the direct CDN approach, the script creates a browser global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://widget.ston.fi/v0/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and your page uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// configuration&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The direct CDN method is attractive for a small static page because there is almost nothing to install.&lt;/p&gt;

&lt;p&gt;The loader is usually the more natural choice when your project already has a build system and application lifecycle. You can import it through your package manager, decide exactly when loading starts, keep the integration inside your JavaScript modules, and coordinate mounting with your framework.&lt;/p&gt;

&lt;p&gt;One detail should not be overlooked: using the npm loader does not replace the CDN distribution model. The loader is a controlled way to access that model from a bundled application.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you verify before shipping?
&lt;/h2&gt;

&lt;p&gt;A working local demo is only the first stage. Before deploying a loader-based Omniston Widget integration, test the complete path from page load to wallet interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Confirm that the widget loads successfully in the actual production environment, not only through your development server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manifest&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify that your TON Connect manifest and icon remain publicly available over HTTPS. TON documentation notes that inaccessible or invalid manifests can cause manifest-related connection errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lifecycle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate away from the widget and back again. Make sure your application does not accidentally create duplicate instances or retain a widget mounted to an obsolete container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wallet state&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your application already manages TON Connect, verify that the widget uses the same intended connection through integrated mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swap configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you set default assets, custom assets, or referral parameters, verify those values rather than assuming that a successfully rendered interface means every option is correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Capture the widget's error event during development. A visible swap box is only one part of the integration. Wallet connection and transaction flows need testing as well.&lt;/p&gt;

&lt;p&gt;The practical takeaway is simple: treat &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt; as the runtime boundary between your application and the CDN-delivered widget. Test the loader, widget configuration, wallet layer, and DOM lifecycle independently. Once those pieces are separated mentally, integrating Omniston becomes much easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;It is an npm package for programmatically loading the Omniston Widget bundle. Your application calls &lt;code&gt;load()&lt;/code&gt;, waits for the bundle to become available, and receives the &lt;code&gt;OmnistonWidget&lt;/code&gt; constructor. The complete widget itself uses STON.fi's CDN distribution model rather than being bundled as a fixed widget copy inside the loader package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does &lt;code&gt;npm install @ston-fi/omniston-widget-loader&lt;/code&gt; install the complete widget?
&lt;/h3&gt;

&lt;p&gt;Not in the conventional sense. The package acts as a loader for the CDN-hosted widget. STON.fi documents this as an intentional distribution model so compatible widget updates can be delivered within a major-version path while applications keep using the same integration pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to import the Omniston Widget CSS separately?
&lt;/h3&gt;

&lt;p&gt;No separate widget stylesheet import is required according to the current STON.fi integration guide. The widget bundle loads its own styles. You can then customize supported visual properties through CSS variables scoped to the element used for &lt;code&gt;widget.mount(...)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use &lt;code&gt;standalone&lt;/code&gt; or &lt;code&gt;integrated&lt;/code&gt; TON Connect mode?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;standalone&lt;/code&gt; when the widget can manage the wallet connection required for its own swap flow. Use &lt;code&gt;integrated&lt;/code&gt; when your application already maintains TON Connect and you want Omniston to share that existing instance. The second approach avoids treating the widget as a separate wallet-connected application inside your dApp.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I lazy-load the Omniston Widget?
&lt;/h3&gt;

&lt;p&gt;Yes. Programmatic runtime loading is one of the main reasons to use the loader. You can call &lt;code&gt;load()&lt;/code&gt; when a swap component opens, when a relevant route becomes active, or at another point chosen by your application rather than declaring the widget globally with a script tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does &lt;code&gt;load()&lt;/code&gt; return?
&lt;/h3&gt;

&lt;p&gt;It resolves with the &lt;code&gt;OmnistonWidget&lt;/code&gt; constructor. You still need to instantiate it with &lt;code&gt;new OmnistonWidget(configuration)&lt;/code&gt; and then call &lt;code&gt;mount()&lt;/code&gt; with an existing DOM element. Loading the constructor and rendering the configured widget are separate stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I remove the widget after mounting it?
&lt;/h3&gt;

&lt;p&gt;Yes. The documented widget lifecycle includes &lt;code&gt;unmount()&lt;/code&gt;, and the widget exposes lifecycle events including &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;unmount&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;. This is especially useful in applications where routes or components appear and disappear without a full browser refresh.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I use the loader instead of the CDN script?
&lt;/h3&gt;

&lt;p&gt;Use the loader when your application already uses npm and a modern build system, especially when you want programmatic control over loading and component lifecycle. Use the direct CDN script when a small static integration benefits more from minimal setup. Both approaches ultimately expose the Omniston Widget constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Omniston Widget - Official overview of the widget, npm loader, CDN distribution, TON Connect modes, configuration, and customization&lt;/li&gt;
&lt;li&gt;STON.fi Full Guide &amp;amp; Reference - Official installation guide covering &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt;, &lt;code&gt;load()&lt;/code&gt;, configuration, lifecycle methods, assets, and TON Connect integration&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Widget GitHub repository - Official repository explaining the CDN distribution model and programmatic loader usage&lt;/li&gt;
&lt;li&gt;npm package registry - Package information and usage example for &lt;code&gt;@ston-fi/omniston-widget-loader&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Help Center - Official overview of embedding the swap widget, TON Connect modes, theming, assets, and referral configuration&lt;/li&gt;
&lt;li&gt;TON Documentation - Official TON Connect guidance covering manifest hosting, accessibility requirements, and available SDK packages&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>web3</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Embed the Omniston Widget with a CDN Script</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sun, 13 Sep 2026 15:43:45 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-embed-the-omniston-widget-with-a-cdn-script-32h9</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-embed-the-omniston-widget-with-a-cdn-script-32h9</guid>
      <description>&lt;p&gt;&lt;em&gt;Add an Omniston swap interface to a website with a single CDN bundle, TON Connect, and a small amount of JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You do not need a package manager or a full frontend build pipeline to embed the Omniston Widget. STON.fi provides the widget as a CDN-hosted JavaScript bundle. Add the script to your page, create an &lt;code&gt;OmnistonWidget&lt;/code&gt; instance, connect it to a TON Connect manifest, and mount it into a DOM element.&lt;/p&gt;

&lt;p&gt;The direct CDN approach is especially useful for static websites, prototypes, landing pages, dashboards, and projects where adding another npm dependency would be unnecessary. You still get the same widget constructor used by the npm loader, but the browser downloads the bundle directly from STON.fi.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the CDN integration actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff3j5pyse7nup0ivoquf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff3j5pyse7nup0ivoquf7.png" alt="What the CDN integration actually does" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The essential script is only one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://widget.ston.fi/v0/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that file loads, it exposes the widget constructor as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OmnistonWidget&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That global constructor is the entry point for configuring and mounting the swap interface.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/v0/&lt;/code&gt; part of the CDN URL is important. STON.fi uses major-versioned CDN paths. Integrations on the same major version can receive non-breaking updates without changing the script URL. A future breaking release would use a different major path such as &lt;code&gt;/v1/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the browser-side flow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the CDN script.&lt;/li&gt;
&lt;li&gt;Create an &lt;code&gt;OmnistonWidget&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Pass the TON Connect configuration.&lt;/li&gt;
&lt;li&gt;Find the container where the widget should appear.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;widget.mount(container)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not need to import a separate widget stylesheet. The widget bundle handles its own styles, while supported CSS custom properties let you change its appearance from the container around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before adding the widget
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faic415lydfprzel416y9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faic415lydfprzel416y9.png" alt="What you need before adding the widget" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The JavaScript is the easy part. Wallet connectivity requires one additional piece: a TON Connect manifest.&lt;/p&gt;

&lt;p&gt;A minimal integration needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a page that can run JavaScript&lt;/li&gt;
&lt;li&gt;a DOM element for the widget&lt;/li&gt;
&lt;li&gt;the Omniston CDN script&lt;/li&gt;
&lt;li&gt;a public TON Connect manifest&lt;/li&gt;
&lt;li&gt;HTTPS in production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The TON Connect manifest tells compatible wallets which application is requesting the connection. It contains basic dApp metadata such as the application URL, name, and icon.&lt;/p&gt;

&lt;p&gt;A minimal manifest can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Omniston App"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iconUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/icon-180.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TON documentation requires the manifest to be publicly reachable without authentication or blocking CORS rules. HTTPS should be used, and the referenced icon should be publicly accessible as PNG or ICO. STON.fi's widget documentation specifically instructs integrators to host their own manifest on the application domain, so following that stricter layout is the safest approach for this integration.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/tonconnect-manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not point a production application at somebody else's manifest. It represents the identity shown to the wallet during connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  The smallest working CDN example
&lt;/h2&gt;

&lt;p&gt;Here is the core integration in one HTML document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Omniston Widget&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"max-width: 420px; margin: 40px auto;"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://widget.ston.fi/v0/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;example.com&lt;/code&gt; with your actual domain and publish the TON Connect manifest there.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;standalone&lt;/code&gt; option is useful because the widget manages TON Connect internally. You provide the manifest URL, and you do not need to create a separate TON Connect instance just to get the widget running. STON.fi recommends this mode for smaller sites that only need the wallet connection as part of the embedded swap experience.&lt;/p&gt;

&lt;p&gt;The important line is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor only creates the widget instance. &lt;code&gt;mount()&lt;/code&gt; attaches its interface to the page.&lt;/p&gt;

&lt;p&gt;That distinction becomes useful later if your application needs to open, close, or move the swap experience dynamically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens after the widget is mounted
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6i7qeepd5mzyyhgl2nia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6i7qeepd5mzyyhgl2nia.png" alt="What happens after the widget is mounted" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Embedding the component does more than place a form on the page.&lt;/p&gt;

&lt;p&gt;Omniston is STON.fi's liquidity aggregation protocol for TON. Instead of requiring your frontend to implement each liquidity venue separately, Omniston can obtain quotes from connected liquidity sources and resolvers and find a route for the requested swap.&lt;/p&gt;

&lt;p&gt;From the developer's perspective, the widget provides the user-facing layer around that process.&lt;/p&gt;

&lt;p&gt;A typical interaction looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The visitor opens your page.&lt;/li&gt;
&lt;li&gt;The CDN bundle creates the swap interface.&lt;/li&gt;
&lt;li&gt;The visitor chooses the assets and amount.&lt;/li&gt;
&lt;li&gt;TON Connect handles wallet connectivity.&lt;/li&gt;
&lt;li&gt;Omniston obtains swap quotes from its available liquidity sources.&lt;/li&gt;
&lt;li&gt;The visitor reviews the resulting swap and authorizes the required transaction through the wallet.&lt;/li&gt;
&lt;li&gt;The resulting operation proceeds through the selected route.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why the widget can be useful when your goal is to add a ready-made swap surface rather than build quote management, asset selection, wallet interaction, and swap UI yourself.&lt;/p&gt;

&lt;p&gt;The widget does not remove the user's wallet from the transaction flow. Wallet authorization remains part of the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  CDN script or npm loader?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhwnfcyh18dn681ultpfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhwnfcyh18dn681ultpfq.png" alt="CDN script or npm loader" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi offers two ways to obtain the same widget constructor.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Direct CDN script&lt;/th&gt;
&lt;th&gt;npm loader&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Package installation&lt;/td&gt;
&lt;td&gt;Not required&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build system&lt;/td&gt;
&lt;td&gt;Not required&lt;/td&gt;
&lt;td&gt;Usually used with one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constructor access&lt;/td&gt;
&lt;td&gt;&lt;code&gt;window.OmnistonWidget&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returned by &lt;code&gt;load()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good fit&lt;/td&gt;
&lt;td&gt;Static pages, simple sites, prototypes&lt;/td&gt;
&lt;td&gt;Bundled JavaScript applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Widget delivery&lt;/td&gt;
&lt;td&gt;STON.fi CDN&lt;/td&gt;
&lt;td&gt;STON.fi CDN through the loader&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The distinction is mainly about how your application loads the code. The widget itself is distributed through the CDN rather than as a conventional fixed widget package. STON.fi explains that this model allows integrations to receive fixes and compatible updates within their selected major version.&lt;/p&gt;

&lt;p&gt;If you already have a modern React, Vue, Svelte, or similar build process, the loader may fit the project architecture better. If you simply want a swap widget on a web page, the CDN script removes an unnecessary installation step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the assets shown to users
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbepnze3ariu16q6r98o6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbepnze3ariu16q6r98o6.png" alt="Configure the assets shown to users" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The minimal configuration is enough to get started, but you can also control which assets appear.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OmnistonWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tonconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/tonconnect-manifest.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;defaultBidAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="na"&gt;defaultAskAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#omniston-widget-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi's current documentation uses the first address above for TON and the second as an example STON jetton address. For production integrations, verify asset addresses from authoritative sources rather than copying unfamiliar addresses from third-party examples.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;customAssets&lt;/code&gt; to add token root addresses. If &lt;code&gt;defaultAssets&lt;/code&gt; remains enabled, those custom assets supplement the built-in list.&lt;/p&gt;

&lt;p&gt;If you set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;defaultAssets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then your custom list becomes the entire selector. Do not disable the default list without supplying assets, because the widget would have nothing to display.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add referral fees only if you need them
&lt;/h2&gt;

&lt;p&gt;The widget can also pass referral configuration.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;referrerAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_TON_WALLET_ADDRESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;referrerFeeBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fee value uses basis points. &lt;code&gt;50&lt;/code&gt; basis points equals &lt;code&gt;0.5%&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;STON.fi currently documents a widget referral range from 1 to 100 basis points, corresponding to 0.01% to 1%. Both the referral address and fee should be configured when you intend to use this feature.&lt;/p&gt;

&lt;p&gt;Referral settlement can differ depending on the liquidity source used by Omniston. That detail matters if you plan to build reporting or withdrawal tooling around referral revenue. The Omniston referral documentation should therefore be treated as the source of truth for the settlement mechanism rather than assuming every route pays referrals in exactly the same way.&lt;/p&gt;

&lt;p&gt;For a simple embed whose only goal is swaps, you can leave referral settings out entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the widget fit your interface
&lt;/h2&gt;

&lt;p&gt;The container passed into &lt;code&gt;mount()&lt;/code&gt; also acts as the scope for supported theme overrides.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;#omniston-widget-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0f172a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--border-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--text-primary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8fafc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because these variables are attached to the widget container, they can be adjusted without applying the same values across the rest of your page.&lt;/p&gt;

&lt;p&gt;You can also force the widget's dark styling through the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"omniston-widget-container"&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi provides a visual widget constructor at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://widget.ston.fi/constructor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can generate configuration and CSS values for a chosen appearance, token setup, and referral configuration. That can be faster than manually experimenting with every available CSS custom property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control mounting and catch errors
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzosemgy6disrd8mvlhg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzosemgy6disrd8mvlhg.png" alt="Control mounting and catch errors" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A production integration should account for more than the happy path.&lt;/p&gt;

&lt;p&gt;The widget exposes lifecycle events including &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;unmount&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Omniston Widget mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Omniston Widget error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unmount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Omniston Widget unmounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also remove the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unmount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same widget instance can later be mounted again when needed. This is useful for interfaces that show swaps inside a modal, expandable panel, or page controlled by client-side navigation.&lt;/p&gt;

&lt;p&gt;A few checks are worth making before deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm that &lt;code&gt;https://widget.ston.fi/v0/index.js&lt;/code&gt; loads successfully.&lt;/li&gt;
&lt;li&gt;Confirm that the widget container exists before calling &lt;code&gt;mount()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open your manifest URL directly and verify that it returns JSON.&lt;/li&gt;
&lt;li&gt;Test the manifest from a clean browser session without authentication.&lt;/li&gt;
&lt;li&gt;Check that its icon is publicly reachable.&lt;/li&gt;
&lt;li&gt;Test wallet connection on both desktop and mobile flows.&lt;/li&gt;
&lt;li&gt;Watch the widget's &lt;code&gt;error&lt;/code&gt; event during development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manifest failures deserve particular attention. TON documentation notes that CORS restrictions, authentication, unreachable files, proxy challenges, invalid content, and inaccessible icons can prevent a wallet from accepting the manifest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; If your website already serves static HTML and JavaScript, start with the direct CDN script and standalone TON Connect mode. Verify the manifest independently first, then mount the default widget before adding custom assets, referral fees, or visual overrides. That sequence makes it much easier to tell whether a problem comes from wallet connectivity, widget loading, or your own configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I use the Omniston Widget without npm?
&lt;/h3&gt;

&lt;p&gt;Yes. Load &lt;code&gt;https://widget.ston.fi/v0/index.js&lt;/code&gt; with a normal &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. The bundle exposes &lt;code&gt;window.OmnistonWidget&lt;/code&gt;, which you can instantiate directly in browser JavaScript. This is the official zero-build integration path and is suitable for static pages as well as applications that can execute ordinary client-side scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need the Omniston SDK as well?
&lt;/h3&gt;

&lt;p&gt;Not for a basic widget integration. The widget provides a ready-made interface around the swap workflow. The lower-level Omniston SDK is more appropriate when you want to design your own swap interface, quote logic, transaction flow, or deeper application behavior instead of embedding the existing widget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does the URL contain &lt;code&gt;/v0/&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;It represents the widget's major version. STON.fi uses major-versioned CDN paths so an integration can receive compatible updates within the same major release. If a future release introduces breaking changes, it can use another path such as &lt;code&gt;/v1/&lt;/code&gt;, allowing developers to adopt that major version deliberately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the CDN method automatically connect the wallet?
&lt;/h3&gt;

&lt;p&gt;The script loads the widget, but wallet connectivity still depends on TON Connect configuration. In standalone mode, you give the widget your manifest URL and it manages the TON Connect integration internally. The wallet still asks the person using the site to connect and authorize relevant actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does my TON Connect manifest fail even though the URL exists?
&lt;/h3&gt;

&lt;p&gt;Reachability alone is not enough. The manifest must return valid JSON and be accessible without authentication or restrictive CORS rules. Proxy challenges can also interfere. Check the response itself, the &lt;code&gt;iconUrl&lt;/code&gt;, HTTPS availability, and whether a wallet can fetch the file independently of your browser session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use my existing TON Connect instance?
&lt;/h3&gt;

&lt;p&gt;Yes. Omniston Widget supports an &lt;code&gt;integrated&lt;/code&gt; mode for applications that already manage TON Connect. STON.fi warns against creating multiple TON Connect instances in the same application because of SDK limitations. If your app already owns the connection state, reuse that instance instead of starting another one inside the widget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I choose which tokens appear in the widget?
&lt;/h3&gt;

&lt;p&gt;Yes. You can set default bid and ask assets, add token root addresses through &lt;code&gt;customAssets&lt;/code&gt;, or disable the standard asset list and provide your own list. If you disable the default assets, make sure your custom list is populated or the asset selector will have nothing useful to show.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the simplest production setup for the Omniston Widget?
&lt;/h3&gt;

&lt;p&gt;Use the major-versioned STON.fi CDN script, host a valid TON Connect manifest on your application domain, initialize the widget in &lt;code&gt;standalone&lt;/code&gt; mode, mount it into an existing DOM element, and test wallet connectivity before adding optional configuration. Once the basic swap flow works, introduce theming, asset restrictions, lifecycle handling, or referral settings as separate changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Omniston Widget - Official overview, CDN quick start, configuration areas, and widget constructor&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Widget Full Guide and Reference - Detailed CDN integration, TON Connect modes, configuration, styling, lifecycle events, and examples&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Widget GitHub Repository - Official widget repository with CDN distribution model and loading examples&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Overview - Official explanation of Omniston aggregation, routing, liquidity sources, and developer integration&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Referral Fees - Current referral parameters and settlement behavior across supported liquidity sources&lt;/li&gt;
&lt;li&gt;TON Connect Get Started - Official requirements for manifests, wallet integration, hosting, and supported JavaScript approaches&lt;/li&gt;
&lt;li&gt;TON Connect Core Concepts - Official manifest fields, connection concepts, and protocol requirements&lt;/li&gt;
&lt;li&gt;TON Connect Troubleshooting - Official guidance for manifest errors, CORS problems, inaccessible icons, and hosting issues&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>web3</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Handle a Failed STON.fi Swap in an App</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Mon, 07 Sep 2026 16:27:12 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-handle-a-failed-stonfi-swap-in-an-app-47oe</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-handle-a-failed-stonfi-swap-in-an-app-47oe</guid>
      <description>&lt;p&gt;&lt;em&gt;How to distinguish wallet rejection, submission failure, on-chain execution failure, and a STON.fi refund without showing users the wrong status.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A failed STON.fi swap should not be handled as one generic exception. In an app, the failure can happen while you simulate the trade, build the transaction, ask the wallet to sign, submit the message to TON, or execute the swap through STON.fi contracts. Those stages have different meanings and require different recovery actions.&lt;/p&gt;

&lt;p&gt;The most important rule is simple: &lt;strong&gt;a resolved TonConnect &lt;code&gt;sendTransaction()&lt;/code&gt; call does not prove that the entire swap succeeded&lt;/strong&gt;. It gives your app the BoC of the broadcast external message. Your app still needs to determine what happened on-chain before presenting the swap as complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start by separating the failure stages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ficxrmc8wmrcv16qwrnmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ficxrmc8wmrcv16qwrnmw.png" alt="Start by separating the failure stages" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A "Swap failed" toast hides too much information. Your application should first identify where execution stopped.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What happened&lt;/th&gt;
&lt;th&gt;What your app should do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;No usable quote was produced&lt;/td&gt;
&lt;td&gt;Keep funds untouched and request a fresh simulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transaction building&lt;/td&gt;
&lt;td&gt;SDK or contract parameters could not be created&lt;/td&gt;
&lt;td&gt;Log the technical error and do not open the wallet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet approval&lt;/td&gt;
&lt;td&gt;The request was rejected or could not be sent&lt;/td&gt;
&lt;td&gt;Return to a retryable pre-submission state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Submitted&lt;/td&gt;
&lt;td&gt;Wallet signed and broadcast the message&lt;/td&gt;
&lt;td&gt;Do not call the swap successful yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-chain execution&lt;/td&gt;
&lt;td&gt;TON or STON.fi processing failed&lt;/td&gt;
&lt;td&gt;Inspect the transaction trace and possible refund&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swap completed&lt;/td&gt;
&lt;td&gt;Requested output reached the intended receiver&lt;/td&gt;
&lt;td&gt;Mark the operation successful&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That distinction matters particularly on TON because contract interactions are asynchronous. A swap can involve several internal messages instead of one atomic execution step. TON documentation explicitly notes that different recipient contracts process messages independently, and failures can produce bounced messages under the appropriate conditions.&lt;/p&gt;

&lt;p&gt;Your frontend therefore needs at least one state between &lt;code&gt;wallet approved&lt;/code&gt; and &lt;code&gt;swap succeeded&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design the swap as a state machine
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fban92x08aaqp7jrn3p98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fban92x08aaqp7jrn3p98.png" alt="Design the swap as a state machine" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small state machine is more reliable than a single &lt;code&gt;isLoading&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SwapStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;simulating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;awaiting_wallet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submitted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirming&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refunded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SwapFailureStage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;simulation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wallet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;execution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical transition is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ready
  -&amp;gt; awaiting_wallet
  -&amp;gt; submitted
  -&amp;gt; confirming
  -&amp;gt; success | refunded | failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ready
  -&amp;gt; awaiting_wallet
  -&amp;gt; success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TonConnect's &lt;code&gt;sendTransaction()&lt;/code&gt; asks the connected wallet to sign and broadcast the transaction. Its response contains a base64 BoC of the broadcast external message. TON documentation recommends using that BoC to find and inspect what happened on-chain.&lt;/p&gt;

&lt;p&gt;This lets your UI say something accurate such as "Transaction submitted" while confirmation is pending rather than prematurely displaying "Swap successful."&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevent avoidable failures before the wallet opens
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvfrhmi7x66c7lr6wmidc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvfrhmi7x66c7lr6wmidc.png" alt="Prevent avoidable failures before the wallet opens" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good failure handling starts before &lt;code&gt;try/catch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;STON.fi's current v2 integration guidance recommends an API-driven workflow: simulate the swap, use the router information returned by the API, construct the matching contracts through &lt;code&gt;dexFactory()&lt;/code&gt;, then build the transaction parameters. Hardcoding a Router can make an integration incompatible with Router versions or types that the API actually selected.&lt;/p&gt;

&lt;p&gt;Before opening TonConnect, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the connected wallet is on the expected network&lt;/li&gt;
&lt;li&gt;the offer amount is positive and converted using the token's actual decimals&lt;/li&gt;
&lt;li&gt;the wallet has the offered asset&lt;/li&gt;
&lt;li&gt;sufficient TON is available for execution costs when required&lt;/li&gt;
&lt;li&gt;the quote is still current&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minAskAmount&lt;/code&gt; comes from the simulation you intend to execute&lt;/li&gt;
&lt;li&gt;the Router and pTON contracts correspond to the simulation result&lt;/li&gt;
&lt;li&gt;the transaction has not already been submitted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STON.fi's React quickstart follows the same broad sequence: fetch assets, simulate the trade, derive contracts from Router information, build the swap parameters, and finally pass the resulting message to TonConnect.&lt;/p&gt;

&lt;p&gt;For the TonConnect request itself, &lt;code&gt;validUntil&lt;/code&gt; is a Unix timestamp in seconds. A typical request looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tonConnectUI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;validUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-239&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;swapParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;swapParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;swapParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toBoc&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping quote creation and transaction submission close together also reduces the chance that market conditions change enough to violate the swap's minimum output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle wallet errors without lying to the user
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ru31azt5ba2jpb7k0jp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ru31azt5ba2jpb7k0jp.png" alt="Handle wallet errors without lying to the user" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A wallet rejection is not an on-chain swap failure. No STON.fi troubleshooting is required if the transaction never reached the blockchain.&lt;/p&gt;

&lt;p&gt;Keep the wallet layer separate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;awaiting_wallet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tonConnectUI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submitted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;confirmSwapOnChain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;boc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;handleWalletOrSubmissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TonConnect defines errors for cases such as a rejected request, bad request, unsupported method, wrong network, or disconnected wallet. A user declining a transaction should normally produce something like "Transaction cancelled" rather than "STON.fi swap failed."&lt;/p&gt;

&lt;p&gt;Also avoid automatic blind retries when submission is ambiguous. Current TonConnect UI documentation specifically warns that some connect-and-send flows can leave the app without a response even though the request may already have reached the wallet. Retrying silently could submit the operation twice.&lt;/p&gt;

&lt;p&gt;Give the user an explicit retry action after you have checked whether a matching transaction already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the outcome on-chain after broadcast
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F16j87rex08fszrrceoru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F16j87rex08fszrrceoru.png" alt="Verify the outcome on-chain after broadcast" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once TonConnect returns the BoC, move the operation to &lt;code&gt;submitted&lt;/code&gt; or &lt;code&gt;confirming&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Store enough context to investigate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingSwap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;offerAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;askAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;minAskUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;routerAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;simulationResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;submittedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;boc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;boc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use your TON data provider or indexer to locate the external message and follow the resulting trace.&lt;/p&gt;

&lt;p&gt;Do not stop at the wallet transaction alone. TON ordinary transactions contain separate compute, action, and possible bounce phases. A contract can execute its compute phase but still encounter a later action failure. The &lt;code&gt;aborted&lt;/code&gt;, compute result, action result, and bounce data help distinguish those cases.&lt;/p&gt;

&lt;p&gt;For a swap, the application-level question is ultimately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did the intended output arrive, or did the STON.fi execution take another path such as a refund?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is stronger evidence than simply observing that the initiating wallet transaction exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read STON.fi refund signals correctly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdgj1d9gfirhgb39a0gll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdgj1d9gfirhgb39a0gll.png" alt="Read STON.fi refund signals correctly" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi DEX v2 has explicit failure and refund mechanics. The Router payload includes a &lt;code&gt;refund_address&lt;/code&gt;, and the contract API defines several operation codes that explain why swap execution could not continue.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;swap_refund_reserve_err&lt;/code&gt;: insufficient liquidity for the swap&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swap_refund_0_out&lt;/code&gt;: calculated output is zero&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swap_refund_slippage&lt;/code&gt;: output is below the required minimum&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swap_pool_locked&lt;/code&gt;: the pool is locked&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transfer_bounce_low_gas&lt;/code&gt;: insufficient gas for the operation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transfer_bounce_invalid_pool&lt;/code&gt;: invalid pool configuration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transfer_bounce_tx_expired&lt;/code&gt;: the transaction expired at the Router&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slippage failure is especially important for applications. STON.fi's Pool specification states that a swap fails when the amount the user would receive is below &lt;code&gt;min_out&lt;/code&gt;. That protects the user from accepting execution worse than the limit encoded in the transaction.&lt;/p&gt;

&lt;p&gt;The recovery action is usually not "retry immediately with a larger slippage tolerance." Instead, fetch a new simulation, show the new expected output, and let the user make another decision.&lt;/p&gt;

&lt;p&gt;There is another TON-specific complication with routed swaps. STON.fi documents that multi-contract transactions on TON are not atomic. If a cross-swap fails after an intermediate step, a complete rollback to the original asset is not always possible. The user can receive an intermediate routing token instead.&lt;/p&gt;

&lt;p&gt;Your balance reconciliation logic should therefore check actual resulting assets instead of assuming every failed swap returns exactly the original token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one failed swap from start to finish
&lt;/h2&gt;

&lt;p&gt;Imagine your app is swapping Jetton A for Jetton B.&lt;/p&gt;

&lt;p&gt;The app simulates the trade and receives a route with an expected output and &lt;code&gt;minAskUnits&lt;/code&gt;. It uses the Router metadata from that simulation with &lt;code&gt;dexFactory()&lt;/code&gt;, builds the STON.fi message, and opens TonConnect.&lt;/p&gt;

&lt;p&gt;The user approves it.&lt;/p&gt;

&lt;p&gt;At this point, your UI should display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Swap submitted
Waiting for on-chain execution...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Swap successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While TON processes the message chain, the pool price changes. The amount available from the swap falls below the encoded minimum.&lt;/p&gt;

&lt;p&gt;STON.fi can reject that execution condition as a slippage failure rather than deliver an output below the user's limit. Your monitoring layer detects the resulting execution or refund path. The app changes the status to &lt;code&gt;refunded&lt;/code&gt;, refreshes balances, and explains what happened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Swap was not executed because the available output
fell below your minimum. Funds were refunded.

Get a new quote before trying again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare that with a wallet rejection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Transaction cancelled.
No swap was submitted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with an unresolved submitted transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Transaction submitted.
Confirmation is still pending.
Do not submit the same swap again yet.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those messages describe three genuinely different states and prevent users from taking the wrong recovery action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; treat the STON.fi transaction builder, TonConnect, TON execution, and the final swap outcome as separate checkpoints. Simulate immediately before submission, build from current Router metadata, store the returned BoC, verify the resulting trace, refresh balances, and only display success after the requested asset outcome has been confirmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does &lt;code&gt;sendTransaction()&lt;/code&gt; succeeding mean my STON.fi swap succeeded?
&lt;/h3&gt;

&lt;p&gt;No. It means the wallet successfully returned the BoC for the transaction it signed and broadcast. Contract execution still occurs on TON. Your app should move to a submitted or confirming state and inspect the resulting on-chain transaction flow before declaring the swap successful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I automatically retry every failed swap?
&lt;/h3&gt;

&lt;p&gt;No. First determine whether the original transaction was never submitted, definitively failed, was refunded, or has an unknown outcome. Automatic retries are risky when submission status is uncertain because the first transaction may still have reached the network. A user-triggered retry after reconciliation is safer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can a swap fail after the wallet approved it?
&lt;/h3&gt;

&lt;p&gt;Wallet approval only authorizes and broadcasts the initial message. TON contracts then process the operation through their execution phases and internal messages. STON.fi can encounter conditions such as insufficient output, expired execution, insufficient gas, a locked pool, or another contract-level failure after approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I do when a swap fails because of slippage?
&lt;/h3&gt;

&lt;p&gt;Request a new simulation and present the updated quote. Do not silently increase the user's slippage tolerance. In STON.fi, the minimum output is an execution constraint, and the swap can be refunded when calculated output falls below that minimum. Changing the tolerance changes the trade the user is agreeing to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a failed STON.fi swap return a different token?
&lt;/h3&gt;

&lt;p&gt;It can in a routed cross-swap. STON.fi explains that TON multi-contract transactions are not fully atomic, so if a routed swap fails after an intermediate conversion, the user may receive an intermediate token rather than a complete rollback into the original asset. Your app should reconcile actual balances after failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I hardcode the STON.fi Router address in my app?
&lt;/h3&gt;

&lt;p&gt;For current production integrations, STON.fi recommends an API-driven approach. The simulation provides Router information that can be passed into &lt;code&gt;dexFactory()&lt;/code&gt; so the SDK selects the appropriate contracts. This also reduces problems caused by Router versions or types changing while your application continues using an old hardcoded configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest flow for handling a failed STON.fi swap in an app?
&lt;/h3&gt;

&lt;p&gt;Simulate first, build the transaction from current Router metadata, request the wallet signature, mark the operation as submitted when TonConnect returns, verify the on-chain result, detect success or refund, refresh balances, and only then show the final status. If the outcome is uncertain, prevent blind retries until your app has reconciled the transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Swap Guide (React) - official example covering simulation, dynamic Router selection, SDK transaction building, and TonConnect submission&lt;/li&gt;
&lt;li&gt;STON.fi Swap v2 SDK documentation - current API-driven workflow for building production swaps from simulation and Router metadata&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 smart contracts - overview of v2 swap mechanics, refunds, deadlines, and production SDK guidance&lt;/li&gt;
&lt;li&gt;STON.fi Router v2 - Router swap payload fields including minimum output, refund address, receiver, and execution deadline&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Op Codes - reference for successful swaps, slippage refunds, liquidity errors, low gas, expired transactions, and other execution outcomes&lt;/li&gt;
&lt;li&gt;STON.fi Swap Examples - official diagrams and explanations for simple swaps, routed swaps, and refund behavior&lt;/li&gt;
&lt;li&gt;TON Connect Send Transaction - official specification of transaction submission, returned BoC, request expiration, network selection, and wallet errors&lt;/li&gt;
&lt;li&gt;TON Ordinary Transactions and Execution Phases - official TON documentation explaining compute, action, bounce, aborted transactions, and asynchronous message execution&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>crypto</category>
      <category>software</category>
      <category>web3</category>
    </item>
    <item>
      <title>How to Estimate Gas for a STON.fi Transaction</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sat, 05 Sep 2026 10:44:22 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-estimate-gas-for-a-stonfi-transaction-5hd8</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-estimate-gas-for-a-stonfi-transaction-5hd8</guid>
      <description>&lt;p&gt;Estimating gas for a STON.fi transaction is less about guessing a fixed fee and more about understanding the TON message path your operation will create. A swap can involve your wallet, a jetton wallet, a STON.fi Router, a liquidity pool, and additional token transfers before the result reaches you.&lt;/p&gt;

&lt;p&gt;For most users and integrations, the safest approach is simple: simulate the exact STON.fi operation, use the gas parameters returned for that route, let the current SDK construct the transaction, and keep enough TON in the wallet to cover the attached execution budget.&lt;/p&gt;

&lt;p&gt;The harder part is understanding what those numbers actually mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why TON gas is different from the Ethereum mental model
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjnbjx1ml123dnajl90bc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjnbjx1ml123dnajl90bc.png" alt="Why TON gas is different from the Ethereum mental model" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developers coming from Ethereum often think about transaction cost as roughly:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gas used × gas price&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;TON works differently at the transaction level. Contract execution still consumes gas, but the amount ultimately spent by a transaction can include several categories of fees.&lt;/p&gt;

&lt;p&gt;A TON transaction can pass through storage, compute, action, and sometimes bounce phases. The network may charge for contract computation, persistent storage, and forwarding messages to other contracts. A multi-contract DeFi operation can therefore create several transactions rather than one isolated smart contract call.&lt;/p&gt;

&lt;p&gt;For a STON.fi swap, that distinction matters because the initial wallet message may trigger a sequence such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your wallet sends the operation.&lt;/li&gt;
&lt;li&gt;A jetton or pTON contract processes the asset transfer.&lt;/li&gt;
&lt;li&gt;The STON.fi Router receives the swap request.&lt;/li&gt;
&lt;li&gt;The Router communicates with the appropriate pool.&lt;/li&gt;
&lt;li&gt;Contracts send the resulting asset toward the destination wallet.&lt;/li&gt;
&lt;li&gt;Remaining TON intended for excesses may be returned according to the transaction flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step can require computation or another internal message.&lt;/p&gt;

&lt;p&gt;So when an interface says a transaction needs a certain amount of TON for "gas," it often refers to an execution budget attached to the transaction, not simply the exact compute fee that validators will eventually keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually contributes to a TON transaction cost
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe1hx0w3ef5lc2i2lpyh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe1hx0w3ef5lc2i2lpyh9.png" alt="What actually contributes to a TON transaction cost" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TON documentation separates several fee components. Understanding them makes STON.fi gas estimates much easier to interpret.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;Why it matters for STON.fi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compute fee&lt;/td&gt;
&lt;td&gt;TVM execution of smart contract code&lt;/td&gt;
&lt;td&gt;Routers, pools, wallets, and related contracts perform computation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forward fee&lt;/td&gt;
&lt;td&gt;Delivery of internal messages&lt;/td&gt;
&lt;td&gt;A swap normally moves messages between multiple contracts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage fee&lt;/td&gt;
&lt;td&gt;Persistent blockchain storage&lt;/td&gt;
&lt;td&gt;Contracts can owe storage fees when they are processed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action-related fees&lt;/td&gt;
&lt;td&gt;Actions created after successful computation&lt;/td&gt;
&lt;td&gt;Token transfers and subsequent internal messages can add cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attached TON budget&lt;/td&gt;
&lt;td&gt;TON carried with a message to fund downstream execution&lt;/td&gt;
&lt;td&gt;A STON.fi operation needs enough value to complete its message chain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TON processes fees at different stages of execution. Official documentation lists import, storage, gas, action, and forwarding costs in the transaction lifecycle.&lt;/p&gt;

&lt;p&gt;This is why the phrase "gas fee" can be misleading in a DEX interface. The amount attached to a transaction may be larger than the amount ultimately consumed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Budget is not the same as final cost
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhektiwsk07zj651fjz1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhektiwsk07zj651fjz1t.png" alt="Budget is not the same as final cost" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose an integration prepares a transaction with a conservative TON execution budget. That does not automatically mean the whole budget becomes a fee.&lt;/p&gt;

&lt;p&gt;Part of the attached value may fund downstream messages, while unused value can be handled as excess according to the contracts and message modes involved. TON's message model explicitly allows value to move between contracts while fees are deducted along the route.&lt;/p&gt;

&lt;p&gt;For this reason, two numbers are useful to distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;required transaction budget&lt;/strong&gt;, which needs to be available for the operation to run safely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;actual network consumption&lt;/strong&gt;, which is what the completed transaction trace ultimately spent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first number matters before signing. The second becomes fully observable after execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the exact STON.fi operation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4fqebguszw5zhaydcemq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4fqebguszw5zhaydcemq.png" alt="Start with the exact STON.fi operation" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is no single universal gas number that should be hardcoded for every STON.fi transaction.&lt;/p&gt;

&lt;p&gt;A TON to jetton swap does not have exactly the same message flow as a jetton to jetton swap. Liquidity provision is different again. Contract versions, token behavior, optional payloads, and the route chosen for the transaction can also affect execution.&lt;/p&gt;

&lt;p&gt;STON.fi currently recommends an API-driven workflow for DEX v2 integrations. The application first simulates the swap, obtains the router and transaction information associated with that simulation, and then uses the correct SDK contracts for that router.&lt;/p&gt;

&lt;p&gt;That makes the route itself the starting point for gas estimation.&lt;/p&gt;

&lt;p&gt;A practical rule is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estimate the transaction you are about to send, not an abstract "STON.fi swap."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider two swaps for the same monetary value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TON to a jetton&lt;/li&gt;
&lt;li&gt;one jetton to another jetton&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their trade value could be identical, but the token transfer and message sequences can differ. Gas therefore follows execution structure more closely than trade value.&lt;/p&gt;

&lt;p&gt;A 10 TON swap does not automatically require ten times as much gas as a 1 TON swap. Increasing the token amount usually does not multiply the amount of smart contract computation by the same factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use STON.fi swap simulation as the primary estimate
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faou42jo7cun8d3v4gghi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faou42jo7cun8d3v4gghi.png" alt="Use STON.fi swap simulation as the primary estimate" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a current integration, the most useful first step is STON.fi's swap simulation endpoint.&lt;/p&gt;

&lt;p&gt;The DEX API exposes &lt;code&gt;POST /v1/swap/simulate&lt;/code&gt;. STON.fi describes the endpoint as calculating expected swap output, fees, and gas costs before execution.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@ston-fi/api&lt;/code&gt; package exposes the same workflow through &lt;code&gt;simulateSwap()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A simplified example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StonApiClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;simulateSwap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;offerAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;offer asset&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;askAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;ask asset&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;offerUnits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;amount in blockchain units&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;slippageTolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.005&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gasParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The STON.fi API added a &lt;code&gt;gasParams&lt;/code&gt; structure to swap simulation responses. Its documented fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gasBudget&lt;/code&gt;: an optional TON gas budget for the transaction&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forwardGas&lt;/code&gt;: the TON amount intended for forwarding&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;estimatedGasConsumption&lt;/code&gt;: estimated gas consumption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fields were introduced specifically so an integration can work from a route-specific estimate rather than relying only on fixed assumptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to interpret the three fields
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;gasBudget&lt;/code&gt; is the practical budget signal. It tells the integration how much TON should be available for the execution requirements associated with the simulated operation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;forwardGas&lt;/code&gt; relates to the TON value that must travel farther through the operation's message chain.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;estimatedGasConsumption&lt;/code&gt; is useful for understanding expected consumption. It should not automatically be treated as an interchangeable replacement for the amount that needs to be attached to the originating transaction.&lt;/p&gt;

&lt;p&gt;In other words, avoid taking &lt;code&gt;estimatedGasConsumption&lt;/code&gt;, adding an arbitrary percentage, and assuming that number can replace the transaction parameters expected by the STON.fi contracts.&lt;/p&gt;

&lt;p&gt;The API and SDK know more about the route than that simplified calculation does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let the SDK build the transaction budget
&lt;/h2&gt;

&lt;p&gt;After simulation, STON.fi's current v2 documentation recommends taking the &lt;code&gt;router&lt;/code&gt; object returned by the API and passing it to &lt;code&gt;dexFactory()&lt;/code&gt;. This selects the contract implementation that matches the router used by the simulated swap.&lt;/p&gt;

&lt;p&gt;Conceptually, the flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Swap request
    |
    v
STON.fi simulation
    |
    +--&amp;gt; expected output
    +--&amp;gt; minimum output
    +--&amp;gt; router information
    +--&amp;gt; gas parameters
    |
    v
Correct SDK contracts
    |
    v
Transaction parameters
    |
    v
Wallet review and signature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value sent with the transaction should come from the transaction construction logic for that exact operation rather than from a stale constant copied from another example.&lt;/p&gt;

&lt;p&gt;This is especially important because STON.fi has multiple DEX contract generations. The current SDK documentation identifies v2 as the latest major architecture while v1 remains supported for backward compatibility. The SDK has also received changes related to gas efficiency and contract routing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be careful when TON itself is the asset being swapped
&lt;/h3&gt;

&lt;p&gt;When the input asset is TON, the amount leaving the wallet can include both economic value and execution funding.&lt;/p&gt;

&lt;p&gt;Imagine that you want to swap 5 TON into a jetton. The wallet may need to send more than exactly 5 TON because the transaction also needs enough TON to execute the operation.&lt;/p&gt;

&lt;p&gt;That does &lt;strong&gt;not&lt;/strong&gt; mean the difference is automatically the final network fee.&lt;/p&gt;

&lt;p&gt;By contrast, when swapping a jetton for another jetton, the jetton amount is transferred through its token contracts while a separate amount of TON is attached to finance execution.&lt;/p&gt;

&lt;p&gt;This distinction is one of the easiest places to misread a wallet confirmation screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you calculate fees yourself?
&lt;/h2&gt;

&lt;p&gt;For a normal STON.fi integration, starting from the official simulation and SDK is usually more robust than reconstructing every fee component manually.&lt;/p&gt;

&lt;p&gt;Manual estimation becomes useful when you are building infrastructure, auditing contract behavior, testing custom payloads, or trying to understand why actual execution differs from your expected budget.&lt;/p&gt;

&lt;p&gt;TON provides tools for both approaches.&lt;/p&gt;

&lt;p&gt;Its API includes an &lt;code&gt;estimateFee&lt;/code&gt; method that accepts a destination address and serialized message body and returns categories including gas, storage, and forwarding fees. It can be used as an additional check once you have a concrete message to evaluate.&lt;/p&gt;

&lt;p&gt;At a lower level, TON documentation explains how contract developers can estimate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compute gas from known gas usage&lt;/li&gt;
&lt;li&gt;forward fees from message size&lt;/li&gt;
&lt;li&gt;storage requirements&lt;/li&gt;
&lt;li&gt;fees across a multi-contract transaction trace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important detail is that a DeFi operation is a system of messages. If contract A sends to contract B, which sends to contract C, estimating only the first compute phase does not describe the whole operation. TON's own gas estimation guidance explicitly treats multi-contract traces as value flows that need enough attached TON for subsequent execution.&lt;/p&gt;

&lt;p&gt;For most STON.fi applications, this gives you a useful hierarchy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi simulation&lt;/strong&gt; for route-specific gas parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi SDK transaction construction&lt;/strong&gt; for the value and payload that should actually be sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TON fee estimation tools&lt;/strong&gt; when you need a lower-level validation of the constructed message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-transaction trace analysis&lt;/strong&gt; when you want to compare the estimate with real execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to validate your estimate after the swap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9vjxrg23dsvl5f6c1xpo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9vjxrg23dsvl5f6c1xpo.png" alt="How to validate your estimate after the swap" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A good gas estimation system should learn from completed transactions instead of treating every estimate as an unquestionable constant.&lt;/p&gt;

&lt;p&gt;After submitting a test transaction, inspect its trace.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether every expected contract action completed&lt;/li&gt;
&lt;li&gt;how much TON was originally attached&lt;/li&gt;
&lt;li&gt;the actual transaction fees across the trace&lt;/li&gt;
&lt;li&gt;whether excess TON was returned&lt;/li&gt;
&lt;li&gt;whether any message bounced&lt;/li&gt;
&lt;li&gt;whether a downstream action ran out of funds&lt;/li&gt;
&lt;li&gt;whether a custom payload introduced additional forwarding work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STON.fi provides endpoints for investigating swap status and transaction action trees, which can help connect the originating transaction to the resulting protocol actions.&lt;/p&gt;

&lt;p&gt;TON explorers and APIs can then expose the underlying blockchain transactions and fee components.&lt;/p&gt;

&lt;p&gt;This gives developers a useful feedback loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;simulate
   |
build
   |
send
   |
inspect trace
   |
compare estimate with actual execution
   |
adjust only when there is evidence to do so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not optimize by cutting the attached TON budget until a transaction barely succeeds. A small saving in temporarily attached TON is rarely worth making the operation fragile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common mistakes to avoid
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Hardcoding an old recommended gas value.&lt;/strong&gt; STON.fi has multiple contract versions, and execution patterns can change. Use current simulation data whenever possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treating the attached TON amount as the final fee.&lt;/strong&gt; The amount sent to finance the operation and the amount eventually consumed are different concepts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Looking only at compute gas.&lt;/strong&gt; Forwarding and other transaction phases also matter on TON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring the route.&lt;/strong&gt; Different asset types and contract paths can produce different message flows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Removing safety budget aggressively.&lt;/strong&gt; A transaction that works in one test does not prove that a lower budget is safe for every equivalent-looking operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using a v1 example as a universal v2 constant.&lt;/strong&gt; Older STON.fi documentation contains recommended fixed gas values for specific v1 swap types, but those values describe that implementation. They should not be blindly generalized to current v2 routing.&lt;/p&gt;

&lt;p&gt;The practical takeaway is straightforward: simulate the exact swap shortly before execution, use the router and gas information returned by STON.fi, build the transaction through the matching SDK contracts, and inspect the final wallet transaction before signing. If you are developing an integration, compare the attached budget with actual transaction traces during testing rather than replacing route-specific values with one permanent gas constant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does every STON.fi swap use the same amount of gas?
&lt;/h3&gt;

&lt;p&gt;No. The required execution budget depends on the operation and its message path. TON to jetton, jetton to jetton, and jetton to TON swaps can involve different transfers and forwarding steps. Contract versions and additional payloads can matter as well. Use the estimate associated with the actual transaction rather than assuming that all STON.fi swaps have one fixed cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a larger swap require proportionally more gas?
&lt;/h3&gt;

&lt;p&gt;Usually not simply because the token amount is larger. Gas primarily reflects the computation and messaging required to execute an operation. A larger trade can affect pricing, price impact, and minimum output, but changing 1 TON to 10 TON does not by itself imply ten times the computational work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the TON attached for gas the same as the final transaction fee?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. Attached TON is a budget available to fund execution and downstream messages. Actual network fees are deducted as transactions execute. Depending on the contract flow, some value can continue through subsequent messages or be handled as excess rather than being consumed entirely as a fee.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if too little TON is attached?
&lt;/h3&gt;

&lt;p&gt;A later step in the transaction chain may not have enough value to pay for computation or forwarding. Depending on where and how the failure occurs, the operation can bounce or fail to complete as intended. Multi-contract TON systems therefore need enough value at the beginning to finance the relevant downstream trace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use TON's &lt;code&gt;estimateFee&lt;/code&gt; API for a STON.fi swap?
&lt;/h3&gt;

&lt;p&gt;Yes, it can be useful as a lower-level check once you have constructed the relevant message. TON's API returns estimates for categories such as gas, storage, and forwarding fees. For a STON.fi integration, however, it is better treated as complementary to STON.fi's route-aware simulation and SDK rather than a reason to ignore protocol-specific gas parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;forwardGas&lt;/code&gt; in a STON.fi simulation?
&lt;/h3&gt;

&lt;p&gt;It represents TON intended to support forwarding farther through the transaction flow. STON.fi swaps can create multiple internal messages, so enough value must move with the operation for later contracts to continue processing it. It should not be confused with the final amount of network fees paid by the wallet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should developers hardcode STON.fi gas values?
&lt;/h3&gt;

&lt;p&gt;Avoid hardcoding a universal value when current simulation data is available. Historical STON.fi SDK versions published recommended constants for particular swap types, but current integrations have access to route-specific gas information through the API. Hardcoded values can become inaccurate as contract versions, routes, or transaction structures change.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest way to estimate gas before a STON.fi transaction?
&lt;/h3&gt;

&lt;p&gt;Simulate the exact operation through the current STON.fi API, read its gas parameters, use the returned router with the matching STON.fi SDK contracts, and let that workflow construct the transaction you present to the wallet. During development, execute representative test transactions and compare the estimates against their completed TON traces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX API Reference - Covers swap simulation, transaction inspection, and DEX API endpoints&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Swap Guide - Describes the current API-driven v2 swap workflow and router selection&lt;/li&gt;
&lt;li&gt;STON.fi SDK Documentation - Covers the supported SDK generations and current v2 integration tooling&lt;/li&gt;
&lt;li&gt;STON.fi API Changelog - Documents the addition of &lt;code&gt;gasBudget&lt;/code&gt;, &lt;code&gt;forwardGas&lt;/code&gt;, and &lt;code&gt;estimatedGasConsumption&lt;/code&gt; to swap simulation responses&lt;/li&gt;
&lt;li&gt;STON.fi SDK Changelog - Provides contract version, routing, and SDK implementation changes relevant to current integrations&lt;/li&gt;
&lt;li&gt;TON Gas Estimation Guide - Explains compute, forward, storage, and multi-contract fee estimation on TON&lt;/li&gt;
&lt;li&gt;TON Transaction Execution Phases - Explains storage, compute, action, bounce, and the sequence in which fees are charged&lt;/li&gt;
&lt;li&gt;TON Estimate Fee API - Describes the network API for estimating storage, gas, and forwarding fees for a message&lt;/li&gt;
&lt;li&gt;TON Message Sending Modes - Explains how message value, gas fees, and forwarding fees interact during internal message delivery&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>crypto</category>
      <category>web3</category>
    </item>
    <item>
      <title>How to Calculate Minimum Received for a STON.fi Swap</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Thu, 03 Sep 2026 05:41:23 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-calculate-minimum-received-for-a-stonfi-swap-1693</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-calculate-minimum-received-for-a-stonfi-swap-1693</guid>
      <description>&lt;p&gt;&lt;em&gt;Understanding the number that protects your swap when the market moves between quote and execution.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When STON.fi shows a swap quote, the amount you expect to receive and the minimum amount you are willing to receive are not necessarily the same number. The second value is your protection against unfavorable price movement while the transaction is being processed.&lt;/p&gt;

&lt;p&gt;The basic calculation is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimum received = expected output × (1 - slippage tolerance)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a swap is expected to return 1,000 tokens and the allowed slippage is 1%, the minimum received is approximately 990 tokens.&lt;/p&gt;

&lt;p&gt;The arithmetic takes seconds. The more important part is understanding which number should be used as the expected output, what slippage actually protects you from, and why price impact should not be subtracted twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The formula behind minimum received
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20bc1wlrn1ji4wl0iw8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20bc1wlrn1ji4wl0iw8z.png" alt="The formula behind minimum receivedn" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose STON.fi calculates that your swap should currently return 2,500 USDT.&lt;/p&gt;

&lt;p&gt;If your slippage tolerance is 1%, convert the percentage into decimal form:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1% = 0.01&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then calculate:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2,500 × (1 - 0.01) = 2,475&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your minimum received is therefore approximately &lt;strong&gt;2,475 USDT&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At 0.5% tolerance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2,500 × (1 - 0.005) = 2,487.5 USDT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At 2% tolerance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2,500 × (1 - 0.02) = 2,450 USDT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The relationship is straightforward: increasing the tolerated slippage lowers the minimum amount that the transaction is allowed to deliver.&lt;/p&gt;

&lt;p&gt;A useful mental model is to treat the quote as the current target and minimum received as the lowest acceptable outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick reference
&lt;/h3&gt;

&lt;p&gt;For an expected output of 1,000 tokens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0.1% slippage gives a minimum of about 999 tokens&lt;/li&gt;
&lt;li&gt;0.5% slippage gives a minimum of about 995 tokens&lt;/li&gt;
&lt;li&gt;1% slippage gives a minimum of about 990 tokens&lt;/li&gt;
&lt;li&gt;2% slippage gives a minimum of about 980 tokens&lt;/li&gt;
&lt;li&gt;5% slippage gives a minimum of about 950 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples illustrate the calculation rather than recommending a particular tolerance. The appropriate level depends on liquidity, volatility, trade size, route conditions, and how much execution uncertainty you are willing to accept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expected output and minimum received are different numbers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmf4sc97a5llcgx5xrf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmf4sc97a5llcgx5xrf2.png" alt="Expected output and minimum received" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A swap interface has to answer two separate questions.&lt;/p&gt;

&lt;p&gt;First: &lt;strong&gt;What should this trade return under current conditions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Second: &lt;strong&gt;How bad can the execution become before the transaction should no longer proceed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those questions produce different values.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quote element&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;th&gt;What affects it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Expected output&lt;/td&gt;
&lt;td&gt;Estimated tokens you should receive now&lt;/td&gt;
&lt;td&gt;Pool reserves, route, fees, trade size, current price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price impact&lt;/td&gt;
&lt;td&gt;How much your own trade changes the execution price&lt;/td&gt;
&lt;td&gt;Trade size relative to available liquidity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slippage tolerance&lt;/td&gt;
&lt;td&gt;Maximum additional price movement you accept&lt;/td&gt;
&lt;td&gt;Your execution protection setting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimum received&lt;/td&gt;
&lt;td&gt;Lowest output permitted by the swap&lt;/td&gt;
&lt;td&gt;Expected output and slippage tolerance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network fee&lt;/td&gt;
&lt;td&gt;Cost of processing messages on TON&lt;/td&gt;
&lt;td&gt;TON network and transaction structure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;STON.fi's own educational material distinguishes price impact from slippage. Price impact is caused by the trade itself, while slippage concerns changes between the price expected and the price available when execution occurs.&lt;/p&gt;

&lt;p&gt;That distinction prevents one of the most common calculation mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not subtract price impact twice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgk8lf5pe1a0o6gmduw31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgk8lf5pe1a0o6gmduw31.png" alt="Do not subtract price impact twice" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine you are swapping enough TON to move the price inside the relevant liquidity pool.&lt;/p&gt;

&lt;p&gt;Before you confirm, the quote already reflects the execution conditions produced by that order. If the trade size causes significant price impact, the estimated output will already be worse than the simple spot-price calculation you might have made before opening the swap interface.&lt;/p&gt;

&lt;p&gt;Now suppose the resulting quote is 5,000 tokens and you allow 1% slippage.&lt;/p&gt;

&lt;p&gt;The calculation is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5,000 × 0.99 = 4,950 tokens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should not first reduce 5,000 by the displayed price impact and then reduce the result again by 1%.&lt;/p&gt;

&lt;p&gt;Doing that would count the effect of your trade twice.&lt;/p&gt;

&lt;p&gt;The sequence is better understood like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;STON.fi calculates the swap under current liquidity conditions.&lt;/li&gt;
&lt;li&gt;The resulting quote incorporates the execution effect of the trade.&lt;/li&gt;
&lt;li&gt;Slippage protection creates a floor below that quote.&lt;/li&gt;
&lt;li&gt;The transaction can proceed only while the resulting output satisfies that floor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why minimum received is calculated from the quoted output rather than from a theoretical external market price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can the quote move before your swap executes?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr95bkkh2nkonffdxmjm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr95bkkh2nkonffdxmjm8.png" alt="Why can the quote move before your swap executes?" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A DEX quote describes the state of liquidity when it is calculated. Blockchain execution happens afterward.&lt;/p&gt;

&lt;p&gt;During that interval, other traders may interact with the same liquidity. Pool reserves can change, the relative price of the assets can move, or the conditions along a route can become less favorable.&lt;/p&gt;

&lt;p&gt;Consider a quote for 800 tokens.&lt;/p&gt;

&lt;p&gt;At the moment you see it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected output = 800&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With 1% tolerance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimum received = 792&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If conditions move slightly and the swap would return 797 tokens, the output remains above your 792-token floor.&lt;/p&gt;

&lt;p&gt;If conditions deteriorate enough that the swap would return only 788 tokens, the protection becomes relevant.&lt;/p&gt;

&lt;p&gt;A slippage limit therefore does not promise that you will receive exactly the quoted amount. It defines the point at which a worse outcome is no longer acceptable.&lt;/p&gt;

&lt;p&gt;This trade-off also explains why extremely tight tolerances can increase the chance of failed execution, while very loose tolerances permit a wider range of unfavorable outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How STON.fi enforces minimum received
&lt;/h2&gt;

&lt;p&gt;The calculation becomes more meaningful when you look at how STON.fi represents it at the contract level.&lt;/p&gt;

&lt;p&gt;In STON.fi DEX v2, the Router passes a &lt;code&gt;min_out&lt;/code&gt; value as part of the swap data. The Pool documentation describes &lt;code&gt;min_out&lt;/code&gt; as the minimum required amount of tokens to receive and states that a swap fails if the amount due to the user would be below this value.&lt;/p&gt;

&lt;p&gt;So minimum received is not merely an informational estimate displayed by an interface.&lt;/p&gt;

&lt;p&gt;It becomes a condition attached to the swap.&lt;/p&gt;

&lt;p&gt;Conceptually, the flow is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quote → slippage protection → minimum output → contract execution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose the current expected output is 12,000 tokens and your tolerance produces an 11,880-token minimum.&lt;/p&gt;

&lt;p&gt;If execution still supports 11,950 tokens, the condition is satisfied.&lt;/p&gt;

&lt;p&gt;If it supports only 11,850, the minimum-output condition is not satisfied.&lt;/p&gt;

&lt;p&gt;For a simple swap, this prevents the trade from deliberately accepting an arbitrarily worse output just because conditions changed after the quote appeared.&lt;/p&gt;

&lt;p&gt;STON.fi's v2 Pool documentation explicitly connects the swap's success condition to &lt;code&gt;min_out&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculating minimum received from a STON.fi quote
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4p58xb4lru5926e6ya8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4p58xb4lru5926e6ya8n.png" alt="How STON.fi enforces minimum received" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For someone reviewing a swap manually, the process only requires the quoted output and the applicable slippage tolerance.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Start with the current expected output
&lt;/h3&gt;

&lt;p&gt;Use the amount generated by the swap quote rather than multiplying the amount you are selling by a price copied from another exchange.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STON.fi expected output: 3,250 tokens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That quote is the useful starting point because it reflects the actual swap being considered.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convert slippage into decimal form
&lt;/h3&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0.5% becomes 0.005&lt;/li&gt;
&lt;li&gt;1% becomes 0.01&lt;/li&gt;
&lt;li&gt;1.5% becomes 0.015&lt;/li&gt;
&lt;li&gt;2% becomes 0.02&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Subtract the tolerance from 1
&lt;/h3&gt;

&lt;p&gt;For 0.5%:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 - 0.005 = 0.995&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multiply the quote by the result
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;3,250 × 0.995 = 3,233.75&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The theoretical minimum received is therefore &lt;strong&gt;3,233.75 tokens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The actual transaction uses blockchain units and token-specific decimals, so an integration should not casually reproduce UI arithmetic with floating-point numbers and then invent its own rounding rules.&lt;/p&gt;

&lt;p&gt;That is where STON.fi's simulation tools become useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  For developers, use &lt;code&gt;minAskUnits&lt;/code&gt; from the simulation
&lt;/h2&gt;

&lt;p&gt;STON.fi's current DEX v2 SDK documentation recommends an API-driven workflow for production swaps.&lt;/p&gt;

&lt;p&gt;The example first calls &lt;code&gt;simulateSwap()&lt;/code&gt; with the offered asset, requested asset, amount, and &lt;code&gt;slippageTolerance&lt;/code&gt;. The resulting simulation contains values including &lt;code&gt;offerUnits&lt;/code&gt;, &lt;code&gt;minAskUnits&lt;/code&gt;, asset addresses, and Router metadata. STON.fi specifically instructs developers to reuse the simulation values when constructing the actual transaction so the signed transaction matches the simulated swap.&lt;/p&gt;

&lt;p&gt;A simplified example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulationResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;simulateSwap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;offerAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;askAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;slippageTolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.01&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minimumOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;simulationResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minAskUnits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;"0.01"&lt;/code&gt; represents a 1% tolerance.&lt;/p&gt;

&lt;p&gt;For a production integration, &lt;code&gt;minAskUnits&lt;/code&gt; is more important than a manually formatted number such as &lt;code&gt;123.45&lt;/code&gt;. Smart contracts work with the asset's base units, and different tokens can use different decimal precision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical developer checklist
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7jkue30ejgretq6etl60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7jkue30ejgretq6etl60.png" alt="Practical developer checklist" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before building the transaction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simulate the current swap rather than relying on an old quote&lt;/li&gt;
&lt;li&gt;pass the intended slippage tolerance into the simulation&lt;/li&gt;
&lt;li&gt;use the simulation's &lt;code&gt;minAskUnits&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;preserve the asset addresses and Router information returned by the simulation&lt;/li&gt;
&lt;li&gt;avoid converting the minimum into floating-point values and rebuilding it unnecessarily&lt;/li&gt;
&lt;li&gt;request a fresh simulation if the quote has become stale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STON.fi's API also provides swap simulation specifically to calculate swap results before execution, including expected swap information, fees, and gas-related data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What minimum received does not include
&lt;/h2&gt;

&lt;p&gt;Minimum received is easy to misuse when every cost associated with a swap is treated as "slippage."&lt;/p&gt;

&lt;p&gt;They are not the same thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trading economics affect the quote.&lt;/strong&gt; Pool pricing, liquidity, trade size, and relevant trading fees influence the output calculated for the swap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slippage protection applies to movement away from that quote.&lt;/strong&gt; It defines how much additional deterioration can be tolerated before the minimum-output condition is violated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TON network costs are separate.&lt;/strong&gt; Gas and message-processing costs exist because TON must execute and forward blockchain messages. TON documentation describes contract execution and forward fees as separate blockchain costs.&lt;/p&gt;

&lt;p&gt;If STON.fi quotes 1,000 units of an asset and your minimum received is 990, you should not subtract the TON network fee from 990 as though the fee were another percentage of the destination token.&lt;/p&gt;

&lt;p&gt;Keeping those layers separate makes the calculation much easier to audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical STON.fi example
&lt;/h2&gt;

&lt;p&gt;Imagine you want to swap TON into another token and STON.fi currently quotes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected output: 10,000 ABC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assume the swap uses a 1% slippage tolerance.&lt;/p&gt;

&lt;p&gt;The manual calculation is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10,000 × (1 - 0.01)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10,000 × 0.99 = 9,900 ABC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected output: 10,000 ABC&lt;/li&gt;
&lt;li&gt;Slippage tolerance: 1%&lt;/li&gt;
&lt;li&gt;Minimum received: approximately 9,900 ABC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine liquidity changes while your transaction is moving through the execution process.&lt;/p&gt;

&lt;p&gt;If the updated swap result is 9,970 ABC, it is still above the minimum.&lt;/p&gt;

&lt;p&gt;If it falls to 9,910 ABC, it is still above the minimum.&lt;/p&gt;

&lt;p&gt;If it falls below the contract's required &lt;code&gt;min_out&lt;/code&gt;, the minimum-output protection is triggered rather than simply accepting the worse exchange result.&lt;/p&gt;

&lt;p&gt;For developers, the same logic should normally be represented by the fresh &lt;code&gt;minAskUnits&lt;/code&gt; returned by STON.fi's swap simulation rather than a hand-calculated decimal value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; when reviewing a STON.fi swap, start from the current quoted output, distinguish price impact from slippage, and treat minimum received as your execution floor. If you are integrating STON.fi programmatically, let the current swap simulation produce &lt;code&gt;minAskUnits&lt;/code&gt; and carry that value into the transaction instead of reconstructing it from an older or rounded quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is minimum received in a crypto swap?
&lt;/h3&gt;

&lt;p&gt;Minimum received is the lowest amount of the destination asset that your swap is allowed to deliver under its slippage protection. If the current quote is 1,000 tokens and a 1% tolerance is applied, the approximate minimum is 990. It is a protective floor, not a prediction that you will necessarily receive exactly that amount.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I calculate minimum received from slippage?
&lt;/h3&gt;

&lt;p&gt;Multiply the expected output by one minus the slippage tolerance expressed as a decimal. For example, with an expected output of 4,000 tokens and 0.5% slippage, calculate &lt;code&gt;4,000 × 0.995&lt;/code&gt;, which gives 3,980 tokens. Blockchain implementations may apply base-unit precision and rounding, so integrations should use protocol-provided values where available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is price impact included in minimum received?
&lt;/h3&gt;

&lt;p&gt;Price impact should first affect the expected swap output because it comes from executing your trade against available liquidity. Slippage protection is then applied relative to that quote. Subtracting displayed price impact from the quote again before calculating minimum received can therefore double-count the same effect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does higher slippage increase minimum received?
&lt;/h3&gt;

&lt;p&gt;No. Higher slippage tolerance lowers the minimum received because you are allowing the transaction to accept a wider deterioration from the original quote. A 2% tolerance creates a lower floor than a 0.5% tolerance. That can make execution less restrictive, but it also allows a less favorable result.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;min_out&lt;/code&gt; on STON.fi?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;min_out&lt;/code&gt; is the contract-level minimum output requirement used in STON.fi swap execution. STON.fi's DEX v2 Pool documentation states that the swap fails if the amount to be received would be below this minimum. It is the on-chain expression of the minimum-output protection discussed in the swap quote.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;minAskUnits&lt;/code&gt; in the STON.fi API?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;minAskUnits&lt;/code&gt; is the minimum requested output returned as part of STON.fi's swap simulation workflow. The DEX v2 SDK documentation shows it in &lt;code&gt;simulationResult&lt;/code&gt; together with the offered amount, asset addresses, and Router metadata. Production integrations should reuse these simulation values when building the corresponding swap transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I calculate STON.fi minimum received manually before every swap?
&lt;/h3&gt;

&lt;p&gt;Manual calculation is useful for understanding and checking the number shown by a quote. For actual execution, especially in a software integration, use a fresh STON.fi simulation and its &lt;code&gt;minAskUnits&lt;/code&gt;. That avoids problems with token decimals, stale quotes, floating-point calculations, and inconsistent rounding between your application and the swap transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I check before confirming a STON.fi swap?
&lt;/h3&gt;

&lt;p&gt;Check the asset pair, input amount, expected output, price impact, minimum received, and network costs. Make sure you understand that expected output is the current estimate while minimum received is the lower execution boundary. If the quote looks unexpectedly poor, review liquidity and trade size rather than simply increasing the tolerated slippage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX v2 Swap SDK - Official production swap workflow, swap simulation, &lt;code&gt;slippageTolerance&lt;/code&gt;, &lt;code&gt;minAskUnits&lt;/code&gt;, and Router handling&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Pool - Official smart contract documentation for &lt;code&gt;min_out&lt;/code&gt; and the minimum-output swap condition&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Router - Official Router swap structure and the &lt;code&gt;min_out&lt;/code&gt; field passed during swap execution&lt;/li&gt;
&lt;li&gt;STON.fi DEX API Reference - Official API overview covering swap simulation before execution&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Smart Contracts - Official overview of the current v2 smart contract architecture and swap functionality&lt;/li&gt;
&lt;li&gt;STON.fi Blog, All You Need to Know About Price Impact on Decentralized Exchanges - Explanation of price impact, slippage, and their distinction in a STON.fi swap context&lt;/li&gt;
&lt;li&gt;TON Documentation, How to Estimate Gas Usage in TON Contracts - Official explanation of TON gas and forward-fee mechanics&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Build a STON.fi Pool Explorer</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sun, 30 Aug 2026 17:33:03 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-build-a-stonfi-pool-explorer-4o4k</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-build-a-stonfi-pool-explorer-4o4k</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical TypeScript guide to discovering pools, joining token metadata, displaying meaningful metrics, handling multiple AMM types, and verifying pool state on TON.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A STON.fi pool explorer is essentially a read-only DeFi application that turns raw pool contracts and indexed protocol data into something people can understand. At minimum, it should answer a few questions quickly: which assets are in a pool, how much liquidity is there, what fees apply, how active is the pool, which STON.fi contract version powers it, and where can the underlying addresses be verified?&lt;/p&gt;

&lt;p&gt;The good news is that you do not need to index TON from scratch. STON.fi exposes a public REST API for pools, assets, routers, statistics, simulations, and other protocol data. You can use that API as the discovery layer, then optionally read the pool contract directly when you want stronger on-chain verification.&lt;/p&gt;

&lt;p&gt;This guide builds that architecture step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a useful STON.fi pool explorer should show
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ld2el2md6vidvv190dk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ld2el2md6vidvv190dk.png" alt="What a useful STON.fi pool explorer should show" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pool explorer becomes useful when it combines several kinds of information that exist separately at the protocol level.&lt;/p&gt;

&lt;p&gt;For each pool, a practical interface should expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;token names, symbols, images, decimals, and contract addresses&lt;/li&gt;
&lt;li&gt;both pool reserves in readable token units&lt;/li&gt;
&lt;li&gt;LP fee and other relevant fee information&lt;/li&gt;
&lt;li&gt;24-hour trading volume&lt;/li&gt;
&lt;li&gt;recent APY values when available&lt;/li&gt;
&lt;li&gt;LP token supply and its USD value&lt;/li&gt;
&lt;li&gt;pool contract and router addresses&lt;/li&gt;
&lt;li&gt;router version and pool type&lt;/li&gt;
&lt;li&gt;warnings for deprecated or problematic assets&lt;/li&gt;
&lt;li&gt;pool-specific parameters for specialized AMMs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STON.fi's API already exposes much of this data. The main engineering problem is joining it correctly.&lt;/p&gt;

&lt;p&gt;A pool response identifies its assets through &lt;code&gt;token0_address&lt;/code&gt; and &lt;code&gt;token1_address&lt;/code&gt;, while token metadata lives in the asset dataset. The pool also contains &lt;code&gt;router_address&lt;/code&gt;, which you can join with the router dataset to identify the contract version and router type.&lt;/p&gt;

&lt;p&gt;A simple data flow therefore looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load pools from &lt;code&gt;/v1/pools&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Load assets from &lt;code&gt;/v1/assets&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Load routers from &lt;code&gt;/v1/routers&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Index assets and routers by address.&lt;/li&gt;
&lt;li&gt;Enrich every pool with token metadata and router information.&lt;/li&gt;
&lt;li&gt;Normalize raw blockchain amounts using token decimals.&lt;/li&gt;
&lt;li&gt;Render searchable pool cards and detailed pool pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is enough for a surprisingly capable first version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model the data around pools, assets, and routers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxrer7pm1wl3yudfio7d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxrer7pm1wl3yudfio7d.png" alt="Model the data around pools, assets, and routers" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is tempting to treat the pool response as a complete object, but keeping the three protocol concepts separate makes the application easier to maintain.&lt;/p&gt;

&lt;p&gt;The current STON.fi pool schema includes fields such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;address
token0_address
token1_address
reserve0
reserve1
lp_fee
protocol_fee
ref_fee
router_address
lp_total_supply
lp_total_supply_usd
volume_24h_usd
apy_1d
apy_7d
apy_30d
deprecated
amp
rate
w0
tags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The asset API provides the presentation layer around those addresses, including &lt;code&gt;display_name&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt;, &lt;code&gt;decimals&lt;/code&gt;, &lt;code&gt;image_url&lt;/code&gt;, pricing fields, tags, and status flags.&lt;/p&gt;

&lt;p&gt;The router endpoint adds another important dimension. Routers expose their major and minor contract versions as well as a &lt;code&gt;router_type&lt;/code&gt;. Current router types can include Constant Product, Stable Swap, Weighted Stable Swap, Weighted Constant Product, and Constant Sum variants.&lt;/p&gt;

&lt;p&gt;That distinction matters because your explorer should not assume that every pool behaves like a basic &lt;code&gt;x * y = k&lt;/code&gt; AMM.&lt;/p&gt;

&lt;p&gt;A useful mental model is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What your explorer gets from it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pool&lt;/td&gt;
&lt;td&gt;reserves, fees, LP data, volume, APY, pool parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asset&lt;/td&gt;
&lt;td&gt;symbol, name, decimals, image, pricing metadata, safety flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;DEX version, router type, contract context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TON contract&lt;/td&gt;
&lt;td&gt;direct verification of current on-chain state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep these layers separate internally even if the UI eventually merges them into a single pool card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetch and join the STON.fi API data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ga3ihrohmw4l7cztnxm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ga3ihrohmw4l7cztnxm.png" alt="Fetch and join the STON.fi API data" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the official &lt;code&gt;@ston-fi/api&lt;/code&gt; TypeScript client, but raw HTTP requests make the underlying explorer architecture especially easy to see.&lt;/p&gt;

&lt;p&gt;Start with a small loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STON_API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ston.fi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;STON_API&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`STON.fi API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token0_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token1_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reserve0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reserve1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;router_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lp_fee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;protocol_fee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ref_fee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lp_total_supply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lp_total_supply_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;volume_24h_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;apy_1d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;apy_7d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;apy_30d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;deprecated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;w0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contract_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;deprecated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;blacklisted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;major_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;minor_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;router_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then retrieve the datasets together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadExplorerData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;poolData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;routerData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pool_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/v1/pools?dex_v2=true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;asset_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Asset&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/v1/assets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;router_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/v1/routers?dex_v2=true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;assetData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contract_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;routerData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;poolData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pool_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;asset0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token0_address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;asset1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token1_address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router_address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have one object that the frontend can render without repeatedly searching arrays.&lt;/p&gt;

&lt;p&gt;For a prototype, loading the complete datasets is convenient. Once your explorer becomes larger, investigate &lt;code&gt;/v1/pools/query&lt;/code&gt;, which supports search terms, sorting, limits, and other query conditions. Server-side filtering can reduce unnecessary data transfer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn raw blockchain values into readable metrics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2he8noj747x3lm9oei35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2he8noj747x3lm9oei35.png" alt="Turn raw blockchain values into readable metrics" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next problem is units.&lt;/p&gt;

&lt;p&gt;STON.fi reserves are returned in basic token units. A jetton with six decimals and a raw reserve of &lt;code&gt;"2500000000"&lt;/code&gt; represents 2,500 tokens, not 2.5 billion tokens.&lt;/p&gt;

&lt;p&gt;You therefore need the decimals from the asset metadata before displaying reserves.&lt;/p&gt;

&lt;p&gt;A BigInt-safe formatter can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fractionString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/0+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fractionString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reserve0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset0&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reserve1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset1&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fees deserve similar care. STON.fi pool contract documentation defines fee values against a divider of 10,000. A fee value of &lt;code&gt;100&lt;/code&gt;, for example, corresponds to 1%.&lt;/p&gt;

&lt;p&gt;For display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatFee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For sorting and presentation, converting USD metrics to JavaScript numbers is usually acceptable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;volume24h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume_24h_usd&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume_24h_usd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For financial calculations where precision matters, keep the original integer or decimal strings and use BigInt or a decimal arithmetic library rather than binary floating-point math.&lt;/p&gt;

&lt;p&gt;APY should also be labeled carefully. Fields such as &lt;code&gt;apy_1d&lt;/code&gt;, &lt;code&gt;apy_7d&lt;/code&gt;, and &lt;code&gt;apy_30d&lt;/code&gt; describe recent annualized conditions. They are useful historical signals, not promised future returns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the pool list and detail views
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foyf1swqlc5ayltxkwxfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foyf1swqlc5ayltxkwxfc.png" alt="Build the pool list and detail views" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With normalized data, the frontend becomes straightforward.&lt;/p&gt;

&lt;p&gt;A compact explorer card might contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PoolCard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token0&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; /&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token1&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Type: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;router_type&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Version:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`v&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;major_version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minor_version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        24h volume:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume_24h_usd&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume_24h_usd&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;LP fee: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatFee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lp_fee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The list page should optimize for comparison. Pair, liquidity value, 24-hour volume, fee, recent APY, pool type, and version are usually enough.&lt;/p&gt;

&lt;p&gt;The detail page can go deeper.&lt;/p&gt;

&lt;p&gt;Useful detail fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;full pool, router, and token contract addresses&lt;/li&gt;
&lt;li&gt;normalized and raw reserves&lt;/li&gt;
&lt;li&gt;LP token supply&lt;/li&gt;
&lt;li&gt;protocol and referral fee settings&lt;/li&gt;
&lt;li&gt;collected protocol fees&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amp&lt;/code&gt;, &lt;code&gt;rate&lt;/code&gt;, or &lt;code&gt;w0&lt;/code&gt; when applicable&lt;/li&gt;
&lt;li&gt;pool and asset tags&lt;/li&gt;
&lt;li&gt;deprecated status&lt;/li&gt;
&lt;li&gt;1-day, 7-day, and 30-day APY&lt;/li&gt;
&lt;li&gt;links to a TON blockchain explorer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always display the underlying token addresses somewhere accessible. TON's token metadata documentation explicitly warns that anyone can create a jetton with a copied name, symbol, description, or image. A professional pool explorer should never identify an asset by ticker alone.&lt;/p&gt;

&lt;p&gt;You can also use STON.fi's asset flags, such as deprecated or blacklisted status, to add visible warnings rather than silently treating every returned token as equivalent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pricing and pool types correctly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fumy9qf1j81tz8wnpr9vd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fumy9qf1j81tz8wnpr9vd.png" alt="Handle pricing and pool types correctly" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the easiest mistakes when building an AMM explorer is calculating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;price = reserve1 / reserve0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and calling the result the pool's current execution price.&lt;/p&gt;

&lt;p&gt;That shortcut can be informative for a conventional constant product pool after adjusting both reserves for token decimals. It is not a universal pricing formula.&lt;/p&gt;

&lt;p&gt;STON.fi supports multiple pool and router types, and the API exposes specialized parameters such as &lt;code&gt;amp&lt;/code&gt;, &lt;code&gt;rate&lt;/code&gt;, and &lt;code&gt;w0&lt;/code&gt;. Those exist because different pool designs do not share one invariant.&lt;/p&gt;

&lt;p&gt;A better explorer separates three concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reserve ratio:&lt;/strong&gt; a description of the pool's current token composition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference or statistical price:&lt;/strong&gt; a price derived from indexed market statistics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executable quote:&lt;/strong&gt; the expected result for a particular trade size under the current pool conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the reader wants to know what a trade would actually return, use STON.fi's swap simulation endpoint rather than extrapolating from reserves. &lt;code&gt;POST /v1/swap/simulate&lt;/code&gt; is designed to calculate expected swap output, fees, gas information, and other execution data before a transaction is built.&lt;/p&gt;

&lt;p&gt;Trade size matters. A quote for 1 TON and a quote for 10,000 TON can imply different effective prices because the trade itself moves through pool liquidity.&lt;/p&gt;

&lt;p&gt;This gives your explorer a useful optional feature: a small "simulate swap" panel on each pool page. It turns a static pool viewer into a tool for understanding liquidity depth without requiring a wallet connection or transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add on-chain verification and production hardening
&lt;/h2&gt;

&lt;p&gt;The STON.fi REST API is the convenient discovery and analytics layer. The pool contract remains the source of on-chain state.&lt;/p&gt;

&lt;p&gt;For DEX v2 pools, the documented &lt;code&gt;get_pool_data&lt;/code&gt; getter exposes values including the router address, LP supply, token reserves, token wallet addresses, and liquidity pool fee. A verification mode can query the relevant contract through a TON RPC provider and compare selected values with the indexed API response.&lt;/p&gt;

&lt;p&gt;That creates two complementary modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast mode:&lt;/strong&gt; use STON.fi API data for discovery, metadata, statistics, search, and normal page rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification mode:&lt;/strong&gt; read selected contract state directly from TON when the reader wants to inspect the underlying pool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not treat a temporary difference as automatic evidence that something is wrong. An indexed API and the latest blockchain state can briefly differ because they are observed at different moments.&lt;/p&gt;

&lt;p&gt;Before publishing the explorer, I would also add this checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache pool, asset, and router requests instead of refetching everything on every render.&lt;/li&gt;
&lt;li&gt;Add graceful handling for missing metadata and nullable USD values.&lt;/li&gt;
&lt;li&gt;Search by token symbol, token address, and pool address.&lt;/li&gt;
&lt;li&gt;Make contract addresses copyable.&lt;/li&gt;
&lt;li&gt;Show deprecated and blacklisted warnings prominently.&lt;/li&gt;
&lt;li&gt;Never use token symbols as unique database keys.&lt;/li&gt;
&lt;li&gt;Distinguish pool types before calculating derived metrics.&lt;/li&gt;
&lt;li&gt;Keep the raw API values available for debugging.&lt;/li&gt;
&lt;li&gt;Record when your application last refreshed its data.&lt;/li&gt;
&lt;li&gt;Treat API schemas as external dependencies and validate responses at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official STON.fi documentation currently states that the DEX API has no usage limits. That is useful for development, but production software should still cache sensible responses and avoid unnecessary traffic because service policies can change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; start the explorer with three STON.fi datasets: pools, assets, and routers. Join them by contract address, normalize reserves using token decimals, and render only metrics whose meaning you can explain precisely. Once that works, add simulation for executable pricing and direct TON contract reads for verification. That architecture keeps the first version simple without locking you into an inaccurate data model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I need to run a TON node to build a STON.fi pool explorer?
&lt;/h3&gt;

&lt;p&gt;No. A basic explorer can use the public STON.fi REST API for pool discovery, token metadata, router information, volume, APY, and other indexed data. A TON RPC provider becomes useful when you want to verify contract state directly or add deeper blockchain functionality, but it is not required for the first working version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which STON.fi endpoint should I start with?
&lt;/h3&gt;

&lt;p&gt;Start with &lt;code&gt;GET /v1/pools&lt;/code&gt;, then join its token addresses with &lt;code&gt;GET /v1/assets&lt;/code&gt; and its router addresses with &lt;code&gt;GET /v1/routers&lt;/code&gt;. This combination gives you the core information needed for a pool directory. You can later use &lt;code&gt;/v1/pools/{address}&lt;/code&gt; for individual pages and &lt;code&gt;/v1/pools/query&lt;/code&gt; for more selective discovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I calculate a token's price directly from pool reserves?
&lt;/h3&gt;

&lt;p&gt;Sometimes, but you should not use one reserve-ratio formula for every STON.fi pool. Different AMM types can use different pricing mechanics. A reserve ratio is useful as a pool-composition metric. For an expected trade result, STON.fi's swap simulation endpoint is a safer source because it evaluates a specific amount against the relevant routing and pool logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I use as the pool's liquidity or TVL figure?
&lt;/h3&gt;

&lt;p&gt;STON.fi pool responses expose LP supply information, including &lt;code&gt;lp_total_supply_usd&lt;/code&gt; when available, alongside the underlying reserves. You can use the USD LP supply value as a convenient liquidity-value metric in your interface, while keeping the field's actual meaning clear. If you calculate your own value from reserves and asset prices, document exactly how that calculation works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do I need the router endpoint if I already have the pool?
&lt;/h3&gt;

&lt;p&gt;The router tells you important context about the contract behind the pool, including its major and minor version and router type. That information matters once your explorer supports multiple STON.fi pool designs. It prevents the frontend from assuming that every pool follows the same pricing model or exposes the same specialized parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should a STON.fi pool explorer trust token names and symbols?
&lt;/h3&gt;

&lt;p&gt;No. Names and symbols are presentation metadata, not unique identities. TON documentation warns that jettons can copy another token's name, symbol, or image. Display contract addresses and use STON.fi metadata flags where appropriate. Internally, index tokens by their contract addresses rather than by symbols such as USDT, TON, or STON.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I verify that the STON.fi API reserves match the blockchain?
&lt;/h3&gt;

&lt;p&gt;Read the pool contract's documented &lt;code&gt;get_pool_data&lt;/code&gt; getter through a TON provider and compare its reserves and other relevant state with the indexed API values. Small temporary differences can occur because indexing and direct blockchain reads happen at different times. For an explorer, API-first rendering plus optional on-chain verification is usually a practical architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX API Reference - official list of pool, asset, router, statistics, simulation, wallet, and market endpoints&lt;/li&gt;
&lt;li&gt;STON.fi REST API documentation - overview of the public DEX data API and integration options&lt;/li&gt;
&lt;li&gt;STON.fi Swagger UI - current REST API schemas, including PoolInfoSchema, AssetInfoSchema, RouterInfoSchema, query parameters, and supported router types&lt;/li&gt;
&lt;li&gt;STON.fi API TypeScript client - official &lt;code&gt;@ston-fi/api&lt;/code&gt; client with methods for retrieving pools, assets, routers, wallet positions, and other protocol data&lt;/li&gt;
&lt;li&gt;STON.fi DEX Architecture - official explanation of routers, pools, LP contracts, liquidity flows, and the protocol contract model&lt;/li&gt;
&lt;li&gt;STON.fi Pool v2 smart contract reference - documents &lt;code&gt;get_pool_data&lt;/code&gt;, reserves, LP supply, fee fields, router address, and other on-chain pool state&lt;/li&gt;
&lt;li&gt;STON.fi v1 to v2 SDK migration guide - explains typed pool support and architectural differences developers should account for across STON.fi versions&lt;/li&gt;
&lt;li&gt;TON Token Metadata - official guidance on jetton metadata fields and why applications should distinguish tokens by contract address rather than names or symbols&lt;/li&gt;
&lt;li&gt;TON Run Get Method API - official TON API documentation for executing read-only smart contract getter methods when adding direct on-chain verification&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Query STON.fi Token and Asset Metadata</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:04:19 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-query-stonfi-token-and-asset-metadata-3bla</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-query-stonfi-token-and-asset-metadata-3bla</guid>
      <description>&lt;p&gt;&lt;em&gt;How to fetch token names, symbols, decimals, images, prices, tags, and contract addresses with the STON.fi REST API and TypeScript client.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are building a token selector, portfolio view, swap interface, analytics dashboard, or any other TON application, you rarely want to decode every jetton's metadata yourself. STON.fi provides an HTTP API that exposes normalized asset information and a TypeScript client that makes those endpoints easier to use.&lt;/p&gt;

&lt;p&gt;For most applications, the workflow is simple: query STON.fi for an asset list, identify every asset by its contract address, read the metadata you need for display, and keep transaction-critical logic separate from labels such as token names and symbols. The API currently provides endpoints for listing assets, fetching one asset by address, and querying assets with search and filtering conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does STON.fi mean by an asset?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyto5e5lvuclljjf428g4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyto5e5lvuclljjf428g4.png" alt="What does STON.fi mean by an asset?" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On TON, fungible tokens normally use the jetton standard. Their metadata can include a name, symbol, decimals, image, and other fields. TEP-64 allows metadata to be stored on-chain, off-chain, or through a semi-chain combination where some values come from the contract and others come from an external document.&lt;/p&gt;

&lt;p&gt;STON.fi gives developers a more convenient application-level view of assets used around the DEX. Instead of decoding cells and resolving metadata yourself for every token, you can query the STON.fi API.&lt;/p&gt;

&lt;p&gt;Depending on the endpoint, an asset can contain information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contract address&lt;/li&gt;
&lt;li&gt;asset kind&lt;/li&gt;
&lt;li&gt;token name and symbol&lt;/li&gt;
&lt;li&gt;decimals&lt;/li&gt;
&lt;li&gt;image URL&lt;/li&gt;
&lt;li&gt;STON.fi DEX price in USD&lt;/li&gt;
&lt;li&gt;tags&lt;/li&gt;
&lt;li&gt;popularity information&lt;/li&gt;
&lt;li&gt;wallet balance when a wallet-aware endpoint is used&lt;/li&gt;
&lt;li&gt;optional extensions and scaling information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API currently distinguishes asset kinds such as &lt;code&gt;Ton&lt;/code&gt;, &lt;code&gt;Wton&lt;/code&gt;, &lt;code&gt;Jetton&lt;/code&gt;, and &lt;code&gt;NotAnAsset&lt;/code&gt;. Its newer asset schema groups display metadata under a &lt;code&gt;meta&lt;/code&gt; object, while the older asset response exposes fields such as &lt;code&gt;symbol&lt;/code&gt;, &lt;code&gt;display_name&lt;/code&gt;, &lt;code&gt;decimals&lt;/code&gt;, and &lt;code&gt;image_url&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;That schema difference is worth noticing because code written for &lt;code&gt;getAsset()&lt;/code&gt; and code written for &lt;code&gt;queryAssets()&lt;/code&gt; may access metadata differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick the query that matches your UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvtz832q0o4rpin1tbt88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvtz832q0o4rpin1tbt88.png" alt="Pick the query that matches your UI" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi provides several related asset endpoints, but they answer different questions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you need&lt;/th&gt;
&lt;th&gt;REST endpoint&lt;/th&gt;
&lt;th&gt;TypeScript client&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Every available DEX asset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/assets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getAssets()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One known asset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/assets/{address}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getAsset(address)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search and filter assets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /v1/assets/query&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;queryAssets(...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assets held by a wallet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/wallets/{address}/assets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getWalletAssets(address)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One wallet asset and its balance&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/wallets/{address}/assets/{asset}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getWalletAsset(...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a production token selector, &lt;code&gt;queryAssets()&lt;/code&gt; is usually more useful than downloading every known asset. It lets you search by text or address and combine the search with STON.fi asset conditions.&lt;/p&gt;

&lt;p&gt;If you already know the contract address, however, fetching that specific asset is simpler and removes the ambiguity that comes with searching by a ticker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query one token directly by address
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flp9vio0w3r0j3rp6ygcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flp9vio0w3r0j3rp6ygcp.png" alt="Query one token directly by address" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most deterministic asset lookup starts with the contract address.&lt;/p&gt;

&lt;p&gt;Using the REST API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStonAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.ston.fi/v1/assets/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`STON.fi API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official API base URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.ston.fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The equivalent operation with the official TypeScript package is shorter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StonApiClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EQ...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;StonApiClient&lt;/code&gt; uses &lt;code&gt;https://api.ston.fi&lt;/code&gt; by default, so no API configuration is required for a basic request. The current client source maps &lt;code&gt;getAsset()&lt;/code&gt; directly to &lt;code&gt;GET /v1/assets/{assetAddress}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This pattern is ideal when an address comes from a trusted configuration, a pool response, a swap quote, or another part of your application where the asset has already been identified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search for tokens without downloading the whole list
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjzufi4izpe73lzahauw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjzufi4izpe73lzahauw.png" alt="Search for tokens without downloading the whole list" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A token picker has a different problem. The visitor may type &lt;code&gt;USD&lt;/code&gt;, &lt;code&gt;STON&lt;/code&gt;, or part of a token name, so you need discovery rather than an exact lookup.&lt;/p&gt;

&lt;p&gt;STON.fi provides &lt;code&gt;POST /v1/assets/query&lt;/code&gt; for this.&lt;/p&gt;

&lt;p&gt;A direct REST request can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchAssets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ston.fi/v1/assets/query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;search_terms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;asset:liquidity:very_high | asset:liquidity:high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Asset query failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset_list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request schema supports search terms containing addresses or text such as token names and symbols. It also supports a condition, sorting parameters, a result limit, unconditional assets, and an optional wallet address.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;@ston-fi/api&lt;/code&gt;, the same query becomes easier to read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryAssets&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;searchTerms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityVeryHigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityHigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi's own quickstart uses the same approach to populate token selectors, combining &lt;code&gt;LiquidityVeryHigh&lt;/code&gt;, &lt;code&gt;LiquidityHigh&lt;/code&gt;, and &lt;code&gt;LiquidityMedium&lt;/code&gt; tags and then storing the returned &lt;code&gt;AssetInfoV2&lt;/code&gt; objects in application state.&lt;/p&gt;

&lt;p&gt;The older &lt;code&gt;searchAssets()&lt;/code&gt; client method still exists, but the current source marks it as deprecated and redirects it through &lt;code&gt;queryAssets()&lt;/code&gt;. New integrations should therefore use &lt;code&gt;queryAssets()&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn the response into clean application data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgzz4pa2msf53wk9a732a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgzz4pa2msf53wk9a732a.png" alt="Turn the response into clean application data" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A raw API object usually contains more information than a component needs. Normalizing it once makes the rest of your frontend much easier to maintain.&lt;/p&gt;

&lt;p&gt;The newer query response exposes display metadata under &lt;code&gt;meta&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AssetInfoV2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TokenOption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;priceUsd&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toTokenOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AssetInfoV2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TokenOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TOKEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;priceUsd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dexPriceUsd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your UI can work with a small predictable model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toTokenOption&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official &lt;code&gt;AssetInfoV2&lt;/code&gt; structure includes the contract address, asset kind, optional balance, DEX price, &lt;code&gt;meta&lt;/code&gt;, popularity information, tags, wallet address, scale, and extensions. Inside &lt;code&gt;meta&lt;/code&gt;, fields such as decimals, symbol, display name, image URL, and custom payload API URI are optional.&lt;/p&gt;

&lt;p&gt;That optionality matters. A robust token selector should not assume that every asset has a complete name, icon, or even every display field.&lt;/p&gt;

&lt;p&gt;A reasonable display fallback is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show &lt;code&gt;displayName&lt;/code&gt; when available.&lt;/li&gt;
&lt;li&gt;Fall back to &lt;code&gt;symbol&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep the contract address available as the definitive identifier.&lt;/li&gt;
&lt;li&gt;Use a local placeholder when no usable image exists.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Decimals are metadata that affect real amounts
&lt;/h2&gt;

&lt;p&gt;A missing icon is mostly a visual problem. Incorrect decimals are different because decimals determine how integer token units become human-readable balances.&lt;/p&gt;

&lt;p&gt;Suppose an API returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EXAMPLE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An on-chain amount of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1250000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;represents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.25 EXAMPLE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;not 1,250,000 tokens.&lt;/p&gt;

&lt;p&gt;Avoid normal JavaScript floating-point arithmetic when converting transaction amounts. A simple display helper can use &lt;code&gt;BigInt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/0+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fraction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TON's token metadata standard defines &lt;code&gt;decimals&lt;/code&gt; as a jetton metadata attribute and specifies 9 as the default when the field is absent. Still, if your application receives incomplete or unexpected STON.fi metadata, treating that object carefully is safer than blindly assuming every response represents a normal jetton.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use tags to improve token discovery
&lt;/h2&gt;

&lt;p&gt;STON.fi does more than return names and icons. Its TypeScript client currently exposes a range of asset tags that can help shape search results and token lists.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Essential&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Popular&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityVeryHigh&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityHigh&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityMedium&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WalletHasBalance&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Deprecated&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Blacklisted&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Suspicious&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fake&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Honeypot&lt;/span&gt;
&lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NonSearchable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact tag set can evolve, so import the constants from the package instead of copying string values throughout your application. The current client source also includes tags for scaled assets, taxable assets, DMCA complaints, wallet liquidity, and several liquidity levels.&lt;/p&gt;

&lt;p&gt;A wallet-aware selector can combine discovery with the connected wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;walletAssets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryAssets&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Essential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Popular&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WalletHasBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you a useful foundation for sections such as "Your tokens" or "Popular assets" without maintaining a separate token registry in your frontend.&lt;/p&gt;

&lt;p&gt;Tags should still be treated as API classification data, not as cryptographic proof that an asset is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Never identify a token by its symbol alone
&lt;/h2&gt;

&lt;p&gt;Imagine your application searches for &lt;code&gt;USD&lt;/code&gt; and receives several assets. Choosing the first item because its ticker looks familiar is a dangerous shortcut.&lt;/p&gt;

&lt;p&gt;TON's own token metadata documentation explicitly warns that anyone can create a jetton using any name, description, or image. Applications should distinguish tokens by their addresses rather than relying on names or tickers.&lt;/p&gt;

&lt;p&gt;For a production STON.fi integration, keep these rules simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;contractAddress&lt;/code&gt; as the asset identifier.&lt;/li&gt;
&lt;li&gt;Treat symbol and display name as presentation metadata.&lt;/li&gt;
&lt;li&gt;Preserve the selected address when requesting quotes or constructing transactions.&lt;/li&gt;
&lt;li&gt;Do not infer authenticity from an icon.&lt;/li&gt;
&lt;li&gt;Consider STON.fi tags when deciding which assets should appear prominently.&lt;/li&gt;
&lt;li&gt;Give users a way to inspect or verify the contract address for unfamiliar assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes especially important for symbols such as &lt;code&gt;USDT&lt;/code&gt;, &lt;code&gt;USD&lt;/code&gt;, &lt;code&gt;TON&lt;/code&gt;, or any popular project ticker that someone could imitate.&lt;/p&gt;

&lt;p&gt;The interface may display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example USD
USD
$1.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but the application state should fundamentally remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EQ...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The address is what connects the display object to the actual TON asset.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical STON.fi token selector
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l62lzls1mmqhny2uldk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l62lzls1mmqhny2uldk.png" alt="A practical STON.fi token selector" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Putting the pieces together, a small React application might query STON.fi as the user types instead of loading the entire asset catalog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AssetInfoV2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AssetInfoV2&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryAssets&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;searchTerms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityVeryHigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityHigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;AssetTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LiquidityMedium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your component can then render the fields STON.fi already normalized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSelectedAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a real product, add loading states, request cancellation or debouncing for live search, image fallbacks, error handling, and caching. Metadata images and other external resources should also be treated as untrusted input. If your backend fetches arbitrary remote resources, apply normal URL validation and server-side request protections.&lt;/p&gt;

&lt;p&gt;STON.fi's own Omniston quickstart follows the same core architecture: fetch assets through &lt;code&gt;StonApiClient&lt;/code&gt;, keep &lt;code&gt;AssetInfoV2&lt;/code&gt; objects in state, display &lt;code&gt;meta.symbol&lt;/code&gt; or &lt;code&gt;meta.displayName&lt;/code&gt;, and pass the selected contract addresses into later swap operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; use &lt;code&gt;getAsset()&lt;/code&gt; when the contract address is already known and &lt;code&gt;queryAssets()&lt;/code&gt; when you are building discovery or search. Keep the contract address as your canonical identifier, normalize optional metadata before it reaches your UI, and use STON.fi's tags to make large token lists easier to navigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I query STON.fi token metadata without installing an SDK?
&lt;/h3&gt;

&lt;p&gt;Yes. The REST API is available at &lt;code&gt;https://api.ston.fi&lt;/code&gt;, so any environment capable of making HTTP requests can use it. &lt;code&gt;GET /v1/assets/{address}&lt;/code&gt; retrieves a specific asset, while &lt;code&gt;POST /v1/assets/query&lt;/code&gt; supports filtered discovery. The &lt;code&gt;@ston-fi/api&lt;/code&gt; package is mainly a convenience layer for TypeScript and JavaScript applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  What metadata does STON.fi return for a token?
&lt;/h3&gt;

&lt;p&gt;Depending on the endpoint and schema, you can receive a contract address, kind, symbol, display name, decimals, image URL, prices, tags, popularity information, optional extensions, and wallet-related fields. Query responses use the newer model where core display metadata is grouped under &lt;code&gt;meta&lt;/code&gt;, and those metadata fields can be optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use &lt;code&gt;getAssets()&lt;/code&gt; or &lt;code&gt;queryAssets()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;getAssets()&lt;/code&gt; when you genuinely need the complete DEX asset collection. Use &lt;code&gt;queryAssets()&lt;/code&gt; for most interactive interfaces because it supports search terms, conditions, wallet-aware queries, sorting, and limits. A search box usually does not need the full asset catalog before the user has typed anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can two TON tokens have the same symbol?
&lt;/h3&gt;

&lt;p&gt;Yes. Names and symbols are metadata, and token creators can choose them. A familiar ticker therefore does not uniquely identify a jetton. TON documentation recommends distinguishing tokens by address. Your frontend can display the symbol prominently, but your application logic should retain and use the contract address.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I do if &lt;code&gt;meta.imageUrl&lt;/code&gt; or &lt;code&gt;meta.displayName&lt;/code&gt; is missing?
&lt;/h3&gt;

&lt;p&gt;Use a fallback. Display the symbol or a shortened address when a name is unavailable, and use a local placeholder image when no valid icon exists. Do not make rendering a token dependent on optional cosmetic metadata. &lt;code&gt;AssetInfoV2&lt;/code&gt; deliberately represents several metadata properties as optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does STON.fi provide token prices together with metadata?
&lt;/h3&gt;

&lt;p&gt;The asset schemas include optional STON.fi DEX price information such as &lt;code&gt;dex_price_usd&lt;/code&gt;, exposed in camelCase by the TypeScript client. Treat price data separately from identity metadata because a price can be absent or change frequently, while the contract address is the persistent identifier used by your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use STON.fi metadata to build a wallet token list?
&lt;/h3&gt;

&lt;p&gt;Yes. STON.fi exposes wallet-specific asset endpoints, and &lt;code&gt;queryAssets()&lt;/code&gt; can also accept a wallet address together with conditions such as &lt;code&gt;AssetTag.WalletHasBalance&lt;/code&gt;. That makes it possible to combine searchable DEX assets with wallet-aware token selection without maintaining a completely separate metadata database.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest way to query a STON.fi asset before using it in a swap?
&lt;/h3&gt;

&lt;p&gt;Start from the exact contract address whenever possible. Retrieve the asset, display its metadata for readability, but keep the address as the selected value passed into your swap logic. For search-based selection, show enough identifying information for the user to distinguish similar tokens and avoid treating a matching name, ticker, or image as proof of identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX API Reference - Official overview of asset, pool, wallet, swap, and other REST endpoints&lt;/li&gt;
&lt;li&gt;STON.fi REST API - Official introduction to the STON.fi HTTP API and TypeScript client&lt;/li&gt;
&lt;li&gt;STON.fi Swagger UI - Current interactive REST API schemas, asset endpoints, request parameters, and response models&lt;/li&gt;
&lt;li&gt;STON.fi API GitHub repository - Official source and usage examples for the &lt;code&gt;@ston-fi/api&lt;/code&gt; TypeScript client&lt;/li&gt;
&lt;li&gt;STON.fi asset types - Official &lt;code&gt;AssetInfo&lt;/code&gt;, &lt;code&gt;AssetInfoV2&lt;/code&gt;, &lt;code&gt;AssetKind&lt;/code&gt;, and &lt;code&gt;AssetTag&lt;/code&gt; definitions&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Quickstart - Official React example showing how &lt;code&gt;StonApiClient&lt;/code&gt; and &lt;code&gt;queryAssets()&lt;/code&gt; populate token selectors&lt;/li&gt;
&lt;li&gt;TON Token Metadata Documentation - Official explanation of on-chain, off-chain, and semi-chain token metadata and token identity considerations&lt;/li&gt;
&lt;li&gt;TEP-64 Token Data Standard - TON specification defining token metadata layouts and jetton metadata fields&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Display STON.fi Pool Data in a Web App</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Fri, 21 Aug 2026 10:52:22 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-display-stonfi-pool-data-in-a-web-app-21c6</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-display-stonfi-pool-data-in-a-web-app-21c6</guid>
      <description>&lt;p&gt;&lt;em&gt;Build a small React and TypeScript dashboard that fetches STON.fi liquidity pools, resolves token metadata, formats reserves, and presents useful market data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Displaying STON.fi pool data in a web app does not require reading TON smart contracts directly. For most dashboards, analytics pages, token explorers, and liquidity interfaces, the simplest route is the official STON.fi REST API or its TypeScript client, &lt;code&gt;@ston-fi/api&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The API already organizes contract data into application-friendly structures. You can request pools, retrieve asset metadata, find pools for a specific token pair, and expose fields such as reserves, USD liquidity values, and 24-hour volume.&lt;/p&gt;

&lt;p&gt;In this guide, we will build a small React interface that turns those responses into readable pool cards without adding wallet connections or transaction logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we will build:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetch the current STON.fi pool list&lt;/li&gt;
&lt;li&gt;resolve token addresses into symbols&lt;/li&gt;
&lt;li&gt;format reserves using each token's decimals&lt;/li&gt;
&lt;li&gt;display liquidity and 24-hour volume&lt;/li&gt;
&lt;li&gt;handle loading, errors, and stale data&lt;/li&gt;
&lt;li&gt;keep the data layer ready for filtering or a larger dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use the STON.fi API instead of reading contracts directly?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmwalw7656kroamoyl0wj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmwalw7656kroamoyl0wj.png" alt="Why use the STON.fi API instead of reading contracts directly" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A liquidity pool ultimately lives on-chain. STON.fi pool contracts contain reserves and other state, and the protocol documentation exposes contract getters such as &lt;code&gt;get_pool_data&lt;/code&gt;. The V2 pool getter, for example, includes the LP token supply, both reserves, token wallet addresses, and fee-related fields.&lt;/p&gt;

&lt;p&gt;You could query those contracts yourself. For a web interface whose job is simply to show pool information, however, that creates work you often do not need.&lt;/p&gt;

&lt;p&gt;STON.fi provides a REST API specifically to organize protocol data for applications. Its current pool endpoints include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET  /v1/pools
GET  /v1/pools/{address}
GET  /v1/pools/by_market/{asset0}/{asset1}
POST /v1/pools/query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The base URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.ston.fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official TypeScript package wraps these endpoints with methods such as &lt;code&gt;getPools()&lt;/code&gt;, &lt;code&gt;getPool()&lt;/code&gt;, &lt;code&gt;getPoolsByAssetPair()&lt;/code&gt;, and &lt;code&gt;queryPools()&lt;/code&gt;. The current client also normalizes API response keys from &lt;code&gt;snake_case&lt;/code&gt; to &lt;code&gt;camelCase&lt;/code&gt;, which is convenient in a TypeScript frontend.&lt;/p&gt;

&lt;p&gt;For a read-only pool dashboard, that is the layer we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which pool fields are actually useful in a UI?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F783senaxsmrebraxrdau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F783senaxsmrebraxrdau.png" alt="Which pool fields are actually useful in a UI?" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pool response contains considerably more information than most users need to see. The current STON.fi schema includes fields for the pool address, token addresses, reserves, LP supply, protocol fees, LP price, USD LP supply, recent APY values, 24-hour USD volume, router address, and parameters used by different pool types.&lt;/p&gt;

&lt;p&gt;A compact market interface can start with just a few fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API value&lt;/th&gt;
&lt;th&gt;What it gives your UI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;token0Address&lt;/code&gt; and &lt;code&gt;token1Address&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Identifies the pool pair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;reserve0&lt;/code&gt; and &lt;code&gt;reserve1&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Current token reserves in base units&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lpTotalSupplyUsd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;USD value associated with total LP supply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volume24hUsd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trading volume during the last 24 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pool contract address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deprecated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Helps avoid presenting deprecated pools as normal active choices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are two important display details here.&lt;/p&gt;

&lt;p&gt;First, token addresses are not good labels. A visitor wants to see something like &lt;code&gt;TON / USDT&lt;/code&gt;, not two long TON addresses. We therefore need the asset list as well as the pool list.&lt;/p&gt;

&lt;p&gt;Second, reserves are raw blockchain quantities. Token metadata defines the number of decimals that must be applied to convert a base-unit balance into a human-readable amount. TON documentation explicitly warns applications to respect token decimals rather than assuming every asset uses the same value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the React project
&lt;/h2&gt;

&lt;p&gt;A basic React and TypeScript application is enough for the example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest stonfi-pools &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;span class="nb"&gt;cd &lt;/span&gt;stonfi-pools
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ston-fi/api
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this dashboard, we do not need &lt;code&gt;@ston-fi/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That distinction is useful. &lt;code&gt;@ston-fi/api&lt;/code&gt; is the HTTP API client and is appropriate for retrieving application data. &lt;code&gt;@ston-fi/sdk&lt;/code&gt; is aimed at interaction with STON.fi DEX contracts, including swaps and liquidity operations.&lt;/p&gt;

&lt;p&gt;Create a small API module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/stonfi.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StonApiClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ston-fi/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StonApiClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client requires no special configuration for the standard API endpoint. The package uses &lt;code&gt;https://api.ston.fi&lt;/code&gt; as its default base URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetch pools and token metadata together
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87b42tm518xiv8pf1fx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87b42tm518xiv8pf1fx1.png" alt="Fetch pools and token metadata together" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;getPools()&lt;/code&gt; gives us the pool data, while &lt;code&gt;getAssets()&lt;/code&gt; gives us the metadata required to turn token addresses into recognizable names and symbols.&lt;/p&gt;

&lt;p&gt;Fetching both in parallel keeps the first render simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./stonfi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPools&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAssets&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPools&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAssets&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Asset&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ignore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;poolList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
          &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPools&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAssets&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nf"&gt;setPools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poolList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setAssets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;
              &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;
              &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unable to load STON.fi data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ignore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading STON.fi pools...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Error: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loaded &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; pools.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React documents &lt;code&gt;useEffect&lt;/code&gt; as one way to synchronize a component with an external system, including manual data fetching. It also recommends cleanup logic so a response does not update a component after the relevant effect has been discarded.&lt;/p&gt;

&lt;p&gt;For a production Next.js, Remix, or similar application, you may prefer the framework's server-side data fetching or a caching library. The STON.fi-specific part does not change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn contract addresses into readable pool pairs
&lt;/h2&gt;

&lt;p&gt;The asset response includes fields such as the contract address, symbol, display name, decimals, and price information. The STON.fi client converts the raw API keys into camelCase before returning them.&lt;/p&gt;

&lt;p&gt;Build a lookup map once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// inside App&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetByAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each pool's token addresses can be resolved efficiently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSymbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;assetByAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Asset&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;assetByAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same metadata lets us convert reserves into display values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/0+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fraction&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fraction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not silently assume nine decimals when metadata is unavailable. Nine is common on TON, but tokens can use another value. USDT, for example, uses six decimals.&lt;/p&gt;

&lt;p&gt;For unknown assets, showing the raw amount or an explicit unavailable state is safer than presenting a confidently formatted but incorrect number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render the pool data
&lt;/h2&gt;

&lt;p&gt;We can now turn the two API responses into a small dashboard.&lt;/p&gt;

&lt;p&gt;Add a USD formatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NumberFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maximumFractionDigits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatUsd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then render the pools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;STON.fi Pools&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"pool-grid"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pools&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deprecated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lpTotalSupplyUsd&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
            &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lpTotalSupplyUsd&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assetByAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token0Address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assetByAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token1Address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reserve0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token0&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; base units`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reserve1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token1&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;formatUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserve1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; base units`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"pool-card"&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token0&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; /&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token1&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Liquidity:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatUsd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lpTotalSupplyUsd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;24h volume:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatUsd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume24hUsd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Reserve 0:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;reserve0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token0&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Reserve 1:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;reserve1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token1&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                Pool: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;...
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point the app has moved from protocol-oriented data to UI-oriented data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STON.fi API
    |
    +-- pools
    |    +-- reserves
    |    +-- liquidity value
    |    +-- volume
    |    +-- pool address
    |
    +-- assets
         +-- symbols
         +-- names
         +-- decimals
              |
              v
       React view model
              |
              v
       readable pool cards
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That transformation layer is worth keeping separate from the markup. It becomes much easier to add search, sorting, charts, or token filters later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetch less data when the page becomes more specific
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwvhfzioabhu5er2oz51a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwvhfzioabhu5er2oz51a.png" alt="Fetch less data when the page becomes more specific" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;getPools()&lt;/code&gt; is a good starting point because it lets you explore the dataset. It should not automatically become the request used by every future screen.&lt;/p&gt;

&lt;p&gt;If a page is about one pool, request one pool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poolAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user has selected two assets, request pools for that pair:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stonApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPoolsByAssetPair&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;asset0Address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;asset1Address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more advanced discovery, STON.fi also exposes &lt;code&gt;queryPools()&lt;/code&gt;. The current client supports search terms, conditions, sorting, limits, wallet-specific context, and a DEX V2 option.&lt;/p&gt;

&lt;p&gt;That gives you a useful progression:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;getPools()&lt;/code&gt; while building a general explorer.&lt;/li&gt;
&lt;li&gt;Move to pair-specific requests when the visitor selects assets.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;getPool()&lt;/code&gt; on detail pages.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;queryPools()&lt;/code&gt; when your interface needs server-side filtering or ranking.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The UI stays the same. Only the retrieval strategy becomes more precise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat pool data as live application data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw15kri15wfi661grtk29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw15kri15wfi661grtk29.png" alt="Treat pool data as live application data" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A working first render is not the end of the integration. Pool reserves and trading volume change as swaps and liquidity operations occur.&lt;/p&gt;

&lt;p&gt;Before shipping, decide how fresh the interface actually needs to be.&lt;/p&gt;

&lt;p&gt;For a pool directory, refreshing every few minutes may be enough. A trading interface may need a different data path and much fresher quoting logic. Do not confuse a periodically refreshed pool dashboard with an executable swap quote.&lt;/p&gt;

&lt;p&gt;A practical production checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache responses instead of requesting the complete pool list on every render&lt;/li&gt;
&lt;li&gt;show a loading state during the initial request&lt;/li&gt;
&lt;li&gt;preserve a clear error state when the API is unavailable&lt;/li&gt;
&lt;li&gt;display when the data was last refreshed&lt;/li&gt;
&lt;li&gt;remove or visually mark deprecated pools&lt;/li&gt;
&lt;li&gt;never use rounded UI numbers as transaction inputs&lt;/li&gt;
&lt;li&gt;keep original string values for financial calculations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The STON.fi documentation currently states that the DEX API has no rate limits, but that should not be treated as a reason to make wasteful requests. API behavior and operational limits can change, and caching makes the application faster regardless.&lt;/p&gt;

&lt;p&gt;Also remember that the STON.fi REST API is intended for mainnet data. If your development workflow depends on testnet contract state, do not assume the same REST endpoint is a testnet indexer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes when displaying STON.fi pools
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqqx4fd3qngq6uk03cqca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqqx4fd3qngq6uk03cqca.png" alt="Common mistakes when displaying STON.fi pools" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Showing raw addresses as the main identity.&lt;/strong&gt; Addresses are essential identifiers, but they make poor primary labels. Resolve them through the asset metadata response and use addresses as secondary verification information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formatting every reserve with nine decimals.&lt;/strong&gt; Token decimals belong to the token metadata. A wrong decimal assumption can produce a dramatically wrong displayed amount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calling &lt;code&gt;getPools()&lt;/code&gt; after every state update.&lt;/strong&gt; Pool data is external network data. Fetch it intentionally, cache it where appropriate, and separate filters that can run locally from filters that genuinely require another API request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treating &lt;code&gt;lpTotalSupplyUsd&lt;/code&gt; as a universal definition of TVL without explanation.&lt;/strong&gt; The API schema describes this field as the USD value of total LP token supply. If your product labels a metric "TVL," document exactly how your application defines it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixing analytics values with transaction calculations.&lt;/strong&gt; A rounded reserve or USD number that looks good in a card is not a substitute for a swap simulation or exact base-unit value.&lt;/p&gt;

&lt;p&gt;For a useful first STON.fi integration, keep the exercise narrow: load pools, resolve their assets, inspect the exact API values in your browser, and compare the displayed reserves with the token decimals before adding more features. Once that layer is reliable, search, sorting, charts, pool detail pages, and wallet-specific liquidity views become incremental improvements rather than a rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I display STON.fi pool data without connecting a wallet?
&lt;/h3&gt;

&lt;p&gt;Yes. Public pool and asset information can be retrieved through the STON.fi REST API without asking the visitor to connect a wallet. A wallet becomes relevant when you want wallet-specific positions or when the application starts constructing transactions. A read-only pool explorer can remain completely independent of TonConnect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need &lt;code&gt;@ston-fi/sdk&lt;/code&gt; to fetch liquidity pools?
&lt;/h3&gt;

&lt;p&gt;No. For the workflow in this article, &lt;code&gt;@ston-fi/api&lt;/code&gt; is the relevant package. It provides methods such as &lt;code&gt;getPools()&lt;/code&gt;, &lt;code&gt;getPool()&lt;/code&gt;, &lt;code&gt;getAssets()&lt;/code&gt;, and &lt;code&gt;getPoolsByAssetPair()&lt;/code&gt;. The separate DEX SDK is intended for interaction with protocol contracts and becomes useful when your application moves beyond displaying data.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does &lt;code&gt;GET /v1/pools&lt;/code&gt; return?
&lt;/h3&gt;

&lt;p&gt;The endpoint returns the STON.fi pool collection. Pool records contain identifiers and state including pool and router addresses, token addresses, reserves, LP-related values, fee fields, recent APY fields, and 24-hour USD volume where available. The exact live schema should always be checked in the official Swagger interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  How should I display token reserves correctly?
&lt;/h3&gt;

&lt;p&gt;Retrieve the corresponding asset metadata and use its &lt;code&gt;decimals&lt;/code&gt; value to convert the base-unit reserve into a human-readable amount. Do not assume that all tokens use the same number of decimals. Keep the original string or integer representation for calculations and perform formatting only at the presentation boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I refresh pool data every second?
&lt;/h3&gt;

&lt;p&gt;Usually not for a general pool dashboard. Choose a refresh interval that matches the purpose of the page, cache shared data, and avoid repeated full-list requests. A fast-changing execution interface should use purpose-built quote or simulation data rather than assuming that a periodically fetched pool card represents an executable price.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I request only pools for one token pair?
&lt;/h3&gt;

&lt;p&gt;Yes. STON.fi exposes &lt;code&gt;GET /v1/pools/by_market/{asset0}/{asset1}&lt;/code&gt;, and the TypeScript client wraps it with &lt;code&gt;getPoolsByAssetPair()&lt;/code&gt;. That is preferable to loading every pool and filtering in the browser when the application already knows the two selected assets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I show a user's STON.fi liquidity positions with the same API?
&lt;/h3&gt;

&lt;p&gt;Yes. The REST API includes wallet-specific pool endpoints, and &lt;code&gt;@ston-fi/api&lt;/code&gt; exposes &lt;code&gt;getWalletPools()&lt;/code&gt; and &lt;code&gt;getWalletPool()&lt;/code&gt;. That is a different UI state from the public pool directory because the response is enriched with information relevant to the specified wallet.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I verify before publishing a STON.fi pool dashboard?
&lt;/h3&gt;

&lt;p&gt;Compare your field names against the current Swagger schema, verify token decimals, confirm that deprecated pools are handled correctly, and test missing optional values such as USD metrics. Also inspect the actual API response rather than copying an old example, since the STON.fi API and TypeScript client continue to evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi REST API - Official overview of the REST interface, API viewers, and current usage notes&lt;/li&gt;
&lt;li&gt;STON.fi API Reference - Official list of pool, asset, wallet, statistics, and other DEX endpoints&lt;/li&gt;
&lt;li&gt;STON.fi Swagger UI - Current interactive REST API schema and response definitions&lt;/li&gt;
&lt;li&gt;STON.fi API TypeScript client - Official source repository for &lt;code&gt;@ston-fi/api&lt;/code&gt;, including pool and asset client methods&lt;/li&gt;
&lt;li&gt;@ston-fi/api on npm - Package installation and TypeScript client usage examples&lt;/li&gt;
&lt;li&gt;STON.fi V2 Pool contract reference - On-chain pool state and &lt;code&gt;get_pool_data&lt;/code&gt; fields behind pool information&lt;/li&gt;
&lt;li&gt;TON token metadata - Official explanation of token metadata and decimal handling for human-readable amounts&lt;/li&gt;
&lt;li&gt;React &lt;code&gt;useEffect&lt;/code&gt; reference - Official React guidance for synchronizing components with external systems and manual data fetching&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Track STON.fi Swap Status with an Indexer</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Tue, 18 Aug 2026 06:42:55 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-track-stonfi-swap-status-with-an-indexer-1n5h</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-track-stonfi-swap-status-with-an-indexer-1n5h</guid>
      <description>&lt;p&gt;&lt;em&gt;How to turn TON transaction data into a reliable pending, processing, completed, or failed state for a STON.fi swap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When a user signs a STON.fi swap, your application still has an important job to do: determine what actually happened on-chain.&lt;/p&gt;

&lt;p&gt;On TON, that is not always as simple as waiting for one transaction hash. A swap can involve several contracts and internal messages, so the wallet transaction that starts the operation is only the beginning of the execution path. A blockchain indexer lets you locate that transaction, follow its trace, inspect the resulting actions, and turn low-level blockchain data into a useful swap status.&lt;/p&gt;

&lt;p&gt;For a production integration, the safest approach is to separate two questions: &lt;strong&gt;Has the TON trace finished?&lt;/strong&gt; and &lt;strong&gt;Did the STON.fi swap itself succeed?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one transaction hash is not enough
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmqtizim3xp94o3z9260.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmqtizim3xp94o3z9260.png" alt="one transaction hash is not enough" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developers coming from EVM networks often expect a swap to map neatly to one transaction. TON works differently.&lt;/p&gt;

&lt;p&gt;A transaction on TON records a state change for one account. If that account sends internal messages to other contracts, those messages can trigger additional transactions. The related messages and transactions form a &lt;strong&gt;trace&lt;/strong&gt;. Because TON uses asynchronous message processing, different parts of that trace may execute across different blocks.&lt;/p&gt;

&lt;p&gt;A simplified STON.fi swap can therefore look conceptually like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your wallet sends the initiating message.&lt;/li&gt;
&lt;li&gt;The wallet transaction sends an internal message toward the swap contracts.&lt;/li&gt;
&lt;li&gt;Router and pool contracts process the request.&lt;/li&gt;
&lt;li&gt;Jetton wallets may process token transfers.&lt;/li&gt;
&lt;li&gt;The output asset reaches the destination wallet.&lt;/li&gt;
&lt;li&gt;Excess TON or other follow-up messages may also be processed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The exact path depends on the swap and protocol version, but the monitoring lesson stays the same: &lt;strong&gt;finding the first transaction does not prove that the entire swap has completed successfully.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TON defines traces specifically to connect these causally related transactions and messages. An indexer makes those traces much easier to query than reconstructing them manually from raw node data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an indexer adds to swap tracking
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F25buy6vbox7w6tqvie96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F25buy6vbox7w6tqvie96.png" alt="What an indexer adds to swap tracking" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An indexer continuously reads blockchain data, parses transactions and messages, and stores structured results in a query-friendly database.&lt;/p&gt;

&lt;p&gt;TON Center API v3 is one example. TON documentation describes it as an indexed access layer that supports historical transactions, traces, decoded Jetton data, and higher-level actions. Its mainnet endpoint is &lt;code&gt;https://toncenter.com/api/v3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a STON.fi integration, that gives you several useful capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find the transaction associated with the message sent by the wallet&lt;/li&gt;
&lt;li&gt;retrieve the full trace related to that transaction&lt;/li&gt;
&lt;li&gt;see whether the trace is still incomplete&lt;/li&gt;
&lt;li&gt;inspect pending messages&lt;/li&gt;
&lt;li&gt;request classified actions when available&lt;/li&gt;
&lt;li&gt;recover historical status after a page reload or backend restart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is much more useful than repeatedly asking whether a single account has a new transaction.&lt;/p&gt;

&lt;p&gt;A good architecture treats the indexer as an &lt;strong&gt;observation layer&lt;/strong&gt;. Your application stores the swap identifiers, queries indexed blockchain state, and then maps the returned data into a much smaller set of statuses that make sense to the person waiting for the swap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a status model for your application
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fun1n4euq93tdb3pefysm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fun1n4euq93tdb3pefysm.png" alt="Build a status model for your application" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do not expose every low-level TON state directly to the UI. Define your own swap lifecycle instead.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Application status&lt;/th&gt;
&lt;th&gt;What you know&lt;/th&gt;
&lt;th&gt;Typical evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Submitted&lt;/td&gt;
&lt;td&gt;Wallet accepted the request&lt;/td&gt;
&lt;td&gt;TON Connect returned the outgoing message BoC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locating&lt;/td&gt;
&lt;td&gt;Message was sent, but the indexed transaction is not available yet&lt;/td&gt;
&lt;td&gt;No matching indexed transaction yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processing&lt;/td&gt;
&lt;td&gt;Initial transaction exists and the trace is still progressing&lt;/td&gt;
&lt;td&gt;Trace is incomplete or still has pending messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifying&lt;/td&gt;
&lt;td&gt;Trace is complete, but the protocol outcome still needs interpretation&lt;/td&gt;
&lt;td&gt;Complete trace and available actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Succeeded&lt;/td&gt;
&lt;td&gt;Swap completed with the expected protocol result&lt;/td&gt;
&lt;td&gt;Successful STON.fi swap status or validated swap action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failed&lt;/td&gt;
&lt;td&gt;Execution completed without a successful swap result&lt;/td&gt;
&lt;td&gt;Failed or aborted protocol action, refund path, or other terminal failure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key distinction is between &lt;strong&gt;trace completion&lt;/strong&gt; and &lt;strong&gt;swap success&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An indexer can tell you that the chain of messages has stopped progressing. It does not automatically mean your application's intended business operation succeeded. For a STON.fi swap, you should also interpret STON.fi-specific data rather than relying only on a generic transaction &lt;code&gt;success&lt;/code&gt; flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the message returned by TON Connect
&lt;/h2&gt;

&lt;p&gt;After a user signs through TON Connect, &lt;code&gt;sendTransaction()&lt;/code&gt; returns a serialized external message as a BoC.&lt;/p&gt;

&lt;p&gt;That BoC is a useful tracking anchor, but TON recommends using the normalized hash of the external message for message lookup. Normalization exists because equivalent external messages can otherwise have different hashes depending on serialization details. TON documents the normalization rules in its TON Connect message lookup guide and notes that normalized message lookup is supported by many providers.&lt;/p&gt;

&lt;p&gt;A shortened TypeScript version follows the same approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loadMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;storeMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ton/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getNormalizedHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromBase64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;beginParse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;external-in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Expected an external-in message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;importFee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;storeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;forceRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this tracking identifier with the swap record in your backend.&lt;/p&gt;

&lt;p&gt;Do not depend on React component state alone. If the user closes the tab immediately after signing, you still want to be able to reconstruct the operation later.&lt;/p&gt;

&lt;p&gt;Your stored swap record might contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wallet address&lt;/li&gt;
&lt;li&gt;normalized external message hash&lt;/li&gt;
&lt;li&gt;STON.fi router used for the swap&lt;/li&gt;
&lt;li&gt;input and output assets&lt;/li&gt;
&lt;li&gt;expected output or minimum output&lt;/li&gt;
&lt;li&gt;STON.fi query ID when available&lt;/li&gt;
&lt;li&gt;creation time&lt;/li&gt;
&lt;li&gt;your current application status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those fields give you enough context to recover after temporary API failures or user disconnects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the transaction into its trace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqfvj8wnzet9xr6gtm6c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqfvj8wnzet9xr6gtm6c0.png" alt=" " width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you know the transaction hash, TON Center API v3 can retrieve a trace with &lt;code&gt;GET /traces&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The endpoint supports filters including &lt;code&gt;trace_id&lt;/code&gt;, &lt;code&gt;tx_hash&lt;/code&gt;, and &lt;code&gt;msg_hash&lt;/code&gt;. You can also request classified actions with &lt;code&gt;include_actions=true&lt;/code&gt;. The returned trace data includes fields such as &lt;code&gt;is_incomplete&lt;/code&gt;, transaction information, actions, and trace metadata.&lt;/p&gt;

&lt;p&gt;A simple backend request can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://toncenter.com/api/v3/traces&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tx_hash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;include_actions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-API-Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TONCENTER_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Indexer returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep API keys on the server. TON Center accepts API keys through the &lt;code&gt;X-API-Key&lt;/code&gt; header, and its documentation explicitly recommends not exposing them in client-side applications or public repositories.&lt;/p&gt;

&lt;p&gt;Your first status function can remain deliberately simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTraceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;traces&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;locating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_incomplete&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trace_info&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;pending_messages&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;processing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;verifying&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the final state is &lt;code&gt;verifying&lt;/code&gt;, not &lt;code&gt;succeeded&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That extra step prevents one of the most common monitoring mistakes: treating a completed trace as proof that the desired swap completed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the STON.fi result, not only TON execution
&lt;/h2&gt;

&lt;p&gt;STON.fi provides protocol-specific APIs that are useful once you need to interpret what happened.&lt;/p&gt;

&lt;p&gt;The current STON.fi DEX API documents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /v1/swap/status&lt;/code&gt; for checking a swap using router address, owner address, and query ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /v1/transaction/query&lt;/code&gt; for resolving a transaction from identifiers such as wallet address plus query ID or an external message hash&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /v1/transaction/action_tree&lt;/code&gt; for obtaining STON.fi actions and their statuses from an originating transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API base URL is &lt;code&gt;https://api.ston.fi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These endpoints solve a different problem from a generic TON indexer.&lt;/p&gt;

&lt;p&gt;The indexer answers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What transactions and messages happened on TON?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;STON.fi-specific decoding answers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What did those transactions mean for this swap?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a direct STON.fi DEX integration, combining both gives you a stronger status pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TON Connect
    |
    v
External message
    |
    v
Indexer finds transaction
    |
    v
Indexer follows TON trace
    |
    v
Trace completes
    |
    v
STON.fi status or action verification
    |
    +--&amp;gt; succeeded
    |
    +--&amp;gt; failed / aborted / recovery path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also makes debugging much easier. If your UI says that a swap failed, you can distinguish between "the initiating transaction was never found", "the TON trace is still executing", and "execution completed but the swap did not produce the intended result."&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes when the swap uses Omniston?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fax1fo7nr2pmvu4xaak3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fax1fo7nr2pmvu4xaak3i.png" alt="What changes when the swap uses Omniston?" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do not confuse generic indexer tracking with Omniston's own trade tracking interface.&lt;/p&gt;

&lt;p&gt;For Omniston swaps, STON.fi provides &lt;code&gt;trackTrade&lt;/code&gt; functionality through its SDKs and the underlying &lt;code&gt;trade.track&lt;/code&gt; API. Tracking uses the quote ID, trader wallet address, and outgoing transaction hash. Omniston can report states such as waiting for the initial transfer, transferring, swapping, receiving funds, and a final settled trade result.&lt;/p&gt;

&lt;p&gt;If you are already building with the Omniston SDK, its native trade tracker should usually be your primary protocol-level status source.&lt;/p&gt;

&lt;p&gt;An indexer is still valuable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;independent on-chain verification&lt;/li&gt;
&lt;li&gt;debugging failed or unusual traces&lt;/li&gt;
&lt;li&gt;rebuilding state after an application restart&lt;/li&gt;
&lt;li&gt;storing your own transaction history&lt;/li&gt;
&lt;li&gt;linking protocol status to raw TON transactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two approaches complement each other. They are not competing definitions of the same status.&lt;/p&gt;

&lt;h2&gt;
  
  
  Polling or streaming?
&lt;/h2&gt;

&lt;p&gt;Polling is usually the easiest starting point.&lt;/p&gt;

&lt;p&gt;After submission, poll quickly while the swap is active, then reduce the frequency after several unsuccessful attempts. Stop polling once you reach a terminal state. Add a maximum tracking window, but do not automatically classify a temporary timeout as an on-chain failure.&lt;/p&gt;

&lt;p&gt;For faster interfaces, TON Center also provides a Streaming API using SSE and WebSockets. It can stream transactions, actions, and traces with &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;confirmed&lt;/code&gt;, and &lt;code&gt;finalized&lt;/code&gt; finality levels. TON documentation warns that the streaming API does not replay events missed during a connection interruption, so applications that require complete state should resynchronize from API v3 after reconnecting.&lt;/p&gt;

&lt;p&gt;A practical production pattern is therefore:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;stream for responsiveness, query the indexer for recovery and truth reconstruction.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical STON.fi tracking checklist
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz0b3rvzsax1f0g240wq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz0b3rvzsax1f0g240wq9.png" alt="A practical STON.fi tracking checklist" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before shipping your status component, test more than the happy path.&lt;/p&gt;

&lt;p&gt;Check that your application can recover a swap after a browser refresh, distinguish "not indexed yet" from "failed", follow the complete trace instead of only the wallet transaction, and validate the STON.fi-level result before displaying success.&lt;/p&gt;

&lt;p&gt;Also store enough identifiers to investigate a transaction later. A wallet address by itself is usually not a strong correlation key when the same wallet can initiate several swaps close together.&lt;/p&gt;

&lt;p&gt;Most importantly, make your status names describe what you actually know. &lt;code&gt;Processing&lt;/code&gt; is safer than &lt;code&gt;Success&lt;/code&gt; while internal messages are still active, and &lt;code&gt;Verifying&lt;/code&gt; is safer than assuming every completed TON trace represents a completed swap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is an indexer in TON?
&lt;/h3&gt;

&lt;p&gt;An indexer reads blockchain data, parses transactions and messages, and stores them in a database optimized for queries. TON Center API v3 is an indexed API that supports traces, historical transactions, actions, Jetton data, and other structured information that is harder to obtain efficiently from raw node access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can a STON.fi swap involve multiple transactions?
&lt;/h3&gt;

&lt;p&gt;TON smart contracts communicate asynchronously through messages. One transaction processes a message for one account, and that account may send messages that trigger transactions on other accounts. A DEX operation can therefore become a trace containing wallet, router, pool, and token-related transactions rather than one monolithic transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does finding the wallet transaction mean the swap succeeded?
&lt;/h3&gt;

&lt;p&gt;No. It proves that the initiating message was processed, not necessarily that the entire swap completed successfully. Follow the resulting trace and then verify the protocol-level swap result before showing a final success state.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I store after sending the swap?
&lt;/h3&gt;

&lt;p&gt;Store a stable correlation record containing the wallet address, tracking hash or transaction identifier, swap creation time, and STON.fi-specific identifiers such as the query ID or router when your integration provides them. This lets your backend reconstruct status even if the frontend disappears.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I poll an indexer continuously?
&lt;/h3&gt;

&lt;p&gt;Only while the operation is unresolved. Poll relatively frequently immediately after submission, then apply backoff. Once the swap reaches a terminal state, stop. For higher responsiveness, use streaming notifications while retaining historical polling as a recovery mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the STON.fi API instead of a TON indexer?
&lt;/h3&gt;

&lt;p&gt;For some status questions, yes. STON.fi exposes swap status, transaction query, and transaction action-tree endpoints that understand STON.fi operations. A generic TON indexer is still useful when you need raw trace visibility, independent verification, historical analysis, or debugging outside STON.fi-specific abstractions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How should I track an Omniston swap?
&lt;/h3&gt;

&lt;p&gt;Use Omniston's native trade tracking when possible. Its SDK tracking accepts the quote ID, trader wallet address, and outgoing transaction hash and provides trade-specific lifecycle information. A TON indexer can then serve as an additional on-chain verification and debugging layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest way to display STON.fi swap status?
&lt;/h3&gt;

&lt;p&gt;Use several stages rather than jumping directly from "sent" to "success": record the wallet submission, locate the transaction, wait for the trace to finish, and then verify the STON.fi-specific outcome. That model reflects TON's asynchronous execution much more accurately and produces a status UI that remains useful when something goes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX API Reference - official REST endpoints for swap status, transaction resolution, and STON.fi action trees&lt;/li&gt;
&lt;li&gt;STON.fi Omniston Swap Overview - official description of Omniston swap execution and the &lt;code&gt;trade.track&lt;/code&gt; lifecycle&lt;/li&gt;
&lt;li&gt;STON.fi Omniston React SDK - official SDK guidance for tracking an initiated Omniston trade&lt;/li&gt;
&lt;li&gt;TON Center API v3 Overview - official description of TON's indexed API layer and available trace and action endpoints&lt;/li&gt;
&lt;li&gt;TON Center Get Traces - official reference for querying traces by transaction, message, or trace identifiers&lt;/li&gt;
&lt;li&gt;TON Connect Message Lookup - official guidance for identifying transactions from messages returned after wallet submission&lt;/li&gt;
&lt;li&gt;TON Traces - explanation of how related messages and transactions form a TON execution trace&lt;/li&gt;
&lt;li&gt;TON Center Streaming API - official documentation for real-time transaction, action, and trace monitoring&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Decode a STON.fi Swap Transaction</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sun, 16 Aug 2026 06:59:27 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-decode-a-stonfi-swap-transaction-940</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-decode-a-stonfi-swap-transaction-940</guid>
      <description>&lt;p&gt;&lt;em&gt;How to read the TON trace behind a swap, identify the STON.fi contracts involved, and verify what actually happened on-chain.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Decoding a STON.fi swap is less about finding one transaction and more about reconstructing a sequence of messages. TON uses an asynchronous execution model, so a swap that looks like one action in the STON.fi interface can produce several transactions across a wallet, jetton wallets, the STON.fi Router, a liquidity pool, and other contracts.&lt;/p&gt;

&lt;p&gt;The practical method is simple: start from the transaction initiated by your wallet, open its full trace, identify each contract, decode the important message bodies, and follow the asset flow until the output tokens reach their destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the trace, not a single transaction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcln0tvhptu72cahbgds9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcln0tvhptu72cahbgds9.png" alt="Start with the trace" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you come from Ethereum, the word "transaction" can create the wrong mental model.&lt;/p&gt;

&lt;p&gt;An Ethereum swap commonly appears as one transaction containing multiple contract calls. TON works differently. A TON transaction records the processing of a message and the resulting state change on one account. When that account sends messages to other accounts, those messages trigger additional transactions.&lt;/p&gt;

&lt;p&gt;The connected sequence is called a &lt;strong&gt;trace&lt;/strong&gt;. TON documentation describes traces as causally connected messages, with explorers usually displaying transactions as nodes and messages as edges.&lt;/p&gt;

&lt;p&gt;That distinction matters immediately when investigating a STON.fi swap. Seeing a successful transaction on your wallet contract does not necessarily tell you that the entire swap finished successfully. It tells you that one part of the trace was processed.&lt;/p&gt;

&lt;p&gt;Think about the operation as three different layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interface action:&lt;/strong&gt; You select two assets, review a quote, and approve a swap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blockchain trace:&lt;/strong&gt; Multiple accounts process messages and send new messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-readable interpretation:&lt;/strong&gt; An explorer or indexer groups those low-level events into labels such as token transfer or swap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third layer is useful, but it is not the blockchain itself. TON's API documentation explicitly notes that higher-level "actions" are classifications produced by indexer logic rather than objects stored directly on-chain.&lt;/p&gt;

&lt;p&gt;For serious debugging, read both the convenient interpretation and the underlying trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you collect before decoding?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frk8akfablcksm0b2u759.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frk8akfablcksm0b2u759.png" alt="What should you collect before decoding" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You usually need one reliable starting point.&lt;/p&gt;

&lt;p&gt;That may be the transaction displayed by your wallet, the transaction linked by the application, or the wallet address and approximate time when you approved the swap. Developers may also have a query ID or the external message hash.&lt;/p&gt;

&lt;p&gt;TON explorers can expose transaction history, messages, fees, execution phases, traces, contract information, and token activity. That makes an explorer the natural first tool for manual investigation.&lt;/p&gt;

&lt;p&gt;STON.fi also exposes transaction-oriented API methods. Its API reference includes endpoints for resolving a transaction, checking swap status, and returning the STON.fi actions triggered by an originating transaction.&lt;/p&gt;

&lt;p&gt;Before digging into individual cells, write down what you already expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the wallet that initiated the swap&lt;/li&gt;
&lt;li&gt;the token you offered&lt;/li&gt;
&lt;li&gt;the approximate input amount&lt;/li&gt;
&lt;li&gt;the token you expected to receive&lt;/li&gt;
&lt;li&gt;the expected or minimum output&lt;/li&gt;
&lt;li&gt;the approximate execution time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These facts give you anchors. If the trace contains dozens of addresses, you do not have to understand every one immediately. You can follow the assets and identify the important contracts first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which accounts matter in a STON.fi swap?
&lt;/h2&gt;

&lt;p&gt;A simple jetton-to-jetton swap can involve more contracts than its interface suggests because jettons themselves use distributed wallet contracts.&lt;/p&gt;

&lt;p&gt;Under the TON jetton standard, each holder has a separate jetton wallet contract for a particular token. The jetton master represents the asset, while individual jetton wallets maintain balances and process transfers.&lt;/p&gt;

&lt;p&gt;For a basic STON.fi swap, these are the main actors to look for:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;What to inspect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Your TON wallet&lt;/td&gt;
&lt;td&gt;Starts the operation&lt;/td&gt;
&lt;td&gt;Initial message and destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your offer jetton wallet&lt;/td&gt;
&lt;td&gt;Sends the input tokens&lt;/td&gt;
&lt;td&gt;Transfer amount and destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router side&lt;/td&gt;
&lt;td&gt;Receives the token transfer and routes the swap&lt;/td&gt;
&lt;td&gt;Transfer notification and swap payload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STON.fi Pool&lt;/td&gt;
&lt;td&gt;Executes the AMM exchange&lt;/td&gt;
&lt;td&gt;Swap message, output conditions, execution result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router payout side&lt;/td&gt;
&lt;td&gt;Coordinates the output transfer&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pay_to&lt;/code&gt; and outgoing token movement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your ask jetton wallet&lt;/td&gt;
&lt;td&gt;Receives output tokens&lt;/td&gt;
&lt;td&gt;Final token balance change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;STON.fi describes the Router as the entry point for DEX calls. For jetton operations, it receives the relevant jetton notification and routes the operation toward the appropriate pool. The Pool handles swap logic and returns the result for settlement.&lt;/p&gt;

&lt;p&gt;Do not identify contracts only by friendly explorer labels. When accuracy matters, compare their addresses and message behavior with the documented STON.fi architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Message op codes turn the trace into a readable story
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fogeasdo9o17652b73rx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fogeasdo9o17652b73rx6.png" alt="Message op codes" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Raw TON messages contain serialized data rather than English instructions. One of the fastest ways to understand them is to inspect the operation code at the beginning of the message body.&lt;/p&gt;

&lt;p&gt;An op code tells a contract which operation the message is requesting.&lt;/p&gt;

&lt;p&gt;Several identifiers are especially useful when following a STON.fi jetton swap:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Message or payload&lt;/th&gt;
&lt;th&gt;Identifier&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jetton &lt;code&gt;transfer&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x0f8a7ea5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A jetton wallet has been asked to transfer tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jetton &lt;code&gt;transfer_notification&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x7362d09c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The receiving owner is being notified about the transferred jettons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STON.fi v2 &lt;code&gt;swap&lt;/code&gt; payload&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x6664de2a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The transferred tokens are intended for a swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STON.fi v2 &lt;code&gt;pay_to&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x657b54f5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Router is being instructed to perform settlement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jetton &lt;code&gt;excesses&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xd53276db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remaining attached TON is being returned&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The standard jetton values come from TEP-74, while STON.fi publishes its own DEX v2 operation code reference.&lt;/p&gt;

&lt;p&gt;You do not need to memorize these numbers. Their value is diagnostic. If an explorer exposes raw or decoded message bodies, the op code lets you verify that a message really represents the operation you think it does.&lt;/p&gt;

&lt;p&gt;A friendly label saying "Swap" is useful. A matching STON.fi swap payload inside the expected part of the trace is stronger evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one jetton-to-jetton swap from start to finish
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjnvgv0o66w6shmckgka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjnvgv0o66w6shmckgka.png" alt="Following one jetton-to-jetton swap on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider a simple case: you swap Token A for Token B through a STON.fi liquidity pool.&lt;/p&gt;

&lt;p&gt;The exact trace can vary depending on contract versions, token implementation, wallet deployment state, routing, and other parameters. Still, the basic asset flow gives you a reliable framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Your wallet starts the operation
&lt;/h3&gt;

&lt;p&gt;A STON.fi frontend can use TON Connect to ask your wallet to send the required blockchain message. TON Connect itself does not take possession of your private keys. It establishes the wallet connection and lets the dApp request transaction signing.&lt;/p&gt;

&lt;p&gt;In the explorer, begin at your wallet transaction.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where did the outgoing message go?&lt;/li&gt;
&lt;li&gt;How much TON was attached?&lt;/li&gt;
&lt;li&gt;Is there a payload?&lt;/li&gt;
&lt;li&gt;Does the destination correspond to the expected jetton wallet or swap entry path?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a jetton input, the first relevant contract is commonly your wallet for Token A rather than the liquidity pool itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Your offer jetton wallet moves Token A
&lt;/h3&gt;

&lt;p&gt;TON jetton transfers are message chains of their own.&lt;/p&gt;

&lt;p&gt;The standard &lt;code&gt;transfer&lt;/code&gt; request tells your jetton wallet how many tokens to send and where they should go. The jetton wallet updates its balance and causes the receiving side's jetton wallet to receive the transferred amount. If forwarding is requested, a &lt;code&gt;transfer_notification&lt;/code&gt; can then reach the owner of that receiving jetton wallet.&lt;/p&gt;

&lt;p&gt;At this point, check the &lt;strong&gt;jetton amount&lt;/strong&gt;, not only the TON attached to the internal message.&lt;/p&gt;

&lt;p&gt;A common decoding mistake is to see a small TON value traveling with the message and assume it represents the size of the trade. For jetton swaps, the trade amount is encoded in the jetton operation. Attached TON is also used to fund execution and message forwarding.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The STON.fi Router recognizes the swap request
&lt;/h3&gt;

&lt;p&gt;The Router is where the generic jetton transfer becomes a DEX operation.&lt;/p&gt;

&lt;p&gt;STON.fi's Router documentation describes handling &lt;code&gt;transfer_notification&lt;/code&gt; messages and forwarding swap requests to the appropriate Pool. STON.fi's v2 swap documentation also defines the swap payload that accompanies the token transfer.&lt;/p&gt;

&lt;p&gt;This part of the trace is especially useful for debugging.&lt;/p&gt;

&lt;p&gt;You want to establish that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the correct input token arrived&lt;/li&gt;
&lt;li&gt;the expected amount was recognized&lt;/li&gt;
&lt;li&gt;the payload requested a swap&lt;/li&gt;
&lt;li&gt;the request was routed to the intended pool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the trace never reaches the expected Pool, the failure happened before actual AMM execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The Pool executes the exchange
&lt;/h3&gt;

&lt;p&gt;The Pool is the point where the input becomes an output amount according to the pool's state and swap rules.&lt;/p&gt;

&lt;p&gt;STON.fi's v2 Pool specification includes swap-related parameters such as the minimum output and receiver information. After successful execution, the Pool can send the swap result toward the Router for settlement through the documented payout flow.&lt;/p&gt;

&lt;p&gt;When examining the Pool transaction, check more than whether an explorer colors it green.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;successful compute and action phases&lt;/li&gt;
&lt;li&gt;no relevant bounce or error downstream&lt;/li&gt;
&lt;li&gt;the output amount&lt;/li&gt;
&lt;li&gt;the receiver&lt;/li&gt;
&lt;li&gt;whether the minimum output condition was satisfied&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is often the most informative transaction in the entire trace because it connects the trade request with the resulting amount.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The Router settles the output
&lt;/h3&gt;

&lt;p&gt;After the Pool calculates the result, the output still has to reach you.&lt;/p&gt;

&lt;p&gt;STON.fi documents the &lt;code&gt;pay_to&lt;/code&gt; operation on the Router. This operation initiates the required jetton transfer from the Router side during swap settlement.&lt;/p&gt;

&lt;p&gt;You can now follow Token B in the opposite direction from the input:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pool result -&amp;gt; Router settlement -&amp;gt; output jetton transfer -&amp;gt; your Token B jetton wallet&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you lose the trail in a large trace, search for the expected output jetton and receiver address.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Your destination jetton wallet receives Token B
&lt;/h3&gt;

&lt;p&gt;The strongest practical confirmation is the final asset movement.&lt;/p&gt;

&lt;p&gt;Find the transaction that credits the Token B jetton wallet owned by your receiving address. Confirm the token identity and amount rather than relying only on a high-level "swap successful" label.&lt;/p&gt;

&lt;p&gt;The trace may continue with excess TON refunds or other bookkeeping messages after the economic result of the swap is already clear. The jetton standard defines an &lt;code&gt;excesses&lt;/code&gt; message specifically for returning remaining TON associated with an operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you prove the swap actually succeeded?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr42ihlngzba2vau71q4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr42ihlngzba2vau71q4y.png" alt="How do you prove the swap actually succeeded on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A green first transaction is not enough.&lt;/p&gt;

&lt;p&gt;TON's asynchronous model allows one contract to process its message successfully while a later part of the trace encounters a different outcome. A swap should therefore be verified end to end.&lt;/p&gt;

&lt;p&gt;A strong verification uses several signals together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The input moved:&lt;/strong&gt; the correct quantity of the offer jetton left your jetton wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Router received the intended operation:&lt;/strong&gt; the relevant notification and STON.fi payload are visible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Pool processed the swap:&lt;/strong&gt; the pool-side transaction completed as expected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No later failure invalidated the intended path:&lt;/strong&gt; inspect bounced or failed messages when present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The output moved:&lt;/strong&gt; the correct ask jetton was transferred toward your receiver.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The destination balance changed:&lt;/strong&gt; your output jetton wallet received the resulting tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STON.fi's API provides another convenient layer. Its swap status and transaction action endpoints can help summarize what the protocol recognized, while the raw trace remains the source for inspecting individual TON transactions and messages.&lt;/p&gt;

&lt;p&gt;This combination is much more reliable than reading only the first or last line shown by a wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not confuse attached TON with swap value or total fees
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn4rekzroxi51x704f019.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn4rekzroxi51x704f019.png" alt="Do not confuse attached TON with swap value" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TON messages frequently carry TON because downstream contracts need funds to execute and send further messages.&lt;/p&gt;

&lt;p&gt;That TON can move through several contracts during one trace. Some may pay transaction and forwarding fees, and unused amounts may later return as excesses.&lt;/p&gt;

&lt;p&gt;TON's documentation describes this carry-value pattern: incoming value becomes part of the receiving contract balance, and contracts use message modes and reserve logic to fund subsequent execution.&lt;/p&gt;

&lt;p&gt;So when you see several internal transfers such as &lt;code&gt;0.05 TON&lt;/code&gt;, &lt;code&gt;0.03 TON&lt;/code&gt;, or smaller amounts, do not simply add them together and call the result the swap fee.&lt;/p&gt;

&lt;p&gt;Instead, separate three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The asset being traded&lt;/strong&gt;, such as a jetton amount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TON attached for execution&lt;/strong&gt;, which can continue through the trace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actual blockchain fees&lt;/strong&gt;, recorded for the individual transactions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TON transactions expose their own fee information, and a multi-contract trace contains multiple transactions.&lt;/p&gt;

&lt;p&gt;For a technical investigation, inspect the fee fields rather than estimating cost from visible message values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the STON.fi action tree and raw trace together
&lt;/h2&gt;

&lt;p&gt;There are two useful ways to decode the same swap.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;raw TON view&lt;/strong&gt; answers questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which account processed this message?&lt;/li&gt;
&lt;li&gt;What was the incoming body?&lt;/li&gt;
&lt;li&gt;Which messages did it create?&lt;/li&gt;
&lt;li&gt;What were the exit results?&lt;/li&gt;
&lt;li&gt;How much TON was attached?&lt;/li&gt;
&lt;li&gt;Which token wallet received the output?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;STON.fi protocol view&lt;/strong&gt; answers the higher-level question: what STON.fi actions were triggered by the originating transaction?&lt;/p&gt;

&lt;p&gt;STON.fi's REST API includes &lt;code&gt;POST /v1/transaction/action_tree&lt;/code&gt;, which returns a flattened list of STON.fi actions and their statuses triggered by an originating transaction. The API reference also documents transaction resolution and swap-status functionality.&lt;/p&gt;

&lt;p&gt;For most investigations, use both.&lt;/p&gt;

&lt;p&gt;Start with the action tree to understand the likely story. Then use the blockchain trace to prove each important part of that story.&lt;/p&gt;

&lt;p&gt;That approach is faster than manually decoding every cell from the beginning, but it does not make you dependent on an indexer's interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A compact STON.fi swap decoding checklist
&lt;/h2&gt;

&lt;p&gt;When inspecting an unfamiliar swap, work through these checks in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find the complete trace&lt;/strong&gt;, not just your wallet transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify the token wallets&lt;/strong&gt;, Router, Pool, and final receiver.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow the offer asset&lt;/strong&gt;, from your balance toward STON.fi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect the swap payload and Pool transaction&lt;/strong&gt;, including output conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow the ask asset&lt;/strong&gt;, from settlement to your receiving jetton wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review failures, bounces, excesses, and fees&lt;/strong&gt; only after the main asset path is clear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the trace is complicated, ignore unrelated branches initially. The central question is always the same: &lt;strong&gt;where did the input asset go, what contract converted it, and where did the output asset arrive?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once those three points are established, op codes, query IDs, fees, and excess messages become supporting evidence rather than noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does a STON.fi swap have one transaction hash?
&lt;/h3&gt;

&lt;p&gt;Not necessarily in the sense Ethereum users usually expect. A TON transaction describes a state change on one account after processing a message. A STON.fi swap can involve several such transactions connected through internal messages. The useful object to inspect is therefore the full trace that begins with the wallet operation and continues through the contracts involved in the swap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does my STON.fi swap contain so many transactions?
&lt;/h3&gt;

&lt;p&gt;Because TON smart contracts communicate asynchronously. Your wallet, jetton wallets, Router, Pool, and destination token wallet can each process separate messages and therefore generate separate transactions. Additional transactions may appear for wallet deployment, refunds, excess TON, or other execution details. A long trace does not by itself indicate that anything went wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I identify a STON.fi swap from its op code?
&lt;/h3&gt;

&lt;p&gt;An op code is strong evidence, but it should not be your only check. STON.fi documents protocol-specific swap operation identifiers, while TON's jetton standard defines codes for transfers and notifications. Confirm the op code together with the contract address, message direction, token identities, amounts, and surrounding trace.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I know whether the swap really delivered my tokens?
&lt;/h3&gt;

&lt;p&gt;Follow the output asset until the receiving jetton wallet is credited. Also confirm that the Pool and settlement transactions completed without a downstream failure that prevented the expected payout. A successful initiating wallet transaction alone is weaker evidence than seeing the actual output token movement in the trace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is the TON amount in an internal message different from my swap amount?
&lt;/h3&gt;

&lt;p&gt;For jetton swaps, the amount being traded is encoded as a jetton amount. TON attached to messages is also used to pay for contract execution and forwarding through the trace. Some unused TON can later be returned. Treat attached TON, jetton quantities, and blockchain fees as separate values when decoding the operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a TON-to-jetton swap have exactly the same trace?
&lt;/h3&gt;

&lt;p&gt;No. Native TON requires a different token path from an ordinary jetton-to-jetton exchange, so the exact contracts and messages can differ. STON.fi provides dedicated TON-to-jetton and jetton-to-TON swap methods in its DEX tooling. The same decoding principle still works: identify the input path, find the Pool execution, then follow the output to its final owner.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the fastest way to decode a STON.fi swap transaction?
&lt;/h3&gt;

&lt;p&gt;Start with the full TON trace, identify the offer and ask token flows, and compare what you see with STON.fi's transaction action tree. Use friendly explorer labels to navigate quickly, but verify important conclusions from contract addresses, message bodies, op codes, amounts, and the final token transfer. That gives you both a readable summary and low-level confirmation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi DEX v2 Swap Examples - official message-flow examples for swaps and multi-step execution&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Op Codes - official reference for STON.fi smart contract operation identifiers&lt;/li&gt;
&lt;li&gt;STON.fi Router v2 - official documentation for Router message handling and settlement operations&lt;/li&gt;
&lt;li&gt;STON.fi Pool v2 - official documentation for Pool state and swap-related operations&lt;/li&gt;
&lt;li&gt;STON.fi API Reference - transaction resolution, swap status, and transaction action tree endpoints&lt;/li&gt;
&lt;li&gt;TON Messages and Transactions Overview - explains how messages, account transactions, fees, and traces relate&lt;/li&gt;
&lt;li&gt;TON Traces - official explanation of causal message traces and their representation in explorers&lt;/li&gt;
&lt;li&gt;TON Jetton Standard - overview of jetton masters and per-owner jetton wallet contracts&lt;/li&gt;
&lt;li&gt;TON Connect Send Transaction - official documentation for wallet transaction requests from dApps&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
