Solidity -在测试合约的同时签署挖矿



我正在尝试创建一个围绕合同的测试,但我有问题理解如何在测试环境中签署它

这是我的合同

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.9 <0.9.0;
import "@divergencetech/ethier/contracts/crypto/SignatureChecker.sol";
import "@divergencetech/ethier/contracts/crypto/SignerManager.sol";
import "@divergencetech/ethier/contracts/erc721/BaseTokenURI.sol";
import "@divergencetech/ethier/contracts/erc721/ERC721ACommon.sol";
import "@divergencetech/ethier/contracts/erc721/ERC721Redeemer.sol";
import "@divergencetech/ethier/contracts/sales/FixedPriceSeller.sol";
import "@divergencetech/ethier/contracts/utils/Monotonic.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
interface ITokenURIGenerator {
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// @author divergence.xyz
contract TestBirds is
ERC721ACommon,
BaseTokenURI,
FixedPriceSeller,
ERC2981,
AccessControlEnumerable
{
using EnumerableSet for EnumerableSet.AddressSet;   
using ERC721Redeemer for ERC721Redeemer.Claims;
using Monotonic for Monotonic.Increaser;
/**
@notice Role of administrative users allowed to expel a Player from the
mission.
@dev See expelFromMission().
*/
bytes32 public constant EXPULSION_ROLE = keccak256("EXPULSION_ROLE");
constructor(
string memory name,
string memory symbol,
string memory baseTokenURI,
address payable beneficiary,
address payable royaltyReceiver
)
ERC721ACommon(name, symbol)
BaseTokenURI(baseTokenURI)
FixedPriceSeller(
2.5 ether,
Seller.SellerConfig({
totalInventory: 10_000,
lockTotalInventory: true,
maxPerAddress: 0,
maxPerTx: 0,
freeQuota: 125,
lockFreeQuota: false,
reserveFreeQuota: true
}),
beneficiary
)
{
_setDefaultRoyalty(royaltyReceiver, 1000);
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
@dev Mint tokens purchased via the Seller.
*/
function _handlePurchase(
address to,
uint256 n,
bool
) internal override {
_safeMint(to, n);
}
/**
@dev Record of already-used signatures.
*/
mapping(bytes32 => bool) public usedMessages;
/**
@notice Mint tokens.
*/
function mintPublic(
address to,
bytes32 nonce,
bytes calldata sig
) external payable {
signers.requireValidSignature(
signaturePayload(to, nonce),
sig,
usedMessages
);
_purchase(to, 1);
}
function alreadyMinted(address to, bytes32 nonce)
external
view
returns (bool)
{
return
usedMessages[
SignatureChecker.generateMessage(signaturePayload(to, nonce))
];
}
/**
@dev Constructs the buffer that is hashed for validation with a minting
signature.
*/
function signaturePayload(address to, bytes32 nonce)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(to, nonce);
}

/**
@dev Required override to select the correct baseTokenURI.
*/
function _baseURI()
internal
view
override(BaseTokenURI, ERC721A)
returns (string memory)
{
return BaseTokenURI._baseURI();
}
/**
@notice If set, contract to which tokenURI() calls are proxied.
*/
ITokenURIGenerator public renderingContract;
/**
@notice Sets the optional tokenURI override contract.
*/
function setRenderingContract(ITokenURIGenerator _contract)
external
onlyOwner
{
renderingContract = _contract;
}
/**
@notice If renderingContract is set then returns its tokenURI(tokenId)
return value, otherwise returns the standard baseTokenURI + tokenId.
*/
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
if (address(renderingContract) != address(0)) {
return renderingContract.tokenURI(tokenId);
}
return super.tokenURI(tokenId);
}
/**
@notice Sets the contract-wide royalty info.
*/
function setRoyaltyInfo(address receiver, uint96 feeBasisPoints)
external
onlyOwner
{
_setDefaultRoyalty(receiver, feeBasisPoints);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721ACommon, ERC2981, AccessControlEnumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}

它可以正常编译,但是当我尝试创建一个mint测试时,我必须生成一个有效的签名…

这是测试

const { expect } = require('chai');
describe("TestBirds", function () {
it ("Should return correct name, URI, owner and beneficiary", async function () {
const [owner, addr1] = await hre.ethers.getSigners()

provider = ethers.provider
const TestBirdsContract = await hre.ethers.getContractFactory("TestBirds")
const testBirdsContractDeployed = await TestBirdsContract.deploy(
"TestBirds",
"APFP",
"https://test.url/",
owner.address,
owner.address)
console.log(await provider.getBalance(owner.address));
await testBirdsContractDeployed.deployed()
const nonce = await ethers.provider.getTransactionCount(owner.address, "latest")
await testBirdsContractDeployed.mintPublic(owner.address, nonce, signature???)

expect(await testBirdsContractDeployed.name()).to.equal("TestBirds")
expect(await testBirdsContractDeployed.tokenURI(0), "https://test.url/0")
expect(await testBirdsContractDeployed.ownerOf(0)).to.equal(owner.address)
})
})

我应该怎么唱才能工作?没有签字我就无法检验合同。如果我从合约中删除签名参数,它会工作,但这不是我想要的。

感谢

似乎唯一缺少的是添加一个签名者。这似乎适用于您的测试合同…

import { expect } from "chai";
import { ethers } from "hardhat";
describe("Test signature", function () {
it("deploy tester contract, and send signed message", async function () {
const TestSignature = await ethers.getContractFactory("TestSignature",owner);
const testSignature = await TestSignature.deploy();
await testSignature.deployed();
const [owner] = await ethers.getSigners();
// missing line
testSignature.addSigner(owner.address);
const params = ethers.utils.solidityPack(
["address", "uint256", "bytes32"],
[owner.address, "10", ethers.utils.keccak256("0x66")]
);
const signed = await owner.signMessage(params);
console.log("owner address", owner.address);
await testSignature.mint(
owner.address,
"10",
ethers.utils.keccak256("0x66"),
signed
);
});
});

我尝试了以下方法,但还没有成功:

import { expect } from "chai";
import { ethers } from "hardhat";
describe("Test signature", function () {
it("deploy tester contract, and send signed message", async function () {
const TestSignature = await ethers.getContractFactory("TestSignature");
const testSignature = await TestSignature.deploy();
await testSignature.deployed();
const [owner] = await ethers.getSigners();
const params = ethers.utils.solidityPack(
["address", "uint256", "bytes32"],
[owner.address, "10", ethers.utils.keccak256("0x66")]
);
const signed = await owner.signMessage(params);
console.log("owner address", owner.address);
await testSignature.mint(
owner.address,
"10",
ethers.utils.keccak256("0x66"),
signed
);
});
});

这是对以下合同的测试:


pragma solidity >=0.8.0 <0.9.0;
// SPDX-License-Identifier: MIT
import "./SignatureChecker.sol";
contract TestSignature {
using EnumerableSet for EnumerableSet.AddressSet;
using SignatureChecker for EnumerableSet.AddressSet;
EnumerableSet.AddressSet internal signers;
constructor() {
signers.add(msg.sender);
}
mapping(bytes32 => bool) public usedMessages;
function mint(
address to,
uint256 price,
bytes32 nonce,
bytes calldata sig
) external payable {
signers.requireValidSignature(
signaturePayload(to, price, nonce),
sig,
usedMessages
);
}
/**
@dev Constructs the buffer that is hashed for validation with a minting signature.
*/
function signaturePayload(
address to,
uint256 price,
bytes32 nonce
) public pure returns (bytes memory) {
return abi.encodePacked(to, price, nonce);
}
function generateMessage(bytes memory data) public pure returns (bytes32) {
return SignatureChecker.generateMessage(data);
}
}

根据我的理解,签名的消息应该与消息匹配,而ECDSA.toEthSignedMessageHash(data)x19Ethereum Signed Message:n附加到消息的开头。匹配后,它可以恢复签名者地址,但它似乎还没有完全正常工作。