0
votes

The domain message is:

     struct Offer{
        address from;
        address to;
        uint256 nonce;
        uint256[] tokenIds;
        uint256 duration;
    }

    bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    bytes32 constant OFFER_TYPEHASH = keccak256(
        "Offer(address from,address to,uint256 nonce,uint256[] memory tokenIds,uint256 duration)"
    );

    function hash(Offer memory offer) public pure returns (bytes32) {
        return keccak256(abi.encode(
            OFFER_TYPEHASH,
            offer.from,
            offer.to,
            offer.nonce,
            keccak256(abi.encodePacked(offer.tokenIds)),
            offer.duration
        ));
    }

 function verify(Offer memory offer, uint8 v, bytes32 r, bytes32 s) public view returns (bool) {
        // Note: we need to use encodePacked here instead of encode.
        bytes32 digest = keccak256(abi.encodePacked(
            "\x19\x01",
            DOMAIN_SEPARATOR,
            hash(offer)
        ));
        return ecrecover(digest, v, r, s) == ExpectedAddress;
    }

I can't resolve issue with array when doing v4 signature.

If I removed tokenIds array from Offer struct, and OfferTypeHash, and also from hash func: everything works well as expected, I can verify signature via web3 and contract.

When I put tokenIds array to struct, I can't verify signature. I googled and tried a lot of examples like:

I use this for hashing the offer:

keccak256(abi.encodePacked(array)) 
    function hash(Offer memory offer) public pure returns (bytes32) {
        return keccak256(abi.encode(
            OFFER_TYPEHASH,
            offer.from,
            offer.to,
            offer.nonce,
            keccak256(abi.encodePacked(offer.tokenIds)),
            offer.duration
        ));
    }

keccak256(abi.encode(array))
keccak256(abi.encodePacked(array)) 
    function hash(Offer memory offer) public pure returns (bytes32) {
        return keccak256(abi.encode(
            OFFER_TYPEHASH,
            offer.from,
            offer.to,
            offer.nonce,
            keccak256(abi.encode(offer.tokenIds)),
            offer.duration
        ));
    }

Even without Keccak:

 function hash(Offer memory offer) public pure returns (bytes32) {
        return keccak256(abi.encode(
            OFFER_TYPEHASH,
            offer.from,
            offer.to,
            offer.nonce,
            keccak256(abi.encode(offer.tokenIds)),
            offer.duration
        ));
    }

I can't figure out: why keccak256(abi.encode is not doing the job?