Can't verify v4 signature with array value

I have next domain message.

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.

when hashing Offer I use
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,
offer.tokenIds,
offer.duration
));
}

I can't figure out why keccak256(abi.encodePacked()) is not doing his job.

I found what is wrong.

Just removed memory from hash ,it will work.
bytes32 constant OFFER_TYPEHASH = keccak256(
    "Offer(address from,address to,uint256 nonce,uint256[] memory tokenIds,uint256 duration)"
);
1 Like