未能在智能合约上验证 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"]))
现在可以正常使用了!
我正在使用一份 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"]))
现在可以正常使用了!