使用说明
WalletMcp——以太坊交易MCP服务器
Stdio JSON-RPC服务器为以太坊主网提供了三种工具:
get_balance--ETH或ERC-20余额查询get_token_price--采用Uniswap V3回退的链式首价swap_tokens--构建真正的Uniswap V3呼叫数据并模拟(无广播)
设计决策
编码结构
- 三层:MCP(标准输入/JSON-RPC)→ 服务(编排)→ 实施(平衡/价格/交换)。这隔离了关注点,使处理程序保持精简,并使核心逻辑可以在没有I/O的情况下进行测试。
- 共享上下文(
ServiceContext)持有provider,以及一个令牌registry后面Arc/RwLock。这使得在发现新令牌时能够进行安全的并发读取和偶尔的写入。 - **stdio上的JSON-RPC保持二进制主机无关性和MCP兼容;stdout保留用于协议有效负载,日志通过以下方式发送到stderr**
tracing.
核心流程
- 令牌元数据和注册表
- 默认元数据保存在(
config/token_defaults.json)用于确定性行为和快速启动。 - 按需发现:如果令牌不在注册表中,但提供了地址,服务器将获取最小的ERC-20元数据并缓存,从而避免对静态配置的硬依赖。
- 我将注册表和主流程解耦,以方便以后的维护。
- 默认元数据保存在(
- 定价政策
- 首先向Chainlink索取价格,以确保完整性和弹性
- 如果不存在,则回退到Uniswap V3 Quoter
- 按构造交换模拟
- 调用Uniswap V3 QuoterV2单跳输出,然后计算滑点。
- 构建链上精确的SwapRouter调用数据发送,然后使用私钥通过节点(eth_estimateGas+eth_call)进行模拟
设置
- 依赖项
- 锈蚀(稳定)和货物
- HTTPS以太坊RPC端点(例如Alchemy/Infura/Public)
- 克隆和构建
cargo build --release
- 配置
- 选项A:环境变量(支持dotenv)
ETH_RPC_URL--HTTPS RPC URL(必需)PRIVATE_KEY--十六进制私钥,有或没有0x(可选;交换模拟需要)DEFAULT_CHAIN_ID--默认为1(主网)
- **选项B:**
Config.toml(生产中首选)。例子:eth_rpc_url = "https://..." private_key = "0xabc..." default_chain_id = 1
- 选项A:环境变量(支持dotenv)
- 令牌注册表默认值
- **in**
config/token_defaults.json(符号、地址、小数、链式馈送、默认Uniswap费用等级)。
- **in**
跑
- 通过stdio启动MCP服务器(从stdin读取JSON-RPC行,将响应写入stdout):
cargo run --release
- 或者运行编译后的二进制文件:
target/release/walletmcp
- **服务器通过以下方式登录到stderr**
tracingstdout是为JSON-RPC有效负载保留的。
MCP调用示例(stdio上的JSON-RPC)
- **获得平衡**
-
参数
address:持有人地址(支票加和或小写)0x...).token(可选):ERC-20地址或已知符号;省略ETH。
-
以太坊
- 请求:
{"jsonrpc":"2.0","id":"1","method":"get_balance","params":{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}}- 示例响应:
{"jsonrpc":"2.0","result":{"decimals":18,"formatted":"3.758181447334319014","raw":"3758181447334319014","symbol":"ETH"},"id":"1"} -
泰达币
- 请求:
{"jsonrpc":"2.0","id":"bal-usdt","method":"get_balance","params":{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","token":"0xdAC17F958D2ee523a2206206994597C13D831ec7"}}- 示例响应:
{"jsonrpc":"2.0","id":"bal-usdc","method":"get_balance","params":{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","token":"USDC"}}
-
- **获取代币价格**
-
参数
base:令牌到价格(地址或符号)。quote(可选):"USD"或"ETH"(默认为"USD").
-
USDC → USD
- 请求:
{"jsonrpc":"2.0","id":"price-1","method":"get_token_price","params":{"base":"USDC"}}- 响应:
{"jsonrpc":"2.0","result":{"base":"USDC","decimals":8,"price":"0.99981815","quote":"USD","source":"chainlink"},"id":"price-1"}
-
- **模拟交换**
- 参数
from_token/to_token:地址或已知符号;符号通过注册表解析。amount_in_wei:在wei中以十进制字符串形式输入金额。slippage_bps(可选):基点公差(默认100=1%)。fee(可选):Uniswap V3收费等级。recipient(可选):输出接收器;默认为签名者地址。sqrt_price_limit(可选):X96价格边界;"0"或者无限制地省略。
- 请求:
{"jsonrpc":"2.0","id":"swap-1","method":"swap_tokens","params":{"from_token":"....","to_token":"0x6B175474E89094C44Da98b954EedeAC495271d0F","amount_in_wei":"10000000000000","slippage_bps":100,"fee":3000,"recipient":"0xYourAddressHere"}} - 示例响应:
{"jsonrpc":"2.0","result":{"amount_out_estimate":"0.033810900284009015","amount_out_min":"0.033472791281168924","calldata_hex":"0x414bf389000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000004fc74ba63ddd9c685f8bb59f25d2c9345d3c72e600000000000000000000000000000000000000000000000000000000690c4e19000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000076eb5389f4721c0000000000000000000000000000000000000000000000000000000000000000","gas_estimate":"121109","router":"0xe592427a0aece92de3edee1f18e0157c05861564"},"id":"swap-1"}
- 参数
备注
- 确切数字因市场状况和RPC提供商状态而异。
- **交换模拟需要**
PRIVATE_KEY被配置为导出发送者并构建真实的事务上下文。
描述
get_balance- 参数
addressstring--持有者地址(0x+40个十六进制字符)。tokenstring | null--可选ERC-20地址或已知符号(每个config/token_defaults.json).忽略获取本地ETH余额。
- **退货**
BalanceOut—{ symbol, raw, decimals, formatted }哪里formatted = raw / 10^decimals. - 错误--地址/符号无效,RPC失败。
- 参数
get_token_price- 参数
basestring——令牌地址或符号(注册表已知或可通过链上ERC-20元数据发现)。quotestring(可选,默认"USD")--其中之一"USD"或"ETH".
- **退货**
PriceOut—{ base, quote, price, source, decimals }哪里source是chainlink,chainlink (via USD/ETH),或uniswap_v3 (fee N). - 注——先用链节;使用令牌注册表中的默认费用退回Uniswap V3 Quoter。
- 错误--不支持的令牌、缺少引号令牌配置、RPC失败。
- 参数
swap_tokens- 参数
from_token/to_tokenstring——地址或已知符号。amount_in_weistring——wei中输入金额的十进制字符串。slippage_bps整数(默认值100)--基点(最大10000).fee整数(默认值3000)--Uniswap V3收费等级(例如500/3000/10000)。recipientstring(可选)——接收输出的地址;默认为签名者地址。sqrt_price_limitstring(可选,高级)--rawX96极限;无限制省略。
- **退货**
SwapSimOut—{ amount_out_estimate, amount_out_min, gas_estimate, calldata_hex, router }. - **要求--**
PRIVATE_KEY必须配置为导出发送器,以进行真实的通话数据和气体估计。 - 错误-无效的数字输入,滑点>10000,报价返回0,气体估算/eth_call失败,RPC问题。
- 参数
错误代码
-32602无效参数;-32601未找到方法;-32603内部/序列化。-32001配置;-32002RPC;-32010价格;-32020互换;-32030钱包;-32040输入/输出。
已知限制和假设
- 注册表是静态的,没有更新
- 仅限单跳Uniswap V3;没有路由搜索或多跳路径。
- 在流动性不足的情况下,下跌的DEX价格可能会很嘈杂/容易操纵;视为指示性。
- **有限的Chainlink覆盖范围:仅在**
token_defaults.json(除非在代码中扩展)。 - 真正的执行需要ERC-20的批准和平衡;这个项目只模拟,从不广播。
- 主网合约地址是Uniswap V3 QuoterV2和SwapRouter的硬编码。
核心功能逻辑(高级)
get_balance(余额查找)
- 接受地址和可选的令牌标识符(地址或符号)。
- 如果没有提供令牌,请读取本地ETH余额,并使用18位小数进行格式化。
- 如果提供了令牌,请通过内存中的注册表解析符号(或使用给定的地址),根据需要获取最小的令牌元数据,读取持有者的令牌余额,并使用该令牌的小数进行格式化。
- 返回符号、原始金额、小数和人类可读的格式化字符串。无效输入或网络问题表现为错误。
get_token_price(定价)
- 解析基础资产(地址或符号)。如果还不知道,则发现链上的最小元数据并将其添加到注册表缓存中;如果仍然无法识别,则返回“不支持的令牌”。
- 应用链式优先策略:
- 如果存在直接的基础/引用oracle提要,请使用它。
- 如果没有,请尝试使用众所周知的提要(base/USD+WETH/USD或base/ETH+WETH/USD)通过美元或以太坊进行枢轴转换。
- 如果没有可用的oracle路径,则使用默认费用级别和代表性报价代币(USDC代表美元,WETH代表ETH)退回单跳DEX现货报价。
- 返回带有源标签的十进制字符串价格。如果缺少所需的引号令牌配置,则返回错误。
swap_tomates(模拟,无广播)
- 解析输入和输出资产,并要求签名者构建一个真实的事务上下文(发送方和执行域)。
- 验证金额和滑点;未提供时,默认收件人为签名者。
- 获取所选费用级别的只读输出估计值。
- 从滑动容差中得出可接受的最小输出,并将真实的路由器呼叫数据与截止日期和收件人组装在一起。
- 估算天然气并模拟交易;使用输出标记的小数格式化输出。
- 返回估计输出、最小输出、气体估计、调用数据和路由器地址。真正的执行需要备抵和足够的余额;此工具仅模拟。
网络呼叫和数据源
- get_balance
- 仅限以太坊RPC。
- **ETH:**
eth_getBalance(address, latest). - **ERC-20:**
eth_call代币合约balanceOf(address),加上可选的元数据读取decimals()和symbol()用于格式化。
- get_token_price
- 以太坊RPC+链上数据源。
- **链环(首选):**
eth_callAggregatorV3合同decimals()和latestRoundData()在主网馈送上(例如,WETH/USD、USDC/USD)。 - 数据透视:当缺少直接数据源时,将两个链式数据源(base/USD与WETH/USD,或base/ETH与WETH/USD)组合在一起。
- **Uniswap V3回退:**
eth_call到QuoterV20x61fFE014bA17989E743c5F6cB21bF9697530B21e使用quoteExactInputSingle(...)获取单跳现货报价。 - **注册表确保步骤(根据需要):**
eth_call代币合约decimals()/symbol()当首次看到令牌时。
- swap_takes(模拟)
- 以太坊RPC+Uniswap V3合约。
- **报价:**
eth_call使用Uniswap QuoterV2进行单跳输出估计。 - **呼叫数据:构建Uniswap V3 SwapRouter**
exactInputSingle(...)交易目标0xE592427A0AEce92De3Edee1F18E0157C05861564. - **模拟:**
eth_estimateGas对于路由器事务,则eth_call对其进行干燥处理;不eth_sendRawTransaction(从不广播)。 - **元数据:如果需要**
eth_call对小数合约进行标记,以格式化输出金额。
测试
汇款:一些单元测试需要完整的配置(ETH_RPC_URL、PRIVATE_KEY)!!!
- **运行快速单元测试:**
cargo test - **标记实时网络测试**
#[ignore]并需要env变量(请参见tests/和评论)。如果您有真实的RPC和资金密钥,请手动启用它们。
安全说明
- 永远不要提交真正的私钥。在本地使用环境变量,在生产中使用安全的秘密管理器。
- **服务器从不广播交易;模拟用途**
eth_estimateGas和eth_call只有。