我是开发智能合约的新手,在测试时遇到了问题。我的目的是确保智能合约不能铸造超过 13 个 ERC721 代币。我的理解是,一个 require 函数可以有第二个字符串参数,如果不满足 require 条件,它会将字符串恢复为错误。这样对吗? 以下是我的智能合约代码:
contract TheCondemned_Episode is ERC721Enumerable {
string[] public episodes;
constructor() ERC721("TheCondemned_e1", "TCe1") public {
}
function mint(string memory _episode) public {
require(episodes.length <= 13, "Cannot make more than 13 episodes");
episodes.push(_episode);
uint _id= episodes.length;
_mint(msg.sender, _id);
}
}
我正在运行的测试如下:
it('Cannot create more than 13 episodes', async() => {
for(var i=0; i===13; i++){
var episode= `Episode ${i}`
await contract.mint(episode)
}
try {
await contract.mint('Episode 14');
assert(true);
}
catch (err) {
return;
}
assert(false, "The contract did not throw.");
测试失败并返回“合约没有抛出”。在测试时从失败的要求条件中捕获恢复字符串的最佳实践是什么?
答案 0 :(得分:0)
我的理解是,require 函数可以有第二个字符串参数,如果不满足 require 条件,该参数会将字符串恢复为错误。这是正确的吗?
没错。下面是一个始终失败的 require()
条件示例,该条件引发异常并显示错误消息。
require(false, 'Error message');
但是,您在 Solidity require()
条件以及 JS 测试片段中存在逻辑错误。
首先,让我们揭开 Solidity 代码。为简单起见,我们假设您只允许制作 1 集。
require(episodes.length <= 1, "Cannot make more than 1 episode");
第一次迭代(预计通过)
episodes.length
为 0,即 <= 1
。条件通过,您铸造第一个令牌,然后推送到 episodes
数组,因此它的 length
在条件之后 变为 1。
第二次迭代(预计失败)
episodes.length
是 1,那仍然是 <= 1
。所以条件也通过了。
解决方案:将 <=
(小于或等于)替换为 <
(小于)。
require(episodes.length < 1, "Cannot make more than 1 episode");
第一次迭代(预计通过)
episodes.length
为 0,即 < 1
。条件通过,您铸造第一个令牌,然后推送到 episodes
数组,因此它的 length
在条件之后 变为 1。
第二次迭代(预计失败)
episodes.length
为 1,如您所料,条件 1 < 1
失败。
我假设您在 JS 代码段中的意图是在循环中调用 mint()
函数 13 次,然后在 try/catch
块中调用 14 次。
然而,循环目前不执行任何迭代。所以实际上,您只执行了一次 mint()
函数(在 try/catch
块中)。
for
循环中的第二个参数是一个条件,说明“只要满足这个条件,这个循环就会一直迭代”。但是由于您在第一个参数中将 i
的值设置为 0,因此不满足循环条件 (i===13
),并且循环甚至不会执行第一次迭代。
解决方案:检查 i
是否是“小于 13”而不是“等于 13”。
for(var i = 0; i < 13; i++) {
这样,循环将迭代 13 次。