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

ERC20代币转至未使用地址时出现0授权错误,求调试方案

ERC20InsufficientAllowance错误排查:已设置最高授权但调用transferFrom时授权额度为0

开发了一套ERC20代币系统,包含XYZtoken.sol与DiscountContract.sol两个合约,核心逻辑为:用户购买商品获得代币、使用代币兑换折扣后,将对应代币转至死地址0x000000000000000000000000000000000000dEaD。

但执行purchaseProducts函数时触发ERC20InsufficientAllowance错误,提示授权额度为0,尽管已通过合约设置最高额度授权。本人Solidity经验有限,缺乏便捷调试手段,已耗时4小时仍未解决,附上合约代码及错误详情,请求帮助排查问题。


合约代码

XYZtoken.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract XYZtoken is ERC20 {

    address payable public owner;

    constructor(uint256 initialSupply) ERC20("XYZtoken", "XYZT") {
        owner = payable (msg.sender);
        _mint(owner, initialSupply);
    }

    function mintExtraTokens(uint256 amount) public onlyOwner {
        _mint(owner, amount);
    }

    function approveDiscountContract(address spender, uint256 amount) public{
        _approve(owner, spender, amount);
    }

    // function usedToken(address unspentaddress, uint256 amount) public {
    //     _burn(unspentaddress, amount);
    // }

    function balanceOf() view public {
        balanceOf(msg.sender);
    }

    modifier onlyOwner {
        require(msg.sender == owner, "Only owner can access this function");
        _;
    }
}

DiscountContract.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./XYZtoken.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract DiscountContract {
    XYZtoken public token;
    address payable public companyAddress;
    address public unspentAddress;

    struct Customer {
        uint256 tokensEarned;
        // uint256 discountRate;
    }

    mapping(address => Customer) public customers;
    
    event TokensEarned(address indexed customer, uint256 amount);
    event DiscountAvailed(address indexed customer, uint256 discountRate);
    event TokensSentToCompanyAddress(address indexed customer, uint256 tokensSent);
    event BalanceLogged(address sender, uint256 amount);
    event excessPaidBack(address sender, uint256 amount);

    constructor(address _tokenAddress) {
        token = XYZtoken(_tokenAddress);
        companyAddress = payable(msg.sender);
        unspentAddress = 0x000000000000000000000000000000000000dEaD;
        token.approveDiscountContract(address(this), type(uint256).max);
    }   

    function availDiscount(address sender) public view returns (uint256) {
        if (token.balanceOf(sender) < 10) {
            return 0;
        }

        // Calculate discount rate based on earned tokens
        uint256 discount = token.balanceOf(sender) / 10;
        if (discount > 5) {
            discount = 5;
        }

        // Transfer the discount tokens from the customer to the unspent address
        return discount;
    }


    function purchaseProducts(uint256 amount) payable external {
        address payable sender = payable(msg.sender);
        // Validate purchase, e.g., product price, availability, etc.
        require(amount > 0, "Amount must be greater than 0");
        require(sender != companyAddress && sender != unspentAddress, "Cannot purchase product");
        //Avail the discount using the tokens
        
        uint256 discount = availDiscount(sender)*10;

        require(discount <=10, "The balance is less than discount");
        // token.approveDiscountContract(address(this), discount*2);
        token.approve(address(this), discount);
        token.transferFrom(sender, unspentAddress, discount);

        uint256 discountedAmount = ((100-discount)/100)*(amount); 
        //Check whether sufficient balance is present or not in the transaction
        require(sender.balance >= discountedAmount*(10**18), "Insufficient ETH balance in the contract");

        //Transfer ETH to the company for
        

        uint256 excessPayment = msg.value - discountedAmount * (10**18);

        // Refund the excess payment to the purchaser
        if (excessPayment > 0) {
            payable(sender).transfer(excessPayment);
            emit excessPaidBack(sender, excessPayment);
        }
        require(msg.value >= discountedAmount * (10**18), "Payment is less than the required amount");

        payable(companyAddress).transfer(discountedAmount*10**18);


        require(msg.value == discountedAmount * (10**18), "Amount sent must match the purchase amount");
        require(token.balanceOf(companyAddress) >= discountedAmount, "Insufficient tokens");
        uint256 earnedTokens = discountedAmount;

        // Mint tokens to the customer
        // token.transferFrom(companyAddress, sender, earnedTokens);
        // token.transferFrom(sender, earnedTokens);
        token.transferFrom(companyAddress, sender, earnedTokens);

        // Update customer's token balance
        customers[sender].tokensEarned += earnedTokens;
        emit TokensEarned(sender, earnedTokens);

        
    }
}

错误信息

transact to DiscountContract.purchaseProducts errored: Error occured: revert.

revert
    The transaction has been reverted to the initial state.
Error provided by the contract:
ERC20InsufficientAllowance
Parameters:
{
 "spender": {
  "value": "0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8",
  "documentation": "Address that may be allowed to operate on tokens without being their owner."
 },
 "allowance": {
  "value": "0",
  "documentation": "Amount of tokens a `spender` is allowed to operate with."
 },
 "needed": {
  "value": "10",
  "documentation": "Minimum amount required to perform a transfer."
 }
}
Debug the transaction to get more information.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:25:20