Eip-712 signature with DefenderRelayerProvider

I am using the OZ defender relayer and want to sign an EIP-712 message. My first thought was to use the ._signTypedData method from ethers, but it seems that the defender relayer signer doesn't adhere to the TypedDataSigner ethers interface.

Next I tried to make a raw RPC call, but it seems the provider does not have the "eth_signTypedData_v4" method. Am I missing something? Is there a workaround for this?

:computer: Environment

Using relayer


See abovev

:1234: Code to reproduce

const provider = new DefenderRelayProvider(credentials);
signature = await provider.send("eth_signTypedData_v4", [
          ) as any,

returns: "Error: The method eth_signTypedData_v4 does not exist/is not available"
1 Like

Hi @Jason_Maier, thanks for reporting this.
I tried to provide you an easy script to do it with our current infra but it is not possible since EIP712 requires to sign a message with a prefix different to the standard “Ethereum Signed Message”, and the “eth_signTypedData_v4” is a wallet-specific JSON RPC, so we are required to update our endpoints to support typed data signatures.

I'm already working on this:

I'll update you when is merged and hopefully available within the next release.


Thanks so much for your reply. Do you have a sense about the timeline of the next release?

One thought I had was the possibility of wrapping the defender relayer in another wallet specific relayer. Do you think this is a possible solution?

Thanks again!


Thanks Ernesto!

For some context, the reason this suddenly became important is that Open Sea just migrated to a new contract, and requires 712 signatures. We've been using Defender for automated market maker bots, and it's been really great, but need this feature to get them back online.

Thanks to both for waiting. This is the current status to support this endpoint:

  • defender: I've already sent a PR (private repo), it's already merged so it should be released within this week. I'll update you
  • defender-relay-client: I still need to start working on this one. In any case, if we happen to release the defender version before the defender client, you'll still be able to use the endpoint anyway (I'll tell you what endpoint path is and what the parameters are)
  • defender-docs: Once all done, I'll be updating the docs with everything regarding the new endpoint and the client

Endpoint PR already merged, usable within this week but probably not yet supported on the client nor documented.

Given that, I'm answering your questions:

Do you have a sense about the timeline of the next release?

We're deploying every week we have new features. Since the new endpoint has already been merged, it's being deployed this week.

One thought I had was the possibility of wrapping the defender relayer in another wallet specific relayer. Do you think this is a possible solution?

Currently, there's no way to sign typed data messages with a Defender Relayer, no matter what's wrapping it, it's something we need to deploy on our end first. That'll be fixed with the new endpoint I added for the next release.

I'll keep you posted

There you go guys

Both are getting merged once the Defender new release is deployed.
Just keep an eye on them.

Also, here's a usage example:

const {
} = require("defender-relay-client/lib/ethers");
const { ethers } = require("ethers");

const { API_KEY, API_SECRET } = process.env;

// All properties on a domain are optional
const domain = {
  name: "Ether Mail",
  version: "1",
  chainId: 1,
  verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",

// The named list of all type definitions
const types = {
  Person: [
    { name: "name", type: "string" },
    { name: "wallet", type: "address" },
  Mail: [
    { name: "from", type: "Person" },
    { name: "to", type: "Person" },
    { name: "contents", type: "string" },

// The data to sign
const value = {
  from: {
    name: "Cow",
    wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  to: {
    name: "Bob",
    wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
  contents: "Hello, Bob!",

const main = async () => {
  const credentials = {
    apiKey: API_KEY,
    apiSecret: API_SECRET,
  const provider = new DefenderRelayProvider(credentials);
  const signer = new DefenderRelaySigner(credentials, provider);
  const signerAddress = await signer.getAddress();

  const signature = await signer._signTypedData(domain, types, value);

  const verifiedAddress = ethers.utils.verifyTypedData(

    ethers.utils.getAddress(signerAddress) ===
  ); // true

main().then(() => process.exit("succcess"));
1 Like


This is great. Thanks for the quick turn around. Always impressed by the OpenZeppelin team.




In response to this note above, I have been able to now use the signTypedData method in local development using the apiRelayer, but when I upload the script to an autotask the method no longer runs with the autotask relayer. I am getting the following error "signer._signTypedData is not a function". Does this have to do with the difference in relayer depending on local (apiRelayer) vs. autotask injection (autotask Relayer)?

Is there some timeline for getting this method onto the autotask relayer?



Hey Jason, thanks for reporting.

Indeed it's that the Autotask Runtime doesn't have the newest version of the defender relay client. I've sent a PR to update it so it should be out by the next release (during the week). In the meantime I'd recommend using the Open Source code we have for the client, and calling directly to the API endpoint, since the endpoint is working.

Only do that if it's strictly needed, we'll be releasing soon with the update anyway.

Awesome. Thanks for this! Will keep you updated and check in later this week

1 Like

Just for reference, the Autotask issue has been addressed.

Best to all