<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[TornadoSwap Guides]]></title><description><![CDATA[TornadoSwap Guides]]></description><link>https://tornadoswap.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ad545dbfa076d04c3781664/2be2b960-2851-4d57-9010-f8b8c5f50d22.png</url><title>TornadoSwap Guides</title><link>https://tornadoswap.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 25 Oct 2026 20:07:44 GMT</lastBuildDate><atom:link href="https://tornadoswap.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a cross-chain swap interface: why a token ticker is not an asset ID]]></title><description><![CDATA[Model coin and network identity in a crypto swap UI, preserve quote inputs, reject stale responses and check live provider availability.]]></description><link>https://tornadoswap.hashnode.dev/building-a-cross-chain-swap-interface-why-a-token-ticker-is-not-an-asset-id</link><guid isPermaLink="true">https://tornadoswap.hashnode.dev/building-a-cross-chain-swap-interface-why-a-token-ticker-is-not-an-asset-id</guid><category><![CDATA[Blockchain development]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[TornadoSwap]]></dc:creator><pubDate>Sun, 18 Oct 2026 22:25:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ad545dbfa076d04c3781664/917ec17b-4001-490e-8b49-07ca69ab7cd3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Disclosure: Written under the TornadoSwap corporate byline with AI assistance. This service-affiliated development guide is based on the current Tornado Swap implementation and linked primary documentation. Examples are explanatory, not live quotes, audited code or evidence of a funded transaction.</p>
<p>A coin picker looks simple until the same symbol appears several times. USDC on Ethereum and USDC on Solana share a ticker, but a quote request cannot treat those options as interchangeable. The network changes what the provider must accept and where the output must be delivered.</p>
<p>For a developer building a cross-chain crypto swap interface, this is a data-modelling problem before it is a design problem. If the application uses the ticker as its only key, the wrong option can survive selection, deduplication, caching or restoration from a saved search. Showing a network badge later does not repair an ambiguous request created earlier.</p>
<p><img src="https://cdn.hashnode.com/uploads/covers/6ad545dbfa076d04c3781664/917ec17b-4001-490e-8b49-07ca69ab7cd3.png" alt="Bitcoin Mainnet branches into separate USDC Ethereum and USDC Solana quote requests." /></p>
<p><em>Original TornadoSwap development illustration using the official Bitcoin and USDC icons. Two USDC network options produce different quote requests. The diagram is explanatory and does not claim that either example has a current provider route.</em></p>
<h2>Make the asset-network pair explicit</h2>
<p>The Tornado Swap interface represents a listed coin with fields including ticker, network, name, amount limits and whether a memo is required. Its catalogue normalisation deduplicates by ticker and network together. A ticker repeated on another network is retained as a separate option.</p>
<p>This design reflects a broader distinction visible in issuer documentation. Circle publishes USDC contract identifiers separately for supported networks and distinguishes mainnet assets from testnet tokens. A familiar symbol does not supply the missing chain or token-contract identity. See Circle's current USDC contract directory: <a href="https://developers.circle.com/stablecoins/usdc-contract-addresses">https://developers.circle.com/stablecoins/usdc-contract-addresses</a></p>
<p>Within a provider integration, preserve the provider's exact network identifiers as transport values. A friendly label such as Ethereum can appear in the UI, while a provider may expect a particular network string in its request. Maintain an explicit mapping rather than deriving the transport value from a translated display name.</p>
<p>A small conceptual key function can express the idea:</p>
<pre><code class="language-typescript">type ListedAsset = { ticker: string; network: string };
const assetKey = (asset: ListedAsset) =&gt;
  JSON.stringify([asset.ticker, asset.network]);

const ethereumUsdc = { ticker: 'usdc', network: 'ERC20' };
const solanaUsdc = { ticker: 'usdc', network: 'SOL' };
// These keys are intentionally different.
assetKey(ethereumUsdc) !== assetKey(solanaUsdc);
</code></pre>
<p>This is an illustrative application key, not a universal token identifier. A larger catalogue may also need chain IDs, contract or mint identifiers, issuer information and native-versus-bridged distinctions. Define the uniqueness guarantee your own catalogue actually provides; a symbol and a loosely normalised network name cannot resolve every token collision.</p>
<h2>Carry identity through the whole request</h2>
<p>A quote needs both sides of the exchange: sending ticker, sending network, receiving ticker, receiving network and input amount. Tornado Swap's request contract reads those fields separately. It rejects an identical sending and receiving ticker-network combination as a no-op while allowing distinct network choices to be evaluated.</p>
<p>Do not reduce the receiving selection back to a ticker when serialising a form. For example, replacing a stored object with just usdc would discard the information the user selected. The same principle applies to page routes, saved searches, analytics labels and React list keys: retain enough context to identify the selected network.</p>
<p>A robust review screen should make the two directions visible. A user exchanging Bitcoin for USDC needs to distinguish the network used for the Bitcoin deposit from the network used for the USDC payout. A single generic network label near the bottom of a card leaves room for a costly misunderstanding.</p>
<h2>A valid catalogue entry is not a live route</h2>
<p>There are two different checks. The first asks whether each selected coin-network option exists in the supported catalogue. The second asks whether a provider currently offers a route for that exact pair and amount. Passing the first check does not prove the second will pass.</p>
<p>In the current implementation, local contract validation checks that both options are listed and that the sending amount falls within the catalogue's limits. The interface then requests provider quotes. An empty quote result is an availability outcome, not a reason to silently change the user's receiving network.</p>
<p>That distinction also matters when building token landing pages. A page can describe an asset-network option without promising that every destination is always available. Keep a clear live-quote step between discovery and order creation. A static pair page or a listed destination is not a standing commitment from an exchange provider.</p>
<h2>Normalise data without inventing support</h2>
<p>External responses can contain duplicate entries, invalid amounts or mixed representations of a boolean. Tornado Swap's normalisation code checks for required strings and finite positive amount limits before exposing coin options. It converts the memo flag into a consistent boolean and deduplicates the ticker-network key.</p>
<p>The useful engineering principle is to define an accepted shape at the boundary. Do not let a malformed entry become a selectable coin just because its ticker and image look convincing. Likewise, do not fill a missing network with a guessed default simply to make a response render.</p>
<p>Keep display formatting separate from transport data. A translation or a more readable label can improve the picker, but it should not silently rewrite the identifiers sent to the provider. When those identifiers need to change, update and verify the mapping deliberately.</p>
<h2>Invalidate quotes when the inputs change</h2>
<p>Once a quote appears, another class of ambiguity can emerge: the form shows the newly selected network, but the estimate belongs to the previous request. Treat the selection, amount and quote as related state rather than independent labels that happen to be nearby.</p>
<p>The Tornado Swap component aborts an earlier quote request and uses a request-version guard while inputs change. The intended result is to keep stale responses from replacing the estimate for a newer selection. The displayed receive amount is labelled approximate, and quote expiry is checked before order creation.</p>
<p>Those mechanisms address interface consistency. They do not guarantee provider availability, a final payout amount or execution time. A server still needs to validate the request it receives rather than trust a browser merely because it rendered the expected controls.</p>
<h2>Address checks remain a separate responsibility</h2>
<p>A listed receiving network does not prove that a supplied wallet address is valid for it or supported by the receiving service. Structural form checks, chain-specific address validation, required memos and a destination platform's deposit policy are different layers.</p>
<p>The current shared address helper trims input and applies basic type and length limits. That is input-shape validation, not cryptographic proof of ownership or a complete blockchain-address validator. Developers should name that boundary accurately instead of describing every non-empty input as verified.</p>
<p>Similarly, a deposit QR code can carry an address without carrying the amount, network or memo. The surrounding order screen must preserve those instructions. Ethereum's network documentation provides useful context for why a network is part of the environment a transaction belongs to: <a href="https://ethereum.org/developers/docs/networks/">https://ethereum.org/developers/docs/networks/</a></p>
<h2>Keep the provider boundary visible</h2>
<p>Tornado Swap compares independent provider offers without requiring a wallet connection to the interface. That removes one browser-wallet interaction, but the chosen provider still handles the deposit, conversion and payout. Provider verification rules and eligibility restrictions continue to apply.</p>
<p>The development lesson is broader than one exchange: model what the user actually chose, preserve it across every boundary, and distinguish catalogue validity from executable availability. A precise asset-network identity makes that possible. A familiar ticker alone does not.</p>
<h2>Service reference and implementation scope</h2>
<p>Tornado Swap: <a href="https://tornadoswap.app/">https://tornadoswap.app/</a>
Implementation reviewed for this guide: catalogue normalisation, pair validation and quote-request handling in the local Tornado Swap source, 19 October 2026. The code fragment above is a simplified example. This guide does not claim exhaustive testing, an independent security audit or guaranteed compatibility with any wallet or provider.</p>
]]></content:encoded></item></channel></rss>