首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查和授予坚实性的作用

检查和授予坚实性的作用
EN

Stack Overflow用户
提问于 2021-10-20 14:05:44
回答 1查看 707关注 0票数 2

我正试图创建一个工厂合同,用于制造ERC721代币,价格取决于预售期间是否有两种不同的价格。

我正在使用来自OpenZeppelin的Access库,并将我的契约设置为两个角色(外加默认的管理员角色)。为了简洁起见,有些行被排除在外:

代码语言:javascript
复制
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./Example.sol";

contract ExampleFactory is AccessControl {
  // ...

  bool public ONLY_WHITELISTED = true;
  uint256 public PRESALE_COST = 6700000 gwei;
  uint256 public SALE_COST = 13400000 gwei;
  uint256 MAX_PRESALE_MINT = 2;
  uint256 MAX_LIVE_MINT = 10;
  uint256 TOTAL_SUPPLY = 100;

  // ...

  bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
  bytes32 public constant ROLE_PRESALE = keccak256("ROLE_PRESALE");
  
  // ...

  constructor(address _nftAddress) {
    nftAddress = _nftAddress;

    // Grant the contract deployer the default admin role: it will be able
    // to grant and revoke any roles
    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    _setupRole(ROLE_MINTER, msg.sender);
    _setupRole(ROLE_PRESALE, msg.sender);
  }

  function mint(uint256 _mintAmount, address _toAddress) public payable {
    // If the user doesn't have the minter role then require payment
    if (hasRole(ROLE_MINTER, msg.sender) == false) {
        if (ONLY_WHITELISTED == true) {
            // If still in whitelist mode then require presale role & enough value
            require(hasRole(ROLE_PRESALE, msg.sender), "address is not whitelisted");
            require(msg.value >= PRESALE_COST * _mintAmount, "tx value too low for quantity");
        } else {
            require(msg.value >= SALE_COST * _mintAmount, "tx value too low for quantity");
        }
    }

    // Check there are enough tokens left to mint
    require(canMint(_mintAmount), "remaining supply too low");

    Example token = Example(nftAddress);
    for (uint256 i = 0; i < _mintAmount; i++) {
        token.mintTo(_toAddress);
    }
  }

  function canMint(uint256 _mintAmount) public view returns (bool) {
    if (hasRole(ROLE_MINTER, msg.sender) == false) {
        if (ONLY_WHITELISTED == true) {
            require((_mintAmount <= MAX_PRESALE_MINT), "max 2 tokens can be minted during presale");
        } else {
            require((_mintAmount <= MAX_LIVE_MINT), "max 10 tokens can be minted during sale");
        }
    }

    Example token = Example(nftAddress);
    uint256 issuedSupply = token.totalSupply();
    return issuedSupply < (TOTAL_SUPPLY - _mintAmount);
  }
}

造币公司有几种不同的途径:

  • 如果用户拥有ROLE_MINTER,他们可以不用付费或限制就可以铸币。
  • 如果ONLY_WHITELISTEDtrue,则交易必须具有足够的预售价格价值,并且必须有ROLE_PRESALE
  • 如果ONLY_WHITELISTEDfalse,任何人都可以造币

我编写了一个测试造币的脚本:

代码语言:javascript
复制
const factoryContract = new web3Instance.eth.Contract(
  FACTORY_ABI,
  FACTORY_CONTRACT_ADDRESS,
  { gasLimit: '1000000' }
);

console.log('Testing mint x3 from minter role')
try {
  const result = await factoryContract.methods
    .mint(3, OWNER_ADDRESS)
    .send({ from: OWNER_ADDRESS });
  console.log('  ✅  Minted 3x. Transaction: ' + result.transactionHash);
} catch (err) {
  console.log('    Mint failed')
  console.log(err)
}

成功地将此标记运行到工厂所有者。这个调用没有附加任何价值,而且它比最大值更多,因此为了使它成功,它必须遵循ROLE_MINTER路径。

但是,如果我从同一个地址调用hasRole,则结果是false,这是没有意义的。

代码语言:javascript
复制
const minterHex = web3.utils.fromAscii('ROLE_MINTER')
const result = await factoryContract.methods.hasRole(minterHex, OWNER_ADDRESS).call({ from: OWNER_ADDRESS });
// result = false

如果我试图从另一个地址(没有角色)运行测试薄荷脚本,它会像预期的那样失败,这表明角色正在工作,但我使用hasRole是错误的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-20 16:02:11

代码语言:javascript
复制
const minterHex = web3.utils.fromAscii('ROLE_MINTER')

此JS片段返回字符串:0x524f4c455f4d494e544552ROLE_MINTER十六进制表示

代码语言:javascript
复制
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");

但是这个稳固的片段返回了keccak256 散列ROLE_MINTER字符串:0xaeaef46186eb59f884e36929b6d682a6ae35e1e43d8f05f058dcefb92b601461

因此,当您查询OWNER_ADDRESS是否有角色0x524f4c455f4d494e544552时,它会返回false,因为这个地址没有这个角色。

可以使用web3.utils.soliditySha3()函数(文档)计算哈希。

代码语言:javascript
复制
const minterHash = web3.utils.soliditySha3('ROLE_MINTER');
const result = await factoryContract.methods.hasRole(minterHash, OWNER_ADDRESS).call();

还请注意,OpenZeppelin hasRole()函数不检查msg.sender,因此不需要在call()函数中指定调用者。这仅仅是hasRole()的第二个论点,你要问的是他们的角色。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69647532

复制
相关文章

相似问题

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