未能在智能合约上验证 merkle 证明

Failing to validate merkle proof on smart contract

我正在使用一份 Invisible Friends NFT 合约 (https://etherscan.io/address/0x59468516a8259058bad1ca5f8f4bff190d30e066#code),我目前正在创建一个铸造页面。除了验证用于白名单铸造的 merkle 证明外,一切进展顺利。

首先,我创建了一个包含 2 个 ETH 地址的数组,将 merkle 树放在一起,计算根哈希并在合约上更新它:

let leafNodes;
let merkleTree;
let merkleProof;
let merkleRoot;
const whitelist = ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"];
leafNodes = whitelist.map(addr => keccak256(addr.concat("5")));
merkleTree = new MerkleTree(leafNodes, keccak256, { sortPairs: true });
merkleRoot = merkleTree.getRoot();
await contract.setMerkleProof(merkleRoot);

现在,当我创建 merkle 证明并尝试在我的前端验证它时,它有效:

merkleProof = merkleTree.getHexProof(keccak256(owner.address.concat("5")));
console.log(merkleTree.verify(merkleProof, keccak256(owner.address.concat("5")), merkleRoot)) => returns "true"

但是,当我尝试使用生成的证明进行铸造时,它失败了:

await contract.mintListed(1, merkleProof, 5, { value: ethers.utils.parseEther("0.25") });
=> "Error: VM Exception while processing transaction: reverted with reason string 'Invalid proof'"

负责merkle证明验证的合约方:

function _verify(
    bytes32[] calldata merkleProof,
    address sender,
    uint256 maxAmount
) private view returns (bool) {
    bytes32 leaf = keccak256(
        abi.encodePacked(sender, maxAmount.toString())
    );
    return MerkleProof.verify(merkleProof, merkleRoot, leaf);
}

这个 returns 错误,因此铸币失败。我不明白为什么它会这样做,因为我在我的前端做同样的事情而且它运行良好。

以及 mintListed 函数本身:

function mintListed(
    uint256 amount,
    bytes32[] calldata merkleProof,
    uint256 maxAmount
) public payable nonReentrant {
    address sender = _msgSender();

    require(isActive, "Sale is closed");
    require(
        amount <= maxAmount - _alreadyMinted[sender],
        "Insufficient mints left"
    );
    require(_verify(merkleProof, sender, maxAmount), "Invalid proof");
    require(msg.value == price * amount, "Incorrect payable amount");

    _alreadyMinted[sender] += amount;
    _internalMint(sender, amount);
}

当我从 merkle 树中删除“maxAmount”并仅使用 keccak256 哈希地址时,它有效,但我确实需要它。

我尝试了不同的方法在 JS 端连接字符串,但没有任何效果。

我设法解决了这个问题。

所以不用

keccak256(addr.concat("5"))); 

我用过

keccak256(ethers.utils.solidityPack(["address", "string"], [addr, "5"]))

现在可以正常使用了!