How to get sign EIP712 with ECDSA verify contract

code solidity

// SPDX-License-Identifier: MIT
 pragma solidity ^0.8.0;
 import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
 import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
 contract SpaceStationV2 is  EIP712  {
    // The galaxy signer(EOA): used to verify EIP-712.
 address public galaxy_signer;
function _hash(
     uint256 _cid,
     address _starNFT,
     uint256 _dummyId,
     uint256 _powah,
     address _account
 ) public view returns (bytes32) {
     return
     _hashTypedDataV4(
         keccak256(
             abi.encode(
                 keccak256(
                     "NFT(uint256 cid,address starNFT,uint256 dummyId,uint256 powah,address account)"
                 ),
                 _cid,
                 _starNFT,
                 _dummyId,
                 _powah,
                 _account
             )
         )
     );
 }
function _verify(bytes32 hash, bytes calldata signature)
 public
 view
 returns (bool)
 {
     return ECDSA.recover(hash, signature) == galaxy_signer;
 }
}

Code use JS:

async function testgetSign() {
    let domain = {
        name: "Galaxy",
        version: "1.0.0",
        chainId: "97",//Come back and hardcode the ID later
        verifyingContract: "0xE66F7BCf50DB58e41eC57917278E7eb67c754279"
    };

    let types = {
        NFT: [
            { name: "cid", type: "uint256" },
            { name: "starNFT", type: "address" },
            { name: "dummyId", type: "uint256" },
            { name: "powah", type: "uint256" },
            { name: "account", type: "address" },
        ]
    };

    let value = {
        cid: "2",
        starNFT: "0x3C0Ef7DA64d37275eB42E560615d484eA293F5f6",
        dummyId: "1",
        powah: "1",
        account: "0xA128b0c7E06f869AF6D81a46851CEcBA40DCE8f2",
    }


    prvtKey = "xxx"

    const wallet = new ethers.Wallet(prvtKey);
    const signature = await wallet.signTypedData(domain, types, value);
    console.log(signature);
}
testgetSign()

galaxy_signer: 0xE66F7BCf50DB58e41eC57917278E7eb67c754279

But I Verify is False : How to get sign with web3js or ethers

You can take a look to our ERC2771Forwarder tests. They're written in ethers: