You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Alloy-RS调用Uniswap ExactInputSingle返回正确amountOut但实际兑换未执行的问题求助

Alloy-RS调用Uniswap ExactInputSingle返回正确amountOut但实际兑换未执行的问题求助

我最近在用Alloy-RS开发Uniswap兑换功能,调用ExactInputSingle函数时遇到了一个奇怪的问题:代码执行没有报错,返回的amountOut数值完全符合预期,但链上实际根本没有发生代币兑换操作。我已经提前设置了金额限制,也排查了参数的正确性,现在怀疑是不是交易没有被签名并发送上链?

先贴一下我的核心代码片段:

let params = ISwapRouter::ExactInputSingleParams {
    tokenIn: token_in,
    tokenOut: token_out,
    fee: U24::from(self.fee),
    recipient: self.wallet_address.clone(),
    deadline: U256::from(deadline),
    amountIn: U256::from(amount_in),
    amountOutMinimum: U256::ZERO, // 暂时不设最小输出限制
    sqrtPriceLimitX96: U160::ZERO,
};

amount_out = (f64::from(router.exactInputSingle(params)
    .call()
    .await?));

执行后得到的输出如下:

In Swap true
tokenIn: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
tokenOut: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
fee: 500
recipient: 0x...
deadline: 1750446136
amountIn: 7000000000000000.0
amountIn_f: 0.007
amountOut: 16988876.0
amountOut_f: 16.988876
amountOutMinimum: 0
sqrtPriceLimitX96: 0

问题核心分析

你遇到的这个问题其实是Alloy-RS中模拟调用(call)和实际交易发送(send)的区别导致的:

  • 你代码里用的.call()方法是只读模拟调用,它只会在本地节点上模拟执行合约函数,计算出预期的返回值(也就是你看到的正确amountOut),但不会把交易广播到区块链网络,自然不会有实际的代币转移。
  • 要执行真实的兑换,你需要使用.send()方法,并且需要用你的钱包签名器(Signer)来签名交易,然后广播到链上。

修正后的代码示例

下面是调整后的代码,替换掉原来的.call()逻辑,改为发送真实交易:

// 假设你已经有了初始化好的SignerMiddleware(包含钱包签名器和Provider)
let params = ISwapRouter::ExactInputSingleParams {
    tokenIn: token_in,
    tokenOut: token_out,
    fee: U24::from(self.fee),
    recipient: self.wallet_address.clone(),
    deadline: U256::from(deadline),
    amountIn: U256::from(amount_in),
    amountOutMinimum: U256::ZERO,
    sqrtPriceLimitX96: U160::ZERO,
};

// 构建交易并发送,而不是模拟调用
let tx_builder = router.exactInputSingle(params);
let tx = tx_builder
    .build()
    .await?; // 构建交易结构体

// 使用SignerMiddleware发送并签名交易
let pending_tx = signer_middleware.send_transaction(tx, None).await?;
let receipt = pending_tx.get_receipt().await?; // 等待交易上链并获取收据

// 确认交易是否成功
if let Some(status) = receipt.status {
    if status == 1 {
        println!("交易成功上链!");
        // 这里可以从收据中解析事件或者再次查询余额确认兑换结果
    } else {
        println!("交易失败,状态码:{:?}", status);
    }
}

额外需要检查的点

  1. 代币授权(Approve):在调用ExactInputSingle之前,你需要确保tokenIn的代币已经授权给Uniswap SwapRouter合约足够的额度,否则交易执行会失败。比如WETH的授权代码:
let approve_tx = weth.approve(router_address, amount_in)
    .build()
    .await?;
let approve_receipt = signer_middleware.send_transaction(approve_tx, None).await?.get_receipt().await?;
  1. Deadline有效性:确认你的deadline参数是未来的时间戳,如果调用时已经过期,交易也会失败。
  2. Gas设置:如果Gas Price或Gas Limit设置过低,交易可能会被网络延迟处理或者直接丢弃,可以在发送交易时手动指定Gas参数:
let tx = tx_builder
    .with_gas_limit(U256::from(200000)) // 根据实际情况调整
    .with_gas_price(U256::from(10_000_000_000)) // 10 Gwei
    .build()
    .await?;
  1. 链环境确认:确保你连接的节点和钱包的链ID一致(比如主网、Sepolia测试网等),避免跨链调用导致的无实际交易问题。

总结

你的核心问题就是把模拟调用当成了实际交易发送,只要把.call()替换为真实的交易签名和发送逻辑,再配合正确的代币授权,就能解决“返回正确amountOut但无实际兑换”的问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:37:59