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

Thirdweb交易报错:交易未在50区块内确认,如何解决?

解决Thirdweb SDK转账超时(Transaction was not mined within 50 blocks)问题

你遇到的交易超时错误,核心原因是代码里的签名者(Signer)使用错误、金额处理不当、授权逻辑混乱,导致交易无法被网络确认。以下是针对性的修复方案:

1. 修复Signer的错误使用

你的代码里用了未定义的signer变量, fallback到随机生成的random钱包——这个随机钱包没有用户的私钥,根本无法发起有效交易。正确的做法是从Thirdweb的React hooks获取用户连接的钱包signer:

import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import { ConnectWallet, useAddress, useSigner } from "@thirdweb-dev/react"; // 新增useSigner

export default function DonationPage() {
    const address = useAddress();
    const signer = useSigner(); // 获取用户连接的钱包signer

    async function sendCoins() {
        if (!signer) {
            alert("请先连接钱包");
            return;
        }
        // 移除随机钱包代码,直接用用户的signer初始化SDK
        const sdk = ThirdwebSDK.fromSigner(signer, "mainnet");
        // ...后续代码
    }
}

2. 修正金额单位转换

你直接使用donationAmount原始数值调用转账方法,但区块链代币的最小单位是wei(ETH)或对应代币的小数位单位,必须将用户输入的金额转换为最小单位:

// 处理ETH转账的金额转换
if (selectedCoin === 'eth') {
    // 将ETH金额转为wei(1ETH = 10^18 wei)
    const amountInWei = ethers.utils.parseEther(donationAmount.toString());
    await sdk.wallet.transfer(CORPORATE_WALLET, amountInWei);
} else {
    const coin = crypto.find(c => c.id === selectedCoin);
    if (!coin?.contract_address) {
        alert("无效的代币合约地址");
        return;
    }
    const contract = await sdk.getContract(coin.contract_address);
    // 获取代币小数位数,转换金额为最小单位
    const decimals = await contract.erc20.decimals();
    const amountInUnits = ethers.utils.parseUnits(donationAmount.toString(), decimals);
    // ...后续授权/转账逻辑
}

3. 重构TransferFrom的授权逻辑

你当前的授权逻辑完全错误:transferFrom是让授权的spender从用户地址转钱,如果你是用用户自己的signer调用transferFrom,spender就是用户自己,根本不需要授权——直接用transfer方法更简单。如果确实需要第三方合约代转,才需要授权给该合约地址:

正确的代币转账方式(无需授权)

// 直接从用户地址转代币到企业钱包,无需授权
await contract.erc20.transfer(CORPORATE_WALLET, amountInUnits);

如果必须用TransferFrom(比如第三方合约代转)

// 授权给第三方合约地址(不是用户自己!)
const spenderAddress = "第三方合约地址"; // 替换为实际需要授权的地址
const allowance = await contract.erc20.allowance(address, spenderAddress);
if (allowance.value.lt(amountInUnits)) {
    // 授权足够的金额
    await contract.erc20.setAllowance(spenderAddress, amountInUnits);
}
// 由第三方合约调用transferFrom,或者你用signer调用时指定spender已授权

4. 其他代码优化

  • 移除冗余的嵌套try-catch,统一错误处理
  • 确保CORPORATE_WALLET、selectedCoin、donationAmount、crypto等变量已正确定义且不为空
  • 增加交易等待的反馈(比如加载状态),避免用户重复触发交易

完整修复后的核心代码示例

import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import { ConnectWallet, useAddress, useSigner } from "@thirdweb-dev/react";
import { ethers } from "ethers";
import { useState } from "react";

// 假设这些变量已在外部定义
const CORPORATE_WALLET = "你的企业钱包地址";
const crypto = [/* 你的代币列表,包含id和contract_address */];

export default function DonationPage() {
    const address = useAddress();
    const signer = useSigner();
    const [selectedCoin, setSelectedCoin] = useState('');
    const [donationAmount, setDonationAmount] = useState('');
    const [isLoading, setIsLoading] = useState(false);

    async function sendCoins() {
        if (!signer || !address || !selectedCoin || !donationAmount || !CORPORATE_WALLET) {
            alert("请完善所有信息并连接钱包");
            return;
        }
        setIsLoading(true);
        try {
            const sdk = ThirdwebSDK.fromSigner(signer, "mainnet");
            
            if (selectedCoin === 'eth') {
                const amountInWei = ethers.utils.parseEther(donationAmount);
                await sdk.wallet.transfer(CORPORATE_WALLET, amountInWei);
            } else {
                const coin = crypto.find(c => c.id === selectedCoin);
                if (!coin?.contract_address) throw new Error("无效的代币合约");
                
                const contract = await sdk.getContract(coin.contract_address);
                const decimals = await contract.erc20.decimals();
                const amountInUnits = ethers.utils.parseUnits(donationAmount, decimals);
                
                // 直接转账,无需授权
                await contract.erc20.transfer(CORPORATE_WALLET, amountInUnits);
            }
            alert("转账成功");
        } catch (error) {
            console.error("转账失败:", error);
            alert(`转账失败: ${error.message || "未知错误"}`);
        } finally {
            setIsLoading(false);
        }
    }

    return (
        <>
            <ConnectWallet />
            {/* 你的UI组件:选择代币、输入金额、转账按钮(禁用loading状态) */}
            <button onClick={sendCoins} disabled={isLoading}>
                {isLoading ? "处理中..." : "确认捐赠"}
            </button>
        </>
    );
}

内容的提问来源于stack exchange,提问作者Shihab Shahriyar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:05:20