<?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 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>
    <item>
      <title>How to Send a STON.fi Swap Transaction from a TON Wallet</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Wed, 12 Aug 2026 16:42:49 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-send-a-stonfi-swap-transaction-from-a-ton-wallet-c63</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-send-a-stonfi-swap-transaction-from-a-ton-wallet-c63</guid>
      <description>&lt;p&gt;&lt;em&gt;Build the swap with STON.fi, hand the transaction to TON Connect, and let the connected wallet sign and broadcast it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A STON.fi swap is not sent by giving your dApp access to a user's private key. Your application prepares the contract message required for the swap, converts it into a TON Connect transaction request, and asks the connected TON wallet to approve it. The wallet remains responsible for signing and broadcasting the transaction.&lt;/p&gt;

&lt;p&gt;For a modern STON.fi integration, the recommended mainnet pattern is to simulate the swap first, use the router metadata returned by STON.fi, build the corresponding transaction parameters with &lt;code&gt;@ston-fi/sdk&lt;/code&gt;, and pass those parameters to &lt;code&gt;sendTransaction()&lt;/code&gt; from TON Connect.&lt;/p&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%2Fr2n1fz5j06n4iurpueof.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%2Fr2n1fz5j06n4iurpueof.png" alt="STON.fi swap flow from TON wallet" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full path looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect the TON wallet.&lt;/li&gt;
&lt;li&gt;Simulate the swap.&lt;/li&gt;
&lt;li&gt;Use the simulation's router information.&lt;/li&gt;
&lt;li&gt;Ask the STON.fi SDK to build the contract message.&lt;/li&gt;
&lt;li&gt;Convert that message into TON Connect format.&lt;/li&gt;
&lt;li&gt;Ask the wallet to sign and broadcast it.&lt;/li&gt;
&lt;li&gt;Verify the resulting transaction on-chain.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The separation between steps 4 and 5 is particularly useful. STON.fi knows how the swap contract should be called. TON Connect knows how to request authorization from the user's wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are you actually sending?
&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%2Fliznori16ygqm3wuv7bf.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%2Fliznori16ygqm3wuv7bf.png" alt="What are actually sending on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you call one of the STON.fi SDK transaction-building methods, the SDK produces transaction parameters describing an internal message. The common result contains three important fields:&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;to&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="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Cell&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;to&lt;/code&gt; is the destination contract address. &lt;code&gt;value&lt;/code&gt; is the amount of TON that must accompany the message. &lt;code&gt;body&lt;/code&gt; is the serialized contract payload describing the operation that STON.fi should execute.&lt;/p&gt;

&lt;p&gt;Your dApp does not sign this message.&lt;/p&gt;

&lt;p&gt;Instead, it transforms those parameters into something TON Connect can send to the 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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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="nx"&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="nx"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction is worth remembering:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STON.fi SDK builds the swap message. TON Connect requests the wallet signature. The wallet broadcasts the transaction.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TON itself is message-driven. Smart contracts receive messages, process their payloads, and may generate transactions that change contract state. The payload created by the STON.fi SDK is therefore not arbitrary metadata. It is the instruction that the relevant contract will interpret when the message arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up TON Connect 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%2Fnbn9juab3onh340ohxbm.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%2Fnbn9juab3onh340ohxbm.png" alt="Set up TON Connect" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a React dApp, TON documentation recommends &lt;code&gt;@tonconnect/ui-react&lt;/code&gt;. The package provides &lt;code&gt;TonConnectUIProvider&lt;/code&gt;, &lt;code&gt;TonConnectButton&lt;/code&gt;, &lt;code&gt;useTonConnectUI&lt;/code&gt;, and wallet-state hooks that you can use without handling private keys yourself.&lt;/p&gt;

&lt;p&gt;Install the packages needed for the basic STON.fi flow:&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/sdk @ston-fi/api @tonconnect/ui-react @ton/ton
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need a public TON Connect manifest. For example:&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://swap.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 STON.fi Swap 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://swap.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;In production, TON requires the manifest to be publicly reachable, and current documentation says it should be served through HTTPS. The wallet uses this metadata to identify the dApp during connection.&lt;/p&gt;

&lt;p&gt;Wrap your React app with the provider:&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;TonConnectUIProvider&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;@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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Root&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TonConnectUIProvider&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://swap.example.com/tonconnect-manifest.json"&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="nc"&gt;App&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="nc"&gt;TonConnectUIProvider&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;Then expose the wallet connection button:&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;TonConnectButton&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;@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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TonConnectButton&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;Inside your swap component you can read the connected address and access the transaction API:&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;useTonAddress&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="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;@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;const&lt;/span&gt; &lt;span class="nx"&gt;userAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonAddress&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;userAddress&lt;/code&gt; is empty, there is no connected account available to sign the swap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulate before building the 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%2Fsygev5z99t9pjgnr6p1k.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%2Fsygev5z99t9pjgnr6p1k.png" alt="Why simulate the swap first on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For STON.fi v2 mainnet swaps, hardcoding a router is not the preferred production pattern. STON.fi documentation recommends obtaining routing information from the API and using the router returned by the simulation. This lets the integration follow the router selected for the actual swap instead of assuming one specific contract configuration.&lt;/p&gt;

&lt;p&gt;A simplified simulation 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;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="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;stonApi&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="nx"&gt;fromAsset&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;askAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toAsset&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The amount supplied as &lt;code&gt;offerUnits&lt;/code&gt; must already be expressed in the asset's smallest units. Do not assume that every TON ecosystem asset uses the same number of decimals. The STON.fi quickstart explicitly uses asset metadata when converting user-facing amounts into blockchain units.&lt;/p&gt;

&lt;p&gt;A simulation is useful for more than displaying an estimated output. It gives the transaction-building stage values such as the offer amount, minimum acceptable output, token addresses, and router information associated with that swap.&lt;/p&gt;

&lt;p&gt;That creates an important safety boundary in your UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changing the input asset should invalidate the old simulation&lt;/li&gt;
&lt;li&gt;changing the output asset should invalidate it&lt;/li&gt;
&lt;li&gt;changing the amount should invalidate it&lt;/li&gt;
&lt;li&gt;changing the slippage setting should trigger a new simulation&lt;/li&gt;
&lt;li&gt;the transaction should be built from the current simulation, not from stale UI state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You want the transaction the wallet sees to correspond to the swap the user just reviewed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the STON.fi swap message
&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%2Fvt89ljqg6lmq9qf88ica.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%2Fvt89ljqg6lmq9qf88ica.png" alt="Build the STON.fi swap message" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have a valid simulation and connected wallet, create the router from the router metadata supplied by STON.fi.&lt;/p&gt;

&lt;p&gt;A compact version of the current API-driven pattern 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;dexFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Client&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/sdk&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;tonClient&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;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&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/v2/jsonRPC&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;routerInfo&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;router&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;dexContracts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tonClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;dexContracts&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="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxyTon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dexContracts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pTON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;routerInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ptonMasterAddress&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 current v2 documentation specifically recommends feeding the router returned by the simulation into &lt;code&gt;dexFactory()&lt;/code&gt; for mainnet-facing integrations rather than hardcoding the router contract.&lt;/p&gt;

&lt;p&gt;Next, prepare the fields shared by the swap variants:&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;sharedTxParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userWalletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;offerAmount&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;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;minAskAmount&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;minAskUnits&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 exact builder depends on what you are swapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  TON to jetton
&lt;/h3&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;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapTonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;askJettonAddress&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;askAddress&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;h3&gt;
  
  
  Jetton to TON
&lt;/h3&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;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToTonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&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;h3&gt;
  
  
  Jetton to jetton
&lt;/h3&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;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;askJettonAddress&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;askAddress&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 important result is the same in each case: you receive the destination, attached TON value, and payload needed for the contract call. STON.fi documents separate transaction builders for TON-to-jetton, jetton-to-TON, and jetton-to-jetton swaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Send the transaction through the TON wallet
&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%2Fmoa5buo8ogycx8icuxdl.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%2Fmoa5buo8ogycx8icuxdl.png" alt="Send the transaction through the TON wallet" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the STON.fi-specific construction work is finished.&lt;/p&gt;

&lt;p&gt;The remaining step is to hand the message to the wallet through TON Connect:&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;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="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;This is the point where the wallet UI should appear and ask the user to review and approve the transaction.&lt;/p&gt;

&lt;p&gt;There are several details here that are easy to overlook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;address&lt;/code&gt;&lt;/strong&gt; comes directly from the STON.fi transaction parameters. Do not replace it with the address of the asset, pool, or some router address stored elsewhere in your UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;amount&lt;/code&gt;&lt;/strong&gt; is the TON value attached to the contract message. Pass the SDK-generated value rather than manually reconstructing the gas requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/strong&gt; is the contract body serialized as a Bag of Cells and encoded in base64 so TON Connect can include it in the outgoing message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;validUntil&lt;/code&gt;&lt;/strong&gt; is a Unix timestamp in seconds. Current TON Connect documentation defines it in seconds and shows the pattern &lt;code&gt;Math.floor(Date.now() / 1000) + 600&lt;/code&gt;. Some older examples in the ecosystem use &lt;code&gt;Date.now()&lt;/code&gt; directly, which produces milliseconds, so this is a field worth checking carefully when adapting existing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;network&lt;/code&gt;&lt;/strong&gt; should be set explicitly. TON Connect currently identifies TON mainnet as &lt;code&gt;-239&lt;/code&gt; and testnet as &lt;code&gt;-3&lt;/code&gt;. If the requested network conflicts with the wallet's connected network, the wallet can reject the request.&lt;/p&gt;

&lt;p&gt;STON.fi's transaction-sending guide uses the same underlying pattern: obtain &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt; from the SDK, then pass them to the wallet implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the full handler together
&lt;/h2&gt;

&lt;p&gt;Here is the essential flow in one React handler:&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;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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dexFactory&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/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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;useTonAddress&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="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;@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;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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SwapButton&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;toAsset&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="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;userAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonAddress&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSwap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;userAddress&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;Connect a wallet first&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="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="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;Simulate the swap first&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;tonClient&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;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;endpoint&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/v2/jsonRPC&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;routerInfo&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;router&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;dexContracts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tonClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;dexContracts&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="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxyTon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dexContracts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pTON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;routerInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ptonMasterAddress&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;sharedTxParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;userWalletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;offerAmount&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;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;minAskAmount&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;minAskUnits&lt;/span&gt;&lt;span class="p"&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;swapParams&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;fromAsset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapTonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;askJettonAddress&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;askAddress&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;else&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;toAsset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToTonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;swapParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedTxParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;askJettonAddress&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;askAddress&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;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="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="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;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;Wallet response:&lt;/span&gt;&lt;span class="dl"&gt;"&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="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;button&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="nx"&gt;handleSwap&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Swap
    &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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code intentionally keeps quote generation separate from transaction sending. In a real application, you should also disable the button while a request is in progress, handle rejected wallet requests separately from network failures, refresh stale simulations, and display useful status feedback.&lt;/p&gt;

&lt;p&gt;TON Connect documents &lt;code&gt;USER_REJECTS_ERROR&lt;/code&gt; separately from malformed requests and unsupported methods, so a user pressing "Cancel" should not be presented as a protocol failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens after the wallet approves?
&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%2Fi4m763t9n7j1nefcc99n.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%2Fi4m763t9n7j1nefcc99n.png" alt="What happens after the wallet approves" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sendTransaction()&lt;/code&gt; asks the connected wallet to sign and broadcast the outgoing message. Current TON Connect documentation says the response can contain the base64 BoC of the broadcast external message, which can then be used as part of an on-chain lookup or tracking flow.&lt;/p&gt;

&lt;p&gt;A resolved wallet promise should therefore not be treated as "the swap is definitely complete."&lt;/p&gt;

&lt;p&gt;There are several different states your interface may need to distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the wallet request was opened&lt;/li&gt;
&lt;li&gt;the user approved the request&lt;/li&gt;
&lt;li&gt;the wallet broadcast the external message&lt;/li&gt;
&lt;li&gt;the relevant contract received and processed the internal message&lt;/li&gt;
&lt;li&gt;the swap completed successfully on-chain&lt;/li&gt;
&lt;li&gt;the resulting token balances became visible in your application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TON transactions are produced as contracts process messages, so wallet authorization and smart contract execution are related but not identical events.&lt;/p&gt;

&lt;p&gt;For a production interface, update the UI only when you have enough evidence for the state you are displaying. "Transaction submitted" is more accurate immediately after wallet submission than "Swap completed."&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes when sending STON.fi swaps
&lt;/h2&gt;

&lt;p&gt;Most integration failures around this final step come from a small number of mismatches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building from stale simulation data.&lt;/strong&gt; If the amount or asset changes after simulation, create a new simulation before building the transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcoding a production router.&lt;/strong&gt; Current STON.fi v2 guidance favors the router metadata returned by its mainnet API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recreating the payload manually.&lt;/strong&gt; Let the STON.fi SDK produce the contract body unless you have a specific low-level reason to construct the message yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using the wrong time unit for &lt;code&gt;validUntil&lt;/code&gt;.&lt;/strong&gt; TON Connect currently expects Unix seconds, not JavaScript milliseconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming wallet approval equals swap completion.&lt;/strong&gt; Submission still has to result in successful on-chain contract execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treating cancellation as an execution error.&lt;/strong&gt; A user can simply reject the wallet prompt, and TON Connect exposes a specific rejection error for that case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing copied mainnet addresses or amounts blindly.&lt;/strong&gt; TON's current documentation explicitly warns that mainnet transfers are irreversible and recommends replacing sample values and testing appropriately before using real funds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; keep the integration boundary simple. Use the STON.fi API to simulate the current swap, let &lt;code&gt;dexFactory()&lt;/code&gt; and the relevant router helper produce the exact transaction parameters, then pass those parameters almost unchanged into TON Connect. Your dApp should coordinate the process, not sign on behalf of the user and not guess the contract payload.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Does my dApp need the user's TON wallet seed phrase to send a STON.fi swap?
&lt;/h3&gt;

&lt;p&gt;No. A normal client-side TON Connect integration should not obtain the user's seed phrase or private key. Your application constructs the requested transaction, while the connected wallet handles approval, signing, and broadcasting. This separation is one of the main reasons to integrate through TON Connect rather than importing wallet credentials into the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does the STON.fi SDK actually provide to TON Connect?
&lt;/h3&gt;

&lt;p&gt;The SDK provides the information required for the contract message, including its destination, attached TON value, and payload cell. Your application serializes the payload to a base64 BoC and places these values inside the &lt;code&gt;messages&lt;/code&gt; array passed to &lt;code&gt;sendTransaction()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why should I simulate the swap before sending it?
&lt;/h3&gt;

&lt;p&gt;Simulation gives you the swap-specific values needed to review and build the transaction, including the minimum output and router information used by the current API-driven v2 workflow. It also gives your interface a natural point to show the expected result before asking the wallet for authorization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should &lt;code&gt;validUntil&lt;/code&gt; use milliseconds or seconds?
&lt;/h3&gt;

&lt;p&gt;Use Unix seconds. Current TON Connect documentation defines &lt;code&gt;validUntil&lt;/code&gt; as Unix seconds and demonstrates it with &lt;code&gt;Math.floor(Date.now() / 1000) + ...&lt;/code&gt;. This is important because JavaScript's &lt;code&gt;Date.now()&lt;/code&gt; alone returns milliseconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does &lt;code&gt;network: "-239"&lt;/code&gt; mean?
&lt;/h3&gt;

&lt;p&gt;It identifies TON mainnet in the current TON Connect transaction request format. Testnet is identified as &lt;code&gt;-3&lt;/code&gt;. Setting the network explicitly lets the wallet reject a transaction request if the connected account is on an incompatible network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can the same wallet flow handle TON-to-jetton and jetton-to-jetton swaps?
&lt;/h3&gt;

&lt;p&gt;Yes, but the STON.fi SDK method used to construct the transaction differs by swap type. The final TON Connect step still follows the same basic model: take the resulting destination, attached value, and payload, then request wallet approval through &lt;code&gt;sendTransaction()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a successful &lt;code&gt;sendTransaction()&lt;/code&gt; response prove that the STON.fi swap finished?
&lt;/h3&gt;

&lt;p&gt;Not by itself. It proves that the wallet-side transaction request reached the submission stage represented by TON Connect's response. Contract processing happens on-chain afterward, so a production dApp should track or verify the resulting operation before presenting the swap as completed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I verify immediately before sending a STON.fi swap from a TON wallet?
&lt;/h3&gt;

&lt;p&gt;Verify that the wallet is still connected, the simulation still matches the selected assets and amount, the minimum output reflects the intended slippage setting, the router comes from the current simulation, and the transaction parameters were generated by the matching STON.fi SDK helper. Only then transform those parameters into the TON Connect request shown to the wallet for approval.&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 end-to-end React example covering wallet connection, swap simulation, router selection, transaction construction, and TonConnect execution&lt;/li&gt;
&lt;li&gt;STON.fi Swap v2 documentation - Official v2 swap documentation describing the API-driven mainnet workflow and dynamic router construction&lt;/li&gt;
&lt;li&gt;STON.fi Transaction Sending - Official explanation of the &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt; transaction parameters returned by SDK transaction builders&lt;/li&gt;
&lt;li&gt;STON.fi Via TonConnect - Official STON.fi example for converting SDK transaction parameters into a TonConnect transaction request&lt;/li&gt;
&lt;li&gt;TON Connect Get Started - Official TON documentation for manifests, React integration, wallet connection, providers, and the TON Connect SDK choices&lt;/li&gt;
&lt;li&gt;TON Connect Send a Transaction - Official current specification for &lt;code&gt;sendTransaction&lt;/code&gt;, &lt;code&gt;validUntil&lt;/code&gt;, network identifiers, raw messages, responses, and wallet errors&lt;/li&gt;
&lt;li&gt;TON Messages and Transactions Overview - Official TON explanation of how messages are processed and how contract state changes become transactions&lt;/li&gt;
&lt;li&gt;STON.fi API Client Source - Official STON.fi API implementation showing the API client and router-related methods used by developer integrations&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Connect TON Connect to a STON.fi dApp</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Thu, 06 Aug 2026 06:34:41 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-connect-ton-connect-to-a-stonfi-dapp-5glh</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-connect-ton-connect-to-a-stonfi-dapp-5glh</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical React integration that connects a TON wallet, reads the wallet state, builds a STON.fi swap, and hands the transaction back to the wallet for approval.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Connecting TON Connect to a STON.fi dApp means giving your application a standard way to discover the user's TON wallet, read the connected address, and request transaction signatures without ever handling the user's private keys.&lt;/p&gt;

&lt;p&gt;For a STON.fi swap interface, the flow is straightforward: TON Connect manages the wallet session, the STON.fi API simulates the swap, the STON.fi SDK builds the contract message, and TON Connect asks the wallet to sign and broadcast it. The dApp coordinates these pieces, but the wallet remains the signing authority throughout the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What TON Connect actually does in a STON.fi dApp
&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%2Fokoc202amuuz6vohroq1.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%2Fokoc202amuuz6vohroq1.png" alt="How integration works on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It helps to separate wallet connectivity from DEX logic.&lt;/p&gt;

&lt;p&gt;STON.fi does not need your application to obtain a seed phrase or private key. Instead, TON Connect creates a communication layer between the dApp and a compatible wallet. After the person chooses a wallet and approves the connection, your frontend receives account information that can be used when preparing STON.fi transactions.&lt;/p&gt;

&lt;p&gt;A typical integration has four responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TON Connect&lt;/strong&gt; manages connection, reconnection, wallet selection, and transaction requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi API&lt;/strong&gt; supplies current asset and swap simulation information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi SDK&lt;/strong&gt; converts swap parameters into contract transaction data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wallet&lt;/strong&gt; reviews, signs, and broadcasts the transaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official STON.fi React quickstart uses exactly this division of responsibilities, combining &lt;code&gt;@tonconnect/ui-react&lt;/code&gt;, &lt;code&gt;@ston-fi/api&lt;/code&gt;, and &lt;code&gt;@ston-fi/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The wallet connection therefore does not perform a swap by itself. It gives your STON.fi integration the address and signing channel needed to perform one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the React dependencies
&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%2F3a9pezvu15h1liz656g5.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%2F3a9pezvu15h1liz656g5.png" alt="Set up the React dependencies on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a React dApp, install the TON Connect React package together with the STON.fi SDK and API client.&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; @tonconnect/ui-react @ston-fi/sdk @ston-fi/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the rest of your application, you may also use TON libraries for blockchain utilities and amount conversion.&lt;/p&gt;

&lt;p&gt;The important architectural point is to keep the responsibilities separate. Avoid implementing wallet-specific connection code for Tonkeeper, MyTonWallet, or other individual wallets when TON Connect already provides a common interface.&lt;/p&gt;

&lt;p&gt;The official TON documentation describes &lt;code&gt;@tonconnect/ui-react&lt;/code&gt; as the React binding around TON Connect UI. It provides the application provider, the standard wallet button, and hooks for accessing the connection and wallet state.&lt;/p&gt;

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

&lt;p&gt;Every TON Connect dApp needs a manifest that tells wallets which application is requesting the connection.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/tonconnect-manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal version looks 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://your-dapp.example"&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 STON.fi dApp"&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://your-dapp.example/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;You can also provide privacy policy and terms URLs when appropriate.&lt;/p&gt;

&lt;p&gt;The manifest is not just decoration. Wallets fetch it to identify your application before presenting the connection request. The URL and icon should therefore point to real public resources when you deploy the dApp.&lt;/p&gt;

&lt;p&gt;Before debugging your React code, open the manifest URL directly in a browser:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If it cannot be fetched there, a wallet may not be able to fetch it either.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Serve the manifest over HTTPS in production.&lt;/li&gt;
&lt;li&gt;Use your real dApp domain.&lt;/li&gt;
&lt;li&gt;Make the icon publicly accessible.&lt;/li&gt;
&lt;li&gt;Keep the application name recognizable.&lt;/li&gt;
&lt;li&gt;Do not copy another project's manifest unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For local development, STON.fi's React guide demonstrates serving the manifest from the application's public directory and pointing the provider at the current origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add TON Connect to the React component tree
&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%2F8jnwnmbd8497ghln240i.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%2F8jnwnmbd8497ghln240i.png" alt="Add TON connect to React on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to wrap the application in &lt;code&gt;TonConnectUIProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a Vite-based React project, your entry file can look like this:&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="nx"&gt;React&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="nx"&gt;ReactDOM&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-dom/client&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;TonConnectUIProvider&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;@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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&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;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&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="nc"&gt;TonConnectUIProvider&lt;/span&gt;
      &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tonconnect-manifest.json`&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="nc"&gt;App&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="nc"&gt;TonConnectUIProvider&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="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&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;Everything that calls TON Connect React hooks must be rendered beneath this provider.&lt;/p&gt;

&lt;p&gt;You can then add the standard connection button:&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;TonConnectButton&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;@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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&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="nc"&gt;TonConnectButton&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;header&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;Clicking it opens the TON Connect wallet picker. After a successful connection, the same component reflects the connected state automatically.&lt;/p&gt;

&lt;p&gt;You can build your own button and call &lt;code&gt;openModal()&lt;/code&gt; if your design requires a custom interface, but starting with &lt;code&gt;TonConnectButton&lt;/code&gt; removes unnecessary connection logic while you build the rest of the STON.fi integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the connected wallet 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%2Fkv3tdevot35yf7uzbnhw.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%2Fkv3tdevot35yf7uzbnhw.png" alt="Read the wallet state on STON.fi correctly" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A STON.fi swap needs the connected wallet address because that address becomes part of the transaction parameters.&lt;/p&gt;

&lt;p&gt;TON Connect exposes it through hooks:&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;useIsConnectionRestored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTonAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTonWallet&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;@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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WalletStatus&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;restored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useIsConnectionRestored&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;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonWallet&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;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonAddress&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;restored&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Restoring wallet connection...&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;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;wallet&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Connect a wallet to continue.&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;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;Connected: &lt;span class="si"&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;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;&lt;code&gt;useIsConnectionRestored()&lt;/code&gt; deserves special attention. TON Connect attempts to restore an existing session when the application loads. Until that process finishes, a missing wallet does not necessarily mean that the person is disconnected. Redirecting or disabling your interface too early can create a visible connection flicker or incorrect state. TON's documentation specifically recommends waiting for restoration before making that decision.&lt;/p&gt;

&lt;p&gt;For your swap interface, that gives you a simple state model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connection state is still being restored.&lt;/li&gt;
&lt;li&gt;No wallet is connected.&lt;/li&gt;
&lt;li&gt;A wallet is connected and the swap interface can use its address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not confuse wallet connection with authentication. If your backend needs cryptographic proof that a person controls an address, TON Connect also supports &lt;code&gt;ton_proof&lt;/code&gt;. A plain connected address is useful for transaction construction, but it should not automatically become a trusted login credential for a sensitive backend session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect the wallet state to a STON.fi 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%2Fmp5ii7rowimvikf62p3s.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%2Fmp5ii7rowimvikf62p3s.png" alt="Build and send a swap on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the two systems meet.&lt;/p&gt;

&lt;p&gt;For production STON.fi swaps, the current v2 documentation recommends an API-driven approach rather than hardcoding a router address. Your dApp first simulates the swap, receives router metadata, creates the matching SDK contracts, and then builds the transaction parameters.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connected wallet
      |
      v
STON.fi swap simulation
      |
      v
Router metadata
      |
      v
STON.fi SDK builds transaction
      |
      v
TON Connect sendTransaction()
      |
      v
Wallet approval
      |
      v
TON blockchain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a focused example for a TON-to-jetton swap:&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;useTonAddress&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="s2"&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="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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toUnits&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/sdk&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tonClient&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;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&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/v2/jsonRPC&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;function&lt;/span&gt; &lt;span class="nf"&gt;SwapButton&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;userAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonAddress&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;swap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;userAddress&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;Connect a wallet first&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;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;stonApi&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;jetton-master-address&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="nf"&gt;toUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&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;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routerInfo&lt;/span&gt; &lt;span class="o"&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;router&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;dexContracts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tonClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;dexContracts&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="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxyTon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dexContracts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pTON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;routerInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ptonMasterAddress&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;txParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapTonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;userWalletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;offerAmount&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;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;askJettonAddress&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;askAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;minAskAmount&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;minAskUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;queryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BigInt&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="p"&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;txParams&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;txParams&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;txParams&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;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;button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userAddress&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="nx"&gt;swap&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Swap with STON.fi
    &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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact token addresses and input amounts should come from your interface rather than hardcoded production values.&lt;/p&gt;

&lt;p&gt;The current STON.fi v2 guidance is especially important here: the REST API returns router information with the simulation result, and &lt;code&gt;dexFactory()&lt;/code&gt; lets the SDK construct contracts appropriate for that router. This avoids making your integration depend on one manually selected production router.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when &lt;code&gt;sendTransaction()&lt;/code&gt; runs?
&lt;/h2&gt;

&lt;p&gt;The STON.fi SDK does not need to sign anything.&lt;/p&gt;

&lt;p&gt;Its job is to produce parameters such as the destination address, attached TON value, and serialized payload. Your code converts those values into a TON Connect transaction request.&lt;/p&gt;

&lt;p&gt;TON Connect then presents that request to the wallet.&lt;/p&gt;

&lt;p&gt;For raw transaction messages, the important fields are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Contract or wallet receiving the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TON value attached in the smallest unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base64 encoded contract message body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validUntil&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unix timestamp after which the request is invalid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;network&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TON network expected by the dApp&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;According to the current TON Connect transaction specification, &lt;code&gt;validUntil&lt;/code&gt; uses Unix seconds. For mainnet, the network identifier is &lt;code&gt;-239&lt;/code&gt;; testnet uses &lt;code&gt;-3&lt;/code&gt;. TON also recommends specifying the network explicitly so a request is rejected if the connected wallet is on a different network.&lt;/p&gt;

&lt;p&gt;When the wallet approves the request, it signs and broadcasts the transaction. Your frontend never receives the private key.&lt;/p&gt;

&lt;p&gt;That boundary is one of the most important design principles in the integration:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STON.fi prepares the DEX action. TON Connect transports the signing request. The wallet authorizes it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid the integration mistakes that cause most problems
&lt;/h2&gt;

&lt;p&gt;The basic connection takes only a small amount of code. Most problems appear around state management, transaction construction, or assumptions about the network.&lt;/p&gt;

&lt;p&gt;Before shipping, check these areas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not hardcode production routing when the STON.fi API can provide it.&lt;/strong&gt; Current STON.fi v2 documentation recommends simulating first and using the router object returned by the API with &lt;code&gt;dexFactory()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not treat a stale simulation as a guaranteed execution price.&lt;/strong&gt; Pool conditions can change between simulation and wallet confirmation. Use the minimum output calculated for the swap and refresh quotes when appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not mix milliseconds and Unix seconds in &lt;code&gt;validUntil&lt;/code&gt;.&lt;/strong&gt; The current TON Connect request format expects seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not enable the swap while the wallet state is unresolved.&lt;/strong&gt; Wait for connection restoration and require an address before generating transaction parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not manually ask for a seed phrase.&lt;/strong&gt; A normal TON Connect integration has no reason to request one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not assume &lt;code&gt;sendTransaction()&lt;/code&gt; means the complete swap succeeded.&lt;/strong&gt; It means the wallet accepted the request and broadcast the signed message. Your interface should separately track the resulting on-chain execution if it needs a final success state.&lt;/p&gt;

&lt;p&gt;There is another TON-specific detail worth remembering. Smart contract interactions can involve multiple messages, and execution across recipient contracts is not automatically equivalent to one atomic operation. STON.fi documentation also describes refund behavior for swaps when execution conditions are not satisfied.&lt;/p&gt;

&lt;p&gt;For a production interface, show transaction states such as submitted, processing, completed, and failed instead of changing the button directly from "Swap" to "Success" as soon as the wallet returns.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical STON.fi integration 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%2F6pmtb8d55k70d15ddjkl.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%2F6pmtb8d55k70d15ddjkl.png" alt="STON.fi integration checklist" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you can test the entire connection as one continuous workflow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the dApp and wait for TON Connect session restoration.&lt;/li&gt;
&lt;li&gt;Connect a compatible TON wallet.&lt;/li&gt;
&lt;li&gt;Confirm that your application receives the correct address.&lt;/li&gt;
&lt;li&gt;Select a source asset, destination asset, and amount.&lt;/li&gt;
&lt;li&gt;Request a fresh STON.fi swap simulation.&lt;/li&gt;
&lt;li&gt;Review the expected output and minimum output in your interface.&lt;/li&gt;
&lt;li&gt;Build the matching transaction through the STON.fi SDK.&lt;/li&gt;
&lt;li&gt;Pass the resulting message to &lt;code&gt;tonConnectUI.sendTransaction()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Review the transaction inside the wallet before signing.&lt;/li&gt;
&lt;li&gt;Track the resulting blockchain operation rather than relying only on the frontend request state.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;STON.fi's official developer documentation recommends using its SDK together with TON Connect for production application interaction instead of manually constructing low-level contract BOCs unless you have a specialized reason to do so.&lt;/p&gt;

&lt;p&gt;The practical takeaway is simple: keep wallet connection, quote generation, transaction construction, and transaction signing as separate layers. Once those boundaries are clear, TON Connect becomes a small but critical bridge between your STON.fi frontend and the wallet that actually authorizes the swap.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Does STON.fi require TON Connect?
&lt;/h3&gt;

&lt;p&gt;A frontend can interact with TON contracts through other technical signing setups, but TON Connect is the standard wallet connection approach for user-facing TON dApps. STON.fi's own React swap quickstart integrates &lt;code&gt;@tonconnect/ui-react&lt;/code&gt; with the STON.fi API and SDK, making it the natural approach for a browser-based application where users sign transactions with their own wallets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does TON Connect give my dApp the user's private key?
&lt;/h3&gt;

&lt;p&gt;No. TON Connect creates a connection with the wallet and lets the dApp submit signing requests. The private key remains under the wallet's control. Your application receives account information and transaction responses, not the seed phrase or private signing key. A dApp asking users to enter their seed phrase is not following the normal TON Connect model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a &lt;code&gt;tonconnect-manifest.json&lt;/code&gt; file?
&lt;/h3&gt;

&lt;p&gt;Yes. The manifest identifies your dApp to compatible wallets and includes information such as the application URL, name, and icon. Host it at a publicly accessible URL and pass that URL to &lt;code&gt;TonConnectUIProvider&lt;/code&gt;. Optional fields can also point to your terms of use and privacy policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use &lt;code&gt;useTonAddress()&lt;/code&gt; or &lt;code&gt;useTonWallet()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Use whichever matches the information you need. A STON.fi transaction often needs the connected address, so &lt;code&gt;useTonAddress()&lt;/code&gt; is convenient. &lt;code&gt;useTonWallet()&lt;/code&gt; gives you the broader connected wallet object. It is also useful to combine them with &lt;code&gt;useIsConnectionRestored()&lt;/code&gt; so your interface does not mistake an unfinished restoration attempt for a disconnected wallet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is connecting a wallet the same as authenticating a user?
&lt;/h3&gt;

&lt;p&gt;No. A wallet connection gives your frontend an account and a communication session. If you need secure backend authentication, TON Connect supports &lt;code&gt;ton_proof&lt;/code&gt;, where the wallet signs proof data that your server verifies. You generally do not need to introduce backend authentication merely to let a connected wallet review and sign a normal STON.fi transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why should a STON.fi dApp simulate the swap before building the transaction?
&lt;/h3&gt;

&lt;p&gt;Simulation gives your application current execution information, including expected amounts, minimum output, and router metadata. Current STON.fi v2 documentation recommends an API-driven production flow in which the simulation result determines the router passed to &lt;code&gt;dexFactory()&lt;/code&gt;. That is safer for maintainability than tying the integration permanently to one hardcoded router address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the STON.fi REST API for testnet swaps?
&lt;/h3&gt;

&lt;p&gt;The current STON.fi v2 SDK documentation states that the REST API at &lt;code&gt;api.ston.fi&lt;/code&gt; serves mainnet data. You can test TON Connect itself and lower-level contract integrations separately, but do not assume the production API-driven STON.fi simulation flow automatically maps to testnet. Follow the specific STON.fi testnet documentation when testing contract operations there.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I verify before letting someone sign a STON.fi swap?
&lt;/h3&gt;

&lt;p&gt;Check that the wallet is connected, the simulation is fresh, the source and destination assets are correct, the amount uses the correct token decimals, the minimum output reflects the intended slippage tolerance, and the transaction is being sent on the expected network. Then let the wallet provide the final approval step instead of attempting to sign anything inside your frontend.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;TON Connect, Get started - Official introduction to manifests and TON Connect integration paths&lt;/li&gt;
&lt;li&gt;TON Connect, Connect a wallet - Official documentation for the provider, wallet button, connection restoration, wallet state, and &lt;code&gt;ton_proof&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;TON Connect, Send a transaction - Official request format for &lt;code&gt;sendTransaction()&lt;/code&gt;, including &lt;code&gt;validUntil&lt;/code&gt;, network selection, and raw messages&lt;/li&gt;
&lt;li&gt;TON Connect React API - Reference for &lt;code&gt;TonConnectUIProvider&lt;/code&gt;, &lt;code&gt;TonConnectButton&lt;/code&gt;, &lt;code&gt;useTonConnectUI&lt;/code&gt;, &lt;code&gt;useTonAddress&lt;/code&gt;, and wallet hooks&lt;/li&gt;
&lt;li&gt;STON.fi Swap Guide (React) - Official end-to-end example combining TON Connect, the STON.fi API, and the STON.fi SDK&lt;/li&gt;
&lt;li&gt;STON.fi SDK v2 Swap - Official production guidance for simulation, dynamic router selection, &lt;code&gt;dexFactory()&lt;/code&gt;, and v2 swap construction&lt;/li&gt;
&lt;li&gt;STON.fi SDK - Overview of the TypeScript and JavaScript SDK and current DEX contract integration tools&lt;/li&gt;
&lt;li&gt;STON.fi REST API Reference - Official API overview covering swap simulation, swap status, pools, assets, and related DEX data&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Smart Contracts - Contract-level documentation and the recommendation to use the official SDK with TON Connect for production application integrations&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Build a Basic STON.fi Swap Interface</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:25:49 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-build-a-basic-stonfi-swap-interface-1l2a</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-build-a-basic-stonfi-swap-interface-1l2a</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical React guide to wallet connection, token selection, swap simulation, transaction building, and on-chain execution on TON.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A basic STON.fi swap interface needs to do much more than place two token selectors next to a Swap button. A useful implementation has to connect a TON wallet, load supported assets, convert human-readable amounts into blockchain units, simulate the trade, preserve the resulting slippage protection, build the correct STON.fi transaction, and finally ask the wallet to sign it.&lt;/p&gt;

&lt;p&gt;The cleanest architecture separates those responsibilities. STON.fi provides a REST API for asset data and swap simulation, its TypeScript SDK builds the contract transaction, and TON Connect handles wallet interaction. Your frontend coordinates the three without ever taking custody of the user's private keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the interface actually needs to do
&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%2Fimmvzg8qxru4k33icscr.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%2Fimmvzg8qxru4k33icscr.png" alt="What the interface actually needs to do in STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a minimal React application, think of the swap as five connected states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Wallet state:&lt;/strong&gt; Is a TON wallet connected, and what is its address?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asset state:&lt;/strong&gt; Which token is being sold and which token is being received?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amount state:&lt;/strong&gt; How many blockchain units does the entered amount represent?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulation state:&lt;/strong&gt; What route, minimum output, and Router should the transaction use?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction state:&lt;/strong&gt; Has the wallet received, rejected, or submitted the transaction?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That division matters because a swap quote is not permanent. If the user changes the source token, destination token, or amount, the previous simulation should immediately become invalid.&lt;/p&gt;

&lt;p&gt;A minimal interface therefore needs only a few visible controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect Wallet&lt;/li&gt;
&lt;li&gt;From token selector&lt;/li&gt;
&lt;li&gt;To token selector&lt;/li&gt;
&lt;li&gt;Amount input&lt;/li&gt;
&lt;li&gt;Simulated output&lt;/li&gt;
&lt;li&gt;Minimum received&lt;/li&gt;
&lt;li&gt;Swap button&lt;/li&gt;
&lt;li&gt;Loading, rejection, and transaction status messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add charts, token balances, price impact displays, routing information, or transaction history later. They are useful improvements, but they are not required to understand the core STON.fi flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the React project
&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%2Fx11xxqpn1go0ruktyvot.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%2Fx11xxqpn1go0ruktyvot.png" alt="React project for STON.fi swap" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi's official React quickstart uses its API client, DEX SDK, and TON Connect together. The essential dependencies are:&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/sdk @ston-fi/api @tonconnect/ui-react @ton/ton
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The roles are intentionally different.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@ston-fi/api&lt;/code&gt; gives the frontend access to STON.fi data and simulation methods. &lt;code&gt;@ston-fi/sdk&lt;/code&gt; converts the selected swap into contract-ready transaction parameters. &lt;code&gt;@tonconnect/ui-react&lt;/code&gt; connects the application to the user's wallet and submits the transaction for approval.&lt;/p&gt;

&lt;p&gt;A simple component tree might 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
├── TonConnectButton
└── SwapForm
    ├── FromAssetSelect
    ├── AmountInput
    ├── ToAssetSelect
    ├── QuotePanel
    └── SwapButton
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You do not need to split the first prototype into that many files. One &lt;code&gt;App.jsx&lt;/code&gt; component is perfectly reasonable while learning the flow. The important part is keeping the logical stages separate in your state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect a TON wallet 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%2Fx6gzknydrrwmkec7gxf6.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%2Fx6gzknydrrwmkec7gxf6.png" alt="Connect a TON wallet and load assets on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TON Connect is the standard wallet connection protocol for TON applications. The dApp receives the connected account and can request signatures or transactions, but the wallet retains control of the keys.&lt;/p&gt;

&lt;p&gt;Wrap the React application with &lt;code&gt;TonConnectUIProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;TonConnectUIProvider&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;@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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TonConnectUIProvider&lt;/span&gt;
  &lt;span class="na"&gt;manifestUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tonconnect-manifest.json`&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="nc"&gt;App&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="nc"&gt;TonConnectUIProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then place a connect button somewhere visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;TonConnectButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTonAddress&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="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;@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;const&lt;/span&gt; &lt;span class="nx"&gt;walletAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTonAddress&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manifest is not an optional branding detail. Wallets use it to identify your application. Host &lt;code&gt;tonconnect-manifest.json&lt;/code&gt; from your own domain and provide your real application name, URL, and icon.&lt;/p&gt;

&lt;p&gt;A basic file looks 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 STON.fi Swap"&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.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;For production, avoid copying another project's manifest or permanently pointing to a demo manifest. The wallet approval screen should identify the application the user is actually interacting with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load assets without assuming every token has nine decimals
&lt;/h2&gt;

&lt;p&gt;The next job is populating the two asset selectors.&lt;/p&gt;

&lt;p&gt;STON.fi exposes asset information through its REST API, including an asset query endpoint. The official API client wraps those calls, so you can initialize it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;api&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;You can then fetch assets when the application loads and keep the result in React state.&lt;/p&gt;

&lt;p&gt;One implementation detail deserves more attention than it usually gets: &lt;strong&gt;do not assume every asset uses nine decimal places.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A wallet might display &lt;code&gt;1.25 TOKEN&lt;/code&gt;, while the blockchain and STON.fi API work with integer base units. The conversion depends on that token's metadata.&lt;/p&gt;

&lt;p&gt;For example, with nine decimals:&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 TOKEN = 1,250,000,000 units
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With six decimals:&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 TOKEN = 1,250,000 units
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STON.fi's own swap quickstart reads the decimal precision dynamically from asset metadata for exactly this reason.&lt;/p&gt;

&lt;p&gt;For production code, avoid converting large token values with floating-point arithmetic such as &lt;code&gt;Number(amount) * 10 ** decimals&lt;/code&gt;. A string-to-BigInt parser is safer:&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;function&lt;/span&gt; &lt;span class="nf"&gt;toUnits&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;whole&lt;/span&gt; &lt;span class="o"&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="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&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="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="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="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="nf"&gt;repeat&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="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="nx"&gt;decimals&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="nc"&gt;BigInt&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="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="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;padded&lt;/span&gt; &lt;span class="o"&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;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;You should also reject negative amounts, malformed decimals, excessive precision, and zero before calling the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulate before allowing the user to sign
&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%2Fpffwbak1s4tjkzjnbzf9.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%2Fpffwbak1s4tjkzjnbzf9.png" alt="How to simulate swap on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The swap button should not construct a trade from an old displayed price or a hardcoded pool.&lt;/p&gt;

&lt;p&gt;STON.fi provides &lt;code&gt;simulateSwap&lt;/code&gt;, which lets the application calculate the swap before execution. Its REST API exposes a dedicated swap simulation endpoint for expected output, fees, and transaction-related data.&lt;/p&gt;

&lt;p&gt;A simplified request 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;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;api&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="nx"&gt;fromAsset&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;askAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toAsset&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;0.01&lt;/code&gt; represents a 1 percent slippage tolerance.&lt;/p&gt;

&lt;p&gt;Simulation is not merely a cosmetic price preview. It connects the UI state to the transaction you will eventually build. In the current DEX v2 integration pattern, the result also supplies routing information that should be reused during transaction construction.&lt;/p&gt;

&lt;p&gt;Your quote panel should show enough information for a meaningful decision. At minimum, display:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;amount being sold&lt;/li&gt;
&lt;li&gt;expected or quoted output&lt;/li&gt;
&lt;li&gt;minimum acceptable output&lt;/li&gt;
&lt;li&gt;selected slippage tolerance&lt;/li&gt;
&lt;li&gt;source and destination assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, clear the simulation whenever the user changes an input.&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;function&lt;/span&gt; &lt;span class="nf"&gt;resetQuote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setSimulation&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onAmountChange&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setAmount&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;resetQuote&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;Otherwise, a user can simulate 10 tokens, change the field to 100, and still see a Swap button associated with the stale 10-token result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let the STON.fi API choose the Router
&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%2F6jc5uohakab4wv6yjwy8.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%2F6jc5uohakab4wv6yjwy8.png" alt="Let the STON.fi API choose the Router" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the most important implementation details in the current STON.fi DEX v2 documentation is that a production application should not hardcode a Router simply because an example contract address worked previously.&lt;/p&gt;

&lt;p&gt;The recommended mainnet flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simulate the swap.&lt;/li&gt;
&lt;li&gt;Read the Router metadata returned by the simulation.&lt;/li&gt;
&lt;li&gt;Pass that Router metadata into &lt;code&gt;dexFactory()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build the transaction with the resulting Router contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;STON.fi explicitly recommends this API-driven approach so integrations can follow Router changes without being tied to a manually embedded contract address. Its REST API currently serves mainnet data, while testnet integration requires a different, manually configured approach.&lt;/p&gt;

&lt;p&gt;The central setup is 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Client&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/sdk&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;tonClient&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;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&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/v2/jsonRPC&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;routerInfo&lt;/span&gt; &lt;span class="o"&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;router&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;contracts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tonClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;contracts&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="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routerInfo&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="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxyTon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contracts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pTON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;routerInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ptonMasterAddress&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The simulation and transaction should remain one logical operation. Reuse fields such as &lt;code&gt;offerUnits&lt;/code&gt;, &lt;code&gt;minAskUnits&lt;/code&gt;, token addresses, and Router metadata from the simulation rather than independently reconstructing the swap from UI values.&lt;/p&gt;

&lt;p&gt;That keeps the transaction you ask the wallet to sign aligned with the trade the interface just showed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the right transaction for the asset pair
&lt;/h2&gt;

&lt;p&gt;STON.fi exposes different Router helpers because TON and jettons do not enter the swap through exactly the same path.&lt;/p&gt;

&lt;p&gt;Your interface therefore needs three branches:&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;common&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userWalletAddress&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="na"&gt;offerAmount&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;offerUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;minAskAmount&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;minAskUnits&lt;/span&gt;&lt;span class="p"&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;txParams&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;fromAsset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;txParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapTonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;common&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;askJettonAddress&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;askAddress&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;else&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;toAsset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;txParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToTonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;common&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proxyTon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;txParams&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSwapJettonToJettonTxParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;common&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;offerJettonAddress&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;offerAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;askJettonAddress&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;askAddress&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 Router helper returns the information the wallet needs, including the destination, attached TON value, and message body.&lt;/p&gt;

&lt;p&gt;At the protocol level, the Router acts as the DEX entry point and directs token operations toward the appropriate pool. The pool contains the AMM state used for the swap. In DEX v2, the swap payload can also carry parameters such as minimum output, receiver, refund information, and an execution deadline.&lt;/p&gt;

&lt;p&gt;For a basic interface, you do not need to manually construct those low-level cells. That is exactly the problem the official SDK is designed to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Send the transaction through TON Connect
&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%2Fvqrrz24aenikb73oopll.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%2Fvqrrz24aenikb73oopll.png" alt="How to send, track and verify the swap on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;txParams&lt;/code&gt; exists, convert it into a TON Connect transaction request.&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;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;txParams&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;txParams&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;txParams&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;There is one small detail here that can prevent a surprisingly confusing bug: &lt;code&gt;validUntil&lt;/code&gt; uses a Unix timestamp in &lt;strong&gt;seconds&lt;/strong&gt;, not JavaScript milliseconds. Five minutes from now is therefore calculated with &lt;code&gt;Math.floor(Date.now() / 1000) + 300&lt;/code&gt;. TON's current TON Connect documentation defines mainnet as network &lt;code&gt;-239&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;sendTransaction()&lt;/code&gt; does not expose the wallet's private key to your React application. Instead, the wallet presents the transaction to the user for approval and then signs and broadcasts it if they accept.&lt;/p&gt;

&lt;p&gt;Your UI should distinguish at least four outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;waiting for wallet approval&lt;/li&gt;
&lt;li&gt;rejected by the user&lt;/li&gt;
&lt;li&gt;submitted to TON&lt;/li&gt;
&lt;li&gt;execution confirmed or failed on-chain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not interpret the successful return of &lt;code&gt;sendTransaction()&lt;/code&gt; as proof that every downstream contract action completed successfully. TON transactions can generate chains of asynchronous messages, so broadcast and final swap settlement are different stages.&lt;/p&gt;

&lt;p&gt;STON.fi exposes swap status and transaction-related API endpoints that can help an application follow the operation after submission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one swap from input to settlement
&lt;/h2&gt;

&lt;p&gt;Consider a user opening your interface to exchange TON for a jetton.&lt;/p&gt;

&lt;p&gt;They connect a wallet through TON Connect and choose TON in the first selector. Your application loads the destination asset metadata and converts the entered TON amount into blockchain units.&lt;/p&gt;

&lt;p&gt;Next, &lt;code&gt;simulateSwap()&lt;/code&gt; asks STON.fi what the trade currently looks like. Instead of merely taking a displayed number from that result, the application stores the entire simulation object.&lt;/p&gt;

&lt;p&gt;The simulation gives the frontend the values that matter for execution, including the minimum acceptable output and Router metadata. &lt;code&gt;dexFactory()&lt;/code&gt; uses that Router description to instantiate the corresponding contracts. Because TON is the source asset, the frontend calls the TON-to-jetton Router helper and receives the prepared transaction parameters.&lt;/p&gt;

&lt;p&gt;Only then does the application open the wallet approval flow.&lt;/p&gt;

&lt;p&gt;The user's decision therefore occurs after the following chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Choose assets
   |
Enter amount
   |
Convert to base units
   |
Simulate through STON.fi API
   |
Review minimum output
   |
Create Router from simulation metadata
   |
Build swap transaction with STON.fi SDK
   |
Request signature through TON Connect
   |
Track on-chain execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the core of a basic STON.fi swap interface. The UI is small because STON.fi's API and SDK handle much of the protocol-specific construction, but the frontend still has an important responsibility: it must preserve the relationship between what was simulated, what was displayed, and what was actually signed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes that make a basic swap unsafe or unreliable
&lt;/h2&gt;

&lt;p&gt;A prototype can appear functional while still containing several subtle integration problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcoding the Router.&lt;/strong&gt; For current DEX v2 mainnet integrations, use Router metadata supplied by the STON.fi simulation and &lt;code&gt;dexFactory()&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using floating-point arithmetic for token amounts.&lt;/strong&gt; Convert decimal strings into integer blockchain units using token-specific metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keeping an old quote after an input changes.&lt;/strong&gt; Clear simulation state whenever the asset pair, amount, or relevant swap setting changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting minimum output to an arbitrary tiny value.&lt;/strong&gt; &lt;code&gt;minAskAmount&lt;/code&gt; is the user's execution protection. Reuse the simulation result rather than replacing it with a convenient placeholder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treating wallet submission as final settlement.&lt;/strong&gt; A signed and broadcast TON transaction can still lead to later contract messages, failures, or refunds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sending transactions from an unidentified dApp.&lt;/strong&gt; Serve a correct TON Connect manifest from your own application domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring user rejection.&lt;/strong&gt; Declining a wallet request is a normal outcome, not an exceptional application failure. Give the user a clean way to retry.&lt;/p&gt;

&lt;p&gt;A solid first version does not need professional trading features. It needs faithful state management and a transaction that corresponds to the quote on screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; build the interface around the simulation object, not around the Swap button. Once a trade has been simulated, treat that result as the source for Router selection, offered units, minimum output, and transaction construction. If anything affecting the trade changes, discard the simulation and request a new one before enabling execution.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Do I need a backend to build a basic STON.fi swap interface?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. A basic React implementation can call the STON.fi API, build the transaction with the SDK, and ask a connected wallet to sign through TON Connect directly from the frontend. A backend becomes useful for application-specific analytics, caching, access control, monitoring, or other services, but it should never require collecting the user's wallet private key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why should a swap be simulated before execution?
&lt;/h3&gt;

&lt;p&gt;Simulation tells the application what the trade currently looks like before the wallet signs anything. It also produces values such as the minimum acceptable output and, in the current STON.fi DEX v2 workflow, Router metadata used to build the actual transaction. If inputs change after simulation, request a new simulation rather than executing the old one.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between expected output and minimum received?
&lt;/h3&gt;

&lt;p&gt;Expected output describes the result indicated by the current quote or simulation. Minimum received is the lower execution boundary created by the selected slippage tolerance. If execution would produce less than that minimum, the swap should not simply proceed at any price. Your interface should make that protection visible instead of hiding it behind the Swap button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I assume every TON token uses nine decimals?
&lt;/h3&gt;

&lt;p&gt;No. Token amounts displayed to people must be converted into integer blockchain units using that asset's own decimal metadata. Hardcoding nine decimals can make an interface submit a radically different amount for tokens with another precision. Read the metadata supplied for the selected asset and use integer-safe conversion logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I hardcode a STON.fi v2 Router address?
&lt;/h3&gt;

&lt;p&gt;Not for the recommended production mainnet flow. Current STON.fi documentation advises developers to simulate the swap first, use the Router metadata contained in that result, and instantiate the corresponding contracts through &lt;code&gt;dexFactory()&lt;/code&gt;. This reduces the chance that an integration becomes tied to an obsolete Router configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does TON Connect execute the STON.fi swap itself?
&lt;/h3&gt;

&lt;p&gt;No. TON Connect is the wallet communication layer. Your application builds the STON.fi transaction, then TON Connect asks the user's wallet to approve, sign, and broadcast it. STON.fi smart contracts process the resulting on-chain messages. Keeping those roles separate makes the integration easier to reason about and prevents the frontend from handling private keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I verify that a STON.fi swap actually completed?
&lt;/h3&gt;

&lt;p&gt;Do not rely only on the fact that the wallet accepted the transaction request. Treat submission and settlement as separate states. Track the resulting on-chain activity or use STON.fi transaction and swap-status facilities where appropriate. Update the interface only when you have evidence of the final result, including a possible failure or refund path.&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 end-to-end example for building a React swap interface with the STON.fi API, SDK, and TON Connect&lt;/li&gt;
&lt;li&gt;STON.fi DEX v2 Swap - Current API-driven production pattern, Router discovery, &lt;code&gt;dexFactory()&lt;/code&gt;, and v2 transaction construction&lt;/li&gt;
&lt;li&gt;STON.fi REST API Reference - Swap simulation, asset queries, Router information, transaction queries, and swap status endpoints&lt;/li&gt;
&lt;li&gt;STON.fi REST API - Overview of the official HTTP interface used alongside the DEX contracts&lt;/li&gt;
&lt;li&gt;STON.fi DEX Architecture - Explanation of the Router, Pool, and contract roles involved in swaps&lt;/li&gt;
&lt;li&gt;STON.fi Router v2 Reference - Low-level swap payload fields, minimum output behavior, deadlines, routing, and refund mechanics&lt;/li&gt;
&lt;li&gt;TON Connect Get Started - Official React setup for the provider, wallet connection, manifest, and connection state&lt;/li&gt;
&lt;li&gt;TON Connect Send Transaction - Official transaction request format, &lt;code&gt;validUntil&lt;/code&gt;, network selection, message format, response, and wallet errors&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Request a Swap Quote from the STON.fi API</title>
      <dc:creator>Ivan “Crypto Vazima” Zimanov</dc:creator>
      <pubDate>Sat, 01 Aug 2026 14:01:11 +0000</pubDate>
      <link>https://dev.to/ivan_cryptovazimazima/how-to-request-a-swap-quote-from-the-stonfi-api-4kdi</link>
      <guid>https://dev.to/ivan_cryptovazimazima/how-to-request-a-swap-quote-from-the-stonfi-api-4kdi</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical guide to simulating a TON swap, reading the returned price data, and carrying the quote safely into transaction construction.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your application needs to ey sign a swap, STON.fi exposes a direct way to request that information: &lt;code&gt;POST https://api.ston.fi/v1/swap/simulate&lt;/code&gt;. STON.fi calls the operation a swap simulation, but in a wallet, trading interface, bot, or backend it serves the role of a swap quote. You provide the asset being sold, the asset being bought, the amount in blockchain units, and a slippage tolerance. The API returns the expected output together with minimum output, fees, price impact, gas information, pool data, and the Router that should be used if you continue to execution.&lt;/p&gt;

&lt;p&gt;The critical detail is that the quote is not just a price. It is routing and execution context for a specific swap at a specific moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a STON.fi swap quote actually gives you
&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%2F30f8kl5u9nho5e71vk8g.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%2F30f8kl5u9nho5e71vk8g.png" alt="STON.fi swap quote flow" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A DEX quote answers a more useful question than "What is token A worth in token B?" It asks, "If I sell this exact amount through the liquidity available now, what should the swap produce?"&lt;/p&gt;

&lt;p&gt;STON.fi's DEX API exposes this through &lt;code&gt;/v1/swap/simulate&lt;/code&gt;. The official API reference describes the endpoint as a pre-execution simulation that calculates expected output, fees, and gas costs. The current response schema also includes &lt;code&gt;price_impact&lt;/code&gt;, &lt;code&gt;min_ask_units&lt;/code&gt;, &lt;code&gt;recommended_min_ask_units&lt;/code&gt;, &lt;code&gt;recommended_slippage_tolerance&lt;/code&gt;, pool information, and a complete &lt;code&gt;router&lt;/code&gt; object. ion matters because an AMM quote depends on the input size and pool state. Two requests for the same pair can return different results if the amount changes or if liquidity changes between requests.&lt;/p&gt;

&lt;p&gt;For a typical interface, the quote should give you enough data to display:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expected amount received&lt;/li&gt;
&lt;li&gt;minimum acceptable amount received&lt;/li&gt;
&lt;li&gt;swap rate&lt;/li&gt;
&lt;li&gt;price impact&lt;/li&gt;
&lt;li&gt;protocol or swap fee information&lt;/li&gt;
&lt;li&gt;estimated gas parameters&lt;/li&gt;
&lt;li&gt;selected pool and Router&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simulation does not execute anything on-chain. No wallet signature is required merely to ask the API for the quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four inputs you need
&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%2Fufzuvmi6orr02puxno3u.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%2Fufzuvmi6orr02puxno3u.png" alt="STON.fi 4 inputs" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a direct swap simulation, four values are essential: the asset you are selling, the asset you want to receive, the amount being sold, and the slippage tolerance. The raw REST endpoint uses snake_case query parameters, while the official TypeScript client exposes camelCase properties. The client then maps them to the REST request.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Raw REST parameter&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;@ston-fi/api&lt;/code&gt; property&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Asset to sell&lt;/td&gt;
&lt;td&gt;&lt;code&gt;offer_address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;offerAddress&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asset to receive&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ask_address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;askAddress&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amount to sell&lt;/td&gt;
&lt;td&gt;&lt;code&gt;units&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;offerUnits&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slippage tolerance&lt;/td&gt;
&lt;td&gt;&lt;code&gt;slippage_tolerance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;slippageTolerance&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The REST endpoint also supports optional parameters such as &lt;code&gt;pool_address&lt;/code&gt;, referral settings, and DEX version restrictions. For a basic quote request, start with the four required values and add optional routing constraints only when your application has a reason to control them.&lt;/p&gt;

&lt;p&gt;One implementation detail is easy to miss: this is a &lt;code&gt;POST&lt;/code&gt; endpoint, but the documented swap inputs are query parameters. The official &lt;code&gt;@ston-fi/api&lt;/code&gt; client does the same internally when it calls &lt;code&gt;/v1/swap/simulate&lt;/code&gt;. The amount to blockchain units first&lt;/p&gt;

&lt;p&gt;&lt;code&gt;units&lt;/code&gt; does not mean a human-readable amount such as &lt;code&gt;"1.5"&lt;/code&gt; unless the token happens to use zero decimals. It means the smallest indivisible units of the offered asset.&lt;/p&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%2F0xeqc16cksfr78ryf4tl.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%2F0xeqc16cksfr78ryf4tl.png" alt="Blockchain units" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TON jettons can use different decimal precision. TON documentation explicitly warns developers not to assume that every jetton has the same &lt;code&gt;decimals&lt;/code&gt; value. For example, many assets use 9 decimals, while USDT on TON uses 6. An incorrect decimal conversion can change the intended amount by orders of magnitude. And is conceptually:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;blockchain units = display amount * 10^decimals&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For production code, avoid ordinary JavaScript floating-point arithmetic for token amounts. A simple string-based conversion can keep the calculation exact:&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;function&lt;/span&gt; &lt;span class="nf"&gt;toUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&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="kd"&gt;const&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="nx"&gt;fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="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="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="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="nf"&gt;repeat&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="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="nx"&gt;decimals&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="nc"&gt;BigInt&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="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="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;padded&lt;/span&gt; &lt;span class="o"&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;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;offerUnits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// "1500000000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fetch the asset's real decimal precision from trusted metadata rather than hardcoding &lt;code&gt;9&lt;/code&gt;. If your project already uses STON.fi tooling, use the metadata returned for the selected asset and keep amounts as strings or integers until you format them for display.&lt;/p&gt;

&lt;h2&gt;
  
  
  Request the quote with the raw REST API
&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%2Ffxsv9p2mi9ulik2lazdf.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%2Ffxsv9p2mi9ulik2lazdf.png" alt="Request the STON.fi quote" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the HTTP level, the request is small. You can call the production API directly with &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, or any HTTP client.&lt;/p&gt;

&lt;p&gt;A generic &lt;code&gt;curl&lt;/code&gt; request looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.ston.fi/v1/swap/simulate?offer_address=&amp;lt;OFFER_ASSET&amp;gt;&amp;amp;ask_address=&amp;lt;ASK_ASSET&amp;gt;&amp;amp;units=&amp;lt;OFFER_UNITS&amp;gt;&amp;amp;slippage_tolerance=0.01"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"accept: application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JavaScript, building the query parameters explicitly makes the request easier to inspect:&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;offerAddress&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;askAddress&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offerUnits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;AMOUNT_IN_SMALLEST_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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&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;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;offer_address&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="na"&gt;ask_address&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="na"&gt;units&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;slippage_tolerance&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;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/swap/simulate?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&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="s2"&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="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 quote 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;quote&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="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;quote&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;0.01&lt;/code&gt; value represents 1 percent slippage tolerance. STON.fi's official TypeScript client currently documents &lt;code&gt;0.01&lt;/code&gt; as a recommended value, while the simulation response can also return a &lt;code&gt;recommended_slippage_tolerance&lt;/code&gt;. Treat slippage as a transaction protection setting, not as another name for price impact. plication, wrap the call in normal network error handling, validate the response shape, and reject zero or malformed amounts before sending the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the official TypeScript client when possible
&lt;/h2&gt;

&lt;p&gt;If you are already working in TypeScript or JavaScript, &lt;code&gt;@ston-fi/api&lt;/code&gt; removes most of the raw HTTP plumbing. The package is the official TypeScript client for the STON.fi HTTP API and exposes &lt;code&gt;simulateSwap()&lt;/code&gt; directly.&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;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;Then request a quote:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`ts&lt;br&gt;
import { StonApiClient } from "@ston-fi/api";&lt;/p&gt;

&lt;p&gt;const client = new StonApiClient();&lt;/p&gt;

&lt;p&gt;const quote = await client.simulateSwap({&lt;br&gt;
  offerAddress: "",&lt;br&gt;
  askAddress: "",&lt;br&gt;
  offerUnits: "",&lt;br&gt;
  slippageTolerance: "0.01",&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;console.log({&lt;br&gt;
  expectedOutput: quote.askUnits,&lt;br&gt;
  minimumOutput: quote.minAskUnits,&lt;br&gt;
  priceImpact: quote.priceImpact,&lt;br&gt;
  swapRate: quote.swapRate,&lt;br&gt;
  router: quote.router,&lt;br&gt;
});&lt;br&gt;
&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There is one naming difference worth remembering. The raw REST response uses fields such as &lt;code&gt;ask_units&lt;/code&gt; and &lt;code&gt;min_ask_units&lt;/code&gt;; the client normalizes API responses into camelCase, so your TypeScript code reads &lt;code&gt;askUnits&lt;/code&gt; and &lt;code&gt;minAskUnits&lt;/code&gt;. The official client source and response types make this mapping visible. applications, this client is the cleaner option because it gives you a stable application-facing interface while still using the same STON.fi REST API underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the response as execution data, not just a number
&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%2Fq8bifcp6ah4w5z5w39bo.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%2Fq8bifcp6ah4w5z5w39bo.png" alt="How to read STON.fi response as execution data" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose your UI only prints &lt;code&gt;ask_units&lt;/code&gt;. You have technically displayed an expected output, but you have thrown away much of the information that makes the quote useful.&lt;/p&gt;

&lt;p&gt;The most important raw REST fields to inspect are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ask_units&lt;/code&gt;: the simulated output amount.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;min_ask_units&lt;/code&gt;: the minimum output associated with the supplied slippage tolerance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recommended_min_ask_units&lt;/code&gt;: the API's recommended minimum output.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;price_impact&lt;/code&gt;: the effect of this swap size on the execution price.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swap_rate&lt;/code&gt;: the simulated exchange rate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fee_units&lt;/code&gt; and &lt;code&gt;fee_percent&lt;/code&gt;: fee information returned for the route.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gas_params&lt;/code&gt;: estimated gas-related values.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pool_address&lt;/code&gt;: the pool selected for the simulation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;router&lt;/code&gt;: the Router metadata returned with the route.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The response type in the official client includes all of these fields. use expected output with guaranteed output.** A quote reflects a simulation against current state. If pool reserves change before the transaction executes, the final conditions can differ. That is why the minimum output and slippage protection exist.&lt;/p&gt;

&lt;p&gt;A useful quote review in your interface can therefore be compact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"You receive" from expected output&lt;/li&gt;
&lt;li&gt;"Minimum received" from the minimum output&lt;/li&gt;
&lt;li&gt;"Price impact" as a separate risk signal&lt;/li&gt;
&lt;li&gt;fee estimate&lt;/li&gt;
&lt;li&gt;a warning when the quote is old or conditions have materially changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a quote is going to sit on screen for a while, request it again before constructing or submitting the transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Carry the returned Router into 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%2F2dz1he4c8fmhw0xysdw8.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%2F2dz1he4c8fmhw0xysdw8.png" alt="From quote to swap on STON.fi" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important production pattern appears after the quote is returned.&lt;/p&gt;

&lt;p&gt;STON.fi's current v2 SDK documentation explicitly recommends an API-driven workflow: simulate first, take the &lt;code&gt;router&lt;/code&gt; object from the simulation result, pass it into &lt;code&gt;dexFactory()&lt;/code&gt;, and then build the transaction against the returned Router rather than hardcoding a Router contract address. The documentation says this approach keeps integrations compatible with Router upgrades. It also states that &lt;code&gt;api.ston.fi&lt;/code&gt; serves mainnet data. off looks like this:&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
ts&lt;br&gt;
import { dexFactory, Client } from "@ston-fi/sdk";&lt;br&gt;
import { StonApiClient } from "@ston-fi/api";&lt;/p&gt;

&lt;p&gt;const apiClient = new StonApiClient();&lt;/p&gt;

&lt;p&gt;const simulationResult = await apiClient.simulateSwap({&lt;br&gt;
  offerAddress: "",&lt;br&gt;
  askAddress: "",&lt;br&gt;
  offerUnits: "",&lt;br&gt;
  slippageTolerance: "0.01",&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;const { router: routerInfo } = simulationResult;&lt;br&gt;
const dexContracts = dexFactory(routerInfo);&lt;/p&gt;

&lt;p&gt;const tonClient = new Client({&lt;br&gt;
  endpoint: "",&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;const router = tonClient.open(&lt;br&gt;
  dexContracts.Router.create(routerInfo.address)&lt;br&gt;
);&lt;br&gt;
&lt;code&gt;`&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At that point, you have moved from "What would this swap look like?" to "Which contract configuration should build this swap?" The quote and transaction are two stages of the same workflow.&lt;/p&gt;

&lt;p&gt;STON.fi's swap documentation also recommends reusing values from the simulation result when constructing the actual transaction. That reduces the chance that your signed payload describes a different route or minimum output from the one your interface just showed. &lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes to avoid
&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%2Fc928ykszcu0s0knbxdoc.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%2Fc928ykszcu0s0knbxdoc.png" alt="Common mistakes to avoid on STON.fi swap" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most integration bugs around quoting are not exotic smart contract failures. They are data-handling mistakes before a transaction is ever built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passing display amounts as **&lt;/strong&gt;&lt;code&gt;units&lt;/code&gt;*&lt;em&gt;**.&lt;/em&gt;* &lt;code&gt;"1"&lt;/code&gt; and &lt;code&gt;"1000000000"&lt;/code&gt; can represent the same human amount for a 9-decimal token, but they are very different API inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming every jetton has 9 decimals.&lt;/strong&gt; Read the token metadata. TON's jetton documentation specifically warns that decimals vary. SON body to the raw simulation endpoint and ignoring its documented query parameters.** If you call REST directly, follow the current OpenAPI schema. If you use &lt;code&gt;@ston-fi/api&lt;/code&gt;, let the client handle the mapping. ice impact and slippage as the same value.** Price impact describes how the trade affects the quoted rate through available liquidity. Slippage tolerance defines how much unfavorable movement you are willing to accept between quote and execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcoding the Router.&lt;/strong&gt; Use the Router returned by the simulation for the mainnet execution flow recommended by STON.fi. uote indefinitely.** A simulation is a snapshot, not a reservation. Refresh it when enough time has passed or when the amount, pair, or slippage setting changes.&lt;/p&gt;

&lt;p&gt;A good practical rule is simple: treat the quote as disposable data that must stay synchronized with the transaction you are about to ask the wallet to sign.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Is &lt;code&gt;/v1/swap/simulate&lt;/code&gt; a real swap?
&lt;/h3&gt;

&lt;p&gt;No. It simulates the swap and returns expected execution data without moving funds or requiring a wallet signature. Execution is a separate step in which your application builds the appropriate TON transaction and asks the wallet to sign it. The simulation is therefore ideal for price previews, validation, and transaction preparation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does &lt;code&gt;units&lt;/code&gt; mean in the STON.fi quote request?
&lt;/h3&gt;

&lt;p&gt;It is the amount of the offered asset in its smallest blockchain units. You must convert the human-readable amount using that asset's &lt;code&gt;decimals&lt;/code&gt; metadata. For a token with 9 decimals, 1.5 tokens is 1,500,000,000 units. Do not assume every TON jetton has 9 decimals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is slippage tolerance the same as price impact?
&lt;/h3&gt;

&lt;p&gt;No. Price impact reflects how the size of the requested swap affects the quoted execution price through pool liquidity. Slippage tolerance is the maximum adverse change your transaction is prepared to accept. STON.fi returns price impact separately and uses the slippage setting when calculating minimum output values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I quote an exact output amount instead?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;POST /v1/reverse_swap/simulate&lt;/code&gt;. The normal &lt;code&gt;/v1/swap/simulate&lt;/code&gt; endpoint starts with a known amount to sell and estimates what you receive. The reverse endpoint starts with the amount you want to receive and calculates the required input. STON.fi exposes both flows in the REST API and in &lt;code&gt;@ston-fi/api&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I hardcode a STON.fi Router address after getting a quote?
&lt;/h3&gt;

&lt;p&gt;No for the normal mainnet integration pattern. STON.fi's current v2 documentation recommends taking the Router metadata from the simulation response and constructing the SDK contracts dynamically with &lt;code&gt;dexFactory()&lt;/code&gt;. That keeps the transaction builder aligned with the route selected by the API and avoids depending on a manually fixed Router address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use &lt;code&gt;api.ston.fi&lt;/code&gt; to request testnet swap quotes?
&lt;/h3&gt;

&lt;p&gt;The current STON.fi v2 swap documentation states that the REST API at &lt;code&gt;api.ston.fi&lt;/code&gt; serves mainnet data. Its testnet instructions use a manual contract setup instead of the mainnet API-driven routing workflow. If you are building a production mainnet integration, use the API-driven pattern; treat testnet as a separate setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should my app check immediately before using a STON.fi quote?
&lt;/h3&gt;

&lt;p&gt;Confirm that the pair, input amount, token decimals, slippage setting, expected output, minimum output, and returned Router still match what the user sees. If the quote is stale, request a fresh simulation. Then build the transaction from that simulation data instead of reconstructing the route from hardcoded values. That keeps the visible quote and the transaction as closely aligned as possible.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;STON.fi DEX API Reference - endpoint overview for swaps, reverse swaps, liquidity, and DEX data&lt;/li&gt;
&lt;li&gt;STON.fi Swagger UI - interactive interface for exploring and testing the REST API&lt;/li&gt;
&lt;li&gt;STON.fi OpenAPI Schema - current machine-readable definition of &lt;code&gt;/v1/swap/simulate&lt;/code&gt;, parameters, and responses&lt;/li&gt;
&lt;li&gt;STON.fi API - official overview of the HTTP API and API viewers&lt;/li&gt;
&lt;li&gt;STON.fi v2 SDK Guide - API-driven mainnet simulation, Router discovery, and transaction construction&lt;/li&gt;
&lt;li&gt;STON.fi Swap Guide for React - end-to-end example using &lt;code&gt;@ston-fi/api&lt;/code&gt;, &lt;code&gt;@ston-fi/sdk&lt;/code&gt;, and TonConnect&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ston-fi/api&lt;/code&gt; - official TypeScript client package and usage examples&lt;/li&gt;
&lt;li&gt;STON.fi API client source - implementation of &lt;code&gt;simulateSwap()&lt;/code&gt; and REST parameter mapping&lt;/li&gt;
&lt;li&gt;STON.fi response types - current fields returned by swap simulation in the official client&lt;/li&gt;
&lt;li&gt;TON Jetton Metadata - authoritative explanation of jetton decimals and smallest-unit conversion&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
