Profile picture of ZaK3939.eth 🇦🇪 🇯🇵

ZaK3939.eth 🇦🇪 🇯🇵

@ZacK_3939

Published: March 19, 2025
1
12
125

Uniswapでスワップをする時、裏側で何が起こっているかを解説します。Swapしたり、流動性提供したりする人にオススメな内容にしました。 Order routingで使われるUniswap APIに関して、0.1% tileの理解まで持っていけると思います。 (わかっている人、途中まで読み飛ばしてね。 Translated by Claude. This is not an official Uniswap tweet but rather research by an individual. Understanding Uniswap Swaps: What Happens Behind the Scenes I'll explain what happens behind the scenes when you swap tokens on Uniswap. This content is recommended for anyone who performs swaps or provides liquidity. By the end, you should have a thorough understanding of the Uniswap API used in order routing, down to the 0.1% tile level of detail. (If you're already familiar with this topic, feel free to skip ahead.)

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

本スレッドでは、Base上で、ETH → KAITO のスワップを例に、どのようにUniswapのルーティングパス(スワップの経路)を決定しているかを解説します。 https://blog.uniswap.org/auto-... In this thread, I'll explain how Uniswap determines routing paths (swap routes) using the example of swapping ETH to KAITO on Base.

まずルーティング処理により、個別のプールを訪れる必要がなく利用することができています。 このルーティングはSOR(smart-order-router)と呼ばれ、https://github.com/Uniswap/sma... で管理されています。 画像のような個別プールに行く必要がないのは嬉しいですよね、(面倒ですよね?) First, thanks to the routing process, you don't need to visit individual pools separately - you can use them automatically. This routing is called SOR (smart-order-router) and is managed at https://github.com/Uniswap/sma... Isn't it nice that you don't have to go to individual pools like shown in the image? (It would be quite tedious, wouldn't it?)

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Uniswapで、ユーザーがトークンと数量を入力すると、Uniswap APIに問い合わせがされ、見積もりとルート情報を取得します。 APIは、SORのalpha-router.tsを実行し、指定されたトークンペアで、v2/v3/v4の経路を探索し、プールの流動性状況、スワップ数量による価格インパクト、ガス代などを総合的に評価して最適なルートを決定します。 When a user enters tokens and quantities on Uniswap, a query is sent to the Uniswap API to retrieve quotes and route information. The API executes the alpha-router.ts from the SOR, which explores routes across v2/v3/v4 for the specified token pair. It comprehensively evaluates pool liquidity conditions, price impact based on swap quantity, gas fees, and other factors to determine the optimal route.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Uniswap APIは、見積もりの結果と、ルーティングパスの情報、Universal Routerのcalldata (コントラクトのcall用のパラメータ)を返却します。 universal Routerにこのcalldataをcallすると、図のパスでトークンのスワップが行われます。 https://docs.uniswap.org/contr... After a few seconds, the Uniswap API returns the quote results, routing path information, and calldata for the Universal Router (parameters for the contract call). When you call the Universal Router with this calldata, the token swap is executed along the path shown in the diagram.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

手数料に関しても、UniswapAPIに見積もりのリクエストを投げる時に、interfaceからAPIには、「0.25%で手数料を処理して」とリクエストを投げているので、calldataはそれを前提にデータが作られ、これを実行することで、Uniswap labsに手数料が送金されています。 When requesting a quote from the Uniswap API, the interface sends a request specifying "process with a 0.25% fee." The calldata is created based on this premise, and when executed, the fee is transferred to Uniswap Labs.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Uniswap labsは入力トークンでも出力トークンでも手数料として指定できますが、出力トークンから手数料をとっています。Uniswapが0.25%を定めているせいか、手数料は他のDeFiでも0.25%はよく使われてる印象です。 Uniswap Labs can specify fees in either the input token or output token, but they take the fee from the output token. Perhaps because Uniswap has set this 0.25% rate, this fee percentage seems to be commonly used across other DeFi platforms as well.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

スリッページ (見積もりからの乖離許容度)は、流動性・FOT(手数料)トークン・失敗率を加味して、自動で設定されています。ざっくり、 - 基本値:流動性から 0~3% (低流動性は高い) - 失敗率補正:失敗が多いものは高い0~3% - FOT補正: Fee On Transfer など転送税を持つ+0~2% 右上の歯車から1%程度に変更することもできます。 Slippage (the tolerance for deviation from the quote) is automatically set based on liquidity, FOT (Fee-On-Transfer) tokens, and failure rates. Roughly speaking: Base value: 0-3% depending on liquidity (higher for low liquidity) Failure rate adjustment for tokens with higher failure rates FOT adjustment for tokens with transfer taxes like Fee-On-Transfer You can also change this to around 1% from the gear icon in the top right.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

設定変更はinterfaceのここから変更できます。ここでスリッページやtxの有効期限を設定することが可能です。 You can change settings from here. This is where you can set slippage and transaction expiration times.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Trade Option からはルーティング時の制限ができます。 Defaultの利用だとSORとUniswapXが比較がされます。 SORは、Uniswapプロトコル内の流動性 (v2/v3/v4)を対象に最適なスワップ経路を計算します。 UniswapXは、複数の第三者(フィラー)が注文を拾い、独自の流動性(他のAMMプールやプライベート在庫など)を使って最良価格で注文を満たそうとします。 レートがUniswap X > SORになると執行がUniswapXになります。通常はレートがUniswapのプールより悪いことが多く、SOR経由になることが多いです。 From Trade Options, you can set limitations for routing. When using the Default setting, SOR and UniswapX are compared. SOR calculates the optimal swap route using liquidity within the Uniswap protocol (v2/v3/v4). UniswapX allows multiple third parties (fillers) to pick up orders and fulfill them at the best price using their own liquidity (other AMM pools or private inventory). The execution switches to UniswapX when the rate is UniswapX > SOR. Typically, the rate through UniswapX is often worse than Uniswap pools, so execution frequently happens via SOR.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

(一般的なユーザーはここでスレッドを離れてもらって構いません。) ユーザ「ETH → KAITO」を入力 -> Uniswap APIへリクエスト -> SOR (経路探索) -> Uniswap APIのレスポンス ユーザーが スワップ実行 でinterfaceが動いてるんだなという理解で100点です。 ここから、技術者やDeFiに興味がある人向けに現在のSORの実装を見ていきたいと思います。 https://github.com/Uniswap/sma... (General users may leave the thread at this point.) User inputs "ETH → KAITO" -> Request to Uniswap API -> SOR (route exploration) -> Response from Uniswap API User executes swap If you understand that this is how the interface operates, you've got 💯. From here, I'd like to examine the current SOR implementation for developers and those interested in DeFi.

SORは下記の7ステップを行います。 1. Subgraph からプール情報を取得 2. TVL等でFilterをし、Candidate Poolsを選定 3. Candidate PoolsからETH→KAITOへ到達する経路を選定 4. 経路 × split [10%,20%,..,100%]を大量問い合わせ 5. 各経路のアウトプットをガスコスト調整 6. 最終的なルートを選定 7. calldata生成 The SOR performs the following 7 steps: 1. Retrieve pool information from the Subgraph 2.Filter by TVL etc. to select Candidate Pools 3. Select routes from Candidate Pools that reach ETH→KAITO 4. Make multiple queries for routes × splits [10%,20%,...,100%] 5. Adjust the output of each route for gas costs 6. Select the final route 7. Generate calldata

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

1の過程でsubgraphからプールを取得します。(キャッシュあり。) ここで取得したプールの情報が下記の工程の全てに影響をします。 In step 1, pools are retrieved from the subgraph (with caching). The pool information obtained here affects all subsequent processes. 実装箇所 (v4の場合):https://github.com/Uniswap/sma...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Graphユーザーはご存知だと思いますが、常に最新かつ完全なデータが取れるわけではないことに注意が必要です。(キャッシュもしているので) 混雑したブロックなどでは、インデックス遅延で最新の流動性が反映されないケースがあるため、最新のプール状況をカバーしているとは限りません。 なので、SORは度々適切な経路を提示することが遅れます、具体的には、新興トークンのプール、取引が頻繁なプールは、Uniswap Poolに限定していたとしても、アグリゲータの提示するレートの方が良かったりします。https://x.com/0x_kyu/status/18... 彼らのindexingが、どのように行われているかの情報はありませんが、自分でindexerを立てて、liqのdeltaとswapのイベントをwatchする方が早いのは間違い無いです。(バックラン系のMEVするなら、さらにnodeを立てる感じですね) As Graph users likely know, it's important to note that you can't always get the most up-to-date and complete data. During congested blocks, the latest liquidity might not be reflected due to indexing delays, so the data doesn't always cover the most recent pool conditions. As a result, SOR sometimes delays providing appropriate routes. Specifically, for emerging token pools and frequently traded pools, even when limited to Uniswap Pools, rates offered by aggregators might be better. https://x.com/0x_kyu/status/18... There's no information on how their indexing is performed, but it's undoubtedly faster to set up your own indexer and watch liquidity delta and swap events.

ちなみにindexerにはこのようなプレイヤーがいます。https://docs.unichain.org/docs... 私のおすすめは @envio_indexer です。graphに比べてsyncが鬼のように早いです。めんどくさい準備もなし、docker環境でぽちぽちでself-hostedで実行できます。 https://github.com/enviodev/un... By the way, there are players like these in the indexer space: https://docs.unichain.org/docs... My recommendation is @envio_indexer. It syncs incredibly fast compared to Graph. There's no troublesome setup required - you can run it self-hosted with just a few clicks in a Docker environment. https://github.com/enviodev/un...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

2では、収集したプールからCandidate Poolsを構築します。 https://github.com/Uniswap/sma... ざっくり言うと、ある程度TVLが高く、かつtokenInやtokenOutに関連しそうなプール」を重複なく最終的にリストアップし、これを candidatePools とします。 topN, topNDirectSwaps, topNTokenInOut などのパラメータなどはchainごとに微妙にチューニングされており、poolが多いchainはきつめのfilter設定になっていたりします。 https://github.com/Uniswap/sma... In step 2, we build Candidate Pools from the collected pools. https://github.com/Uniswap/sma... Roughly speaking, it creates a final list without duplicates of "pools with relatively high TVL that are likely related to tokenIn or tokenOut" - these become the candidatePools. Parameters like topN, topNDirectSwaps, and topNTokenInOut are slightly tuned for each chain, with chains that have many pools getting stricter filter settings.

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

驚いたことに、v4で特殊な手数料を作ったりしてもルーティングがされないことに気づきました。例えば、2%等の手数料プールはSORの対象プールから落ちます。 また、HookにAddress_Zero以外を設定している場合、Hookを使っているpoolは、SORの対象では無いので注意が必要そうです。要するに、bunniとかflaunchはSORの恩恵を受けていません。 https://github.com/Uniswap/sma... よくみると、Baseだけ特殊な設定がありますね。こちらを確認してみるとおもしろいかもしれません。 https://gov.uniswap.org/t/rfc-... Surprisingly, I noticed that routing doesn't work when creating special fees with v4. For example, fee pools like 2% are dropped from SOR's target pools. Also, it seems important to note that if you set anything other than Address_Zero in the Hook, pools using Hooks aren't targeted by SOR. In other words, services like bunni and flaunch aren't benefiting from SOR. https://github.com/Uniswap/sma... Looking closely, Base has special settings. It might be interesting to check this out: https://gov.uniswap.org/t/rfc-...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

v4の導入で、特定条件で Fee を下げるようなHookが出ると思うので、ここは手数料が1%以下等、equal条件から変更が入ると嬉しいですね。 また、Hooked Poolはいわゆるwhitelist方式を採用し、attest poolとして別途、経路候補としてルーティングパスを追加されることを望みます。https://x.com/coinbase/status/... I think we'll see Hooks that lower fees under specific conditions, so it would be nice if there were changes from the equal condition to something like fees of 1% or less. Additionally, I hope Hooked Pools will adopt a whitelist method and be added separately as attest pools for routing path candidates. https://x.com/coinbase/status/...

ちなみに、各poolのswap eventを監視すると、Matchaの0x ExchangeやCowSwapのGPv2Settlementや1inch:のAggregationRouterV5等、それぞれ特徴的なコントラクトアドレスからオーダーが来ていることが確認できるかもしれません。 このように、SORで漏れているプールへの流動性提供の際は、当該プールがどこからorderflowがきているかを確認する必要がありますね。 全くルーティングがされていないプールにLPとして参加する場合は、手数料が稼げないばかりか、LVRといった価格裁定によるトキシックオーダーを受けるだけのプールの可能性があります。 2%プールとかは、よくよくみるとなんか手数料凄いもらえているように見えて、LVR食らっただけかもしれませんと言うことです。 bunniはCowswapから来ているようです。 https://x.com/boredGenius/stat... By the way, if you monitor the swap events of each pool, you might be able to confirm that orders come from distinctive contract addresses such as Matcha's 0x Exchange, CowSwap's GPv2Settlement, and 1inch's AggregationRouterV5. When providing liquidity to pools missed by SOR, it's necessary to check where the orderflow for that pool is coming from. If you participate as an LP in a pool that isn't being routed to at all, you might not only fail to earn fees but also end up in a pool that only receives toxic orders from price arbitrage like LVR. Those 2% pools might appear to be earning great fees at first glance, but it could just be that they've been hit by LVR. It seems bunni is coming from Cowswap.

2のfilter処理に関しては、TVLfilterに関して言及をしておく必要があります。ここでは、プール全体の TVL が大きくても、現在価格近辺の “tick範囲内” に十分な流動性が無いようなプールも拾います。 要するにサブグラフ上の TVL だけを基準に “大きいプールだ” とフィルタしており、実際にはactive tickの周辺が窪んだ。いわゆる滑りが大きいプールを選んでいる可能性があります。(最終的にアウトプットトークンが少なくルーティングの経路にならない可能性が高いですが) Regarding the filtering process in step 2, we need to mention the TVL filter. Here, it picks up pools where even though the overall TVL of the pool is large, there might not be sufficient liquidity within the "tick range" near the current price. Essentially, it filters based only on "large pools" according to TVL on the subgraph, and may actually be selecting pools where the area around the active tick is depleted. These are what we call pools with high slippage. (Though ultimately, these are unlikely to become routing paths as they would result in fewer output tokens.)

2で選定されているプールはETH->USDC やUSDC->KAITOのような片側だけ一致しているプールを含むため、候補プールそれぞれから、ETH→KAITOへ到達する経路を列挙します。hop数の最大回数(何個プールを経由するか)等もオプションで設定されています。 この処理でこのような経路候補が選定されます。 1. v3プールA (eth->weth->USDC )→プールB (USDC- >KAITO) 2. v4プールC (eth->kaito) 3. v2 プール D (ETH → USDT) + v3 プール X (USDT → KAITO) In step 2, the selected pools include those that match only on one side, like ETH->USDC or USDC->KAITO. Therefore, it enumerates routes from each candidate pool to reach ETH→KAITO. The maximum number of hops (how many pools to go through) is also configurable in the options. This process selects route candidates like: 1. v3 pool A (eth->weth->USDC) → pool B (USDC->KAITO) 2. v4 pool C (eth->kaito) 3. v2 pool D (ETH → USDT) + v3 pool X (USDT → KAITO) https://github.com/Uniswap/sma...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

この探索方式は、総当たり的なアプローチ に近く、計算量が大きくなる傾向にあります。グラフアルゴリズムを採用し、Dijkstra法 や A*探索 では、グラフの重みを考慮しながら最短経路探索をしているアグリゲータもいるのでは無いかと思います。 個人的に、クロスチェーンスワップをSORとしてサポートをする場合は、ブリッジの枝評価を行い、Neo4jとかを採用しグラフ問題として解く。とかRustやGoに書き換える必要があるのでは無いかと思います。もっと高速化しないといけないような気がしますね。 This search method is close to a brute-force approach and tends to be computationally intensive. I think there may be aggregators that use graph algorithms like Dijkstra's algorithm or A* search to find the shortest path while considering graph weights. Personally, if SOR were to support cross-chain swaps, I think it would need to evaluate bridge branches and adopt something like Neo4j to solve it as a graph problem, or perhaps rewrite the code in Rust or Go. It seems like there's a need for more speed optimization.

4では、大量のルート × 分散されたamount割合で一括クォートしにいきます。ここで活躍するのはmulticall処理です。見積もりに失敗した場合は、nullとして扱われます。 チェーンごとに OnChainQuoteProvider の最適化パラメータを調整しており、なるべく一括で見積もりができるようにしていますが、ここは比較的時間がかかることが多いです。 In step 4, it performs batch quotes with numerous routes × distributed amount proportions. This is where multicall processing plays a crucial role. If a quote fails, it's treated as null. The optimization parameters for the OnChainQuoteProvider are adjusted for each chain to enable batch quotes as much as possible, but this step often takes a relatively long time. https://github.com/Uniswap/sma...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

次に5,6の処理としてガスのアジャストを行い、最終的な Split 構成を「30% はv3ルートA、70% はv4ルートB」といった割合を決定します。マルチホップとしてv2/v4に分割でプール経由するようなパスは、ガス代でかなり調整されうると思います。 For steps 5 and 6, gas adjustments are made to determine the final split configuration, such as "30% through v3 route A, 70% through v4 route B." I think multi-hop paths that go through pools with splits across v2/v4 could be significantly adjusted based on gas costs. https://github.com/Uniswap/sma...

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

7で、ルート/分割の全情報をモジュールにまとめ、 universalRouter 用の calldataを生成してフロントに返した結果がこのようにルートとして表示されユーザーが実行できるようになります。 (xの仕様でこれ以上ポストできなくなりました。告知:今度envio使って、流動性データ掴んで、カスタムhook作るワークショップでもしようと思います。) In step 7, all the route/split information is compiled into modules, and calldata for universalRouter is generated and returned to the frontend. This is then displayed as the route, allowing users to execute it. (Due to Twitter's character limitations, I can't post anymore, so this is the end.) tysm

Image in tweet by ZaK3939.eth 🇦🇪 🇯🇵

Share this thread

Read on Twitter

View original thread

Navigate thread

1/25