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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:05:51