首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何接收可靠智能合同处理函数返回的值?

如何接收可靠智能合同处理函数返回的值?
EN

Stack Overflow用户
提问于 2022-05-24 03:21:03
回答 2查看 3K关注 0票数 9

我正在编写一个NFT智能契约,我将通过硬帽进行测试并部署到RSK上。

代码语言:javascript
复制
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract MyNFT is ERC721URIStorage {
    uint private _counter;
    address private _owner;

    constructor() ERC721("My NFT", "MNFT") {
      _owner = msg.sender;
    }

    function owner() public view returns (address) {
      return _owner;
    }

    function mintNFT(address recipient, string memory tokenURI)
        public returns (uint256)
    {
        require(msg.sender == owner(), "Only owner is allowed to mint");
        uint newItemId = ++_counter;
        ERC721._mint(recipient, newItemId);
        ERC721URIStorage._setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

这里我有两个公共函数:ownermintNFT,它们都返回一些值。在我的测试中,我想读取来自这两个函数的返回值。以下是我在“硬帽子”上进行的测试:

代码语言:javascript
复制
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("My NFT", () => {
  let deployer;
  let myNFT;

  // deploy NFT before the tests
  before(async () => {
    [deployer] = await ethers.getSigners();
    const MyNFT = await ethers.getContractFactory('MyNFT');
    myNFT = await MyNFT.deploy();
    await myNFT.deployed();
  });

  describe('Receiving a value returned by a view function', () => {
    it('The deployer should be the s/c owner', async  () => {
      const owner = await myNFT.owner();
      expect(owner).to.equal(deployer.address);
    });
  });
  
  describe('Receiving a value returned by a transacting function', () => {
    it('Should return a correct ID of the newly minted item', async () => {
      const newMintItem = {
        id: 1,
        uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
      };
      const newItemId = await myNFT.mintNFT(deployer.address, newMintItem.uri);
      expect(newItemId).to.equal(newMintItem.id);
    });
  });
});

对于owner函数,我得到了我期望的结果:它返回我的帐户地址,第一个测试成功通过。但是,当涉及到mintNFT函数时,我没有得到我所期望的:而不是新创建的项ID,而是得到了完全不同的东西,第二个测试失败了。

为什么两个非常相似的测试给我不同的结果?如何从发送事务的函数中获得返回值?作为参考,这是我使用的hardhat.config.js文件:

代码语言:javascript
复制
require("@nomiclabs/hardhat-waffle");

module.exports = {
  solidity: "0.8.4",
  defaultNetwork: 'rskregtest',
  networks: {
    rskregtest: {
      chainId: 33,
      url: 'http://localhost:4444',
    },
  },
};
EN

回答 2

Stack Overflow用户

发布于 2022-05-24 09:52:33

从事务返回的值在EVM之外不可用。

您可以发出事件,也可以创建值的公共view getter函数。

代码语言:javascript
复制
contract MyNFT is ERC721URIStorage {
    // `public` visibility autogenerates view function named `_counter()`
    uint public _counter;
    event NFTMinted(uint256 indexed _id);

    function mintNFT(address recipient, string memory tokenURI)
        public returns (uint256)
    {
        // ...
        emit NFTMinted(newItemId);
        return newItemId;
    }
}
代码语言:javascript
复制
it('Should return a correct ID of the newly minted item', async () => {
    const newMintItem = {
        id: 1,
        uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
    };

    // testing the emitted event
    await expect(myNFT.mintNFT(deployer.address, newMintItem.uri))
        .to.emit(myNFT, "NFTMinted")
        .withArgs(newMintItem.id);

    // testing the getter value
    const counter = await myNFT._counter();
    expect(counter).to.equal(newMintItem.id);
});

博士:https://ethereum-waffle.readthedocs.io/en/latest/matchers.html#emitting-events

票数 9
EN

Stack Overflow用户

发布于 2022-05-24 17:47:20

您不能直接接收来自要将事务发送到脱机的函数的返回值。您只能在链上这样做,即当一个SC函数调用另一个SC函数时。

但是,在这种情况下,您可以通过事件获得值,因为ERC721规范包括一个Transfer事件:

代码语言:javascript
复制
    /// @dev This emits when ownership of any NFT changes by any mechanism.
    ///  This event emits when NFTs are created (`from` == 0) and destroyed
    ///  (`to` == 0). Exception: during contract creation, any number of NFTs
    ///  may be created and assigned without emitting Transfer. At the time of
    ///  any transfer, the approved address for that NFT (if any) is reset to none.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

Ethers.js中,您已经在硬件测试中使用了它,而不是智能契约函数返回值,您将在这一行中得到一个返回的事务响应对象

代码语言:javascript
复制
const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);

接下来,您需要通过调用交易收据上的wait来获得txResponse

代码语言:javascript
复制
const txReceipt = await txResponse.wait();

反过来,txReceipt包含一个events数组,该数组包含事务发出的所有事件。在这种情况下,期望它包含一个Transfer事件,指示从零地址到您的帐户地址的第一个薄荷项转移。通过从events数组中提取第一个元素来获取此事件:

代码语言:javascript
复制
const [transferEvent] = txReceipt.events;

接下来,从tokenId参数中获取transferEvent属性,这将是您新创建的NFT的Id:

代码语言:javascript
复制
const { tokenId } = transferEvent.args;

整个测试结果如下:

代码语言:javascript
复制
describe('Receiving a value returned by a transacting function', () => {
    it('Should return a correct ID of the newly minted item', async () => {
      const newMintItem = {
        id: 1,
        uri: 'ipfs://QmY6KX35Rg25rnaffmZzGUFb3raRhtPA5JEFeSSWQA4GHL',
      };
      const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);
      const txReceipt = await txResponse.wait();
      const [transferEvent] = txReceipt.events;
      const { tokenId } = transferEvent.args;
      expect(tokenId).to.equal(newMintItem.id);
    });
  });
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72356857

复制
相关文章

相似问题

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