如何让Web3News合约与NewsToken交互实现代币支付?
问题分析与解决方案
核心错误原因
你的getAccessToArticle1函数里,newsToken.approve(address(this), minimumPayment)这行代码是Web3News合约地址发起的调用,但ERC20的approve方法要求必须由**代币持有者(也就是调用getAccessToArticle1的用户msg.sender)**主动发起授权。这就导致合约尝试给自己授权的操作完全无效,后续执行transferFrom时会因为用户未授权合约花费代币而失败。
正确实现流程
ERC20代币的转账(transferFrom)需要两步操作,必须由用户主动完成第一步:
- 用户先通过钱包/前端调用
NewsToken合约的approve方法,授权Web3News合约可以从自己账户中转出minimumPayment数量的NWT代币。 - 用户再调用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
相关产品推荐
相关产品推荐

