<?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: Web3KD</title>
    <description>The latest articles on DEV Community by Web3KD (@web3kd).</description>
    <link>https://dev.to/web3kd</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%2F4024978%2Fe4f1ed94-2c13-4e18-906e-5a59a0cdbe0a.png</url>
      <title>DEV Community: Web3KD</title>
      <link>https://dev.to/web3kd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/web3kd"/>
    <language>en</language>
    <item>
      <title>The DeFi API for AI Agents: What Would It Need to Look Like?</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:48:00 +0000</pubDate>
      <link>https://dev.to/web3kd/the-defi-api-for-ai-agents-what-would-it-need-to-look-like-2kmc</link>
      <guid>https://dev.to/web3kd/the-defi-api-for-ai-agents-what-would-it-need-to-look-like-2kmc</guid>
      <description>&lt;h1&gt;
  
  
  The DeFi API for AI Agents: What Would It Need to Look Like?
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Humans read a quote, glance at slippage, and click confirm. An AI agent can't glance at anything — it needs the entire decision made of structured data it can parse, verify, and act on without a screen in between. STON.fi's Omniston protocol already looks a lot like a first draft of that answer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every DeFi interface built so far has one implicit assumption baked into it: a human is looking at the screen. The price is formatted for eyes. The slippage warning is a sentence, not a machine-checkable field. The "confirm" button assumes a person weighing a decision, not a program executing a policy. That assumption breaks the moment you try to hand a wallet to an autonomous agent instead of a person — and 2026 is the year that stopped being theoretical for a lot of builders on TON.&lt;/p&gt;

&lt;p&gt;So what would a DeFi API actually need to look like if the primary caller was an AI agent instead of a human? Not "AI-themed marketing copy on a swap button" — an actual protocol-level answer. It turns out Omniston, STON.fi's liquidity aggregation and cross-chain execution layer, already satisfies more of that answer than most people give it credit for, largely because it was built API-first rather than UI-first from day one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💭 My honest take: most "AI + DeFi" content skips straight to autonomous trading bots without asking the more boring, more important question first — what does the &lt;em&gt;interface itself&lt;/em&gt; need to guarantee before any agent can safely act on it at all? That's the question this piece is actually about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ✅ Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agents don't need prettier UIs — they need structured, parseable data at every step: quotes, execution status, errors, and refund conditions.&lt;/li&gt;
&lt;li&gt;A quote an agent can act on needs a stable identifier, an expiration, and machine-readable terms — not just a displayed number.&lt;/li&gt;
&lt;li&gt;Execution status needs to be observable programmatically, not inferred from a wallet notification a human would read.&lt;/li&gt;
&lt;li&gt;Omniston's SDK already exposes most of this surface — &lt;code&gt;requestForQuote&lt;/code&gt;, &lt;code&gt;buildTransfer&lt;/code&gt;, and &lt;code&gt;swapTrack&lt;/code&gt; map almost directly onto what an agent loop needs.&lt;/li&gt;
&lt;li&gt;The gap that remains isn't the API surface — it's standardized, cross-protocol schemas and scoped signing permissions that don't hand an agent your entire wallet.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Why "Just Use the Existing API" Isn't Quite Enough
&lt;/h2&gt;

&lt;p&gt;A REST or WebSocket API that returns JSON already looks "machine-readable" on the surface. But an interface built for humans-via-frontend and one built for agents-via-API diverge in a few specific ways that matter a lot once nobody's eyes are actually on the screen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quotes need to be addressable, not just displayable.&lt;/strong&gt; A human reads "≈ 4.82 USDT" and moves on. An agent needs a stable &lt;code&gt;quoteId&lt;/code&gt; it can reference in a follow-up call, check for expiry, and use to build the exact transaction that quote described — not a re-derived approximation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State needs to be pollable or streamable, not inferred.&lt;/strong&gt; A human notices their wallet app changed. An agent needs to explicitly subscribe to or query execution status and get back a typed result: pending, settled, refundable, failed — not guess from a UI element that doesn't exist for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors need to be classifiable, not just readable.&lt;/strong&gt; "Transaction failed" is fine for a person to read and shrug at. An agent needs to know &lt;em&gt;why&lt;/em&gt; — insufficient gas, stale quote, slippage exceeded — so it can decide whether to retry, adjust parameters, or halt entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settlement guarantees need to be provable, not assumed.&lt;/strong&gt; An agent moving funds autonomously needs the underlying execution model to guarantee — cryptographically, not just contractually — that a failed trade doesn't silently strand funds.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔌 Omniston as a Working Example, Not a Hypothetical
&lt;/h2&gt;

&lt;p&gt;This is where it stops being theoretical. Omniston's Node.js SDK is built around exactly this shape: request a quote, get a typed, addressable object back, build a transaction from it, and track settlement as an observable stream — all without a UI in the loop at any point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Requesting a Quote
&lt;/h3&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;Omniston&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/omniston-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;omniston&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;Omniston&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://omni-ws.ston.fi&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;quoteStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestForQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;settlementParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="cm"&gt;/* which settlement methods to allow */&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* asset the agent is offering */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* asset the agent wants */&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="cm"&gt;/* offer amount */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;quoteStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;quoteEvent&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="c1"&gt;// quoteEvent carries a stable quoteId, expiry, and settlement terms —&lt;/span&gt;
  &lt;span class="c1"&gt;// an agent can log, validate, or discard this without ever rendering it&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's already true here that a UI-first API wouldn't guarantee: the quote arrives as a typed event on a stream, not a string formatted for display. An agent can apply its own policy — "only accept quotes with price impact under X%" — entirely in code, before anything ever gets signed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Building a Transaction From That Exact Quote
&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;tx&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;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildTransfer&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;span class="c1"&gt;// the exact quote object received above — not a re-derived price&lt;/span&gt;
  &lt;span class="na"&gt;sourceAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TON&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;agentWalletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;destinationAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TON&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;agentWalletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;gasExcessAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TON&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;agentWalletAddress&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;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ton&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="c1"&gt;// messages is ready to sign and send — no re-interpretation needed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the addressability property from earlier, made concrete: the transaction is built from the &lt;em&gt;exact&lt;/em&gt; quote object, not a fresh price lookup that could have drifted. For a human, that drift shows up as slippage tolerance. For an agent, it needs to be closer to a contract: this quote, or nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Tracking Settlement as a Stream, Not a Guess
&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;swapTrackStream&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;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;swapTrack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;quoteId&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;span class="nx"&gt;quoteId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;traderAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;outgoingTxQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// tx hash, message hash, or outgoing message body&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;swapTrackStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;$case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// agent can log and wait&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;settled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// agent can safely mark the position as complete&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&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="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// agent knows funds returned — no manual investigation needed&lt;/span&gt;
        &lt;span class="k"&gt;break&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 arguably the most important piece for agent-native design: settlement status is a subscribable stream with typed cases, not a wallet push notification meant for a person to read. An agent loop can &lt;code&gt;await&lt;/code&gt; a terminal state and branch its own logic on exactly what happened — no screen-scraping, no polling a UI, no assuming success because nothing obviously broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Mapping This Back to the Four Requirements
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;What a human-first API gives you&lt;/th&gt;
&lt;th&gt;What Omniston's SDK actually gives an agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Addressable quotes&lt;/td&gt;
&lt;td&gt;A displayed rate&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;quoteId&lt;/code&gt;-bound, typed quote object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observable state&lt;/td&gt;
&lt;td&gt;A UI notification&lt;/td&gt;
&lt;td&gt;A subscribable &lt;code&gt;swapTrack&lt;/code&gt; stream with typed cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Classifiable errors&lt;/td&gt;
&lt;td&gt;A toast message&lt;/td&gt;
&lt;td&gt;Typed event cases an agent can branch logic on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provable settlement&lt;/td&gt;
&lt;td&gt;"Trust the app"&lt;/td&gt;
&lt;td&gt;HTLC-based atomic settlement — refund or settle, never stranded&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row matters more for agents than for humans, arguably. A person who gets a confusing error can pause, screenshot it, ask someone. An agent executing autonomously needs the underlying settlement model itself to guarantee it can't end up in a state with no defined outcome — which is exactly what atomic, HTLC-based settlement is built to provide regardless of who or what initiated the trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧 What's Still Genuinely Missing
&lt;/h2&gt;

&lt;p&gt;None of this means the problem is solved. A few gaps are real, and worth naming honestly rather than glossing over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No standardized cross-protocol quote schema yet.&lt;/strong&gt; Omniston's typed quote object works beautifully &lt;em&gt;within&lt;/em&gt; Omniston. An agent comparing quotes across multiple unrelated DeFi protocols still has to normalize different shapes by hand — there's no shared "agent quote format" the way there's an emerging shared format for, say, tool-calling schemas in LLM APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing permissions are still mostly all-or-nothing.&lt;/strong&gt; Handing an agent a wallet today generally means handing it broad signing capability, not a scoped permission like "up to $200, only this pair, only this week." Session-scoped, policy-bound signing is the piece that would let people actually trust autonomous agents with real capital, and it's not solved at the wallet layer yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolver selection isn't yet exposed as agent-tunable criteria.&lt;/strong&gt; An agent might reasonably want to weight resolver reputation or historical fill reliability into its own decision-making, not just accept whichever quote wins on price. That's a reasonable next layer on top of what already exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠 A Minimal Sketch of an Agent-Friendly Wrapper
&lt;/h2&gt;

&lt;p&gt;Putting the pieces above together, here's a conceptual sketch — illustrative pseudocode, not a drop-in production snippet — of what an agent's decision loop could look like sitting on top of the primitives above:&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;agentSwapDecision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AgentPolicy&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="nf"&gt;getBestQuote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;policy&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="k"&gt;if &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;span class="nx"&gt;priceImpact&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxPriceImpact&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;price_impact_exceeded&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;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresInMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minQuoteLifetimeMs&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quote_too_stale&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;tx&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;buildTransferFromQuote&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settlement&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;executeAndTrack&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="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quoteId&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;settlement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$case&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;settled&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quoteId&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;span class="nx"&gt;quoteId&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;escalate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;settlement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$case&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 point of this sketch isn't the code itself — it's that every branch is a policy decision made &lt;em&gt;before&lt;/em&gt; signing, on typed data, with a defined fallback. That's the actual shape of "a DeFi API built for agents": not a smarter chatbot bolted onto a swap button, but a protocol where every step an agent needs to reason about is already a typed, addressable, observable object instead of something meant to be read off a screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Conclusion
&lt;/h2&gt;

&lt;p&gt;The honest answer to "what would a DeFi API for AI agents need to look like" turns out to be less exotic than the framing suggests. It needs addressable quotes, observable execution, classifiable errors, and settlement guarantees that don't depend on anyone reading anything. Omniston's SDK already builds most of that surface for a reason that has nothing to do with AI hype — it was designed to be integration-first, so any program, human-facing or not, could reason about a swap the same way. The open work left isn't reinventing that foundation; it's standardizing it across protocols and giving agents narrower, safer permissions than "hold the whole wallet."&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Can an AI agent already use Omniston to execute swaps autonomously today?&lt;/strong&gt;&lt;br&gt;
Technically, yes — the SDK exposes quote requests, transaction building, and settlement tracking as programmatic, typed calls that don't require a UI. Whether it's advisable depends entirely on the wallet permissions and safeguards wrapped around the agent, which is a separate, still-unsolved layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does using a typed API like Omniston's remove the need for slippage protection?&lt;/strong&gt;&lt;br&gt;
No. Price impact and slippage are still real; a typed API just lets an agent check those values programmatically and reject a quote automatically instead of a human eyeballing a percentage before confirming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single biggest missing piece for safe agent-driven DeFi?&lt;/strong&gt;&lt;br&gt;
Scoped, policy-bound signing permissions. Most wallet integrations today still hand an agent broad signing capability rather than a narrow, revocable permission — that gap matters more than any missing API feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does atomic, HTLC-based settlement matter specifically for agents rather than humans?&lt;/strong&gt;&lt;br&gt;
Because an agent can't "notice something looks off" and pause the way a person might. The settlement model itself needs to guarantee a defined outcome — settled or refunded, never stranded — so an autonomous process never ends up in an undefined state it has to resolve manually.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Omniston SDK — Node.js&lt;/strong&gt; — Full flow for quote requests, transaction building, and settlement tracking: &lt;a href="https://docs.ston.fi/developer-section/omniston/omniston-nodejs" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/omniston-nodejs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omniston Protocol Overview&lt;/strong&gt; — Architecture and settlement modes, including cross-chain HTLC flows: &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omniston SDK Reference&lt;/strong&gt; — Package overview and installation for TypeScript/JavaScript integration: &lt;a href="https://docs.ston.fi/developer-section/omniston/sdk" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/sdk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi Developer Introduction&lt;/strong&gt; — Full index of SDKs, REST API, and integration guides: &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Indexing Blockchain Data: Why DeFi Apps Need More Than RPC Calls</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sun, 23 Aug 2026 13:14:38 +0000</pubDate>
      <link>https://dev.to/web3kd/indexing-blockchain-data-why-defi-apps-need-more-than-rpc-calls-c0c</link>
      <guid>https://dev.to/web3kd/indexing-blockchain-data-why-defi-apps-need-more-than-rpc-calls-c0c</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Indexing Blockchain Data: Why DeFi Apps Need More Than RPC Calls&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Ask a new blockchain developer how their app will "read the chain," and the answer is almost always the same: call the RPC. It's the obvious starting point, and for a narrow class of questions — what's this wallet's current balance, has this specific transaction confirmed — it's genuinely sufficient. The moment a DeFi app needs to answer a slightly more interesting question — every trade this pool has ever seen, every wallet that's ever farmed this token, how liquidity depth has shifted over the past month — RPC calls alone stop being a viable architecture, and most teams discover this the expensive way, in production, under load.&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%2F9upzi94t4hfs1jmr13tx.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%2F9upzi94t4hfs1jmr13tx.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn't a niche concern reserved for large-scale analytics dashboards. Even a modest DeFi frontend showing a pool's recent trade history, a user's farming rewards over time, or a simple "top pools by volume" leaderboard is already asking the kind of question raw RPC access wasn't designed to answer efficiently. The gap between "my app connects to the blockchain" and "my app can actually show users the data they expect" is almost entirely made of this distinction, and it's worth understanding precisely rather than discovering by accident when an endpoint starts timing out under real traffic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "RPCs provide connectivity, indexers make data usable, oracles connect applications to the real world and other chains, Layer-2s make execution affordable, and storage keeps assets and history available." &lt;em&gt;— Web3 Infrastructure Stack overview, 2026&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🗄️ &lt;strong&gt;&lt;em&gt;What an RPC Node Is Actually Built to Answer&lt;/em&gt;&lt;/strong&gt;
&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%2Fb3m77i92e0s7ztnjgiu3.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%2Fb3m77i92e0s7ztnjgiu3.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An RPC endpoint is a gateway to a single node's current or near-current state — it excels at point-in-time, single-entity questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's this address's balance right now&lt;/li&gt;
&lt;li&gt;Has this transaction confirmed&lt;/li&gt;
&lt;li&gt;What does calling this contract method return, given current state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it's structurally weak at is aggregation across time or across many entities at once — "every swap in this pool over the last 30 days" isn't a single state read, it's a query across a history the node wasn't built to summarize on demand. Asking an RPC node to answer that means either replaying enormous ranges of blocks per request, or accepting that the app simply can't answer that question efficiently at all.&lt;/p&gt;

&lt;p&gt;This limitation isn't a bug in any particular provider's implementation — it's a direct consequence of what a node is actually built to do. A node maintains current state and validates new blocks; it was never meant to be a general-purpose historical database, and asking it to behave like one means fighting the grain of its own design. Industry infrastructure guides increasingly frame this plainly: request volume that would be trivial for a purpose-built index can be enough to "overwhelm shared-tier endpoints" when routed through raw RPC methods instead, and even dedicated, paid RPC tiers hit real limits once a query pattern crosses from "look up one thing" into "reconstruct history across many things."&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where This Breaks in Practice: TON's Own Architecture as the Clearest Example&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;TON is a genuinely useful case study here, because its own design makes the RPC-only limitation unusually visible rather than a subtle inefficiency.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "The TON DeFi ecosystem — including DEXes like STON.fi, lending protocols, and Jetton issuance — requires both real-time method access (v2) for transaction submission and indexer access (v3) for token balance lookups, liquidity pool reads, and historical trade data. A provider that only surfaces v2 forces teams to run their own indexer or accept incomplete data coverage." &lt;em&gt;— Chainstack, TON RPC Provider Guide, 2026&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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%2Ff8jjpshzxvhh4zxsqbz1.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%2Ff8jjpshzxvhh4zxsqbz1.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a direct, named acknowledgment that a DEX like STON.fi cannot function on RPC access alone. TON's asynchronous, sharded architecture — messages between contracts don't resolve in the same block the way a single-chain synchronous call does — makes naive "just poll the RPC repeatedly" patterns even less viable than on more traditional chains. Heavy read patterns specific to this ecosystem — enumerating jetton masters, tracing transactions by message, reconstructing a pool's trade history — are explicitly called out as workloads that "overwhelm shared-tier endpoints quickly." This isn't a hypothetical scaling concern; it's a documented, current-year operational reality for exactly the kind of app STON.fi is.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 &lt;strong&gt;What an Indexer Actually Does Differently&lt;/strong&gt;
&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%2Fdpkgvhqcgat3tfplwnuv.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%2Fdpkgvhqcgat3tfplwnuv.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An indexer isn't a faster RPC node — it's a fundamentally different data shape sitting behind the chain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It watches the chain continuously and writes relevant events into a queryable database as they happen, rather than waiting to be asked&lt;/li&gt;
&lt;li&gt;It pre-aggregates the kind of historical, cross-entity questions an RPC node can't answer efficiently — total volume by pool, every position a wallet has ever held, time-series depth over a date range&lt;/li&gt;
&lt;li&gt;It exposes that data through a query interface — commonly GraphQL or SQL — built for exactly the aggregation patterns a raw JSON-RPC method was never designed to serve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The distinction matters architecturally: an RPC node answers "what is true right now, about this one thing." An indexer answers "what has been true, across everything, over time" — and a DeFi frontend genuinely needs both, for different parts of the same interface.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡ &lt;strong&gt;Where STON.fi's Own Architecture Already Reflects This Split&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This isn't just an abstract infrastructure argument — it shows up directly in how STON.fi structures its own developer-facing API. STON.fi's REST API exposes pool data, jetton information, protocol statistics, and fee data specifically so integrating developers never have to run their own indexing pipeline just to answer "what does this pool's history look like" — the aggregation work has already been done, once, centrally, rather than pushed onto every team building on top of the protocol.&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;// Without an indexing layer, "get this pool's 30-day volume" means:&lt;/span&gt;
&lt;span class="c1"&gt;// manually paginating through raw transaction history yourself&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;getVolumeTheHardWay&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;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;let&lt;/span&gt; &lt;span class="nx"&gt;allTxs&lt;/span&gt; &lt;span class="o"&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;cursor&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="k"&gt;do&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;batch&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;rpcClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransactions&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cursor&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;100&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;allTxs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allTxs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;allTxs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;ENOUGH_TO_COVER_30_DAYS&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;aggregateVolumeFromRawTxs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allTxs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// now do this correctly, yourself&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// With STON.fi's own indexed API, the same question is one call&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;getVolumeTheRealWay&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;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;stats&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;stonfiApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPoolStats&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30d&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;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// already aggregated server-side&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second function isn't just shorter code — it's the entire architectural point of this article expressed as two functions doing the same job at radically different costs, in both engineering time and runtime load on shared infrastructure.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🛰️ &lt;strong&gt;The Broader Infrastructure Landscape Solving This Same Problem&lt;/strong&gt;
&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%2Faoy6cspgv4mvwxkbd7y4.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%2Faoy6cspgv4mvwxkbd7y4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi's own API is one answer to this problem, specific to its own protocol data. The wider ecosystem has converged on a few recognizable patterns for the general case:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subgraph-style indexing.&lt;/strong&gt; A widely adopted pattern across DeFi and NFT protocols generally: define what on-chain events matter, and a hosted indexing layer continuously ingests and exposes them through a standard query interface — the developer writes what to track, not how to scan the chain for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming pipelines into owned infrastructure.&lt;/strong&gt; Rather than querying a third party's hosted index at request time, some platforms stream relevant on-chain events directly into a team's own database in near real time — trading some setup complexity for full ownership of the resulting data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High-throughput retrieval layers purpose-built for historical backfills.&lt;/strong&gt; Distinct from live indexing, this category focuses specifically on event-heavy, high-volume historical queries — the kind of workload that would otherwise mean manually replaying enormous block ranges through standard RPC calls, compressed instead into a retrieval layer built for exactly that access pattern.&lt;/p&gt;

&lt;p&gt;Each of these exists because the same underlying gap keeps appearing across every chain and every serious DeFi application: raw node access answers current-state questions well and historical, aggregate questions poorly, and that gap doesn't close by adding more RPC capacity — it closes by adding a genuinely different kind of infrastructure layer. Teams that try to close it by simply paying for a bigger or faster RPC plan tend to discover that the ceiling moves, but doesn't disappear — the query pattern was always the mismatch, not the provider's raw throughput.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚖️ &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2Fzx8u9hfy0rj7k82b2o7b.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%2Fzx8u9hfy0rj7k82b2o7b.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 Point-in-time reads vs. historical aggregation.&lt;/strong&gt; An RPC call answers "what is the state right now." An index answers "what has the state been, summarized, over a range" — and a real DeFi frontend needs both simultaneously, often on the same screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Single-entity queries vs. cross-entity queries.&lt;/strong&gt; Checking one wallet's balance is RPC-shaped. Ranking every liquidity provider in a pool by size is index-shaped. Trying to force the second pattern through the first tool is where naive architectures fail under real load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Request-time computation vs. pre-aggregated results.&lt;/strong&gt; Computing 30-day volume by replaying transactions on every page load is request-time work that scales badly with traffic. An indexed API returning a pre-computed figure scales with how often the underlying data actually changes, not with how many users ask about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚔️ Running your own indexing stack vs. relying on a protocol's own indexed API.&lt;/strong&gt; Self-hosting an indexing pipeline offers full control but comes with real, ongoing operational cost. Using a protocol's own indexed endpoints — where they exist, as with STON.fi's own REST API — removes that operational burden entirely for exactly the queries that protocol already needed to answer for its own frontend.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Justifies Adding an Indexing Layer
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Any question that spans time or many entities at once.&lt;/strong&gt; Historical volume, wallet-level position history, and pool-ranking queries are the clearest signal that plain RPC access has been outgrown.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request patterns that would otherwise mean repeated, expensive chain scans.&lt;/strong&gt; If serving a single page requires replaying a meaningful range of transaction history on every load, that computation belongs in a pre-aggregated index, not in the request path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read patterns explicitly documented as overwhelming shared infrastructure.&lt;/strong&gt; When a chain's own tooling ecosystem calls out specific query patterns as needing dedicated indexer access rather than standard RPC methods, that's a direct, reliable signal for architecture decisions, not a guess.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An indexer is not a faster RPC node.&lt;/strong&gt; It's a structurally different data layer, built for aggregation and history rather than point-in-time state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using a protocol's own indexed API isn't a shortcut — it's often the correct architecture.&lt;/strong&gt; When STON.fi already exposes pool and fee data through its own API, rebuilding that aggregation independently duplicates work the protocol has already done well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TON's async, sharded design makes this distinction more visible than on some other chains, not less relevant.&lt;/strong&gt; The v2/v3 RPC split documented by TON infrastructure providers exists specifically because this chain's architecture makes naive polling patterns fail faster and more visibly than on a simpler synchronous chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;RPC calls answer the question DeFi apps ask least interestingly — "what's true right now, about this one thing" — and answer it well. The moment an app needs to answer anything that spans history or many entities at once, which is most of what a real trading interface actually shows a user, RPC access alone stops scaling, and the documented reality on TON specifically — where DEXes like STON.fi are explicitly named as needing indexer-grade access alongside standard RPC methods — makes that gap unusually concrete rather than theoretical. Building on top of a protocol's own indexed API where one exists, rather than reimplementing that aggregation independently, is usually the correct answer, not a compromise.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chainstack — "Top 6 TON RPC Providers for Mini Apps and Production in 2026" (STON.fi-specific v2/v3 requirements) — &lt;a href="https://chainstack.com/top-6-ton-rpc-providers-for-telegram-mini-apps-and-production-workloads-in-2026/" rel="noopener noreferrer"&gt;https://chainstack.com/top-6-ton-rpc-providers-for-telegram-mini-apps-and-production-workloads-in-2026/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Blockchain Council — "Web3 Infrastructure Stack 2026: What You Need" — &lt;a href="https://www.blockchain-council.org/web-3/web3-infrastructure-stack-2026-rpcs-indexers-oracles-layer-2s-storage/" rel="noopener noreferrer"&gt;https://www.blockchain-council.org/web-3/web3-infrastructure-stack-2026-rpcs-indexers-oracles-layer-2s-storage/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ormi Labs — "What Is Blockchain Indexing? Types, Limitations and Tools" — &lt;a href="https://blog.ormilabs.com/what-is-blockchain-indexing-part1/" rel="noopener noreferrer"&gt;https://blog.ormilabs.com/what-is-blockchain-indexing-part1/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OnFinality — "The 2026 Guide to Blockchain Infrastructure Providers" — &lt;a href="https://blog.onfinality.io/2026-guide-to-blockchain-infrastructure/" rel="noopener noreferrer"&gt;https://blog.onfinality.io/2026-guide-to-blockchain-infrastructure/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Developer Documentation Introduction — &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on publicly available infrastructure documentation and STON.fi's public developer documentation as of mid-2026. Provider pricing, API coverage, and TON's own RPC architecture evolve over time — always verify current details directly on the relevant provider's documentation before making infrastructure decisions.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Transaction Lifecycle: What Actually Happens After You Click Swap</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sun, 23 Aug 2026 12:26:15 +0000</pubDate>
      <link>https://dev.to/web3kd/transaction-lifecycle-what-actually-happens-after-you-click-swap-aeg</link>
      <guid>https://dev.to/web3kd/transaction-lifecycle-what-actually-happens-after-you-click-swap-aeg</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Transaction Lifecycle: What Actually Happens After You Click Swap&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;A swap transaction isn't one event — it's a state machine, moving through distinct, named phases between the moment a user taps "confirm" and the moment funds actually settle. This piece traces that lifecycle stage by stage on STON.fi, with the actual code shape at each transition, because this is genuinely an engineering topic underneath the trading language, and it deserves to be read as one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "Simulate the swap to obtain routing metadata (expected amounts, vault info, and the full router object). Feed simulationResult.router directly into dexFactory() to build contracts dynamically." &lt;em&gt;— STON.fi, SDK v2 Swap Documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🎞️ &lt;strong&gt;&lt;em&gt;The Six States a Transaction Actually Passes Through&lt;/em&gt;&lt;/strong&gt;
&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%2Fd9rla925ucclc1okv4hu.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%2Fd9rla925ucclc1okv4hu.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before the code, the shape of the lifecycle itself:&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;Simulated&lt;/strong&gt; — a live calculation against current reserves, no commitment yet&lt;br&gt;
→ &lt;strong&gt;Parameterized&lt;/strong&gt; — the simulation's output converted into concrete transaction fields&lt;br&gt;
→ &lt;strong&gt;Handed off&lt;/strong&gt; — passed to the wallet layer for review&lt;br&gt;
→ &lt;strong&gt;Signed&lt;/strong&gt; — the trader's actual commitment point&lt;br&gt;
→ &lt;strong&gt;Broadcast&lt;/strong&gt; — submitted to the network with a built-in expiration&lt;br&gt;
→ &lt;strong&gt;Settled&lt;/strong&gt; — atomically completed, or reverted, with no state in between&lt;/p&gt;

&lt;p&gt;Every one of these is a distinct, inspectable moment. Treating "confirm swap" as one atomic user action hides that six separate things have to happen correctly, in order, for that action to actually succeed.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;State One: Simulated&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nothing here is final, and that's the entire point of this stage existing separately from what follows.&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;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;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;offerJetton&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;askJetton&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="nx"&gt;amount&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="s1"&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="c1"&gt;// simulationResult now carries: expected output, fee breakdown, and&lt;/span&gt;
&lt;span class="c1"&gt;// simulationResult.router — the current router object, not a saved address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step can run any number of times, freely, with zero cost — which is precisely why it's a poor idea to cache and reuse an old simulation result rather than re-running it right before the next stage.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ &lt;strong&gt;State Two: Parameterized&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The simulation's output gets converted into the actual fields a transaction needs — this is where "approximately what you'll get" becomes "exactly what will be enforced on-chain."&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;router&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;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="c1"&gt;// never hardcoded&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;getSwapJettonToJettonTxParams&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;offerJettonAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;offerJetton&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;askJetton&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;amount&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="nf"&gt;calculateMinAskAmount&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;askUnits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slippageBps&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="nf"&gt;generateQueryId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;minAskAmount&lt;/code&gt; field is the crux of this state: it's the moment a slippage percentage typed into a UI becomes a specific integer that a smart contract will actually check against.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🖊️ &lt;strong&gt;State Three: Handed Off, Then Signed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These are technically two states, but they happen across a single user-facing moment — the wallet prompt — so it's worth treating them 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="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;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="s1"&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;Everything before this call was recalculable and free. &lt;code&gt;sendTransaction&lt;/code&gt; is where that stops being true — the user's wallet signature is the actual, irreversible commitment point in the entire lifecycle. Before it, the transaction is a proposal. After it, it's a request the network will actually act on.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  📤 &lt;strong&gt;State Four: Broadcast&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once signed, the payload — a base64-encoded BOC, TON's native cell serialization format — actually leaves the client and enters the network. The &lt;code&gt;validUntil&lt;/code&gt; field set in the previous state now becomes active protection:&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;// If the network hasn't processed this by validUntil, it's discarded —&lt;/span&gt;
&lt;span class="c1"&gt;// never executed against reserves that may no longer reflect this quote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also the point where, for a same-chain swap, TON's transaction model takes over: the transaction will either execute completely or fail completely. There's no documented partial-execution state at this layer — a multi-chunk route either lands as calculated, chunk by chunk, or the whole thing reverts.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔁 &lt;strong&gt;State Five: Settlement — and Where Cross-Chain Genuinely Diverges&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For a same-chain trade, settlement is close to instantaneous once the transaction is included in a block. For a cross-chain trade, this state gets meaningfully more complex, because TON's own atomicity guarantee doesn't extend to a second, separate blockchain automatically.&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;// Cross-chain settlement adds an HTLC layer on top of the same lifecycle:&lt;/span&gt;
&lt;span class="c1"&gt;// - funds lock behind a shared hash + time condition on both chains&lt;/span&gt;
&lt;span class="c1"&gt;// - completion reveals the secret and releases both sides&lt;/span&gt;
&lt;span class="c1"&gt;// - if either side fails to complete in time, the time lock&lt;/span&gt;
&lt;span class="c1"&gt;//   auto-refunds the locked side rather than leaving it stuck&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why a cross-chain swap through STON.fi's Omniston takes measurably longer than a same-chain one — it's not inefficiency, it's a deliberate trade of speed for a correctness guarantee that two independent blockchains don't provide each other on their own.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🎞️ &lt;strong&gt;Watching the State Machine From the Outside&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A well-built integration doesn't just fire a transaction and hope — it subscribes to the lifecycle's own status stream rather than polling a balance and guessing.&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;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackTrade&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rfqId&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&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;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;confirmSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partiallyFilled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// Reflects the quote-matching stage, not a broken on-chain transaction —&lt;/span&gt;
      &lt;span class="c1"&gt;// some connected liquidity didn't fully match before execution&lt;/span&gt;
      &lt;span class="nf"&gt;handlePartialFill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aborted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;showRetryOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&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;Treating &lt;code&gt;partiallyFilled&lt;/code&gt; as equivalent to a crashed transaction is a common misread — it describes what happened during quote-matching among resolvers and pools, before final on-chain execution, not a submitted transaction that stopped halfway.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚖️ &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2F1nuu5oxb531r73bb7p1w.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%2F1nuu5oxb531r73bb7p1w.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 Free states vs. committed states.&lt;/strong&gt; Everything through "parameterized" costs nothing and binds nobody. Everything from "signed" onward is real. Conflating these two categories is the most common source of confusion about what a "failed" swap actually means at each point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Same-chain settlement vs. cross-chain settlement.&lt;/strong&gt; One relies on native blockchain atomicity and settles quickly. The other layers HTLC-based correctness on top, deliberately trading speed for a guarantee TON alone can't provide across a chain boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Polling vs. subscribing.&lt;/strong&gt; Manually checking a wallet balance after broadcasting is a weak signal — the trade could be pending, reverted, or still routing. Subscribing to &lt;code&gt;trackTrade&lt;/code&gt; gets an explicit state instead of an inference.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Makes This Lifecycle Safe to Build On
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every state before signature is inspectable and repeatable.&lt;/strong&gt; A developer — or a curious user — can trigger and re-trigger simulation and parameter-building without any real-world consequence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The transaction's own fields, not external assumptions, enforce the guarantees.&lt;/strong&gt; &lt;code&gt;minAskAmount&lt;/code&gt; and &lt;code&gt;validUntil&lt;/code&gt; are baked into the payload itself, not just displayed in a UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status is streamed, not inferred.&lt;/strong&gt; &lt;code&gt;trackTrade&lt;/code&gt; reports real states instead of forcing an integration to guess from a balance check.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Broadcast" and "settled" are not the same state.&lt;/strong&gt; A transaction can be genuinely on the network and still fail atomically at settlement if conditions shifted enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;partiallyFilled&lt;/code&gt; belongs to quote-matching, not execution.&lt;/strong&gt; Once a transaction actually broadcasts on TON, it's binary — complete or reverted — with this status reflecting an earlier stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain lifecycle length is a designed tradeoff.&lt;/strong&gt; The extra time isn't latency to optimize away; it's the HTLC window that prevents funds from ever being stuck between two chains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;"What happens after you click swap" is really six distinct, inspectable states — simulated, parameterized, handed off, signed, broadcast, and settled — each with its own guarantees and its own failure mode. Building against this lifecycle explicitly, rather than treating a swap as one opaque action, is what separates an integration that degrades gracefully under real-world conditions from one that just breaks silently the first time a pool's reserves shift at the wrong moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi — SDK v2 Swap Documentation — &lt;a href="https://docs.ston.fi/developer-section/dex/sdk/v2/swap" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/dex/sdk/v2/swap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Transaction Sending via TON Connect — &lt;a href="https://docs.ston.fi/developer-section/common/transaction-sending/tonconnect" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/common/transaction-sending/tonconnect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston gRPC Integration Guide (trackTrade, fill states) — &lt;a href="https://docs.ston.fi/developer-section/omniston/swap/grpc" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/swap/grpc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Blog — "What Is Atomic Swap Execution and Why Does It Matter?" — &lt;a href="https://blog.ston.fi/what-is-atomic-swap-execution-and-why-does-it-matter/" rel="noopener noreferrer"&gt;https://blog.ston.fi/what-is-atomic-swap-execution-and-why-does-it-matter/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston Protocol Overview (HTLC cross-chain settlement) — &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's public developer documentation as of mid-2026. Code examples are simplified for clarity and are not a verbatim copy of the official SDK. Transaction flow and protocol mechanics evolve as the system ships updates — always verify current functionality directly on docs.ston.fi before shipping a production integration.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Last Mile: Taking a STON.fi Integration From Test Network to Real Users</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sat, 22 Aug 2026 11:31:54 +0000</pubDate>
      <link>https://dev.to/web3kd/the-last-mile-taking-a-stonfi-integration-from-test-network-to-real-users-2ho0</link>
      <guid>https://dev.to/web3kd/the-last-mile-taking-a-stonfi-integration-from-test-network-to-real-users-2ho0</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;The Last Mile: Taking a STON.fi Integration From Test Network to Real Users&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Getting a swap working in a test environment is the easy 80% of shipping a STON.fi integration. The remaining 20% — the part that actually determines whether real users lose money to a preventable bug — is almost entirely about the gap between "works in sandbox" and "safe on mainnet." This piece walks through that gap concretely, with the specific patterns STON.fi's own documentation flags as production-critical.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "The production-ready pattern is API-driven. Always let the STON.fi API dictate which router to use, and work against the mainnet endpoint. This keeps your integration compatible with future router upgrades and avoids hardcoding contract addresses." &lt;em&gt;— STON.fi, SDK v2 Swap Documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧳 &lt;strong&gt;&lt;em&gt;Why "It Worked in Testing" Isn't the Bar&lt;/em&gt;&lt;/strong&gt;
&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%2Fwg5684jr96a0q6g9ddeh.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%2Fwg5684jr96a0q6g9ddeh.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test environments are deliberately forgiving in ways production isn't. Three gaps close the distance between the two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔲 &lt;strong&gt;Endpoints are genuinely separate, not a toggle.&lt;/strong&gt; &lt;code&gt;wss://omni-ws-sandbox.ston.fi&lt;/code&gt; and &lt;code&gt;wss://omni-ws.ston.fi&lt;/code&gt; are different environments entirely — a misconfigured environment variable is the single most avoidable production incident.&lt;/li&gt;
&lt;li&gt;🔳 &lt;strong&gt;Contract addresses differ, and mixing them is dangerous, not just broken.&lt;/strong&gt; STON.fi's own DEX core repository lists distinct mainnet (&lt;code&gt;EQB3ncy...&lt;/code&gt;) and testnet (&lt;code&gt;EQBsGx9...&lt;/code&gt;) router addresses, and third-party integration docs explicitly warn against sending funds across that boundary in either direction.&lt;/li&gt;
&lt;li&gt;▶️ &lt;strong&gt;Hardcoded values that "worked" in testing quietly rot in production.&lt;/strong&gt; A fee constant or router address that was correct on day one silently becomes wrong the moment STON.fi ships a router upgrade — which is precisely the failure mode the API-driven pattern exists to prevent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are exotic mistakes. They're the ordinary, boring gaps that separate a demo from a system real money moves through.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Single Highest-Leverage Rule: Let the API Decide, Don't Decide for It&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If this article had to compress into one sentence, it would be this one, because STON.fi's own documentation states it as explicitly as production advice ever gets stated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "STON.fi's REST API (api.ston.fi) only serves mainnet data, so every production swap should follow this flow: simulate the swap to obtain routing metadata, feed simulationResult.router directly into dexFactory() to build contracts dynamically." &lt;em&gt;— STON.fi, SDK v2 Swap Documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The instinct after testing successfully is to lock in what worked — save the router address you tested against, hardcode it, ship it. That instinct is exactly backwards for this ecosystem. STON.fi's router can be upgraded, and an integration that hardcodes a specific router address instead of asking the API which one to use will break silently the next time that happens — not with an error message, but with a transaction that's quietly built against a router that's no longer the current one.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🚧 &lt;strong&gt;The Shipping Checklist, One Gap at a Time&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🔲 Confirm every environment variable before the first sandbox test, not the last.&lt;/strong&gt; Both the WebSocket endpoint and the REST API base URL need to point at sandbox during testing and mainnet in production — a single missed variable in a deploy config is enough to send test transactions against real liquidity, or worse, production transactions against a test router.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔳 Never hardcode a router or contract address, even one that's "definitely stable."&lt;/strong&gt; Follow the documented pattern exactly: simulate first, then feed the simulation's own router object into &lt;code&gt;dexFactory()&lt;/code&gt; to build contracts dynamically. This single pattern absorbs future router upgrades automatically, without a code change on your side.&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;// ❌ Hardcoded — breaks silently on the next router upgrade&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="nf"&gt;dexFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ API-driven — always current, per STON.fi's own recommended pattern&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;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="nx"&gt;swapParams&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="nf"&gt;dexFactory&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶️ Calculate fees dynamically, never as a hardcoded constant.&lt;/strong&gt; STON.fi's own SDK constants for fees exist mainly as fallbacks — the documented best practice is calculating fees from current config parameters rather than relying on values that were correct when the code was written but aren't guaranteed to stay that way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;◀️ Prefer the SDK and TonConnect over manual BOC compilation, unless you have a genuinely specialized need.&lt;/strong&gt; STON.fi's own API reference is explicit that custom BOC compilation should be reserved for advanced use cases — the SDK handles edge cases and receives official support that a hand-rolled transaction builder won't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔲 Test both refund paths and the documented exit codes before launch, not after a user reports a problem.&lt;/strong&gt; This means deliberately exercising the failure modes covered in STON.fi's own error handling — a zero &lt;code&gt;minAskAmount&lt;/code&gt;, insufficient gas producing exit code 37, and both the default and explicitly-set &lt;code&gt;refundAddress&lt;/code&gt; behaviors — as part of the pre-launch test suite, not as reactive debugging once something has already gone wrong for a real user.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🗝️ &lt;strong&gt;What Changes Once Real Referral Fees and Real Vaults Are Involved&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If an integration routes through a referral program, there's a specific mechanic worth understanding before launch rather than after the first payout question comes in.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "DEX v2 accumulates each swap's referral portion in a dedicated Vault contract (one per referrer × token pair). Fees can be configured in the 0.01%–1% range and must later be withdrawn by the referrer." &lt;em&gt;— STON.fi, v2 Smart Contract Documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means referral revenue doesn't arrive automatically in a wallet — it accrues in a per-referrer, per-pair Vault contract that requires an explicit withdrawal step. An integration's launch checklist should include verifying that this withdrawal flow actually works end to end in sandbox, not just that the referral fee is correctly attached to outgoing swap transactions. A referral fee that accrues correctly but can never actually be withdrawn is a production bug that looks like a success in every log line up until someone tries to claim it.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  📶 &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;💧 Hardcoded stability vs. adaptive stability.&lt;/strong&gt; A hardcoded router address feels more stable during development because it never changes on you unexpectedly. In production, that's exactly backwards — the API-driven pattern is the version that actually stays stable as STON.fi's own infrastructure evolves underneath it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Sandbox correctness vs. production correctness.&lt;/strong&gt; Sandbox testing proves your logic is right for the inputs you thought to test. Production correctness additionally requires that your environment configuration, fee calculation, and referral withdrawal flow are all verified against real, current mainnet state — a genuinely broader bar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Reactive debugging vs. pre-launch failure testing.&lt;/strong&gt; Discovering an exit-code handling gap from a confused user's support ticket costs far more — in trust and in engineering time — than deliberately triggering that same exit code in a sandbox test the week before launch.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What a Genuinely Production-Ready Integration Gets Right
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every router and contract address comes from a live simulation, never a saved constant.&lt;/strong&gt; This single pattern absorbs STON.fi's own infrastructure changes automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment separation is verified in CI, not assumed from a config file.&lt;/strong&gt; Sandbox and mainnet endpoints get explicitly checked before any test suite runs, closing off the most common and most avoidable production incident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referral and fee mechanics are tested end to end, including withdrawal.&lt;/strong&gt; Fees accruing correctly is only half the mechanism — confirming they can actually be claimed is the other half most teams skip.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox and mainnet contract addresses are not interchangeable, and mixing them is an active risk, not just an error.&lt;/strong&gt; Third-party integration guides explicitly warn against sending funds across that boundary in either direction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A router upgrade on STON.fi's side is not your integration's emergency if you followed the API-driven pattern.&lt;/strong&gt; It only becomes one if a router address was hardcoded somewhere it shouldn't have been.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual BOC compilation is a deliberate, advanced choice, not a shortcut.&lt;/strong&gt; STON.fi's own documentation reserves it for specialized cases precisely because the SDK already handles the edge cases a hand-rolled path would need to reimplement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;Shipping a STON.fi integration from sandbox to mainnet isn't about writing more code — it's about removing the specific hardcoded assumptions that work fine in a test environment and quietly fail in a production one: fixed router addresses instead of live simulation results, static fee constants instead of dynamic config reads, and untested refund or withdrawal paths that only get discovered once a real user is waiting on them. The gap between a working demo and a production-ready integration is almost entirely made of these small, documented, entirely avoidable decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi — SDK v2 Swap Documentation (API-driven pattern, dexFactory) — &lt;a href="https://docs.ston.fi/developer-section/dex/sdk/v2/swap" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/dex/sdk/v2/swap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — v2 Smart Contract Documentation (referral Vaults, fee configuration) — &lt;a href="https://docs.ston.fi/developer-section/dex/smart-contracts/v2" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/dex/smart-contracts/v2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Developer Documentation Introduction — &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub — ston-fi/dex-core (mainnet/testnet addresses, bug bounty contact) — &lt;a href="https://github.com/ston-fi/dex-core" rel="noopener noreferrer"&gt;https://github.com/ston-fi/dex-core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tact Documentation — STON.fi Integration Cookbook (testnet/mainnet fund-mixing warning) — &lt;a href="https://docs.tact-lang.org/cookbook/dexes/stonfi/" rel="noopener noreferrer"&gt;https://docs.tact-lang.org/cookbook/dexes/stonfi/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's public developer documentation and open-source repositories as of mid-2026. Contract addresses, fee ranges, and recommended patterns evolve as the protocol ships updates — always verify current details directly on docs.ston.fi before shipping a production integration.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>Liquidity Fragmentation Across Chains: A Technical Breakdown of How STON.fi Actually Routes Around It</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sat, 22 Aug 2026 11:16:28 +0000</pubDate>
      <link>https://dev.to/web3kd/liquidity-fragmentation-across-chains-a-technical-breakdown-of-how-stonfi-actually-routes-around-1i29</link>
      <guid>https://dev.to/web3kd/liquidity-fragmentation-across-chains-a-technical-breakdown-of-how-stonfi-actually-routes-around-1i29</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Liquidity Fragmentation Across Chains: A Technical Breakdown of How STON.fi Actually Routes Around It&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;DeFi's total value locked tells a story of scale. It doesn't tell you where that value actually sits, how deep any single pool is, or what happens when a real-sized trade tries to move through it. In 2026, those two stories have diverged sharply — and TON, still a comparatively young liquidity environment, feels this gap more acutely than a chain with decades of accumulated depth. This piece breaks down the mechanics of fragmentation generally, and then looks specifically at how STON.fi's Omniston layer is architected to route around exactly this problem rather than pretend it doesn't exist.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "A swap that would have minimal price impact in a single deep pool instead moves the market more when split across thin pools. As of 2026, aggregate slippage costs in DeFi exceed $2.7 billion annually." &lt;em&gt;— Spark, DeFi glossary&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧊 &lt;strong&gt;&lt;em&gt;Fragmentation Happens at Two Levels, and They Compound Each Other&lt;/em&gt;&lt;/strong&gt;
&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%2Fogg34tkuopwt7zkdhogi.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%2Fogg34tkuopwt7zkdhogi.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The instinct is to think of fragmentation as a single problem — "liquidity is spread across chains." In practice it's two separate, stacking problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔷 &lt;strong&gt;Within-chain fragmentation.&lt;/strong&gt; Even on one blockchain, liquidity splits across competing protocols and pool configurations. Uniswap v3 alone introduced four fee tiers per pair; combined with v4's hook-enabled pools, SushiSwap, Curve, and Balancer, a single token pair can have 10 to 20 active pools on Ethereum mainnet alone, each operating independently with its own depth.&lt;/li&gt;
&lt;li&gt;🔶 &lt;strong&gt;Cross-chain fragmentation.&lt;/strong&gt; The more severe layer. DeFiLlama tracks nearly 400 blockchains, and L2Beat records over 70 active Ethereum rollups alone, holding more than $48 billion in combined TVL. A stablecoin like USDC is natively deployed on over 30 blockchains — the same dollar-denominated liquidity scattered across all of them, unable to net against itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These two levels stack multiplicatively, not additively. A token doesn't just get diluted once, across chains — it gets diluted again, within each chain, across every pool and fee tier competing for the same pair.&lt;/p&gt;

&lt;p&gt;TON illustrates both levels clearly. Within TON alone, a given pair can have liquidity split across STON.fi's own v1 and v2 pools, plus entirely separate pools on DeDust and TonCo — the within-chain fragmentation problem, just at a smaller scale than Ethereum's twenty-pool extremes. Cross-chain, TON's DeFi liquidity is a fraction of Ethereum's, meaning any given asset bridged onto TON typically has meaningfully less depth locally than its home chain, even before accounting for how that TON-side liquidity is itself further split across STON.fi, DeDust, and TonCo.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Metric That Actually Matters, and Why TVL Hides the Problem&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is the technical crux of the entire fragmentation conversation, and it's the point most surface-level coverage misses entirely.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "When measuring effective depth at 1–2% slippage on each chain, execution quality deteriorated outside the primary venue. Capital had expanded in nominal terms, but usable liquidity had fragmented." &lt;em&gt;— independent multi-chain liquidity analysis, Medium, 2026&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aggregate TVL is additive by construction — deploy the same protocol on twenty chains, and the headline number goes up regardless of whether any single chain's pool can actually absorb a meaningful trade. The metric that actually reflects tradeable liquidity is effective depth at a fixed slippage threshold — how much size can execute at, say, 1-2% price impact — and that number does not scale the way TVL does. A protocol can show $2 billion in aggregate pool capital and still lose on realized price to a source holding zero standing inventory at all, simply because that $2 billion was never concentrated enough anywhere to matter for the specific trade being priced.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧮 &lt;strong&gt;Making "TVL Isn't Depth" Concrete: The Actual Math&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The claim above is easy to state and easy to under-appreciate without seeing the arithmetic. On a constant-product pool (&lt;code&gt;x * y = k&lt;/code&gt;), the effective depth at a given slippage tolerance is a direct function of reserves, not a fixed fraction of TVL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;effective_depth_at_slippage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reserve_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reserve_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_slippage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Returns the max input size that keeps price impact under max_slippage
    on a constant-product pool. This is what &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;depth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; actually means —
    not the pool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s total dollar value.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reserve_in&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;reserve_out&lt;/span&gt;
    &lt;span class="n"&gt;target_price_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;max_slippage&lt;/span&gt;
    &lt;span class="c1"&gt;# Solve for new reserve_in such that new marginal price = target_price_ratio * spot price
&lt;/span&gt;    &lt;span class="n"&gt;new_reserve_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reserve_in&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_price_ratio&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_reserve_in&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;reserve_in&lt;/span&gt;

&lt;span class="c1"&gt;# Two pools, identical $1M TVL, wildly different tradeable depth
&lt;/span&gt;&lt;span class="n"&gt;pool_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;effective_depth_at_slippage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reserve_in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reserve_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_slippage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pool_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;effective_depth_at_slippage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reserve_in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reserve_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;950_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_slippage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pool A (balanced): $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pool_a&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tradeable at 1% slippage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pool B (imbalanced): $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pool_b&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tradeable at 1% slippage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Same $1M TVL headline. Meaningfully different real depth.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also exactly why splitting a large order across ten $1M pools performs worse than routing it through one $10M pool — each independent &lt;code&gt;effective_depth_at_slippage&lt;/code&gt; call hits its own limit far sooner than a single, larger reserve pair would.&lt;/p&gt;

&lt;p&gt;A solver-style router, by contrast, treats fragmentation as a given and queries every available source before committing to a route. This is, functionally, what Omniston does on every STON.fi swap:&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;findBestExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TokenPair&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;bigint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Omniston's actual pattern: query every connected paradigm at once&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;stonfiPools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;otherAmmPools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolverQuotes&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="nf"&gt;queryStonfiPools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pair&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="c1"&gt;// STON.fi v1/v2 — deterministic, reserve-based&lt;/span&gt;
    &lt;span class="nf"&gt;queryOtherAmms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pair&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="c1"&gt;// DeDust, TonCo — same TON liquidity graph&lt;/span&gt;
    &lt;span class="nf"&gt;queryResolverNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pair&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="c1"&gt;// escrow swaps — no standing inventory, live quotes&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;allQuotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;stonfiPools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherAmmPools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;resolverQuotes&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="c1"&gt;// Depth-weighted selection or a split route — never a forced single source&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;selectOptimalRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allQuotes&lt;/span&gt;&lt;span class="p"&gt;,&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="na"&gt;maxSlippage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&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 structural point is the same one made above, just made executable: fragmentation isn't something either snippet "fixes." The first one measures it honestly instead of hiding behind TVL. The second one routes around it by refusing to commit to a single fragmented source in the first place.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔬 &lt;strong&gt;The Mechanics, One Layer at a Time&lt;/strong&gt;
&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%2Fdtoqks26hyxlyzlxem1z.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%2Fdtoqks26hyxlyzlxem1z.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴 Isolated pool math, restated.&lt;/strong&gt; On a constant-product AMM, price impact scales with trade size relative to a specific pool's reserves — not relative to that asset's liquidity anywhere else. Ten pools each holding $1 million don't behave like one pool holding $10 million for a large trade; each one independently hits its own steep pricing region far sooner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟡 Bridges connect prices, not liquidity.&lt;/strong&gt; Bridges let capital move between chains and let prices converge through arbitrage, but they don't fuse two pools into one deeper pool. Each chain remains what one analysis calls a semi-independent market — sharing a brand, not necessarily sharing resilience or depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔵 Emissions-driven liquidity is mobile by design.&lt;/strong&gt; Capital that arrived because of a token emissions program has no structural reason to stay once the program ends. Liquidity genuinely integrated into local DeFi primitives is slower to exit; liquidity chasing incentives is fast to exit — and multi-chain deployments disproportionately attract the fast-exiting kind, because that's exactly the capital most responsive to a new emissions campaign on a new chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟢 Bridge concentration is itself a fragility, not just an inconvenience.&lt;/strong&gt; Roughly $2.3 trillion in assets now sits locked across cross-chain bridges — meaning the infrastructure meant to solve fragmentation has become a concentrated point of failure in its own right. A major exploit on a widely-used bridge doesn't just affect that bridge's users; it can simultaneously impair liquidity and collateral rebalancing across every ecosystem that depends on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟣 The composition of DeFi TVL itself has shifted toward this exact risk.&lt;/strong&gt; Bridges now hold more aggregate TVL ($45.38 billion) than lending ($36.50 billion) or liquid staking ($31.77 billion) combined, per DeFiLlama — a reversal from the lending-dominant composition that held through 2024, and a direct reflection of how much value now depends on cross-chain connective infrastructure rather than sitting natively in one place.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧭 &lt;strong&gt;Three Architectural Responses, and Where Each One Actually Breaks Down&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AMM-native routing (Curve, Uniswap-style, bridged).&lt;/strong&gt; Prices long-tail assets well because pool math is transparent and permissionless, but this approach fragments stablecoin depth across pools by design — every new chain deployment is a new, independent pool competing for the same underlying dollar-denominated liquidity rather than adding to a shared depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bridge-fed unified pools (Stargate-style, LayerZero-messaging-based).&lt;/strong&gt; These move a genuinely shared pool's liquidity across chains rather than deploying separate pools per chain, which solves the within-asset fragmentation problem directly — but they cap out on total depth and charge for the capital being moved, and they concentrate risk into the bridge's own security model, which is precisely the systemic exposure described above.&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%2Fhbbgabb2g8wc3jucj3tl.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%2Fhbbgabb2g8wc3jucj3tl.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solver-networked, intent-based settlement (RFQ-style architectures) — where STON.fi's Omniston fits.&lt;/strong&gt; Rather than holding standing inventory in a fixed pool at all, this model matches a trade intent against whichever source — AMM, bridge, or private market maker — offers the best price at that specific moment, sourcing from multiple paradigms simultaneously instead of committing to one. Omniston is a concrete, working example of exactly this pattern on TON: it queries STON.fi's own pools, external AMMs like DeDust and TonCo, and independent RFQ resolvers all at once, then either selects the single best source or splits the trade across several. STON.fi's own measurements show this cross-DEX optimization delivering roughly 32% lower price impact compared to routing the same trade through a single source — a directly quantified instance of the industry-wide pattern described above, not just a theoretical claim. For pairs where public pools on any of the connected DEXs simply lack depth, Omniston's escrow swaps extend the same logic further, tapping private resolver liquidity that never shows up in any pool's TVL at all — the TON-specific answer to exactly the "public liquidity has a ceiling" problem this entire article is about.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚖️ &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2F9ep5fk0fq0rvszfifyn0.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%2F9ep5fk0fq0rvszfifyn0.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 TVL vs. effective depth at fixed slippage.&lt;/strong&gt; TVL answers "how much capital is deployed." Effective depth answers "how much of that capital can actually absorb my trade at an acceptable price" — and the gap between those two numbers is exactly where fragmentation hides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Within-chain vs. cross-chain fragmentation.&lt;/strong&gt; A trader who solves for cross-chain routing but ignores the ten-to-twenty competing pools for the same pair on a single chain has only solved half the problem — both layers degrade execution independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Sticky liquidity vs. mercenary liquidity.&lt;/strong&gt; Capital integrated into local DeFi primitives behaves differently under stress than capital parked purely for an emissions multiplier — the second kind is structurally the first to leave, and multi-chain expansions systematically attract more of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚔️ Concentrated bridge risk vs. distributed solver risk.&lt;/strong&gt; A bridge-fed unified pool centralizes risk into one piece of infrastructure; a solver network distributes it across many independent, competing quote-providers — a meaningfully different risk shape even when both solve the same surface-level liquidity problem.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Reduces Fragmentation's Impact
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measuring and routing by effective depth, not TVL.&lt;/strong&gt; Any system that prices its own execution quality by aggregate locked capital rather than tested depth at real trade sizes is measuring the wrong thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sourcing across paradigms simultaneously, not committing to one.&lt;/strong&gt; Solver-networked and RFQ-based approaches that check AMMs, bridges, and private market makers in parallel structurally outperform any single-paradigm approach on realized price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distinguishing sticky liquidity from mercenary liquidity when evaluating a chain's real resilience.&lt;/strong&gt; Aggregate TVL growth driven primarily by emissions is a leading indicator of future fragility, not current strength.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More chains does not mean more usable liquidity by default.&lt;/strong&gt; Aggregate TVL can double while effective, tradeable depth on any single venue outside the primary one actually deteriorates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bridges solve price convergence, not liquidity depth.&lt;/strong&gt; Arbitrage can keep prices aligned across fragmented pools without ever making any individual pool deeper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bridge-concentrated TVL is a systemic risk factor, not just an efficiency question.&lt;/strong&gt; With more value now sitting in bridge infrastructure than in lending or liquid staking combined, a single major exploit has correspondingly wider blast radius.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;Liquidity fragmentation across chains isn't solved by adding more chains, and it isn't accurately measured by aggregate TVL — it's a structural consequence of isolated pool math compounding across both protocols within a chain and chains within an ecosystem, worsened by mercenary capital that arrives for incentives and leaves with them, and further complicated by the fact that the infrastructure built to connect fragmented liquidity has itself become one of DeFi's largest concentrated risk surfaces. STON.fi's Omniston layer is a working, measured example of the architecture actually making progress on this: not by consolidating TON's liquidity into one bigger pool, but by querying STON.fi's own pools, DeDust, TonCo, and private resolver liquidity simultaneously on every trade, and routing — or splitting — accordingly. Fragmentation didn't get solved by fewer chains or fewer pools. On TON specifically, it got routed around.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Blog — "Cross-DEX Swaps via Omniston" (measured 32% lower price impact) — &lt;a href="https://blog.ston.fi/cross-dex-swaps-via-ton/" rel="noopener noreferrer"&gt;https://blog.ston.fi/cross-dex-swaps-via-ton/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston Protocol Overview (multi-source RFQ architecture) — &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Spark — "Liquidity Fragmentation" Glossary Entry — &lt;a href="https://www.spark.money/glossary/liquidity-fragmentation" rel="noopener noreferrer"&gt;https://www.spark.money/glossary/liquidity-fragmentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Medium, Ice ❄️ — "Multi-Chain Liquidity: Expansion or Fragmentation? A Field Perspective" — &lt;a href="https://ice0913.medium.com/multi-chain-liquidity-expansion-or-fragmentation-a-field-perspective-bcc7ae5ca3bb" rel="noopener noreferrer"&gt;https://ice0913.medium.com/multi-chain-liquidity-expansion-or-fragmentation-a-field-perspective-bcc7ae5ca3bb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CoinLaw — "DeFi Market Statistics 2026: TVL, Chains &amp;amp; DEXs" — &lt;a href="https://coinlaw.io/decentralized-finance-market-statistics/" rel="noopener noreferrer"&gt;https://coinlaw.io/decentralized-finance-market-statistics/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Eco — "Top Cross-Chain Liquidity Protocols for 2026" — &lt;a href="https://eco.com/support/en/articles/11776421-top-cross-chain-liquidity-protocols-for-2026" rel="noopener noreferrer"&gt;https://eco.com/support/en/articles/11776421-top-cross-chain-liquidity-protocols-for-2026&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Symbiosis — "How DeFi Works Now: 2026 Tech Stack Explained" — &lt;a href="https://symbiosis.finance/blog/defi-in-2025-2026-what-changed-technically" rel="noopener noreferrer"&gt;https://symbiosis.finance/blog/defi-in-2025-2026-what-changed-technically&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CryptoDaily — "Stablecoin Liquidity Explained: Why Custom Tokens Fragment" — &lt;a href="https://cryptodaily.co.uk/2026/07/stablecoin-liquidity-custom-tokens-fragment" rel="noopener noreferrer"&gt;https://cryptodaily.co.uk/2026/07/stablecoin-liquidity-custom-tokens-fragment&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on publicly available industry data and analysis as of mid-2026. TVL, slippage, and depth figures shift constantly with market conditions — always verify current numbers directly on DeFiLlama or the relevant protocol before making decisions involving real funds.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>web3</category>
      <category>lowcode</category>
      <category>ai</category>
    </item>
    <item>
      <title>Ecosystem Map: How STON.fi, Omniston, and xStocks Connect on TON</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Fri, 21 Aug 2026 11:24:41 +0000</pubDate>
      <link>https://dev.to/web3kd/ecosystem-map-how-stonfi-omniston-and-xstocks-connect-on-ton-30kh</link>
      <guid>https://dev.to/web3kd/ecosystem-map-how-stonfi-omniston-and-xstocks-connect-on-ton-30kh</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Ecosystem Map: How STON.fi, Omniston, and xStocks Connect on TON&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Three names get mentioned together constantly in TON DeFi conversations, and it's easy to assume they're roughly interchangeable — different marketing terms for the same underlying thing. They're not. Each one is a genuinely distinct layer, and understanding where one ends and the next begins is the difference between a surface-level impression of "TON has DeFi and stocks now" and actually understanding the architecture connecting them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "STON.fi technically integrates the last step. It does not issue the product, does not hold the legacy instruments, and does not run the custody; it surfaces the on-chain jetton and routes swaps around it." &lt;em&gt;— STON.fi Blog, "How xStocks Actually Work"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 &lt;strong&gt;&lt;em&gt;Three Layers, Three Different Jobs&lt;/em&gt;&lt;/strong&gt;
&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%2Fzeei57ihuqv8u4o6t1yc.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%2Fzeei57ihuqv8u4o6t1yc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎫 &lt;strong&gt;STON.fi&lt;/strong&gt; is the trading surface — the AMM, the app, the interface where swaps, liquidity provision, farming, and staking actually happen&lt;/li&gt;
&lt;li&gt;🏷️ &lt;strong&gt;Omniston&lt;/strong&gt; is the routing and liquidity-sourcing layer underneath STON.fi — it decides where a trade actually gets filled, whether that's a public pool, another DEX, or private resolver liquidity&lt;/li&gt;
&lt;li&gt;🪧 &lt;strong&gt;xStocks&lt;/strong&gt; is an asset category, not a protocol at all — tokenized real-world equities that happen to be tradeable through STON.fi, routed by Omniston, but issued and backed by an entirely separate, regulated entity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The relationship isn't three peers. It's a stack: an asset class (xStocks) flows through a routing engine (Omniston) that surfaces inside a trading interface (STON.fi). Each layer can be understood independently, but the interesting part is exactly where they connect.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where xStocks Actually Come From Before They Ever Reach TON&lt;/strong&gt;
&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%2F8nihpm5lan4vbwldms9a.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%2F8nihpm5lan4vbwldms9a.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's tempting to think of an xStock as something STON.fi created. It didn't — and tracing the actual path clarifies what STON.fi's role really is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "Traditional asset → regulated product → bToken on an origin chain → wrapped representation on TON → xStock jetton you see in your wallet." &lt;em&gt;— STON.fi Blog&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;xStocks are issued by Backed Finance, a regulated entity that holds the actual underlying equities — real shares of Apple, Tesla, Nvidia, and others — through licensed custodians. Backed mints a blockchain-native representation of that holding, originally on an EVM chain, which then gets wrapped into a TON-native jetton. By the time an xStock shows up as AAPLx or TSLAx in a TON wallet, it's already passed through several steps of regulated tokenization that have nothing to do with STON.fi at all. STON.fi's actual job starts at the very last step: making that jetton tradeable.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧬 &lt;strong&gt;How Omniston Specifically Had to Adapt for xStocks&lt;/strong&gt;
&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%2Fa8c300prtrdusx2bxwur.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%2Fa8c300prtrdusx2bxwur.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the part that actually reveals how these layers connect technically, not just conceptually.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "The harder challenge was liquidity: unlike established crypto pairs, xStocks don't yet have deep AMM pools across pairs. Technically, AMM support is there. But we also introduced an additional execution path — escrow swaps — so users can access deeper liquidity. Today, most xStocks volume executes through escrow." &lt;em&gt;— Fedorov, STON.fi team, via BeInCrypto&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;xStocks behave like any other TON jetton technically, but they don't yet have the deep, organic AMM liquidity that established crypto pairs have built up over time. Omniston's answer wasn't to force xStocks trades through thin public pools — it was to lean on escrow swaps, the same private-resolver liquidity mechanism built to solve liquidity gaps generally, now handling the majority of actual xStocks trading volume. This is a concrete example of one layer (Omniston) adapting specifically to support a new asset category (xStocks) surfacing through the trading layer (STON.fi) — the connection isn't abstract, it's a real routing decision happening on real trades.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🏦 &lt;strong&gt;The Full Map, Layer by Layer&lt;/strong&gt;
&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%2Fxp5o2ri9a37x6pphz3k0.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%2Fxp5o2ri9a37x6pphz3k0.png" alt=" " width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪙 Issuance and custody — outside the TON stack entirely&lt;/strong&gt; Backed Finance holds the actual underlying equities through regulated custodians and mints the tokenized representation. Kraken provides institutional validation. Neither of these entities is part of STON.fi or Omniston — they're the foundation the whole thing rests on, sitting entirely outside TON's technical stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧾 Token standard — where regulation meets on-chain mechanics&lt;/strong&gt; xStocks follow the TON jetton standard for basic transfers and wallet compatibility, but specifically use Scaled UI Jettons (TEP-526) — a standard that lets a token's displayed balance reflect a scaling factor over time, used here to represent accumulated dividend value without STON.fi itself distributing any dividends directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎫 STON.fi — the trading surface&lt;/strong&gt; A dedicated page at ston.fi/xstocks lets eligible users swap TON or USDT directly for xStocks like AAPLx, TSLAx, NVDAx, GOOGLx, AMZNx, and broader index exposure. Once acquired, xStocks behave like any other jetton — they can be held, used in other TON DeFi applications, or provided as liquidity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏷️ Omniston — the routing decision underneath every xStocks trade&lt;/strong&gt; Because AMM depth for xStocks pairs is still thin, Omniston evaluates both public pool liquidity and private resolver-priced liquidity for every xStocks trade, routing through whichever actually delivers a better realized price — which in practice means escrow swaps carry most of the real volume today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪧 Wallets and Telegram — the distribution layer on top of all of it&lt;/strong&gt; Because xStocks comply with the jetton standard, they're automatically recognized by TON-native wallets — TON Wallet, Tonkeeper, MyTONWallet — including the wallet built directly into Telegram, meaning the full stack described above ultimately surfaces inside an app hundreds of millions of people already have open daily.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧑‍💻 &lt;strong&gt;What the Connection Between These Layers Actually Looks Like in Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since the interesting part of this map is a real routing decision, not just a diagram, it's worth seeing what that decision looks like from a developer's side. The snippets below are illustrative, written in the style of STON.fi's documented SDK patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requesting a quote for an xStock behaves identically to any other jetton&lt;/strong&gt; — the trading surface (STON.fi) doesn't need special-case code, because the asset category difference is invisible at this layer:&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;Omniston&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;settlementMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-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;omniston&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;Omniston&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://omni-ws.ston.fi&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rfqId&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="nx"&gt;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;quoteRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...usdt_jetton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...aaplx_jetton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// an xStock&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;settlementMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;settlementMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Swap&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;&lt;strong&gt;Where the layers actually diverge is inside the quote response itself&lt;/strong&gt; — this is the concrete, code-level evidence of Omniston's routing adaptation for thin-liquidity assets like xStocks:&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;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rfqId&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&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="nx"&gt;event&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="s1"&gt;quoteUpdated&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Settlement source:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&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;span class="nx"&gt;settlementSource&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// For an established crypto pair, this is often 'amm_pool'&lt;/span&gt;
    &lt;span class="c1"&gt;// For most xStocks pairs today, this commonly resolves to 'escrow_resolver'&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;strong&gt;Detecting the TEP-526 scaling factor on an xStock jetton&lt;/strong&gt;, relevant if a wallet or app wants to display accumulated dividend value correctly rather than a raw balance:&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;getDisplayBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jettonWalletAddress&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;jettonData&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;runMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jettonWalletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get_wallet_data&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;rawBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jettonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&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;scalingFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jettonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scalingFactor&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="c1"&gt;// TEP-526, defaults to 1 for non-scaled jettons&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rawBalance&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scalingFactor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// what the user should actually see&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing in the first snippet knows or cares that it's trading an xStock — that's the point. The routing and scaling differences live entirely inside Omniston's decision logic and the token's own metadata, not in application-level branching a developer has to write themselves.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2F39ylhkrz3sbg9kvydvw4.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%2F39ylhkrz3sbg9kvydvw4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 What STON.fi controls vs. what it doesn't.&lt;/strong&gt; STON.fi controls the trading interface and the on-chain swap mechanics. It doesn't control issuance, custody, regulatory compliance, or the underlying equity itself — that entire layer belongs to Backed Finance, independently of anything happening on TON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Crypto-native pairs vs. xStocks pairs, at the routing level.&lt;/strong&gt; A deep, established crypto pair might resolve almost entirely through public AMM pools. An xStocks pair, at least currently, resolves mostly through escrow — a genuinely different routing outcome for a genuinely different liquidity situation, decided automatically by the same underlying Omniston logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Traditional market hours vs. on-chain availability.&lt;/strong&gt; Once tokenized, an xStock trades whenever TON itself is live — 24/7, independent of when the underlying equity's home exchange is actually open, which is a structural difference from the asset it represents, not just a convenience feature.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Connects These Three Layers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A shared token standard, not shared ownership.&lt;/strong&gt; xStocks work inside STON.fi because they follow TON's jetton standard, not because STON.fi issues or controls them in any way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omniston adapting its routing logic for a new asset category.&lt;/strong&gt; The rise in escrow-swap usage for xStocks is a direct, measurable consequence of a new asset type surfacing through the existing routing engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet-level recognition tying the whole stack to actual distribution.&lt;/strong&gt; Because of jetton-standard compliance, the entire chain — from regulated custody to a TON swap — ends up one tap away inside apps people already use daily, including Telegram.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi is not the issuer of xStocks, and doesn't hold the underlying equities.&lt;/strong&gt; That responsibility sits entirely with Backed Finance and its regulated custodians.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most xStocks liquidity today runs through escrow, not public AMM pools.&lt;/strong&gt; This is a current state of a growing asset category, not a permanent architectural limitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xStocks are not available to all users.&lt;/strong&gt; Eligibility restrictions apply, and prospective users should check current terms directly rather than assume universal access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;STON.fi, Omniston, and xStocks aren't three versions of the same thing — they're three layers of one connected stack, each doing a genuinely different job. Backed Finance and its custodians handle issuance and regulatory backing, entirely outside TON. Omniston handles the routing decision for every trade, adapting its own liquidity strategy specifically because xStocks arrived with a different liquidity profile than crypto-native pairs. STON.fi surfaces all of it as an actual tradeable interface, one that jetton-standard compliance then makes visible inside wallets — including Telegram's — that people already have open. Understanding the map means understanding that "STON.fi has stocks now" is really shorthand for a much more layered, cross-entity system working together underneath one interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Blog — "How xStocks Actually Work: From Real-World Asset to TON Jetton" — &lt;a href="https://blog.ston.fi/how-xstocks-actually-work-from-real-world-asset-to-ton-jetton/" rel="noopener noreferrer"&gt;https://blog.ston.fi/how-xstocks-actually-work-from-real-world-asset-to-ton-jetton/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Blog — "xStocks: Explore Tokenized Market" — &lt;a href="https://blog.ston.fi/xstocks-explore-tokenized-market/" rel="noopener noreferrer"&gt;https://blog.ston.fi/xstocks-explore-tokenized-market/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — xStocks Trading Page — &lt;a href="https://ston.fi/xstocks" rel="noopener noreferrer"&gt;https://ston.fi/xstocks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Blog — "xStocks Are Live on TON: Real-World Stocks, Now On-Chain" — &lt;a href="https://blog.ton.org/x-stocks-are-live-on-ton-real-world-stocks-now-on-chain" rel="noopener noreferrer"&gt;https://blog.ton.org/x-stocks-are-live-on-ton-real-world-stocks-now-on-chain&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BeInCrypto — "How STON.fi's Omniston Scaled DeFi on TON" (escrow model for xStocks, direct team quotes) — &lt;a href="https://beincrypto.com/stonfi-omniston-scaling-lessons/" rel="noopener noreferrer"&gt;https://beincrypto.com/stonfi-omniston-scaling-lessons/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's and TON's public documentation and announcements as of mid-2026. Asset availability, eligibility requirements, and routing behavior evolve as the ecosystem grows — always verify current details directly on ston.fi and docs.ston.fi before making decisions involving real funds.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>web3</category>
    </item>
    <item>
      <title>Testing for Failed Transactions: A Builder's Checklist for STON.fi Integrations</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Fri, 21 Aug 2026 10:29:26 +0000</pubDate>
      <link>https://dev.to/web3kd/testing-for-failed-transactions-a-builders-checklist-for-stonfi-integrations-2b7l</link>
      <guid>https://dev.to/web3kd/testing-for-failed-transactions-a-builders-checklist-for-stonfi-integrations-2b7l</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Testing for Failed Transactions: A Builder's Checklist for STON.fi Integrations&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Most integration bugs don't show up in code review. They show up in production, as a transaction that "just failed," with an exit code the team has to look up and a user asking why their swap didn't go through. This checklist exists to catch those failures before they ship — with the actual exit codes, the actual sandbox environment, and real failure patterns pulled from genuine integration issues developers have hit building on STON.fi.&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%2Fnr6280zwru4e0nglfr68.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%2Fnr6280zwru4e0nglfr68.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "For most integrations, we recommend using our Node.js SDK or React SDK. The SDKs handle WebSocket connections, quote streaming, transaction building, and error handling automatically." &lt;em&gt;— STON.fi, Omniston Swap Overview documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧯 &lt;strong&gt;&lt;em&gt;Start With the Environment You're Actually Testing Against&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before writing a single test case, confirm which endpoint your code is hitting. This sounds obvious and is still the source of a surprising number of "why did this work yesterday" bugs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1️⃣ &lt;strong&gt;Production:&lt;/strong&gt; &lt;code&gt;wss://omni-ws.ston.fi&lt;/code&gt; — real liquidity, real funds, real consequences for a bad transaction&lt;/li&gt;
&lt;li&gt;2️⃣ &lt;strong&gt;Sandbox:&lt;/strong&gt; &lt;code&gt;wss://omni-ws-sandbox.ston.fi&lt;/code&gt; — explicitly documented as for development and testing only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running integration tests against production because the sandbox URL wasn't configured is a completely avoidable failure mode, and it's worth a dedicated environment-variable check in CI specifically to catch it before any test suite runs.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Exit Codes Worth Knowing Before You Debug Blind&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When a transaction fails on TON, it returns a numeric exit code — and knowing what a handful of the common ones actually mean turns a mystery failure into a five-minute fix.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "If all funds of the inbound message have already been consumed and there are not enough funds to pay for the failed action... an error with exit code 37 is thrown: Not enough GRAMs." &lt;em&gt;— TON Docs, TVM Exit Codes reference&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Exit Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Typical Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;Invalid action list&lt;/td&gt;
&lt;td&gt;A malformed or exotic cell in the action list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;Not enough GRAMs&lt;/td&gt;
&lt;td&gt;Insufficient TON to cover the action's cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;Not enough extra currencies&lt;/td&gt;
&lt;td&gt;Insufficient balance of a non-TON currency the action needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;Outbound message doesn't fit into a cell&lt;/td&gt;
&lt;td&gt;The message payload exceeds TON's cell size limits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These aren't hypothetical — real developers integrating STON.fi's SDK have hit specific exit codes like 11 and 709 in production issues, tracing back to jetton wallet address resolution and reverse-swap parameter mistakes respectively. Logging the raw exit code, not just "transaction failed," is the single highest-leverage change most integrations can make to their error handling.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🩹 &lt;strong&gt;The Checklist: Failure Modes to Actually Test For&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;3️⃣ Test with &lt;code&gt;minAskAmount&lt;/code&gt; set to zero, deliberately, once.&lt;/strong&gt; This is a real mistake pulled directly from a public integration issue — a developer building a swap left &lt;code&gt;minAskAmount: 0&lt;/code&gt;, which means no slippage protection exists at all. Test this scenario specifically to confirm your own code never ships with this default, since a zero minimum will "succeed" a transaction that delivers almost nothing back.&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;// ❌ Never ship this — no slippage protection at all&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;buildSwapJettonTxParams&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// any price gets accepted&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Always derive a real minimum from your slippage tolerance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minAskAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateMinAskAmount&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;span class="nx"&gt;askAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slippageBps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4️⃣ Test insufficient gas explicitly.&lt;/strong&gt; A swap transaction needs enough TON reserved to cover network fees on top of the trade itself. Write a test that intentionally underfunds the gas amount and confirms your app surfaces exit code 37 clearly, rather than a generic failure message.&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;testInsufficientGas&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="nf"&gt;sendSwap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;validParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gasAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// too low&lt;/span&gt;
  &lt;span class="nf"&gt;expect&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;exitCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&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;userMessage&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/insufficient.*gas/i&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;strong&gt;5️⃣ Test reverse-swap parameter direction.&lt;/strong&gt; A real, documented issue came from treating a reverse swap (jetton-to-TON) as identical to a regular swap with &lt;code&gt;askJettonAddress&lt;/code&gt; simply swapped to a proxy TON address — this produced exit code 709 for at least one developer. If your integration supports both directions, test each direction as a genuinely separate code path, not a parameter flip on the same function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6️⃣ Test a stale or expired quote.&lt;/strong&gt; Simulate a delay between requesting a quote and submitting the transaction, long enough that the quote should reasonably be considered outdated. Confirm your integration re-requests rather than blindly submitting stale terms.&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;testStaleQuote&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;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rfqId&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="nf"&gt;getQuote&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// simulate user hesitation&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="nf"&gt;executeSwap&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;span class="nx"&gt;rfqId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Expect either a fresh re-quote or a clean, explicit failure —&lt;/span&gt;
  &lt;span class="c1"&gt;// never a silent execution against 60-second-old terms&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refreshed&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="s1"&gt;expired&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;toContain&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;status&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;/p&gt;

&lt;h3&gt;
  
  
  🔎 &lt;strong&gt;Verifying the Failure Path, Not Just the Success Path&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A transaction that fails cleanly and refunds correctly is a successful outcome from a testing standpoint — it's the failures that fail &lt;em&gt;silently&lt;/em&gt; or &lt;em&gt;incorrectly&lt;/em&gt; that actually cause damage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "(Optional) The address where funds should be returned if the transaction fails. If not specified, funds are returned to the sender's wallet." &lt;em&gt;— STON.fi, Omniston Swap Overview documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test both branches of this explicitly:&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refund handling&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns funds to sender when refundAddress is omitted&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="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;result&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;simulateFailedSwap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;refundAddress&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="nf"&gt;expect&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;refundedTo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;senderWallet&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns funds to the specified refundAddress when set&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="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;result&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;simulateFailedSwap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;refundAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customAddress&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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;refundedTo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customAddress&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;Skipping this test specifically is how teams discover, in production, that an edge case in their refund logic sent funds somewhere unexpected — exactly the kind of bug that's cheap to catch in sandbox and expensive to discover after a real user reports missing funds.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🛡️ &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2F279dr9tk7u6n4mgdkhax.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%2F279dr9tk7u6n4mgdkhax.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 SDK-handled errors vs. low-level protocol errors.&lt;/strong&gt; STON.fi's own documentation is explicit that the Node.js and React SDKs handle error handling automatically for most integrations — testing at the low-level WebSocket protocol layer is only necessary if you've deliberately opted out of that abstraction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Sandbox coverage vs. production monitoring.&lt;/strong&gt; Sandbox testing catches logic errors before deployment; it doesn't replace production monitoring for exit codes appearing at real volume, since some failure conditions — like transient network congestion — are difficult to reproduce reliably in a test environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Synchronous failures vs. timing-dependent failures.&lt;/strong&gt; A malformed parameter fails immediately and predictably. A stale quote or a race between simulation and execution only fails under specific timing conditions, which is exactly why deliberate delay-based tests matter more than they might seem to.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What a Genuinely Solid Test Suite Covers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every documented exit code your integration is likely to hit&lt;/strong&gt;, logged with enough context to debug without re-running the transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both refund paths&lt;/strong&gt; — default sender refund and an explicitly specified &lt;code&gt;refundAddress&lt;/code&gt; — verified independently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At least one deliberately broken test per parameter that guards user funds&lt;/strong&gt;, especially &lt;code&gt;minAskAmount&lt;/code&gt;, since a silent zero-default is a real, documented failure mode.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A generic "transaction failed" message is a testing gap, not a UI limitation.&lt;/strong&gt; The exit code is available; surfacing it (or a translation of it) is a choice, not a constraint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox and production are genuinely separate environments, not a toggle on the same endpoint.&lt;/strong&gt; Confirm which one every test run is actually targeting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real GitHub issues are a legitimate test-case source.&lt;/strong&gt; Public integration problems other developers have hit are, functionally, a pre-written regression test suite for exactly the mistakes worth guarding against.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;Testing for failed transactions on STON.fi isn't about imagining hypothetical edge cases — it's about deliberately reproducing the specific, documented failure modes that real integrations have already hit: zero-slippage-protection defaults, insufficient gas, reverse-swap parameter mix-ups, stale quotes, and untested refund paths. A checklist built from real exit codes and real reported issues catches these before a user does, which is the entire point of testing a payment-adjacent integration in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TON Docs — TVM Exit Codes Reference — &lt;a href="https://docs.ton.org/v3/documentation/tvm/exit-codes" rel="noopener noreferrer"&gt;https://docs.ton.org/v3/documentation/tvm/exit-codes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston Swap Overview (sandbox/production endpoints, refundAddress) — &lt;a href="https://docs.ston.fi/developer-section/omniston/swap/overview" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/swap/overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi SDK — GitHub Issues (real reported integration failures) — &lt;a href="https://github.com/ston-fi/sdk/issues" rel="noopener noreferrer"&gt;https://github.com/ston-fi/sdk/issues&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — React Swap Quickstart Guide — &lt;a href="https://docs.ston.fi/developer-section/quickstart/swap" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/quickstart/swap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — SDK v2 Swap Documentation — &lt;a href="https://docs.ston.fi/developer-section/dex/sdk/v2/swap" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/dex/sdk/v2/swap&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's public developer documentation, TON's official exit code reference, and publicly reported integration issues as of mid-2026. Exit codes, SDK behavior, and endpoints evolve as the protocol ships updates — always verify current details directly on docs.ston.fi before shipping a production integration.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How the Best Price Actually Gets Found: A Technical Breakdown of Omniston's Quote-Sourcing Engine</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:48:49 +0000</pubDate>
      <link>https://dev.to/web3kd/how-the-best-price-actually-gets-found-a-technical-breakdown-of-omnistons-quote-sourcing-engine-5enn</link>
      <guid>https://dev.to/web3kd/how-the-best-price-actually-gets-found-a-technical-breakdown-of-omnistons-quote-sourcing-engine-5enn</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;How the Best Price Actually Gets Found: A Technical Breakdown of Omniston's Quote-Sourcing Engine&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Ask "what's the best price for this swap?" and most DEXs answer by reading one number off one pool. Omniston, STON.fi's routing layer, answers that question by running an entire sourcing architecture underneath a single request — querying multiple, structurally different kinds of liquidity at once and comparing what comes back. This piece breaks down that architecture: not the marketing pitch, but the actual layers and data flow behind "best price."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "Omniston is STON.fi's aggregation layer that finds best rates by combining on-chain liquidity sources and RFQ resolvers." &lt;em&gt;— STON.fi developer documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 &lt;strong&gt;&lt;em&gt;The Two Fundamentally Different Kinds of Liquidity Being Queried&lt;/em&gt;&lt;/strong&gt;
&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%2Fs2ovufx8k0uzmhdarejx.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%2Fs2ovufx8k0uzmhdarejx.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The architecture isn't querying one type of source multiple times — it's querying two genuinely different kinds of liquidity, each with its own logic, and comparing across them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧿 &lt;strong&gt;On-chain AMM pools.&lt;/strong&gt; STON.fi's own pools, plus external TON AMMs like DeDust and TonCo, priced by their own constant-product or stableswap curves, readable directly from on-chain reserves.&lt;/li&gt;
&lt;li&gt;🔱 &lt;strong&gt;RFQ resolvers.&lt;/strong&gt; Independent market makers who don't have a fixed public pool at all — they respond to a specific request with a price they're personally willing to honor, decided fresh each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't competing implementations of the same idea. An AMM pool's price is a deterministic function of its current reserves — anyone can calculate it. A resolver's quote is a decision, informed by inventory and risk appetite, that doesn't exist until it's actually asked for. Sourcing "the best quote" means comparing a calculation against a decision, in real time, and that's a meaningfully harder problem than just checking which of several static numbers is bigger.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why a Single Integration Point Matters More Than It Sounds&lt;/strong&gt;
&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%2F8szvwf5yosqzrt4q9gr2.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%2F8szvwf5yosqzrt4q9gr2.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It would be easy to assume "aggregation" just means "check several places and pick the best." The harder engineering problem is that these sources don't share a common interface on their own — a DEX pool and an independent resolver don't naturally speak the same protocol.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "Omniston connects to multiple DEXs and RFQ resolvers, allowing users to access a wide range of liquidity sources through a single integration point." &lt;em&gt;— independent Omniston protocol breakdown, 2025&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That single integration point is doing real translation work: normalizing an on-chain pool read and an off-chain-adjacent resolver's signed quote into one comparable format, so a developer building on top of STON.fi never has to write separate logic for "if it's a pool" versus "if it's a resolver." That abstraction is a meaningful part of what "RFQ architecture" actually refers to — not just the request-for-quote handshake itself, but the whole normalization layer sitting behind it.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔭 &lt;strong&gt;The Architecture, Layer by Layer&lt;/strong&gt;
&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%2Fh3lzhuvyg3hgil1bg9cv.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%2Fh3lzhuvyg3hgil1bg9cv.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧰 The client-facing layer&lt;/strong&gt; A trader or an integrated app sends one swap request through the SDK or API — one call, regardless of how many sources ultimately get queried underneath it. This layer's whole job is hiding the complexity of everything below it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛎️ The RFQ core&lt;/strong&gt; This is the coordination layer: it receives the request, assigns it a unique &lt;code&gt;rfq_id&lt;/code&gt;, and fans it out to every connected source simultaneously — both triggering fresh reads from AMM pools and broadcasting the request to resolvers over their open gRPC streams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪝 The resolver network&lt;/strong&gt; A distributed set of independent market makers, each running their own service, each deciding independently what to offer for that specific request. Nothing here is centrally controlled — the RFQ core is a coordinator, not a price-setter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚜️ On-chain pool readers&lt;/strong&gt; In parallel with the resolver broadcast, the same request triggers a read against connected AMM pools' current reserves — STON.fi's own v1 and v2 pools, plus external pools like DeDust and TonCo — calculating what each would offer for that exact trade size right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎗️ The comparison and selection engine&lt;/strong&gt; Once responses come back from both categories of source, this layer evaluates them together — price, but also depth and reliability — and either selects a single winning source or constructs a split route across several, depending on what actually produces the best outcome for that specific trade.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧑‍💻 &lt;strong&gt;What the Sourcing Layer Actually Looks Like in Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since this is genuinely an engineering architecture underneath the trading language, it's worth seeing the real shape of it. The snippets below are illustrative — written in the style of STON.fi's documented SDK patterns, simplified for clarity rather than copied verbatim from the official docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One request, fanned out to two source types in parallel:&lt;/strong&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Omniston&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;settlementMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-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;omniston&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;Omniston&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://omni-ws.ston.fi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// A single call — the fan-out to pools and resolvers happens underneath this&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;rfqId&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="nx"&gt;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;quoteRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...offer_jetton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...ask_jetton&lt;/span&gt;&lt;span class="dl"&gt;'&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;settlementMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;settlementMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Swap&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;&lt;strong&gt;Inside the RFQ core, roughly what's happening on receipt of that request:&lt;/strong&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleQuoteRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QuoteRequest&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;RfqId&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;rfqId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateRfqId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Two structurally different source types, queried in parallel&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;poolQuotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolverQuotes&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="nf"&gt;readAmmPoolReserves&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// deterministic — calculated from on-chain state&lt;/span&gt;
    &lt;span class="nf"&gt;broadcastToResolvers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rfqId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// decision-based — awaits live responses&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;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalizeQuotes&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;poolQuotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;resolverQuotes&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;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;selectBestRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// single winner, or a split across several&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rfqId&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;strong&gt;Normalizing two genuinely different quote shapes into one comparable format:&lt;/strong&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;normalizeQuotes&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PoolReserveRead&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ResolverResponse&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;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;raw&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;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reserves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pool&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;askAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calcConstantProductOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reserves&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resolver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;askAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotedAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxFillSize&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;That normalization step is the actual engineering core of "RFQ architecture" — a pool read and a resolver's signed response start out as two incompatible shapes, and everything downstream (comparison, routing, splitting) depends on collapsing them into one interface first.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧰 &lt;strong&gt;Cross-Chain Adds a Third Dimension Entirely&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Same-chain sourcing is already a two-source comparison problem. Cross-chain sourcing adds settlement architecture into the same decision.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "Omniston uses the same RFQ flow for both TON and cross-chain swaps... cross-chain settlement is handled through HTLC-based atomic swaps." &lt;em&gt;— STON.fi, Omniston Protocol documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a cross-chain request, the sourcing engine isn't just asking "who has the best price" — it's asking that question &lt;em&gt;and&lt;/em&gt; factoring in which resolvers can actually settle safely across two separate blockchains. A resolver quoting a cross-chain leg has to be able to lock destination-side assets in an HTLC, paired against the trader's source-side lock, sharing the same cryptographic condition. The "best quote" for a cross-chain trade is filtered, from the start, to resolvers capable of that settlement guarantee — not just whoever happens to quote the tightest number.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔭 &lt;strong&gt;Comparing on the Dimensions That Actually Matter&lt;/strong&gt;
&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%2Ffbmp8qedv5pcnseraaa2.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%2Ffbmp8qedv5pcnseraaa2.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💧 Deterministic sources vs. decision-based sources.&lt;/strong&gt; An AMM pool's price can be calculated by anyone with reserve data; a resolver's quote is a live decision that only exists once requested. The architecture has to treat these as genuinely different categories of input, not variations on the same thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧭 Single-source lookup vs. normalized multi-source comparison.&lt;/strong&gt; Without a shared integration layer, comparing a pool's calculated price against a resolver's signed quote would require bespoke logic for every source added. The RFQ core exists specifically to remove that burden from anyone building on top of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ Same-chain sourcing vs. cross-chain sourcing.&lt;/strong&gt; Same-chain sourcing is purely a pricing comparison. Cross-chain sourcing is a pricing comparison filtered by settlement capability — a resolver can't win a cross-chain quote it can't actually settle safely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚖️ Single winner vs. split route.&lt;/strong&gt; The sourcing engine doesn't default to picking one winner — if splitting a trade across several sources genuinely produces a better blended outcome, that becomes the selected route instead.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Makes This Sourcing Architecture Work
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Two structurally different source types, compared on equal footing.&lt;/strong&gt; Deterministic pool math and live resolver decisions get normalized into one comparable format rather than handled as separate systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single coordination layer removes integration burden.&lt;/strong&gt; Anyone building on top of STON.fi queries one interface, not a growing list of bespoke connections to individual pools and market makers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain quotes are pre-filtered by settlement capability.&lt;/strong&gt; A resolver can't win a cross-chain trade it can't actually settle atomically, which protects the trader before price even enters the comparison.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Best quote" isn't always a single winner.&lt;/strong&gt; The architecture is equally capable of returning a split route when that genuinely beats any single source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolver quotes are decisions, not standing offers.&lt;/strong&gt; A quote reflects that resolver's willingness at that specific moment — it isn't a permanent price sitting on a shelf.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain sourcing carries a narrower pool of eligible resolvers by design.&lt;/strong&gt; That's a safety filter, not a limitation — capability to settle safely comes before price in that specific comparison.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;Sourcing the best quote isn't a single lookup — it's an architecture running two structurally different comparison problems in parallel: deterministic pool math on one side, live resolver decisions on the other, normalized through a shared coordination layer and, for cross-chain trades, filtered by settlement capability before price ever enters the picture. Understanding that architecture is the difference between assuming "best price" means "checked a few extra pools" and seeing it for what it actually is — a real-time comparison engine built specifically because those source types were never going to be comparable on their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi — Omniston Protocol Overview — &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — How to Become a Resolver (RFQ flow, gRPC API) — &lt;a href="https://docs.ston.fi/developer-section/omniston/resolvers/guide" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/resolvers/guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Blog — "Cross-Chain Portfolio Rebalancing: How HTLC and RFQ Swaps Work" — &lt;a href="https://blog.ston.fi/cross-chain-portfolio-rebalancing-how-htlc-and-rfq-swaps-work-for-defi-users/" rel="noopener noreferrer"&gt;https://blog.ston.fi/cross-chain-portfolio-rebalancing-how-htlc-and-rfq-swaps-work-for-defi-users/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Docs — Introduction (AMM and Omniston overview) — &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Medium, Web3King — "Omniston by STON.fi: Revolutionizing Liquidity Aggregation, pt. 2" — &lt;a href="https://medium.com/@web3king/omniston-by-ston-fi-revolutionizing-liquidity-aggregation-on-the-ton-blockchain-pt2-748db5057f6c" rel="noopener noreferrer"&gt;https://medium.com/@web3king/omniston-by-ston-fi-revolutionizing-liquidity-aggregation-on-the-ton-blockchain-pt2-748db5057f6c&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's public developer documentation as of mid-2026. Architecture details and supported protocols evolve as the system ships updates — always verify current functionality directly on docs.ston.fi before making decisions involving real funds.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>python</category>
    </item>
    <item>
      <title>The Hidden Auction Behind Every Quote: How Resolver Competition Actually Sets Your Price</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:07:20 +0000</pubDate>
      <link>https://dev.to/web3kd/the-hidden-auction-behind-every-quote-how-resolver-competition-actually-sets-your-price-1m8a</link>
      <guid>https://dev.to/web3kd/the-hidden-auction-behind-every-quote-how-resolver-competition-actually-sets-your-price-1m8a</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;The Hidden Auction Behind Every Quote: How Resolver Competition Actually Sets Your Price&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Every time someone requests a quote on STON.fi through Omniston, something closer to a live auction happens than a lookup. A group of independent market makers — resolvers — get notified simultaneously, and they compete, in real time, for the right to fill that specific order. Most traders never see this happen. This piece looks at the actual mechanics of that competition, not the marketing shorthand of "best price guaranteed."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "A resolver is a service that provides token exchange rates and executes trades... when a trader sends a quote request, they will first receive a QuoteRequestAck containing the rfq_id that uniquely identifies their request." &lt;em&gt;— STON.fi, "How to Become a Resolver" documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🎪 &lt;strong&gt;&lt;em&gt;Why This Is Genuinely an Auction, Not a Price Feed&lt;/em&gt;&lt;/strong&gt;
&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%2Fizcsj7anmf55mrrjv7s4.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%2Fizcsj7anmf55mrrjv7s4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The distinction matters more than it sounds. A price feed is passive — one number, updated periodically, the same for everyone who checks it. What Omniston runs instead is active and request-specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⬢ A trader's quote request gets broadcast to every connected resolver simultaneously, not looked up from a shared table&lt;/li&gt;
&lt;li&gt;⬡ Each resolver independently decides what price it's willing to offer for that specific size, at that specific moment&lt;/li&gt;
&lt;li&gt;⬟ The system compares every response and selects the winner — the resolver offering the best terms takes the trade&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two people requesting the same nominal trade seconds apart aren't reading the same number off a board. They're each triggering their own independent round of competitive bidding among resolvers deciding, in real time, what they're willing to offer.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What's Actually Happening on the Wire&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This isn't a vague "competition happens somewhere" claim — it's a defined, technical protocol with named stages, and understanding those stages is what makes the pricing mechanism legible rather than a black box.&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%2Fpmtj1jew3kql0evu7ds7.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%2Fpmtj1jew3kql0evu7ds7.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "The resolver API uses a bidirectional gRPC stream." &lt;em&gt;— STON.fi resolver integration documentation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Resolvers connect to Omniston over a persistent, two-way gRPC stream — not a one-off API call per quote, but an ongoing connection kept open specifically so resolvers can react to requests the moment they arrive. When a trade request comes in, connected resolvers receive a &lt;code&gt;QuoteRequestedEvent&lt;/code&gt;. Each resolver's own pricing logic decides, in that moment, what rate it's able to offer for that specific size and pair — informed by its own inventory, its own risk appetite, and its own read of where the broader market is trading. That response becomes a &lt;code&gt;QuoteAcceptedEvent&lt;/code&gt; if it clears validation, carrying a &lt;code&gt;quote_id&lt;/code&gt; that ties it back to the original request.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🕰️ &lt;strong&gt;The Sequence, Step by Step&lt;/strong&gt;
&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%2Fbm1ucg6bdbg31sqwhzb8.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%2Fbm1ucg6bdbg31sqwhzb8.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔓 Step one: the request gets a fingerprint&lt;/strong&gt; The moment a trader submits a swap request, they receive a &lt;code&gt;QuoteRequestAck&lt;/code&gt; containing an &lt;code&gt;rfq_id&lt;/code&gt; — a unique identifier tying every subsequent quote, acceptance, and execution back to that exact request. Nothing about this trade's pricing exists independently of this specific, timestamped ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛰️ Step two: every connected resolver hears it at once&lt;/strong&gt; Rather than the trader polling sources one at a time, the request goes out to every resolver in the connected network simultaneously via the open gRPC stream, as a &lt;code&gt;QuoteRequestedEvent&lt;/code&gt;. Whichever resolvers are online and willing to price that pair all see the same request at effectively the same moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧨 Step three: independent, competing pricing decisions&lt;/strong&gt; Each resolver decides on its own terms what it's willing to offer — this isn't coordinated or shared between resolvers. A resolver holding more inventory of the requested output token, or with a more aggressive risk model that day, might quote tighter than one that's cautious or thin on that specific asset. This genuine independence is what makes it competition rather than a cartel reading from the same sheet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⬠ Step four: validation and selection&lt;/strong&gt; Quotes that clear come back as &lt;code&gt;QuoteAcceptedEvent&lt;/code&gt;s, each carrying its own &lt;code&gt;quote_id&lt;/code&gt;. Omniston compares what's actually come back and selects the winning terms — not necessarily just the single best headline number in isolation, but weighed against depth and reliability, consistent with how the broader routing engine treats any liquidity source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⬣ Step five: execution against the winning quote&lt;/strong&gt; Once a quote is selected, execution proceeds against those specific terms — for same-chain trades, through standard TON settlement; for cross-chain trades, through resolver-funded HTLCs on the destination side paired against the trader's locked funds on the source side, so the resolver's win doesn't create counterparty risk for the trader even after being selected.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🧑‍💻 &lt;strong&gt;What This Actually Looks Like in Code&lt;/strong&gt;
&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%2F210vzxshtpik92cymm0x.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%2F210vzxshtpik92cymm0x.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since this is genuinely an engineering topic underneath the trading language, it's worth seeing the real shape of it — both sides of the wire, illustrated in the style of STON.fi's documented SDK and resolver API patterns (simplified for clarity, not copied verbatim from the official docs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the trader side&lt;/strong&gt;, requesting a quote through the Omniston SDK looks something 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;Omniston&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;settlementMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ston-fi/omniston-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;omniston&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;Omniston&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://omni-ws.ston.fi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Every request gets its own tracked identity, per rfq_id&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;rfqId&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="nx"&gt;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;quoteRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...offer_jetton&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;askAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ton&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EQC...ask_jetton&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;amount&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// 1 unit, 9 decimals&lt;/span&gt;
    &lt;span class="na"&gt;settlementMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;settlementMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Swap&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="c1"&gt;// Stream quotes as resolvers respond — the "auction" arriving in real time&lt;/span&gt;
&lt;span class="nx"&gt;omniston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rfqId&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&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="nx"&gt;event&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="s1"&gt;quoteUpdated&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New competing quote:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&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;span class="nx"&gt;askAmount&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;&lt;strong&gt;On the resolver side&lt;/strong&gt;, the market maker's own service is listening on that open gRPC stream for exactly this kind of request, and answers independently:&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;resolverStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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="nx"&gt;event&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="nx"&gt;event&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="s1"&gt;QuoteRequestedEvent&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rfqId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offerAmount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quoteRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// This resolver's own pricing logic — inventory, risk, market read&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myAskAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computeCompetitivePrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offerAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;askAsset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offerAmount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;resolverStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;QuoteResponse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;rfqId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;askAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myAskAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;signWithEd25519&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rfqId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myAskAmount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// resolver's own key&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;Nothing coordinates these two snippets except the shared &lt;code&gt;rfqId&lt;/code&gt;. The trader's client is just listening for whatever comes back; the resolver's service is independently deciding what to offer. That gap — no shared logic, only a shared identifier — is the actual mechanical definition of "competition" in this system, not a figure of speech.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h3&gt;
  
  
  🔓 &lt;strong&gt;Why This Genuinely Helps Even Thin, Unusual Pairs&lt;/strong&gt;
&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%2Fbvlm74uogthhkb4kepc9.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%2Fbvlm74uogthhkb4kepc9.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resolver competition isn't just a marginal improvement on liquid pairs — it's specifically valuable for the trades a pure AMM pool struggles with most.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🗨️&lt;/em&gt; "RFQ functionality, where 'resolvers' (smart quote engines) compete to offer the best rates, ensures competitive pricing even for low-liquidity tokens." &lt;em&gt;— independent Omniston SDK writeup, Medium, 2025&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A public AMM pool for an obscure pair might simply not have meaningful depth — no amount of routing sophistication fixes liquidity that was never deposited. Resolvers don't have that same constraint, because they're not limited to whatever's sitting in a public pool. A resolver can price a trade based on inventory it's holding off-chain-adjacent, or its own hedging capability elsewhere, offering competitive terms for a pair that would otherwise slip badly through thin public liquidity alone.&lt;/p&gt;

&lt;p&gt;▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ What Genuinely Makes This Competitive Pricing Work
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every quote request is independently broadcast, not looked up.&lt;/strong&gt; There's no shared, stale price table — each &lt;code&gt;rfq_id&lt;/code&gt; triggers its own fresh round of bidding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolvers price independently, not in coordination.&lt;/strong&gt; Genuine competition, not a shared formula, is what creates pressure toward tighter pricing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The protocol, not the trader, verifies and selects.&lt;/strong&gt; Validation and selection happen inside Omniston's own logic, removing the burden of manually comparing raw resolver responses.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ What's Worth Understanding Correctly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A resolver's quote isn't guaranteed forever.&lt;/strong&gt; Quotes carry their own validity window; conditions that shift between quoting and execution can change what's actually available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More resolvers online doesn't guarantee a better price on every single request.&lt;/strong&gt; It raises the odds of competitive pricing, but any individual resolver can choose not to quote tightly on a given trade for its own inventory reasons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain resolver settlement still relies on HTLC-based atomicity for safety.&lt;/strong&gt; Winning a quote auction and completing settlement safely are two different guarantees, and the second one is what actually protects a trader's funds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏁 Bottom Line
&lt;/h2&gt;

&lt;p&gt;The price shown on a STON.fi swap isn't pulled from a static table — it's the outcome of a live, per-request auction among independent resolvers, run over a persistent connection and tracked end to end by a unique request ID from the first ping to final execution. That structure is exactly why resolver-based pricing tends to hold up even on pairs a public AMM pool alone would struggle to price well, and why two seemingly identical requests can genuinely produce two different, equally legitimate outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi — How to Become a Resolver (gRPC API, RFQ flow, quote lifecycle) — &lt;a href="https://docs.ston.fi/developer-section/omniston/resolvers/guide" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/resolvers/guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston Protocol Overview — &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Blog — "Cross-Chain Portfolio Rebalancing: How HTLC and RFQ Swaps Work" — &lt;a href="https://blog.ston.fi/cross-chain-portfolio-rebalancing-how-htlc-and-rfq-swaps-work-for-defi-users/" rel="noopener noreferrer"&gt;https://blog.ston.fi/cross-chain-portfolio-rebalancing-how-htlc-and-rfq-swaps-work-for-defi-users/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Medium, Motivator Peter — "Omniston SDK: Powering Seamless DeFi on TON with STON.fi" — &lt;a href="https://medium.com/@peterifreke/omniston-sdk-powering-seamless-defi-on-ton-with-ston-fi-380f03aa3d0c" rel="noopener noreferrer"&gt;https://medium.com/@peterifreke/omniston-sdk-powering-seamless-defi-on-ton-with-ston-fi-380f03aa3d0c&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Medium, Web3King — "Omniston by STON.fi: Revolutionizing Liquidity Aggregation, pt. 2" — &lt;a href="https://medium.com/@web3king/omniston-by-ston-fi-revolutionizing-liquidity-aggregation-on-the-ton-blockchain-pt2-748db5057f6c" rel="noopener noreferrer"&gt;https://medium.com/@web3king/omniston-by-ston-fi-revolutionizing-liquidity-aggregation-on-the-ton-blockchain-pt2-748db5057f6c&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This article reflects independent research based on STON.fi's public resolver and protocol documentation as of mid-2026. Resolver participation and protocol mechanics evolve as the network grows — always verify current functionality directly on docs.ston.fi before making decisions involving real funds.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ecosystem Map: How STON.fi, Omniston, and xStocks Connect on TON</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sat, 15 Aug 2026 17:38:05 +0000</pubDate>
      <link>https://dev.to/web3kd/ecosystem-map-how-stonfi-omniston-and-xstocks-connect-on-ton-29l1</link>
      <guid>https://dev.to/web3kd/ecosystem-map-how-stonfi-omniston-and-xstocks-connect-on-ton-29l1</guid>
      <description>&lt;h1&gt;
  
  
  Ecosystem Map: How STON.fi, Omniston, and xStocks Connect on TON
&lt;/h1&gt;

&lt;p&gt;It's easy to see "STON.fi," "Omniston," and "xStocks" mentioned in the same sentence and assume they're three interchangeable names for the same product. They're not — they're three distinct layers of a stack, each solving a different problem, and understanding where one ends and the next begins is the difference between building an integration that actually works and one that quietly breaks the moment a trade routes somewhere you didn't expect. STON.fi is the AMM and the app people actually open. Omniston is the aggregation and execution layer underneath it, connecting multiple liquidity sources — including ones STON.fi doesn't own — through a single interface. xStocks is a real-world-asset product that plugs into that stack without STON.fi ever touching the underlying liquidity itself. This piece maps out how those three pieces actually connect, with the specific technical seams a developer needs to know about.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Layers, in One Sentence Each
&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%2Fvxc9q8ehsbmsgo2zxwya.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%2Fvxc9q8ehsbmsgo2zxwya.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi&lt;/strong&gt; is the AMM protocol and app: liquidity pools, LP positions, farming, and the interface most users interact with directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omniston&lt;/strong&gt; is the aggregation and execution layer: it takes a swap request, shops it across STON.fi's own pools, other TON DEXs, and off-chain RFQ resolvers, and returns whichever route quotes best — through either standard on-chain settlement or resolver-driven escrow settlement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xStocks&lt;/strong&gt; is a real-world-asset product — tokenized equities and ETFs issued by Backed Finance — that's accessible &lt;em&gt;through&lt;/em&gt; STON.fi's interface and Omniston's routing, but doesn't live in a STON.fi-owned liquidity pool at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one most write-ups gloss over, and it's worth sitting with, because it's the clearest illustration of how these three pieces actually divide responsibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer One: STON.fi — the AMM and the Front Door
&lt;/h2&gt;

&lt;p&gt;STON.fi is TON's largest native DEX by volume, running a classic AMM model (v1 and v2 contracts, audited by Trail of Bits, with ongoing bug bounty coverage through Certik and HackenProof) where liquidity providers deposit paired assets into pools and earn trading fees plus farming rewards. This is the layer most people mean when they say "I swapped on STON.fi" — the app, the pool pages, the farming dashboard, the LP deposit and withdrawal flows.&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%2Feyv7niqq938vuvpi0pmm.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%2Feyv7niqq938vuvpi0pmm.png" alt=" " width="800" height="450"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Critically, STON.fi's own pools are just &lt;em&gt;one&lt;/em&gt; of the liquidity sources available once Omniston is in the picture — not the only one, and, for certain products like xStocks, not involved at all. STON.fi is where you go to provide liquidity and farm; it's not necessarily where your swap's liquidity actually comes from once you hit the swap button.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer Two: Omniston — the Routing and Execution Brain
&lt;/h2&gt;

&lt;p&gt;Omniston is a liquidity aggregation protocol purpose-built for TON. Conceptually, it does the same job a DEX aggregator does on Ethereum — shop a trade across multiple sources and route to the best price — but its execution model has grown a second, distinct mode beyond standard on-chain swapping.&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%2Fnhjvddhmem8yxq0lj1sg.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%2Fnhjvddhmem8yxq0lj1sg.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard aggregated swaps.&lt;/strong&gt; A user (or an app, via the SDK) sends a swap request to Omniston. Omniston fans that request out as a Request-for-Quote (RFQ) to connected sources — STON.fi's own pools, other TON DEXs, and independent RFQ resolvers — collects competing quotes, and executes against whichever wins. This is the flow covered by &lt;code&gt;useRfq()&lt;/code&gt; and &lt;code&gt;useTonBuildSwap()&lt;/code&gt; in the Omniston SDK, using a &lt;code&gt;swap&lt;/code&gt;-type settlement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Escrow-based resolver swaps.&lt;/strong&gt; Later in Omniston's development, a second execution class was introduced: resolver-driven, escrow-based settlement. Instead of routing through an on-chain pool, a professional market maker ("resolver") commits to a specific price, and the trade settles through a hashed-timelock-contract (HTLC) escrow — the trade either completes exactly at the quoted price or the funds return automatically to their original owner. This is the &lt;code&gt;order&lt;/code&gt;-type settlement path in the SDK, and it's what lets Omniston access private OTC-style liquidity that no public AMM pool holds at all. It's also the mechanism behind Omniston's native cross-chain swaps: no wrapped tokens, no bridge custody — an HTLC guarantees both sides of a cross-chain trade complete together or not at all.&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;// Requesting a quote — Omniston decides which settlement type fits&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;useRfq&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;QuoteRequest&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;SettlementParams&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/omniston-sdk-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;settlementParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SettlementParams&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Standard on-chain AMM routing&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxPriceSlippagePips&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&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="c1"&gt;// Resolver-driven escrow settlement (HTLC-backed)&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;order&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flexibleIntegratorFee&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="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;quoteRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QuoteRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;inputAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;usdtAssetId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;outputAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;targetAssetId&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputUnits&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amountInBaseUnits&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;settlementParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Omniston picks whichever route quotes best across both types&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing both settlement types in the same request is the important detail here: it doesn't commit you to one execution model up front — it tells Omniston "quote me the best of either," and the response tells you which one actually won. For a plain jetton-to-jetton swap on deep, liquid pairs, &lt;code&gt;swap&lt;/code&gt; settlement usually wins. For thinner pairs or asset classes with no public pool at all — which is exactly xStocks' situation — &lt;code&gt;order&lt;/code&gt;/escrow settlement is often the &lt;em&gt;only&lt;/em&gt; route that returns a quote at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer Three: xStocks — Real-World Assets Riding on Top
&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%2Fngol2f4n2egm785qcz4c.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%2Fngol2f4n2egm785qcz4c.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;xStocks are tokenized U.S. equities and ETFs — AAPLx, TSLAx, NVDAx, GOOGLx, AMZNx, and others — issued by Backed Finance, a regulated third-party entity that holds the underlying real shares and mints a 1:1-backed jetton representing them on TON. Because they follow the standard TON jetton format, any wallet or app that already understands jettons recognizes xStocks automatically, with no custom integration work required just to &lt;em&gt;hold&lt;/em&gt; one.&lt;/p&gt;

&lt;p&gt;Here's the detail that makes this a genuinely interesting case study rather than "STON.fi added some new tokens": &lt;strong&gt;STON.fi's own documentation is explicit that STON.fi does not list xStocks trading pairs and does not operate liquidity pools for xStocks.&lt;/strong&gt; There is no &lt;code&gt;AAPLx/USDT&lt;/code&gt; pool sitting in STON.fi's AMM contracts the way there is for, say, &lt;code&gt;TON/USDT&lt;/code&gt;. Users can open the STON.fi app, select an xStock, and swap into it — but that swap is served through Omniston's escrow/resolver settlement path, sourcing price from RFQ resolvers who quote against the real, off-chain equity price, not from an on-chain STON.fi pool at all.&lt;/p&gt;

&lt;p&gt;That's the whole architecture in miniature: STON.fi provides the interface a user recognizes, Omniston provides the execution and quote-sourcing plumbing, and xStocks exists as an asset class that only works &lt;em&gt;because&lt;/em&gt; Omniston's escrow layer exists — a plain AMM pool model has no good way to price something like a stock that needs to track a live off-chain market and settle atomically against a regulated issuer's commitments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tracing One Swap Through All Three Layers
&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%2F71vtlu5hpxudxwe9eelu.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%2F71vtlu5hpxudxwe9eelu.png" alt=" " width="799" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Walking through a concrete example makes the division of labor clearer than describing it abstractly. Say a user opens the STON.fi app and swaps USDT for TSLAx.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;STON.fi (interface layer):&lt;/strong&gt; The user picks USDT and TSLAx in the STON.fi app's swap screen — same UI pattern as any other swap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omniston (routing layer):&lt;/strong&gt; The app sends the swap request to Omniston. Omniston checks its connected sources for a route. Because there's no STON.fi pool or standard DEX pool for TSLAx, standard &lt;code&gt;swap&lt;/code&gt; settlement returns no usable quote — so Omniston falls back to querying RFQ resolvers under &lt;code&gt;order&lt;/code&gt;/escrow settlement instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolver quote (execution layer):&lt;/strong&gt; A resolver — a market maker with access to Backed Finance's issuance/redemption flow and real Tesla-share pricing — returns a firm quote: this much USDT for this much TSLAx, valid for a short window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTLC escrow settlement:&lt;/strong&gt; The user accepts. Funds lock into an HTLC-based escrow. Either the resolver delivers TSLAx at the committed price and the USDT releases to them, or the whole thing reverts and the user's USDT returns automatically — no partial fills, no counterparty risk beyond the smart contract itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet delivery:&lt;/strong&gt; TSLAx lands in the user's wallet as a standard jetton, immediately transferable, usable as collateral elsewhere in TON DeFi, and tradable 24/7 — independent of NYSE trading hours, since it's a resolver-priced synthetic exposure rather than a direct order routed to a traditional exchange.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At no point in that flow does STON.fi's own AMM liquidity get touched — which is exactly why STON.fi's docs are careful to say they don't operate xStocks pools, even though the STON.fi app is where most users will actually encounter and swap xStocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Layered Design Actually Matters for Builders
&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%2Fkeabwp6f6cc68z79sndy.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%2Fkeabwp6f6cc68z79sndy.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Composability without re-implementation.&lt;/strong&gt; Because Omniston sits underneath STON.fi rather than being bolted onto it, any third-party app — a wallet, a trading dashboard, a Telegram bot — can integrate the Omniston SDK directly and get access to the same aggregated liquidity, including escrow-settled products like xStocks, without building their own routing logic or negotiating separate resolver relationships.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New asset classes don't require new AMM math.&lt;/strong&gt; A traditional AMM pool assumes both sides of a pair are freely tradable on-chain assets with organic price discovery through the pool itself. xStocks breaks that assumption — its "correct" price lives off-chain, tied to a real, regulated, KYC'd issuer. Trying to force that into a constant-product pool would either require enormous, unrealistic liquidity or produce constant, exploitable mispricing. Routing it through resolver-quoted escrow settlement sidesteps the problem entirely: the resolver, not a bonding curve, is responsible for pricing accuracy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-chain and RWA products share the same underlying mechanism.&lt;/strong&gt; It's not a coincidence that Omniston's HTLC/escrow settlement powers both cross-chain swaps and xStocks — both cases involve one side of a trade that a standard on-chain AMM pool structurally can't represent well: a different chain's native asset in one case, an off-chain regulated security in the other. The same trust-minimized settlement primitive solves both problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest Limitations Worth Knowing
&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%2Fdk26lljoguh7jn92rzwm.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%2Fdk26lljoguh7jn92rzwm.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resolver dependency is a real, if different, kind of counterparty exposure.&lt;/strong&gt; HTLC settlement removes bridge-style custodial risk, but a resolver quote is still only as good as that resolver's willingness and ability to fill it — thin resolver participation on an illiquid pair can mean wide effective spreads or outright &lt;code&gt;noQuote&lt;/code&gt; responses, the same way thin AMM liquidity produces bad slippage elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;xStocks carry issuer and regulatory risk that's separate from TON or STON.fi entirely.&lt;/strong&gt; Because xStocks are backed and issued by Backed Finance under its own prospectus-style documentation, their risk profile includes issuer solvency, custodial arrangements for the underlying shares, and regulatory eligibility restrictions — xStocks are explicitly unavailable to users in the US, EU/EEA, UK, Canada, Australia, and Belgium, which is a meaningfully different constraint than anything native to TON's own token standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The escrow/order settlement path is newer and less battle-tested than plain AMM swapping.&lt;/strong&gt; Standard &lt;code&gt;swap&lt;/code&gt; settlement through STON.fi's audited AMM contracts has years of production history behind it; escrow-based resolver settlement is a comparatively recent addition to Omniston's execution model, and integrators should treat it with the same "verify before relying on it heavily" caution they'd apply to any newer piece of financial infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;STON.fi, Omniston, and xStocks aren't three brands for one product — they're a genuine three-layer stack, and the seams between them are exactly where the interesting engineering lives. STON.fi gives users a front door and gives liquidity providers a place to actually earn yield. Omniston is the part doing the real work underneath every swap button, quietly deciding whether a trade should route through an on-chain pool or a resolver-quoted escrow. And xStocks is proof that the escrow layer isn't just a cross-chain trick — it's a general-purpose way to bring assets onto TON that no AMM pool could reasonably price on its own. For a developer building on top of this stack, the practical takeaway is simple: integrate against Omniston if you want access to everything — pools, other DEXs, and resolver-priced assets like xStocks — in one consistent API, rather than assuming STON.fi's own pools are the whole liquidity picture.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STON.fi Developer Docs — Introduction: &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Omniston Protocol Overview: &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Omniston — product site: &lt;a href="https://ston.fi/omniston" rel="noopener noreferrer"&gt;https://ston.fi/omniston&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;xStocks on STON.fi — official page and risk disclosures: &lt;a href="https://ston.fi/xstocks" rel="noopener noreferrer"&gt;https://ston.fi/xstocks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi Blog — "xStocks: Explore Tokenized Market": &lt;a href="https://blog.ston.fi/xstocks-explore-tokenized-market/" rel="noopener noreferrer"&gt;https://blog.ston.fi/xstocks-explore-tokenized-market/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Blog — "xStocks Are Live on TON: Real-World Stocks, Now On-Chain": &lt;a href="https://blog.ton.org/x-stocks-are-live-on-ton-real-world-stocks-now-on-chain" rel="noopener noreferrer"&gt;https://blog.ton.org/x-stocks-are-live-on-ton-real-world-stocks-now-on-chain&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DL News — "xStocks arrive on STON.fi, allowing users to access equities the DeFi way": &lt;a href="https://www.dlnews.com/external/xstocks-arrive-on-stonfi-allowing-users-to-access-equities-the-defi-way/" rel="noopener noreferrer"&gt;https://www.dlnews.com/external/xstocks-arrive-on-stonfi-allowing-users-to-access-equities-the-defi-way/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;top.co Insights — "Omniston and the Next Phase of Liquidity Infrastructure": &lt;a href="https://top.co/insights/Omniston-Next-Phase-Liquidity-Infrastructure" rel="noopener noreferrer"&gt;https://top.co/insights/Omniston-Next-Phase-Liquidity-Infrastructure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Omniston SDK — Node.js Quickstart: &lt;a href="https://docs.ston.fi/developer-section/omniston/sdk/nodejs" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/sdk/nodejs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Omniston SDK — React Quickstart: &lt;a href="https://docs.ston.fi/developer-section/omniston/sdk/react" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/sdk/react&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DefiLlama — STON.fi protocol metrics: &lt;a href="https://defillama.com/protocol/ston.fi" rel="noopener noreferrer"&gt;https://defillama.com/protocol/ston.fi&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is based on STON.fi, Omniston, and xStocks documentation and public announcements as of mid-2026. Product architecture, supported settlement types, and asset availability by jurisdiction can change — verify current specifics against docs.ston.fi and ston.fi/xstocks before relying on them for a production integration or an investment decision. xStocks are not available to residents of certain jurisdictions and carry issuer, custodial, and regulatory risk separate from TON-native assets.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Testing for Failed Transactions: A Builder's Checklist for STON.fi Integrations</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Sat, 15 Aug 2026 16:52:50 +0000</pubDate>
      <link>https://dev.to/web3kd/testing-for-failed-transactions-a-builders-checklist-for-stonfi-integrations-4ili</link>
      <guid>https://dev.to/web3kd/testing-for-failed-transactions-a-builders-checklist-for-stonfi-integrations-4ili</guid>
      <description>&lt;h1&gt;
  
  
  Testing for Failed Transactions: A Builder's Checklist for STON.fi Integrations
&lt;/h1&gt;

&lt;p&gt;Most swap tutorials end at the happy path — quote comes back, user confirms, transaction lands, balance updates. Ship that alone and you've tested maybe 60% of what your integration will actually encounter in production. TON's transaction model is asynchronous and message-based in a way Ethereum developers in particular tend to underestimate: a "failed" swap on TON isn't a single clean revert, it's a cascade of messages that can partially succeed, bounce, get refunded as the wrong token, or silently eat gas without telling anyone why. This checklist is built around the specific ways STON.fi and Omniston integrations actually fail — not hypothetical edge cases, but the documented, reproducible ones — so you can write tests against them before your users find them for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The failure you didn't write a test for isn't rare — it's just the one you haven't hit in staging yet."&lt;/em&gt; — a note from the trenches&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why TON Failures Don't Look Like EVM Failures
&lt;/h2&gt;

&lt;p&gt;If your testing instincts come from Solidity, recalibrate them here. On Ethereum, a reverted transaction rolls back cleanly — state changes, gas spent, done. On TON, a "transaction" is really a chain of asynchronous messages between contracts, and each one goes through its own sequence of phases: &lt;strong&gt;storage&lt;/strong&gt; (fees for the space a contract occupies), &lt;strong&gt;credit&lt;/strong&gt; (crediting the incoming message value), &lt;strong&gt;compute&lt;/strong&gt; (running the actual contract logic), &lt;strong&gt;action&lt;/strong&gt; (executing whatever the compute phase decided to do — sending messages, updating state), and &lt;strong&gt;bounce&lt;/strong&gt; (firing only if compute failed &lt;em&gt;and&lt;/em&gt; the inbound message had the bounce flag set).&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%2Fmws5my7y68ndyr54idsc.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%2Fmws5my7y68ndyr54idsc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That last phase is the one that trips people up. A bounce isn't a revert — it's a new message sent back to the original sender, and it only happens automatically if the message was sent in bounceable mode with enough remaining balance to cover the bounce itself. If your integration's logic assumes "the transaction either fully succeeds or the user gets their money back exactly as before," you'll eventually hit a case where that's false — because a bounced message can't itself be bounced again, and a bounce triggered by a genuine out-of-gas condition may never get delivered at all.&lt;/p&gt;

&lt;p&gt;There's a second wrinkle specific to jetton transfers: if your contract receives a &lt;code&gt;TransferNotification&lt;/code&gt; for incoming jettons and that handler throws, bouncing the message is often the &lt;em&gt;worst&lt;/em&gt; outcome — the standard jetton wallet contract has no defined behavior for un-bouncing tokens that already moved, meaning a naive bounce-on-error pattern can leave jettons stuck permanently. The fix is a &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; around notification handling rather than letting an exception propagate into an automatic bounce — a detail that's easy to miss if you copy a generic "throw on invalid input" pattern from EVM-style contract code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Failure Taxonomy: What Actually Breaks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Slippage-Triggered Refunds
&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%2Fh4quwcn0147qqfayjtu3.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%2Fh4quwcn0147qqfayjtu3.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the most common "failure" your users will hit, and it's not really a bug — it's the protection working as intended. If the pool's price moves past the &lt;code&gt;max_price_slippage_bps&lt;/code&gt; you set before the swap settles, the router refunds the input rather than executing at a worse price than agreed. STON.fi's own Omniston API defaults slippage to a value expressed in basis points — &lt;code&gt;100&lt;/code&gt; means 1% — and it's worth testing both ends of this deliberately: too tight, and normal volatility triggers refunds constantly; too loose, and you've quietly removed the protection slippage exists for in the first place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Test both extremes explicitly, don't just pick one "reasonable" value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tightSlippage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// 0.1% — expect frequent refunds on volatile pairs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;looseSlippage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// 5% — expect rare refunds, worse realized prices&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Multi-Hop and Cross-Router Swaps Don't Refund Cleanly
&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%2Fryr3c3azg67y6ljtjqih.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%2Fryr3c3azg67y6ljtjqih.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there's no direct pool for your pair, STON.fi routes through an intermediary token — sometimes across multiple routers. Here's the detail worth testing specifically: &lt;strong&gt;because multi-contract transactions on TON aren't atomic, a cross-swap that fails partway through can't be fully refunded in the original input token.&lt;/strong&gt; Per STON.fi's own documentation, if the trade fails after the first hop has already executed, the user receives the &lt;em&gt;intermediate&lt;/em&gt; token from that hop, not their original asset back. A test suite that only checks "did the user get token B or token A back" will miss this — you need a third assertion for "did the user get stuck holding the intermediate token instead."&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Gas Miscalculation and Exit Code 11
&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%2Fyireaxxqso4nnz46r4ve.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%2Fyireaxxqso4nnz46r4ve.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Real-world example, pulled from a documented STON.fi SDK issue: a developer's swap transaction was accepted and broadcast successfully, but failed on-chain with &lt;code&gt;exit_code: 11&lt;/code&gt; — a generic compute-phase failure — traced back to a gas/parameter mismatch in how the swap transaction was constructed for a jetton-to-jetton pair specifically (as opposed to the TON-to-jetton path, which worked fine in the same codebase). The lesson generalizes: &lt;strong&gt;"the SDK call didn't throw" is not the same as "the swap will succeed."&lt;/strong&gt; Any integration test suite needs a step that checks the actual on-chain exit code after submission, not just that &lt;code&gt;sendTransaction()&lt;/code&gt; resolved without an error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I've lost more debugging hours to a transaction that broadcasts cleanly and fails silently on-chain than to any error the SDK actually threw at me."&lt;/em&gt; — a note from the trenches&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. TonConnect-Level Rejections (Before the Chain Ever Sees It)
&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%2F793d3co9fl1pezens5b8.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%2F793d3co9fl1pezens5b8.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A meaningful share of "failed transactions" never reach a block at all — they fail at the wallet layer. TonConnect's documented failure surface includes a specific, testable set of cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An address sent in raw format (&lt;code&gt;0:abc…&lt;/code&gt;) where the wallet expected the friendly, bounceable-flag-encoded format&lt;/li&gt;
&lt;li&gt;A payload that includes both &lt;code&gt;messages&lt;/code&gt; and &lt;code&gt;items&lt;/code&gt; in the same request — the spec requires exactly one, never both&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;valid_until&lt;/code&gt; already in the past by the time the wallet receives the request&lt;/li&gt;
&lt;li&gt;A network mismatch between what the dApp requested and what the wallet has selected&lt;/li&gt;
&lt;li&gt;The user simply rejecting the transaction — which TonConnect's own guidance says should be treated as a "changed their mind" path, shown as a soft message, and explicitly &lt;em&gt;not&lt;/em&gt; logged as a system error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point matters for your monitoring, not just your tests: if user rejections and genuine on-chain failures land in the same error bucket in your dashboards, you'll chase phantom bugs that are really just people closing the confirmation dialog.&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSwap&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="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;txRequest&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="nf"&gt;isUserRejection&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="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;Transaction cancelled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// not an error — don't alert on this&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;}&lt;/span&gt;
    &lt;span class="nf"&gt;reportFailure&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="c1"&gt;// genuine failure — this one goes to monitoring&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;
  
  
  5. Stale Quotes on the Omniston Side
&lt;/h3&gt;

&lt;p&gt;Because &lt;code&gt;useRfq()&lt;/code&gt; is a live subscription, a quote your UI displayed ten seconds ago may no longer be the one Omniston actually settles against if you don't rebuild the transaction from the latest event. Test this by deliberately introducing latency between "user sees a quote" and "user confirms" in your test harness — a few seconds is enough on a volatile pair to demonstrate the gap between a stale UI value and what actually executes.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Reference Table Worth Keeping Nearby
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Exit Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;What to Test For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stack underflow&lt;/td&gt;
&lt;td&gt;Malformed or truncated payload construction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stack overflow&lt;/td&gt;
&lt;td&gt;Deeply nested or malformed cell structures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Integer out of expected range&lt;/td&gt;
&lt;td&gt;Exit codes or values outside 16-bit bounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;11&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generic compute failure (varies by contract)&lt;/td&gt;
&lt;td&gt;Gas/parameter mismatches — verify per-path, not just per-SDK-method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Account state size exceeded&lt;/td&gt;
&lt;td&gt;Rare, but test for it if your integration writes custom state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;65535&lt;/code&gt; (&lt;code&gt;0xffff&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Unknown opcode&lt;/td&gt;
&lt;td&gt;A message the receiving contract wasn't built to handle at all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TON reserves exit codes &lt;code&gt;0&lt;/code&gt;–&lt;code&gt;127&lt;/code&gt; for protocol-level meanings; codes &lt;code&gt;256&lt;/code&gt;–&lt;code&gt;65535&lt;/code&gt; are open for contract-specific errors, which means the &lt;em&gt;same&lt;/em&gt; exit code can mean something different depending on which contract threw it — always confirm the meaning against the specific contract's own documentation rather than assuming a code means the same thing everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building an Actual Test Matrix
&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%2Flmzahpbyv8xzphlyyar3.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%2Flmzahpbyv8xzphlyyar3.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rather than testing "does a swap work," structure your suite around the failure taxonomy above. A reasonable matrix for a swap feature looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Happy path&lt;/strong&gt; — quote, build, sign, settle, balance updates correctly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slippage refund (tight)&lt;/strong&gt; — deliberately set slippage low enough on a live-ish sandbox environment to force a refund, confirm the user gets their original input back&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slippage refund (edge)&lt;/strong&gt; — set slippage to the exact boundary and confirm consistent behavior, not flakiness&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-hop partial-fill scenario&lt;/strong&gt; — simulate a cross-swap failing after the first hop, confirm your UI correctly represents "you received the intermediate token" rather than showing a generic failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet rejection&lt;/strong&gt; — simulate the user declining in the wallet UI, confirm it's tracked as a cancellation, not an error&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expired &lt;code&gt;valid_until&lt;/code&gt;&lt;/strong&gt; — construct a transaction with a validity window already in the past, confirm your UI handles the resulting wallet-level rejection gracefully&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale quote&lt;/strong&gt; — inject artificial delay between quote display and confirm, verify you're building against the latest quote event, not a cached one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Malformed address format&lt;/strong&gt; — feed a raw-format address into a &lt;code&gt;sendTransaction&lt;/code&gt; call intentionally, confirm your address-formatting layer catches it before it reaches the wallet
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sandbox-based unit test skeleton for the slippage-refund case&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;Blockchain&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/sandbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap slippage protection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refunds input when price moves past max_price_slippage_bps&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="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;blockchain&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;Blockchain&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trader&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;blockchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;treasury&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Simulate a pool state that has moved since quote issuance&lt;/span&gt;
    &lt;span class="c1"&gt;// ...set up router/pool contracts with adjusted reserves...&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="nf"&gt;sendSwap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;trader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxPriceSlippageBps&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="c1"&gt;// intentionally tight&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&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;refunded&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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;expect&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;refundedAsset&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputAsset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// not the intermediate token&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;h2&gt;
  
  
  Monitoring After You Ship
&lt;/h2&gt;

&lt;p&gt;Tests catch what you thought to test for. Production catches everything else. A few numbers worth tracking on an ongoing basis once real traffic hits your integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refund rate as a percentage of attempted swaps&lt;/strong&gt;, segmented by pair — a sudden spike on one specific pair usually means either a liquidity change or your default slippage setting is now too tight for that pair's current volatility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet-rejection rate vs. genuine on-chain failure rate&lt;/strong&gt;, tracked as separate metrics — conflating them, as noted above, wastes debugging time on a "problem" that's actually users changing their minds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit code distribution&lt;/strong&gt; for any failures that do reach the chain — a new exit code appearing that wasn't in your test matrix is a signal to go add it, not just a data point to log and forget&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"A test suite that never grows after launch is testing yesterday's failure modes, not today's."&lt;/em&gt; — a note from the trenches&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Checklist, Compressed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Test slippage refunds at tight, loose, and boundary values — not just one "reasonable" default&lt;/li&gt;
&lt;li&gt;[ ] Explicitly test the multi-hop partial-refund case — assert on the intermediate-token outcome, not just success/failure&lt;/li&gt;
&lt;li&gt;[ ] Verify on-chain exit codes post-submission, not just that the SDK call resolved&lt;/li&gt;
&lt;li&gt;[ ] Handle jetton &lt;code&gt;TransferNotification&lt;/code&gt; failures with try/catch, not bounce-on-error&lt;/li&gt;
&lt;li&gt;[ ] Separate wallet-rejection tracking from genuine on-chain failure tracking, in both tests and production monitoring&lt;/li&gt;
&lt;li&gt;[ ] Test with an intentionally expired &lt;code&gt;valid_until&lt;/code&gt; to confirm graceful handling&lt;/li&gt;
&lt;li&gt;[ ] Test address-format validation before a request ever reaches TonConnect&lt;/li&gt;
&lt;li&gt;[ ] Rebuild transactions from the latest quote event, and test for the stale-quote case directly&lt;/li&gt;
&lt;li&gt;[ ] Track refund rate, rejection rate, and exit-code distribution after launch — not just uptime&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;None of the failure modes above are exotic — they're documented, reproducible, and, in at least one case, sitting in a public GitHub issue with the exact exit code attached. What makes them worth a dedicated checklist is that TON's asynchronous, message-based execution model produces failure shapes that don't map cleanly onto EVM-trained intuition: partial fills that land you in the wrong token, bounces that can't be un-bounced, wallet-level rejections that never touch a block at all. Test for the specific way STON.fi and Omniston fail, not just the generic way swaps fail, and the gap between your staging environment and your first angry support ticket gets a lot smaller.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TON Docs — Execution Phases: &lt;a href="https://docs.ton.org/foundations/phases" rel="noopener noreferrer"&gt;https://docs.ton.org/foundations/phases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Docs — Exit Codes: &lt;a href="https://docs.ton.org/blockchain-basics/tvm/exit-codes" rel="noopener noreferrer"&gt;https://docs.ton.org/blockchain-basics/tvm/exit-codes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Docs — Accept Message Effects: &lt;a href="https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/accept-message-effects" rel="noopener noreferrer"&gt;https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/accept-message-effects&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Docs — Internal Messages (bounce mechanics): &lt;a href="https://docs.ton.org/blockchain-basics/primitives/messages/internal" rel="noopener noreferrer"&gt;https://docs.ton.org/blockchain-basics/primitives/messages/internal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TON Docs — TON Connect Troubleshooting: &lt;a href="https://docs.ton.org/applications/ton-connect/troubleshooting" rel="noopener noreferrer"&gt;https://docs.ton.org/applications/ton-connect/troubleshooting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CertiK — "Secure Smart Contract Programming in Tact: Popular Mistakes in the TON Ecosystem": &lt;a href="https://www.certik.com/blog/secure-smart-contract-programming-in-tact-popular-mistakes-in-the-ton" rel="noopener noreferrer"&gt;https://www.certik.com/blog/secure-smart-contract-programming-in-tact-popular-mistakes-in-the-ton&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Swap Examples (v2, cross-swap and refund behavior): &lt;a href="https://docs.ston.fi/developer-section/dex/smart-contracts/v2/examples/swap" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/dex/smart-contracts/v2/examples/swap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;STON.fi — Omniston Swap Overview (settlement params, slippage): &lt;a href="https://docs.ston.fi/developer-section/omniston/swap/overview" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/swap/overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ston-fi/sdk&lt;/code&gt; GitHub Issues (real documented exit-code failures): &lt;a href="https://github.com/ston-fi/sdk/issues" rel="noopener noreferrer"&gt;https://github.com/ston-fi/sdk/issues&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ton/sandbox&lt;/code&gt; package: &lt;a href="https://www.npmjs.com/package/@ton/sandbox" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ton/sandbox&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This checklist is based on TON and STON.fi/Omniston documentation, plus publicly documented integration issues, as of mid-2026. Exit code meanings can vary by contract, and API parameter names/formats evolve — verify specifics against current docs.ton.org and docs.ston.fi before relying on them in a production test suite.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SDK Integration Walkthrough: Building Your First STON.fi Swap Feature</title>
      <dc:creator>Web3KD</dc:creator>
      <pubDate>Fri, 14 Aug 2026 13:27:09 +0000</pubDate>
      <link>https://dev.to/web3kd/sdk-integration-walkthrough-building-your-first-stonfi-swap-feature-2m3a</link>
      <guid>https://dev.to/web3kd/sdk-integration-walkthrough-building-your-first-stonfi-swap-feature-2m3a</guid>
      <description>&lt;p&gt;Adding a token swap to a dApp sounds simple until you actually sit down to do it: you need live pricing, a way to route through the best available liquidity, transaction building that matches the target chain's quirks, wallet signing, and a way to track whether the trade actually went through. On TON, STON.fi's SDKs handle most of that heavy lifting for you - specifically the Omniston layer, which aggregates quotes across on-chain pools and off-chain RFQ resolvers and hands you back a ready-to-sign transaction. This walkthrough builds a working swap feature from a blank React project to a working "Swap" button, using the official @ston-fi/omniston-sdk-react package, TonConnect for wallet signing, and the actual API surface exposed by the SDK as of its v1beta8 protocol version.&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%2F5kuw8wj9fvhpxml16vbx.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%2F5kuw8wj9fvhpxml16vbx.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the end, you'll have a component that lets a user pick two tokens, see a live quote update as market conditions shift, sign a transaction with their wallet, and watch the swap's status change from pending to confirmed - all without writing a single line of raw smart contract code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You'll Need Before&amp;nbsp;Starting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18+ and a package manager (npm, yarn, or pnpm)&lt;/li&gt;
&lt;li&gt;A React project (Vite or Next.js both work fine - this walkthrough uses a generic React setup so it's easy to adapt)&lt;/li&gt;
&lt;li&gt;A TON wallet for testing - Tonkeeper or MyTonWallet both support TonConnect&lt;/li&gt;
&lt;li&gt;Basic familiarity with React hooks and async/await - no prior TON or blockchain development experience is required&lt;/li&gt;
&lt;/ul&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%2Fcmzaweafxqfpdft3ac1w.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%2Fcmzaweafxqfpdft3ac1w.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STON.fi actually ships two related but distinct SDK families: the classic &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
@ston-fi/sdk,&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
 which talks directly to STON.fi's own Router and Pool contracts, and &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
@ston-fi/omniston-sdk&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
 (plus its React binding), which talks to Omniston - STON.fi's aggregation layer that shops a trade across multiple liquidity sources, not just STON.fi's own pools, and returns whichever route quotes best. For a new swap feature in 2026, Omniston is the more future-proof choice: it gets you STON.fi's own liquidity and other connected sources through one consistent API, so that's what this walkthrough uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install the Dependencies&lt;/strong&gt;&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%2F3l5z3yvhvagq6ccsdire.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%2F3l5z3yvhvagq6ccsdire.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start by scaffolding a React project if you don't already have one, then add the Omniston React SDK alongside TonConnect for wallet interaction.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
npm install @ston-fi/omniston-sdk-react&lt;br&gt;
npm install @tonconnect/ui-react&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
@ston-fi/omniston-sdk-react&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
 is a TypeScript-first package built on top of RxJS observables and TanStack Query, so you get loading states, retries, and stream handling out of the box instead of writing that plumbing yourself. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
@tonconnect/ui-react&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
 gives you a drop-in wallet connect button and a signer you'll use later to actually authorize the swap transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Wire Up Wallet Connection&lt;/strong&gt;&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%2F3j3w0evf8qwwlyz4wf8v.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%2F3j3w0evf8qwwlyz4wf8v.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before a user can swap anything, they need a connected wallet. TonConnect handles the connection modal, deep-linking into wallet apps, and session persistence for you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
// src/providers/WalletProvider.tsx&lt;br&gt;
import { TonConnectUIProvider } from "@tonconnect/ui-react";&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const manifestUrl = "https://your-app-domain.com/tonconnect-manifest.json";&lt;br&gt;
export function WalletProvider({ children }: React.PropsWithChildren) {&lt;br&gt;
  return (&lt;br&gt;
    &amp;lt;TonConnectUIProvider manifestUrl={manifestUrl}&amp;gt;&lt;br&gt;
      {children}&lt;br&gt;
    &amp;lt;/TonConnectUIProvider&amp;gt;&lt;br&gt;
  );&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The tonconnect-manifest.json file needs to be hosted at a publicly reachable URL and describes your app's name, icon, and domain to the wallet the user connects with - this is a TonConnect requirement, not a STON.fi-specific one, and most starter templates include a sample manifest you can adapt.&lt;br&gt;
With the provider in place, dropping a connect button anywhere in your UI is a one-liner:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { TonConnectButton } from "@tonconnect/ui-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;function Header() {&lt;br&gt;
  return (&lt;br&gt;
    &amp;lt;header&amp;gt;&lt;br&gt;
      &amp;lt;TonConnectButton /&amp;gt;&lt;br&gt;
    &amp;lt;/header&amp;gt;&lt;br&gt;
  );&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Set Up the Omniston&amp;nbsp;Provider&lt;/strong&gt;&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%2F480o6myqsz491nrm2591.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%2F480o6myqsz491nrm2591.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, create an Omniston instance and wrap your app (or just the swap feature's subtree) in OmnistonProvider. This gives every component under it access to Omniston's hooks without prop-drilling a client instance around.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/providers/OmnistonProvider.tsx&lt;br&gt;
import { Omniston, OmnistonProvider } from "@ston-fi/omniston-sdk-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const omniston = new Omniston({&lt;br&gt;
  apiUrl: "wss://omni-ws.ston.fi",&lt;br&gt;
});&lt;br&gt;
export function AppOmnistonProvider({ children }: React.PropsWithChildren) {&lt;br&gt;
  return &amp;lt;OmnistonProvider omniston={omniston}&amp;gt;{children}&amp;lt;/OmnistonProvider&amp;gt;;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;While you're building and testing, point at the sandbox endpoint instead so test trades don't touch real liquidity:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const omniston = new Omniston({&lt;br&gt;
  apiUrl: "wss://omni-ws-sandbox.ston.fi",&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If your app already has a TanStack Query client set up elsewhere, pass it in so Omniston reuses it instead of spinning up a second one:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;OmnistonProvider omniston={omniston} queryClient={queryClient}&amp;gt;&lt;br&gt;
  {children}&lt;br&gt;
&amp;lt;/OmnistonProvider&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nest this provider inside your TonConnectUIProvider from Step 2 - the order doesn't matter functionally, but keeping wallet context outermost tends to make the component tree easier to reason about as the app grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Define What You're&amp;nbsp;Swapping&lt;/strong&gt;&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%2Fcf2o5twlmw1d1amcxea0.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%2Fcf2o5twlmw1d1amcxea0.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Omniston identifies tokens with an AssetId structure rather than a raw contract address string, which keeps the API consistent across chains (TON, EVM chains, and whatever gets added later). For a TON-native jetton swap - say, USDT to STON - that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/assets.ts&lt;br&gt;
import type { AssetId } from "@ston-fi/omniston-sdk-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export const USDT: AssetId = {&lt;br&gt;
  chain: {&lt;br&gt;
    $case: "ton",&lt;br&gt;
    value: {&lt;br&gt;
      kind: {&lt;br&gt;
        $case: "jetton",&lt;br&gt;
        value: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",&lt;br&gt;
      },&lt;br&gt;
    },&lt;br&gt;
  },&lt;br&gt;
};&lt;br&gt;
export const STON: AssetId = {&lt;br&gt;
  chain: {&lt;br&gt;
    $case: "ton",&lt;br&gt;
    value: {&lt;br&gt;
      kind: {&lt;br&gt;
        $case: "jetton",&lt;br&gt;
        value: "EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO",&lt;br&gt;
      },&lt;br&gt;
    },&lt;br&gt;
  },&lt;br&gt;
};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In a real app you'd source this list from a token registry or search API rather than hardcoding it, but hardcoding two tokens is the fastest way to get a working prototype before you build out a token picker UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Request a Live&amp;nbsp;Quote&lt;/strong&gt;&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%2F2i8hxz0v84jdv13esf7q.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%2F2i8hxz0v84jdv13esf7q.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where Omniston's aggregation actually happens. useRfq() opens a subscription - not a one-shot HTTP request - because prices move and Omniston keeps pushing updated quotes as long as you're subscribed. You also need to decide up front which settlement methods you're willing to accept: swap for classic on-chain execution, order for signed-order/HTLC flows (useful for cross-chain trades), or both if you want Omniston to pick whichever is best.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/useSwapQuote.ts&lt;br&gt;
import {&lt;br&gt;
  useRfq,&lt;br&gt;
  type QuoteRequest,&lt;br&gt;
  type SettlementParams,&lt;br&gt;
} from "@ston-fi/omniston-sdk-react";&lt;br&gt;
import { USDT, STON } from "./assets";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const settlementParams: SettlementParams[] = [&lt;br&gt;
  {&lt;br&gt;
    params: {&lt;br&gt;
      $case: "swap",&lt;br&gt;
      value: {&lt;br&gt;
        maxPriceSlippagePips: 10_000, // 1% max slippage&lt;br&gt;
        flexibleIntegratorFee: true,&lt;br&gt;
      },&lt;br&gt;
    },&lt;br&gt;
  },&lt;br&gt;
];&lt;br&gt;
export function useSwapQuote(amountInBaseUnits: string) {&lt;br&gt;
  const quoteRequest: QuoteRequest = {&lt;br&gt;
    inputAsset: USDT,&lt;br&gt;
    outputAsset: STON,&lt;br&gt;
    amount: {&lt;br&gt;
      $case: "inputUnits",&lt;br&gt;
      value: amountInBaseUnits,&lt;br&gt;
    },&lt;br&gt;
    settlementParams,&lt;br&gt;
  };&lt;br&gt;
  return useRfq(quoteRequest);&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the component that consumes it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/QuotePreview.tsx&lt;br&gt;
import { useSwapQuote } from "./useSwapQuote";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export function QuotePreview({ amount }: { amount: string }) {&lt;br&gt;
  const { data: event, error } = useSwapQuote(amount);&lt;br&gt;
  if (error) {&lt;br&gt;
    return &amp;lt;p className="error"&amp;gt;Couldn't fetch a quote right now.&amp;lt;/p&amp;gt;;&lt;br&gt;
  }&lt;br&gt;
  switch (event?.$case) {&lt;br&gt;
    case "ack":&lt;br&gt;
      return &amp;lt;p&amp;gt;Looking for the best rate…&amp;lt;/p&amp;gt;;&lt;br&gt;
    case "quoteUpdated":&lt;br&gt;
      return &amp;lt;p&amp;gt;Quote ready - id: {event.value.quoteId}&amp;lt;/p&amp;gt;;&lt;br&gt;
    case "noQuote":&lt;br&gt;
      return &amp;lt;p&amp;gt;No route available for this pair right now.&amp;lt;/p&amp;gt;;&lt;br&gt;
    case "unsubscribed":&lt;br&gt;
      return &amp;lt;p&amp;gt;Quote stream closed.&amp;lt;/p&amp;gt;;&lt;br&gt;
    default:&lt;br&gt;
      return &amp;lt;p&amp;gt;Waiting for quote…&amp;lt;/p&amp;gt;;&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A few things worth flagging here for anyone integrating this for the first time: the maxPriceSlippagePips value is in "pips" (hundredths of a basis point), so 10_000 means 1% - it's easy to be off by an order of magnitude here if you're used to plain percentage inputs, so double-check this value against your UI's slippage setting before shipping. Second, quoteUpdated can fire more than once for the same RFQ - that's the aggregator refreshing the price as the request stays open, not a bug - so store the latest quote in state rather than assuming the first one you see is final.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Build the Swap Transaction&lt;/strong&gt;&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%2F62kaobxyb398uux3shm6.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%2F62kaobxyb398uux3shm6.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have a quote and the user has confirmed they want to proceed, branch on quote.settlementData?.$case to figure out whether you're in a swap flow or an order flow, then call the matching builder. For a straightforward TON-to-TON swap, that's useTonBuildSwap().&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/useBuildSwapTx.ts&lt;br&gt;
import {&lt;br&gt;
  useTonBuildSwap,&lt;br&gt;
  type ChainAddress,&lt;br&gt;
  type QuoteOfType,&lt;br&gt;
} from "@ston-fi/omniston-sdk-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export function useBuildSwapTx(&lt;br&gt;
  quote: QuoteOfType&amp;lt;"swap"&amp;gt;,&lt;br&gt;
  traderAddress: ChainAddress&lt;br&gt;
) {&lt;br&gt;
  return useTonBuildSwap({&lt;br&gt;
    quoteId: quote.quoteId,&lt;br&gt;
    transferSrcAddress: traderAddress,&lt;br&gt;
    refundSrcAddress: traderAddress,&lt;br&gt;
    gasExcessAddress: traderAddress,&lt;br&gt;
    traderDstAddress: traderAddress,&lt;br&gt;
  });&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each of those four address fields serves a distinct purpose, and getting them wrong is one of the more common integration mistakes: transferSrcAddress is where the input tokens are pulled from, refundSrcAddress is where funds go if the swap fails partway, gasExcessAddress recovers any unused gas, and traderDstAddress is where the output tokens land. In the common case they're all the same connected wallet address, but keeping them as separate parameters means your app can support more advanced flows later (like swapping on behalf of a smart contract wallet) without changing the API shape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Sign and Send the Transaction with TonConnect&lt;/strong&gt;&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%2F0unci57nyo75y65sg52r.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%2F0unci57nyo75y65sg52r.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;useTonBuildSwap() gives you back a set of unsigned messages - it doesn't sign or broadcast anything itself. That's intentional: signing is wallet territory, and Omniston stays wallet-agnostic. Here's how to hand those messages to TonConnect:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/SwapButton.tsx&lt;br&gt;
import { useTonConnectUI, useTonAddress } from "@tonconnect/ui-react";&lt;br&gt;
import { useBuildSwapTx } from "./useBuildSwapTx";&lt;br&gt;
import type { QuoteOfType } from "@ston-fi/omniston-sdk-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export function SwapButton({ quote }: { quote: QuoteOfType&amp;lt;"swap"&amp;gt; }) {&lt;br&gt;
  const [tonConnectUI] = useTonConnectUI();&lt;br&gt;
  const rawAddress = useTonAddress();&lt;br&gt;
  const traderAddress = {&lt;br&gt;
    chain: { $case: "ton" as const, value: rawAddress },&lt;br&gt;
  };&lt;br&gt;
  const { data: swapTx } = useBuildSwapTx(quote, traderAddress);&lt;br&gt;
  async function handleSwap() {&lt;br&gt;
    if (!swapTx) return;&lt;br&gt;
    await tonConnectUI.sendTransaction({&lt;br&gt;
      validUntil: Math.floor(Date.now() / 1000) + 300, // 5-minute validity window&lt;br&gt;
      messages: swapTx.messages.map((message) =&amp;gt; ({&lt;br&gt;
        address: message.address,&lt;br&gt;
        amount: message.amount,&lt;br&gt;
        payload: message.payload,&lt;br&gt;
      })),&lt;br&gt;
    });&lt;br&gt;
  }&lt;br&gt;
  return (&lt;br&gt;
    &amp;lt;button onClick={handleSwap} disabled={!swapTx}&amp;gt;&lt;br&gt;
      Confirm Swap&lt;br&gt;
    &amp;lt;/button&amp;gt;&lt;br&gt;
  );&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The validUntil field matters more than it looks like it should: if you set it too far in the future, a stale transaction can sit in the wallet's queue and eventually execute against a quote that's no longer accurate, potentially at a much worse price than the user agreed to. A five-minute window is a reasonable default for most swap UIs - long enough that a slow wallet app doesn't time out, short enough that market movement doesn't invalidate the trade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8: Track the Swap's&amp;nbsp;Status&lt;/strong&gt;&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%2Fmqh6ouact1m0hfuuapta.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%2Fmqh6ouact1m0hfuuapta.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sending the transaction isn't the end of the story - the user still wants to know whether it actually went through. swapTrack() gives you a live status stream keyed off the quote and the outgoing transaction.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// src/features/swap/useSwapTracking.ts&lt;br&gt;
import { useEffect, useState } from "react";&lt;br&gt;
import { useOmniston, type ChainAddress, type Quote } from "@ston-fi/omniston-sdk-react";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export function useSwapTracking(&lt;br&gt;
  quote: Quote,&lt;br&gt;
  traderAddress: ChainAddress,&lt;br&gt;
  outgoingTxQuery: string&lt;br&gt;
) {&lt;br&gt;
  const omniston = useOmniston();&lt;br&gt;
  const [status, setStatus] = useState&amp;lt;string&amp;gt;("pending");&lt;br&gt;
  useEffect(() =&amp;gt; {&lt;br&gt;
    let unsubscribe = () =&amp;gt; {};&lt;br&gt;
    void omniston&lt;br&gt;
      .swapTrack({&lt;br&gt;
        quoteId: quote.quoteId,&lt;br&gt;
        traderAddress,&lt;br&gt;
        outgoingTxQuery,&lt;br&gt;
      })&lt;br&gt;
      .then((stream) =&amp;gt; {&lt;br&gt;
        const subscription = stream.subscribe({&lt;br&gt;
          next(event) {&lt;br&gt;
            switch (event?.$case) {&lt;br&gt;
              case "awaitingTransfer":&lt;br&gt;
                setStatus("Waiting for wallet transfer to confirm…");&lt;br&gt;
                break;&lt;br&gt;
              case "progress":&lt;br&gt;
                setStatus(event.value.status);&lt;br&gt;
                break;&lt;br&gt;
              case "unsubscribed":&lt;br&gt;
                setStatus("Tracking stream closed");&lt;br&gt;
                break;&lt;br&gt;
            }&lt;br&gt;
          },&lt;br&gt;
        });&lt;br&gt;
        unsubscribe = () =&amp;gt; subscription.unsubscribe();&lt;br&gt;
      });&lt;br&gt;
    return () =&amp;gt; unsubscribe();&lt;br&gt;
  }, [omniston, quote.quoteId, traderAddress, outgoingTxQuery]);&lt;br&gt;
  return status;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;outgoingTxQuery can be a transaction hash, message hash, or the outgoing message body - whichever identifier your wallet integration surfaces most reliably after sendTransaction() resolves. TonConnect's sendTransaction() response includes a boc (bag of cells) you can decode to extract this, though the exact extraction step depends on which TonConnect version and helper library you're using, so it's worth checking the current TonConnect docs for the specific decode helper rather than assuming the API surface hasn't shifted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Pitfalls Worth Knowing Before You&amp;nbsp;Ship&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treating the RFQ stream as a single request&lt;/strong&gt;. Because useRfq() is a subscription, holding a quote in state and never re-checking it before building the transaction can mean signing against a price that's since moved. Always build the transaction from the latest quote event, not whatever was first received.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skipping the sandbox environment.&lt;/strong&gt; It's tempting to point straight at production (wss://omni-ws.ston.fi) while developing, but the sandbox endpoint exists precisely so test trades don't compete for real liquidity or risk real funds during development - use it until your flow is stable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming every quote is a swap quote.&lt;/strong&gt; Because Omniston can return either swap or order settlement data depending on route and settlement params, code that only handles useTonBuildSwap() will silently break the moment a quote comes back as an order (which happens more often for cross-chain routes). Always branch on quote.settlementData?.$case rather than assuming one shape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring the SDK's pre-1.0 status.&lt;/strong&gt; As of writing, @ston-fi/omniston-sdk is still under active development with a major version of zero, meaning breaking changes can land in minor releases under semantic versioning conventions. Pin your version explicitly in package.json rather than trusting a caret range, and check the changelog before bumping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going From Prototype to Production&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few things worth doing before this ships to real users, beyond what's covered above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcode fewer addresses.&lt;/strong&gt; Replace the hardcoded USDT/STON asset IDs from Step 4 with a proper token search or registry integration so users can swap any supported pair, not just the two you picked for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surface slippage as a user-facing setting,&lt;/strong&gt; rather than a fixed constant in code - traders on volatile pairs often want to widen or tighten maxPriceSlippagePips themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handle the noQuote case gracefully&lt;/strong&gt; in your UI instead of leaving a blank state - it happens for illiquid pairs or when input size exceeds what any connected resolver can fill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add error boundaries around the wallet-signing step&lt;/strong&gt; specifically, since users rejecting a transaction in their wallet app is a normal, expected outcome your UI needs to handle without looking broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What you've built here - a live quote stream, a build-and-sign flow through TonConnect, and status tracking - is the same core loop every swap feature on TON ultimately needs, whether it's a full DEX front end or a single "swap" button tucked into an unrelated dApp. The heavy lifting Omniston does for you (multi-source routing, quote refreshing, settlement-type branching) is exactly the part that's tedious and error-prone to hand-roll against raw contracts. From here, the natural next steps are wiring in a real token list, adding the order/HTLC flow for cross-chain swaps if your app needs them, and hardening the edge cases called out above before pointing the integration at production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Sources &amp;amp; Further&amp;nbsp;Reading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;STON.fi Developer Docs - Introduction: &lt;a href="https://docs.ston.fi/" rel="noopener noreferrer"&gt;https://docs.ston.fi/&lt;/a&gt;&lt;br&gt;
Omniston SDK - Node.js Quickstart: &lt;a href="https://docs.ston.fi/developer-section/omniston/sdk/nodejs" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/sdk/nodejs&lt;/a&gt;&lt;br&gt;
Omniston SDK - React Quickstart: &lt;a href="https://docs.ston.fi/developer-section/omniston/sdk/react" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston/sdk/react&lt;/a&gt;&lt;br&gt;
Omniston Protocol Overview: &lt;a href="https://docs.ston.fi/developer-section/omniston" rel="noopener noreferrer"&gt;https://docs.ston.fi/developer-section/omniston&lt;/a&gt;&lt;br&gt;
@ston-fi/omniston-sdk on npm: &lt;a href="https://www.npmjs.com/package/@ston-fi/omniston-sdk" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ston-fi/omniston-sdk&lt;/a&gt;&lt;br&gt;
@ston-fi/omniston-sdk-react on npm: &lt;a href="https://www.npmjs.com/package/@ston-fi/omniston-sdk-react" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ston-fi/omniston-sdk-react&lt;/a&gt;&lt;br&gt;
@ston-fi/sdk (classic DEX SDK) on npm: &lt;a href="https://www.npmjs.com/package/@ston-fi/sdk" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ston-fi/sdk&lt;/a&gt;&lt;br&gt;
STON.fi SDK - GitHub source: &lt;a href="https://github.com/ston-fi/sdk" rel="noopener noreferrer"&gt;https://github.com/ston-fi/sdk&lt;/a&gt;&lt;br&gt;
Omniston SDK - GitHub source and example React app: &lt;a href="https://github.com/ston-fi/omniston-sdk/tree/main/examples/react-app" rel="noopener noreferrer"&gt;https://github.com/ston-fi/omniston-sdk/tree/main/examples/react-app&lt;/a&gt;&lt;br&gt;
Live SDK demo app: &lt;a href="https://sdk-demo-app.ston.fi" rel="noopener noreferrer"&gt;https://sdk-demo-app.ston.fi&lt;/a&gt;&lt;br&gt;
TonConnect UI React docs: &lt;a href="https://docs.tonconnect.io/docs/quick-start/react" rel="noopener noreferrer"&gt;https://docs.tonconnect.io/docs/quick-start/react&lt;/a&gt;&lt;br&gt;
TON Core - &lt;a class="mentioned-user" href="https://dev.to/ton"&gt;@ton&lt;/a&gt;/ton package installation guide: &lt;a href="https://www.npmjs.com/package/@ton/ton" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ton/ton&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This walkthrough is based on the STON.fi and Omniston SDK documentation as of mid-2026 (protocol version v1beta8). Both the SDK API surface and the underlying protocol are under active development - verify method signatures and package versions against the current docs at docs.ston.fi before shipping to production, and check the official demo app (sdk-demo-app.ston.fi) for a working reference implementation.&lt;/p&gt;

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