
Uniswap Universal Router Decoder
io.github.Elnaril由 GitHub 账号 Elnaril 发布v4.0.0更新于 Oct 29, 2026
Decode and encode Uniswap Universal Router calldata (V2, V3, V4). Read-only: never signs or sends.
发布方自己的服务:370.ai — AI Gateway: 100+ Chat Models, Image & Speech Generation
概览
本地 MCP 服务器,用于解码和编码 Uniswap Universal Router 的 V2、V3、V4 调用数据,只读,不签名也不发送交易。
- 可以做什么
- 把 Universal Router 交易输入解码为命令、参数、截止时间和尾部数据
- 按交易哈希从 RPC 端点获取并解码整笔交易
- 编码与解码 Uniswap V3 交换路径,并构建 V4 的 pool key、path key 和 pool id
- 从解码结果重建调用数据,可先解码、修改路线再重新编码
- 编码可链式组合的路由命令,如各类交换、ETH 包装、Permit2 授权、分账、sweep 和转账
- 适用场景
- 适合需要弄清某笔 Uniswap Universal Router 交易究竟做了什么,或希望助手在你自己签名之前生成、调整交换、流动性或 Permit2 流程的路由调用数据时使用。
- 运行要求
- 以 Python 包形式在本地运行(可用 uvx 或 pip 安装)。按哈希解码整笔交易需要以太坊 RPC 端点,通过环境变量 RPC_URL 提供;解码原始调用数据和编码则不需要。
安装
在 SourceWeft 中
- 打开 控制台中的 Uniswap Universal Router Decoder,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
Uniswap Universal Router Decoder & Encoder
Many thanks to everyone who has ☕️ offered some coffees! ☕️ or ⭐ starred this project! ⭐
It is greatly appreciated! :)
Project Information
[PyPI - Python Version] [GitHub release (latest by date)] [PyPi Repository] [GitHub] [Uniswap Universal Router Decoder MCP on mcprush]
Code Quality
[Tests & Lint] [CodeQL] [Test Coverage] [Imports: isort] [Type Checker: basedpyright] [Linter: flake8]
Release Notes
See the release notes page
v4.0.0 - breaking changes
- Update COMMAND_TYPE_MASK to 0x7f to match UR
- Add support for the PAY_PORTION_FULL_PRECISION command (0x07)
- Add support for the BALANCE_CHECK_ERC20 command (0x0e)
- Add support for the V3_POSITION_MANAGER_PERMIT command (0x11)
- Add support for the V3_POSITION_MANAGER_CALL command (0x12)
- Add support for the EXECUTE_SUB_PLAN command (0x21)
- Add
revert_on_failto the encoder methods for the commands whose failure the UR can tolerate - Capture the bytes some callers append after the UR arguments as
trailing_data, and re-append them when rebuilding the calldata, so a decoded call can be rebuilt byte-for-byte - Make the chained function builders public and expose the
encoder&decodermodules - Reduce CI time
- Add a
publish.ymlGitHub Actions workflow that automatically publishes the package to PyPI and the MCP Registry with OIDC Trusted Publishing - Agent-friendly changes:
- Add
Encoder.function_input()/AsyncEncoder.function_input()to rebuild the calldata from a decoded call - Add
decoded_input_to_dict()andtransaction_to_dict()to render the decoder output as JSON-friendly dicts - Add the
ur-decodeandur-encodecommand line tools, includingur-encode v3-pathand itsencode_v3_pathMCP counterpart - Add the
ur-mcpMCP server (optionalmcpextra) so AI agents can drive the codec, includingencode_calldatato rebuild the calldata from a decoded call - Annotate the MCP tools as read-only so a host can auto-approve them, and give them human-readable titles
- The command descriptions (
ur-encode list/describeand thelist_commands/describe_commandMCP tools) now describe the decoded call format and its ABI parameters, instead of the encoder methods - Add the MCP Registry metadata (
server.json) to make theur-mcpserver discoverable - Add
AGENTS.mdandllms.txtfor AI agents, plus amcpPyPI keyword - Add
tests/test_version_consistency.pyto keep the packaging version,server.jsonand the READMEmcp-name:marker in sync
- Add
Overview and Points of Attention
The object of this library is to decode & encode transactions sent to the Uniswap Universal Router (UR) on Ethereum Mainnet, though it would work on any compatible chain where the UR is deployed. See Version Mapping below. This Python SDK is based on, and intended to be used with web3.py
The target audience is Python developers who are familiar with the Ethereum blockchain concepts and web3.py, and how DEXes work.
The same codec is also available without Python, through the ur-decode / ur-encode command line tools and the optional
ur-mcp MCP server (see "Command line interface" and "MCP server" below): both print JSON, so shell scripts and AI
agents can drive it too.
⚠ Before using this library, ensure you are familiar with general blockchain concepts. The Python API also expects web3.py knowledge in particular.
⚠ Not all UR functions supported by this SDK are available through the CLI or MCP tools:
run ur-encode list and look for the "rebuildable" flag.
List of supported Uniswap Universal Router Functions
All the ✅ commands can be decoded and encoded. V4_SWAP, V4_POSITION_MANAGER_CALL and EXECUTE_SUB_PLAN can also
be decoded, but they cannot be rebuilt from a decoded call (see "How to rebuild the calldata from a decoded call").
Version Mapping
Here is the mapping between the Universal Router versions and the SDK ones
Installation
A good practice is to use Python virtual environments, here is a tutorial.
The library can be pip installed from pypi.org as usual:
To install it from source:
or for contributors:
Usage
The library exposes 2 classes, RouterCodec and AsyncRouterCodec with several public methods
that can be used to decode or encode UR data and transactions.
Both RouterCodec and AsyncRouterCodec are used the same way but either synchronously
or asynchronously for the relevant parts, ie when doing rpc calls.
How to instantiate the router codec
1/ When no need for rpc calls
2/ Using the URL of an rpc endpoint
Sync code:
Async code:
3/ Using a Web3/AsyncWeb3 instance
Sync code:
Async code:
How to decode a Uniswap Universal Router transaction input
To decode a transaction input, use the decode.function_input() method as follows:
Example of decoded input returned by decode.function_input():
decode.function_input() reports the bytes some callers append after the UR arguments as trailing_data (see the
example above). Pass find_trailing_data=False to ignore them.
Tip: You can format the decoded input like above with this Gedit plugin ;)
How to decode a Uniswap Universal Router transaction
It's also possible to decode the whole transaction, given its hash
and providing the codec has been built with either a valid Web3 instance or the link to a rpc endpoint.
The decoder will get the transaction from the blockchain and decode it, along with its input data:
How to encode/decode a Uniswap V3 swap path
RouterCodec exposes two mirror methods: encode.v3_path() builds a Uniswap V3 path from the ordered tokens and the
pool fees between them, and decode.v3_path() reads one back.
decode.v3_path() returns a tuple, starting with the "in-token" and ending with the "out-token", with the pool fees
between each pair. Both methods use that same order: V3_SWAP_EXACT_OUT reverses the path when encoding, and the
decoder reverses it back.
How to get the decoded data as JSON-friendly dicts
The decoder returns rich Python objects (web3 contract functions, raw bytes, ...) that are not directly serialisable. Two helpers render that output as plain dicts/lists/strings, ready to be printed as JSON or sent to another system:
decoded_input_to_dict()takes the output ofdecode.function_input()transaction_to_dict()takes the output ofdecode.transaction()
Bytes are rendered as "0x"-prefixed hex strings, and each decoded command becomes a dict with a command name,
its params, and a revert_on_fail flag:
How to encode
The Uniswap Universal Router allows the chaining of several functions in the same transaction. This codec supports it (at least for supported functions) and exposes public methods that can be chained.
The chaining starts with the encode.chain() method and ends with the build() one which returns the full encoded data to be included in the transaction.
Below some examples of encoded data for one function and one example for 2 functions.
Starting with v3.0.0, it is possible to start the chaining with encode() instead of encode.chain(), making the code a bit more concise.
Default values for deadlines and expirations can be computed with the static methods get_default_deadline() and get_default_expiration() respectively.
These 2 functions accept a custom duration in seconds as argument.
revert_on_fail can be passed to the methods whose command the UR can tolerate failing: permit2_permit(),
permit2_permit_batch(), balance_check_erc20(), v3_position_manager_permit(), v3_decrease_liquidity(),
v3_collect(), v3_burn(), v4_initialize_pool(), build_v4_posm_call() and execute_sub_plan(). It defaults to
True; set it to False to let the transaction continue if that command fails. The other methods don't accept it,
because the UR ignores that flag for their command.
How to rebuild the calldata from a decoded call
As an alternative to chaining the encoder methods, encode.function_input() builds the calldata from the decoded form
of an execute call. It is the mirror of decode.function_input(): where the decoder turns a function input into
commands, this turns the decoded commands back into a function input, so a route can be decoded, edited, and re-encoded.
The expected shape is the one produced by decoded_input_to_dict() (and by the ur-decode CLI and the MCP server):
its params.inputs hold the commands, using the names and parameters the decoder reports (the Universal Router ABI
names).
The function key is optional and defaults to execute, and the commands bytes are ignored: the command list is
rebuilt from the inputs entries. The deadline key is optional too; when it is absent, the plain
execute(bytes,bytes[]) form is used instead of execute(bytes,bytes[],uint256).
Some callers append a tag after the ABI-encoded arguments, which the UR ignores. The decoder reports it as
params.trailing_data, and encode.function_input() re-appends it, so a decoded call can be rebuilt byte-for-byte.
The chained builders take the same value as an optional trailing_data argument of build(), after deadline.
Commands the decoder expands into structures (V4_SWAP, V4_POSITION_MANAGER_CALL, EXECUTE_SUB_PLAN) cannot be
rebuilt this way and raise a ValueError.
revert_on_fail is honoured only for the commands whose failure the UR can tolerate (PERMIT2_PERMIT,
PERMIT2_PERMIT_BATCH, BALANCE_CHECK_ERC20, V3_POSITION_MANAGER_PERMIT, V3_POSITION_MANAGER_CALL,
V4_INITIALIZE_POOL, V4_POSITION_MANAGER_CALL, EXECUTE_SUB_PLAN). For every other command the UR ignores the
flag, so it is always cleared. The same applies to the encoder methods: those commands take a revert_on_fail
argument (default True), the others do not.
AsyncRouterCodec exposes the same method (encode.function_input()); it is synchronous, so no await is needed.
How to encode a call to the Uniswap Universal Router function WRAP_ETH
This function can be used to convert eth to weth using the UR.
How to encode a call to the Uniswap V2 function V2_SWAP_EXACT_IN
This function can be used to swap tokens on a V2 pool. Correct allowances must have been set before sending such transaction.
For more details, see this tutorial
How to encode a call to the Uniswap V2 function V2_SWAP_EXACT_OUT
This function can be used to swap tokens on a V2 pool. Correct allowances must have been set before sending such transaction.
How to encode a call to the Uniswap V3 function V3_SWAP_EXACT_IN
This function can be used to swap tokens on a V3 pool. Correct allowances must have been set before sending such transaction.
How to encode a call to the Uniswap V3 function V3_SWAP_EXACT_OUT
This function can be used to swap tokens on a V3 pool. Correct allowances must have been set before sending such transaction.
How to encode a call to the Uniswap Universal Router function PERMIT2_PERMIT
This function is used to give an allowance to the universal router via the Permit2 contract (0x000000000022D473030F116dDEE9F6B43aC78BA3).
It is also necessary to approve the Permit2 contract using the token approve function.
See this tutorial
After that, you can swap tokens using the Uniswap universal router.
How to get the current permit2 allowance, expiration and nonce
You can get the nonce you need to build the permit2 signable message like this:
How to chain a call to PERMIT2_PERMIT and V2_SWAP_EXACT_IN in the same transaction
Don't forget to give a token allowance to the Permit2 contract as well.
Uniswap V4 Functions
How to build a Uniswap V4 pool key
PoolKey is used to identify a pool.
How to build a Uniswap V4 path key
PathKey is used to identify pools in a multi-hop swaps.
How to encode a Uniswap V4 pool id
Pool ids are used by V4 contracts to identify pools. For example, you'll need it to request the StateView contract.
How to initialize a Uniswap V4 pool with the Universal Router function V4_INITIALIZE_POOL
How to mint a Uniswap V4 position with the Universal Router function V4_POSITION_MANAGER_CALL
Example where a position on a ETH/TOKEN pool is minted between tick_0 and tick_1
How to perform a Uniswap V4 swap with the Universal Router function V4_SWAP
Example using the V4 SWAP_EXACT_IN_SINGLE function to swap ETH for a token
Example using the V4 SWAP_EXACT_IN function to swap ETH for a token through 2 pools
path: eth -> token a -> token b
Other chainable functions
(See integration tests for full examples)
PAY_PORTION
Example where a recipient is paid 1% of the USDC amount:
PAY_PORTION_FULL_PRECISION
Same as PAY_PORTION but with full precision, where 10**18 represents 100%. Example where a recipient is paid 50% of the USDC amount:
SWEEP
Example where the sender gets back all remaining USDC:
TRANSFER
Example where a USDC amount is sent to a recipient:
BALANCE_CHECK_ERC20
Reverts if the owner's balance of the given ERC20 token is lower than the minimum amount. Example where the router must hold at least 1 USDC:
EXECUTE_SUB_PLAN
Executes a nested plan of commands. The Universal Router calls itself to run the sub-plan, so its commands
are executed in the same transaction and share the same context (recipients, balances, ...).
The sub-plan is built with encode.chain() just like the main plan.
Example where a sub-plan transferring USDC is nested in the main plan:
V3_POSITION_MANAGER_PERMIT
Approves a spender for a specific V3 position (NFT) using an EIP-712 signature instead of a transaction.
The signable message is built with create_v3_position_manager_permit_signable_message(), then signed.
Example where the spender is approved for the position token_id:
V3_POSITION_MANAGER_CALL
Calls one of the 3 V3 position manager functions the UR allows: decreaseLiquidity, collect or burn.
Only one function can be called per V3_POSITION_MANAGER_CALL command: the UR forwards the input as a single
call and rejects anything else (including multicall). To run several of them, chain several commands in the
same transaction (see the integration test).
The UR must be approved for the position first (see V3_POSITION_MANAGER_PERMIT).
decreaseLiquidityremoves liquidity from the position. The freed tokens are NOT sent out: they are recorded astokensOwed0/tokensOwed1on the position, together with ALL the fees earned since the last update (fees are not prorated, even if only part of the liquidity is removed).collectsendsmin(amountMax, tokensOwed)to the recipient.tokensOwedholds both the principal freed bydecreaseLiquidityand the fees, socollectalone harvests the fees without touching the liquidity.burndeletes the position (NFT). It requires the position to be empty (liquidity == 0andtokensOwed0 == tokensOwed1 == 0), hence the usualdecreaseLiquidity->collect->burnorder.
Note: increaseLiquidity and mint are not reachable through the UR (only the 3 functions above are allowed),
they must be called directly on the V3 position manager.
Example where the liquidity of a V3 position is decreased:
Example where the tokens owed to a V3 position are collected:
Example where an empty V3 position is burned:
PERMIT2_TRANSFER_FROM
To use this function, the Universal Router needs to be PERMIT2'ed.
Example where 1 WETH is transferred from the caller address to the v4 position manager
PERMIT2_PERMIT_BATCH & PERMIT2_TRANSFER_FROM_BATCH
Check the corresponding integration tests for an example of how to use these functions.
How to build directly a transaction to the Uniswap Universal Router
The SDK provides a handy method to build very easily the full transaction in addition to the input data. It can compute most of the transaction parameters (if the codec has been instantiated with a valid w3 or rpc url) or you can provide them.
See the corresponding integration tests for an async example
Example where a swap is encoded and a transaction is built automatically:
And that's it! You can now sign and send this transaction. A few other important parameters:
value: the quantity of ETH in wei you send to the Universal Router (for example when you wrap them before a swap)trx_speed: an enum which influences the transaction rank in the block. Values are:TransactionSpeed.SLOWTransactionSpeed.AVERAGETransactionSpeed.FAST(default)TransactionSpeed.FASTER
max_fee_per_gas_limit: if the computedmax_fee_per_gasis greater thanmax_fee_per_gas_limitaValueErrorwill be raised to allow you to stay in control. Default is 100 gwei.
How to use the trx_speed parameter:
Command line interface
The package installs two commands that print JSON to stdout, handy for shell scripts or to let an agent drive the codec:
ur-encode: describe the decoded call format and the commands, rebuild calldata from a decoded call, or encode a V3 pathur-decode: decode a transaction, raw calldata, a custom error or a V3 path
A plan file holds a decoded execute call, exactly as ur-decode calldata prints it:
MCP server
The optional mcp extra installs ur-mcp, a side-effect free Model Context
Protocol server that exposes the codec to AI agents over stdio. Its tools only
inspect or derive Universal Router data: they never sign or broadcast a transaction.
It provides eight tools:
list_commands/describe_command: discover the decoded call format and the commandsdecode_transaction: fetch and decode a transaction sent to the UR (needs an RPC endpoint)decode_calldata,encode_calldata,decode_error,decode_v3_path,encode_v3_path: decode/encode data without an RPC endpoint
encode_calldata is the mirror of decode_calldata: it rebuilds the calldata from a decoded call, so an agent can
decode a route, edit it and re-encode it (the MCP counterpart of ur-encode build).
The tools are annotated as read-only (readOnlyHint), and only decode_transaction as open-world (openWorldHint),
so a host can auto-approve them instead of prompting on every call. Each tool also carries a human-readable title
(title) for the host UI.
decode_transaction uses the rpc_url tool argument, or the RPC_URL / ETH_RPC_URL environment variables, so a
host can be pointed at any chain by configuring the server environment.
To wire it into an MCP host (Zed, Claude Desktop, ...):
Utility functions
How to compute the gas fees
The SDK provides handy methods to compute the current "priority fee" and "max fee per gas":
Sync code:
Async code:
Ticks, sqrtPriceX96 and liquidity
These functions can be useful to estimate the arguments needed to mint positions.
⚠️ The implementation of all tick, sqrtPriceX96, and liquidity related functions differs from the contracts: if you want the exact same results/numbers, do not use them.
They can be imported from uniswap_universal_router_decoder.utils.
For examples, check the integration tests for Uniswap V4.
Tutorials and Recipes on the Uniswap Universal Router:
See the SDK Wiki.
News and Q&A:
See the Discussions and 𝕏
来源:README.md,提交 dc4a725
工具
0版本历史
1- v4.0.0最新Oct 29, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
其他 Router 集成
370.ai — AI Gateway: 100+ Chat Models, Image & Speech Generation
ai.router官方发布者
远程 AI 网关 MCP 服务器,让助手用一个 370.ai API 密钥调用 100 多个聊天模型、生成图片并把文字转为语音。

AI Media Router
由 GitHub 账号 jutsuhq 发布
本地 MCP 服务器,用你自己的 API 密钥通过 40 多家供应商生成图片和视频,支持比价和可搜索的本地素材库。

Bike Router
由 GitHub 账号 JonasHeinickeBio 发布
连接自建 pyBikeRouter API 的 MCP 服务器,可规划基于 OSM 的骑行路线,并附带天气、景点与 GeoJSON/GPX 导出。

x402 Router
由 GitHub 账号 camerxnduff 发布
只读 MCP 服务器,可搜索经探测的 x402 按次付费端点注册表,并为助手路由到评分最高的端点。

GenPark Consistent Hash Ring Router
由 GitHub 账号 alphaparkinc 发布
一个本地 MCP 服务器,提供带虚拟节点的一致性哈希环,用于分布式 LLM 缓存路由与智能体分区。