Skip to content

Support EIP-712 typed-data signing for Hedera ED25519 accounts #692

Description

@mshakeg

Summary

Hedera wallets already commonly support EIP-712 signing for ECDSA alias accounts through eth_signTypedData_v4. It would be valuable to extend that same typed-data UX to Hedera ED25519 accounts, especially for dapps that need signatures verifiable on-chain through the Hedera Account Service (HAS) precompile.

The pragmatic proposal is:

  1. Support eth_signTypedData_v4 for Hedera ED25519 accounts represented by their long-zero EVM address.
  2. Have wallets compute the normal EIP-712 digest and sign that 32-byte digest with the account's ED25519 key.
  3. Return a raw 0x-prefixed 64-byte ED25519 signature.
  4. Do not apply the Hedera "\x19Hedera Signed Message:\n" prefix to EIP-712 typed data.

As a more explicit alternative, Hedera could introduce a native method such as hedera_signTypedData_v4, but eth_signTypedData_v4 support for ED25519 accounts is likely the lowest-friction path for existing dapps and EVM tooling.

Motivation

Some Hedera accounts are ED25519 accounts, not ECDSA alias accounts. These accounts can still authorize smart-contract flows on-chain when signatures are verified through HAS, but current wallet support for EIP-712 typed data appears focused on ECDSA alias accounts.

This creates a gap for protocols that rely on EIP-712 signatures. The on-chain path already works when the ED25519 key signs the same 32-byte EIP-712 digest that the contract computes. The missing piece is wallet support for producing that signature with a good typed-data UX.

Proposed behavior

For an ED25519 account, a dapp should be able to request:

await provider.request({
  method: "eth_signTypedData_v4",
  params: [
    "0x00000000000000000000000000000000000003fe", // long-zero EVM address for 0.0.1022, example only
    JSON.stringify(typedData),
  ],
});

The wallet would:

  1. Resolve the long-zero EVM address to the selected Hedera account.
  2. Render the typed data to the user using the same or similar UI used for ECDSA eth_signTypedData_v4.
  3. Compute the EIP-712 v4 digest:
keccak256("\x19\x01" || domainSeparator || hashStruct(message))
  1. Sign that 32-byte digest with the account's ED25519 key.
  2. Return the raw ED25519 signature as 0x + 64 bytes.

ECDSA accounts should keep their existing behavior and continue returning standard 65-byte secp256k1 signatures.

Important: do not apply the Hedera message prefix

For this method, the wallet should not apply:

"\x19Hedera Signed Message:\n" + len(message) + message

That prefix belongs to hedera_signMessage / personal-message signing. It should not be added to EIP-712 typed data.

EIP-712 already has its own domain separation:

"\x19\x01" || domainSeparator || hashStruct(message)

The domain separator can include fields like:

  • name
  • version
  • chainId
  • verifyingContract

Adding the Hedera personal-message prefix on top of EIP-712 would produce a different digest from what contracts expect and would be redundant from a domain-separation perspective.

Why this matters for on-chain verification

Current HAS isAuthorizedRaw verification expects a 32-byte message hash. For ED25519 signatures, this means contracts can verify an ED25519 signature over a 32-byte EIP-712 digest.

This shape works:

typedDataDigest = EIP712Hash(domain, types, message) // bytes32
signature = ed25519_sign(typedDataDigest)
HAS verifies account + typedDataDigest + signature

This shape does not work for current HAS verification:

signature = ed25519_sign("\x19Hedera Signed Message:\n" + len + typedDataDigestOrJson)

because the wallet signs variable-length raw prefixed bytes, while HAS verifies a 32-byte hash.

Compatibility note

Returning a 64-byte ED25519 signature from eth_signTypedData_v4 is not standard Ethereum secp256k1 behavior. Generic Ethereum libraries may assume a 65-byte recoverable ECDSA signature and try to use ecrecover semantics.

For Hedera ED25519 accounts, verification must be understood as:

account key + EIP-712 digest + 64-byte ED25519 signature

not:

ecrecover(EIP-712 digest, signature)

That should be documented clearly so dapps know that ED25519 typed-data signatures are intended for Hedera-aware verification paths such as HAS.

WalletConnect / hedera-wallet-connect impact

For the pragmatic eth_signTypedData_v4 approach, the work in hedera-wallet-connect may be mostly documentation, examples, and ensuring method negotiation allows the request under Hedera EVM chains such as:

eip155:295
eip155:296

The larger implementation work is likely in wallet code:

  • advertise/approve eth_signTypedData_v4 for Hedera EVM sessions
  • support ED25519 accounts represented by long-zero EVM addresses
  • compute the EIP-712 v4 digest
  • render typed-data fields safely to the user
  • sign the digest with the ED25519 key
  • return a 0x-prefixed 64-byte signature

Alternative: hedera_signTypedData_v4

If overloading eth_signTypedData_v4 with ED25519 behavior is considered too surprising, a Hedera-native method could be added instead:

hedera_signTypedData_v4

Potential params:

{
  signerAccountId: "hedera:testnet:0.0.1022",
  typedData: {
    domain: { name, version, chainId, verifyingContract },
    types,
    primaryType,
    message,
  }
}

Potential result:

{
  signature: "0x...", // 64-byte ED25519 or 65-byte ECDSA depending on account key
  accountId: "0.0.1022",
  evmAddress: "0x00000000000000000000000000000000000003fe"
}

This is cleaner semantically, but it requires more ecosystem coordination because dapps and wallets would need to adopt a new Hedera-specific method. For that reason, eth_signTypedData_v4 support for ED25519 accounts seems like the better first step.

Suggested acceptance criteria

  • A dapp can request eth_signTypedData_v4 for a Hedera ED25519 account's long-zero EVM address.
  • The wallet displays the EIP-712 typed data to the user.
  • The wallet signs the EIP-712 digest directly with the ED25519 key.
  • The returned signature is 0x + 64 bytes.
  • The wallet does not apply the Hedera personal-message prefix.
  • A Hedera smart contract can verify the returned signature through HAS against the same EIP-712 digest.
  • Documentation clearly explains that ED25519 typed-data signatures are not recoverable Ethereum ECDSA signatures.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions