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
相关产品推荐
相关产品推荐

