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

如何让Web3News合约与NewsToken交互实现代币支付?

问题分析与解决方案

核心错误原因

你的getAccessToArticle1函数里,newsToken.approve(address(this), minimumPayment)这行代码是Web3News合约地址发起的调用,但ERC20的approve方法要求必须由**代币持有者(也就是调用getAccessToArticle1的用户msg.sender)**主动发起授权。这就导致合约尝试给自己授权的操作完全无效,后续执行transferFrom时会因为用户未授权合约花费代币而失败。

正确实现流程

ERC20代币的转账(transferFrom)需要两步操作,必须由用户主动完成第一步:

  1. 用户先通过钱包/前端调用NewsToken合约的approve方法,授权Web3News合约可以从自己账户中转出minimumPayment数量的NWT代币。
  2. 用户再调用Web3News合约的getAccessToArticle1方法,合约此时执行transferFrom完成转账并标记用户为已购买。

修正后的合约代码

修改getAccessToArticle1函数,移除无效的合约内approve调用,添加授权额度检查:

function getAccessToArticle1() public {
    // 检查用户代币余额足够
    require(newsToken.balanceOf(msg.sender) >= minimumPayment, "Not enough tokens");
    // 检查用户已授权合约足够的额度
    require(newsToken.allowance(msg.sender, address(this)) >= minimumPayment, "Contract not authorized to transfer tokens");
    // 执行转账:从用户账户转到作者账户
    bool success = newsToken.transferFrom(msg.sender, writer, minimumPayment);
    require(success, "Token transfer failed");
    // 标记用户为已购买
    buyers[msg.sender] = true;
}

额外优化点

  • 移除函数的payable修饰符:因为这是代币支付,不需要接收ETH,payable会误导用户。
  • 对transferFrom的返回值做检查:OpenZeppelin的ERC20实现中,transferFrom默认会在失败时revert,但显式检查返回值可以兼容更严格的ERC20实现。

前端/用户操作说明

用户在调用getAccessToArticle1之前,必须先调用NewsToken的approve方法:

// 示例前端代码(ethers.js)
const newsTokenContract = new ethers.Contract(tokenAddress, tokenAbi, signer);
// 授权Web3News合约可以花费minimumPayment数量的NWT
await newsTokenContract.approve(web3NewsContractAddress, minimumPayment);
// 然后调用获取文章权限的方法
const web3NewsContract = new ethers.Contract(web3NewsAddress, web3NewsAbi, signer);
await web3NewsContract.getAccessToArticle1();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:45:25