首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >_burn()奇性

_burn()奇性
EN

Ethereum用户
提问于 2023-02-09 20:58:02
回答 1查看 35关注 0票数 0

我偶然发现了burn()在OpenZeppelin ERC20 contracts中的一个问题。我有以下测试:

代码语言:javascript
复制
import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import { ethers } from "hardhat";
import {rpcBlock} from "hardhat/internal/core/jsonrpc/types/output/block";
import {address} from "hardhat/internal/core/config/config-validation";

describe("MSGSNDR", function () {
  // We define a fixture to reuse the same setup in every test.
  // We use loadFixture to run this setup once, snapshot that state,
  // and reset Hardhat Network to that snapshot in every test.
  async function deployContractFixture() {

    // Contracts are deployed using the first signer/account by default
    const [owner, otherAccount, yetAnotherAccount] = await ethers.getSigners();

    const MSGSNDR = await ethers.getContractFactory("MSGSNDR");
    const msgsndr = await MSGSNDR.deploy("MSGSNDR", "MSGS");

    return { msgsndr, owner, otherAccount, yetAnotherAccount };
  }

  describe("Burnable", function () {

    it("burn(): burn 2_400 wei", async function () {
      const { msgsndr, owner, otherAccount } = await loadFixture(deployContractFixture);

      await msgsndr.mint(otherAccount.address, 10_000);
      await expect(msgsndr.connect(otherAccount).burn(2_400))
          .to.emit(msgsndr, 'Transfer')
          .withArgs(otherAccount.address, ethers.constants.AddressZero, 2_400);
      expect(await msgsndr.balanceOf(otherAccount.address)).to.equal(7_600);
    });
  });
});

我正在测试_burn()的行为,发现以下两个版本的合同行为方式不同:

  1. 这个合同失败了。它使用从_burn()逐字复制的OpenZeppelin GitHub回购
代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import 'hardhat/console.sol';

contract MSGSNDR is ERC20, ERC20Burnable, Ownable {

    mapping(address => uint256) private _balances;
    uint256 private _totalSupply;

    constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {
        _totalSupply = 10_000;
    }

    function mint(address to, uint256 _amount) public {

        _mint(to, _amount);

    }

    /**
     * copied from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d59306bd06a241083841c2e4a39db08e1f3722cc/contracts/token/ERC20/ERC20.sol
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal override virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }
}
  1. 这份合同到期了。
代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import 'hardhat/console.sol';

contract MSGSNDR is ERC20, ERC20Burnable, Ownable {

    mapping(address => uint256) private _balances;
    uint256 private _totalSupply;

    constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {
        _totalSupply = 10_000;
    }

    function mint(address to, uint256 _amount) public {

        _mint(to, _amount);

    }
}

是什么导致了这种行为的改变?

EN

回答 1

Ethereum用户

回答已采纳

发布于 2023-02-10 08:48:01

  • 在Remix中调试了几个xx分钟之后,回复消息是:"ERC20:燃烧量超过余额“。
  • 我意识到要将_balances()和_totalSupply放在MSGSNDR中,您可以在契约中重新定义它们,尽管它们已经在ERC20契约中定义为私有。
  • 这导致了这样的问题:当契约调用_balances(account)时,它们返回到0,但是在另一方,balanceOf(account)完全正常工作。
  • 解决办法是:
  1. 而不是直接分配总量供应,你可以铸币给所有者你想要的数量。
  2. 而不是使用_balances()使用balanceOf()。
  3. 最后,删除代码中的_balances()和_totalSupply分配行。
票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/144641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档