Solidity合约.transfer()未转账问题及ERC20捐赠凭证实现需求
问题排查与修复方案
1. 测试代码未等待交易确认
你的测试代码调用donation.sendDonation()时未添加await,导致代码直接跳过交易执行流程,提前打印"Donation sent!",实际交易并未完成,看起来像是转账没执行。
修复后的测试代码:
const [address, fund] = await ethers.getSigners() // 部署合约 const donation = ( await createContract<DonationPolygon>('DonationPolygon', fund.address) ).connect(address) console.log(`合约部署地址: ${donation.address}`) console.log('获取当前MATIC价格...') console.log(await donation._getNativeCurrencyPrice()) console.log('发起捐赠...') // 等待交易上链完成 await donation.sendDonation({ value: ethers.utils.parseEther('5') }) console.log('捐赠完成!') // 新增余额校验,验证转账是否成功 const recipientBalance = await ethers.provider.getBalance(fund.address) console.log(`收款方余额更新为: ${ethers.utils.formatEther(recipientBalance)}`)
2. Solidity合约转账方式的潜在问题
transfer()函数有2300 gas的硬性限制,如果recipient是合约地址,且其receive()或fallback()函数需要更多gas,转账会直接失败。建议改用call()方式,兼容性更强且无gas限制:
修改合约中的sendDonation函数:
function sendDonation(address deptAddress) external payable { // 使用call转账并校验是否成功 (bool success, ) = recipient.call{value: msg.value}(""); require(success, "转账失败"); // 计算铸造数量:统一单位避免精度问题 uint256 maticUsdPrice = _getNativeCurrencyPrice(); // msg.value是wei单位,转换为USD等价的ERC20代币(18位小数) uint256 mintAmount = (msg.value * maticUsdPrice) / 1e10; _mint(deptAddress, mintAmount); }
3. Chainlink价格获取的精度修正
你的_getNativeCurrencyPrice是占位符,实际使用Chainlink时,Polygon上MATIC/USD喂价的精度为8位小数(比如0.8美元会返回80000000)。需要适配精度调整计算逻辑:
// 引入Chainlink喂价合约 AggregatorV3Interface internal priceFeed; constructor(address payable _recipient) ERC20("Co2 Dept Receipt", "Co2") { recipient = _recipient; // Polygon链上MATIC/USD喂价合约地址 priceFeed = AggregatorV3Interface(0xAB594600376Ec9fD91F8e885dADF0CE036862dE0); } function _getNativeCurrencyPrice() public view returns (uint256) { (, int256 price, , , ) = priceFeed.latestRoundData(); // 转换为uint类型,保持Chainlink返回的8位小数精度 return uint256(price); }
4. 补充安全与权限控制
- 添加
onlyOwner限制收款地址修改权限,防止恶意篡改:
function setRecipient(address payable _newRecipient) external onlyOwner { recipient = _newRecipient; }
- 可引入OpenZeppelin的
ReentrancyGuard,进一步防范重入攻击风险。
内容的提问来源于stack exchange,提问作者Herbie Vine
相关产品推荐
相关产品推荐

