Skip to main content

Validate Signatures

info

We use the terms "accounts" and "wallets" as defined by the Ethereum foundation. Read this if you are unsure how these terms are different.

In Web3, it's common to verify that a user controls their account by asking them to sign a message. The popular Sign-In with Ethereum (SIWE) library, for example, asks the user to sign a message in order to log into a DApp.

Signing (and validating signatures) is a little different for smart contract accounts, however. In this guide, we will walk you through how to:

  • Generate signatures for your ZeroDev account
  • Validate signatures generated by ZeroDev accounts

Note that the very nature of account abstraction means that different AA accounts may implement different signing schemes. In this guide, we are referring specifically to ZeroDev's default ECDSA account.

Understanding smart contract signatures

Before we discuss AA and ZeroDev accounts specifically, let's first talk about how validating signatures works for smart contract accounts in general. If you are already familiar with ERC-1271, you can safely skip this section.

With EOAs, the address of the account is effectively the public key of the private key that controls the account and signs messages. Therefore, validating a signature is as simple as this.

However, for a smart contract account, the account address is not cryptographically linked to the private key, so the approach above won't work.

The standard that underpins contract signatures is ERC-1271. Basically, a contract account is free to define a isValidSignature function that validates signatures however it wants. For example, the default ZeroDev account simply validates that the signature is signed by the ECDSA owner of the account.

Signatures for AA (ERC-4337) accounts

ERC-4337 (the account abstraction standard) has an important optimization known as "counterfactual deployment." That is, it's possible to know the address of a ERC-4337 account even before it's deployed. This is useful because you can use the address to receive assets, even before paying any gas to actually deploy the account.

However, counterfactual deployment introduces a complication for validating smart contract signatures: it's impossible to call isValidSignature if the contract is not yet deployed. This leads to a big UX issue for ERC-4337 accounts, since users with undeployed accounts find themselves unable to log into DApps. But if a user must deploy their account (and therefore pay gas) before they can log into a DApp, the UX is a step backwards comparing to EOA, where you can generate accounts for free.

To address this issue, ERC-6492 was introduced. We have an in-depth article about ERC-6492, but the TLDR is that we can generate the signature in such a way that tells the validator (whoever that needs to validate the signature) to "fake-deploy" the contract account before calling its isValidSignature function.

In the following tutorial, we will show you how to generate and validate ERC-6492 signatures.

Generating signatures

A ZeroDev provider supports four signing functions:

  • signMessage
  • signTypedData
  • signMessageWith6492
  • signTypedDataWith6492

The first two, signMessage and signTypedData, are just like those you would find in libraries like Ethers. We offer these functions for compatibility reasons.

It's recommended, however, that you use signMessageWith6492 and signTypedDataWith6492, so that people can validate your signatures even if your account is not deployed. Note that ERC-6492 signatures are exactly the same as ERC-1271 signatures if the contract account is deployed. It's only when the contract account is NOT deployed that ERC-6492 appends additional data to the signatures. Therefore, using ERC-6492 has no downsides since it doesn't change the shape and size of the signature unless it's necessary.

Validating signatures

While libraries like Viem can validate ERC-1271 signatures (and therefore ERC-6492 signatures if the account has been deployed), currently very few libraries can validate ERC-6492 signatures for undeployed accounts. Among those, we recommend Ambire's signature validator library.

For example, to validate a message generated from signMessageWith6492, you can do:

import ethers from 'ethers';
import { verifyMessage } from '@ambire/signature-validator';

const provider = new ethers.providers.JsonRpcProvider('https://polygon-rpc.com')

async function run() {
const isValidSig = await verifyMessage({
// The smart contract account address
signer: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9',
message: 'Hello world',
// Signature should be generated from `signMessageWith6492`
signature: '0x9863d84f3119ac01d9e3bf9294e6c0c3572a07780fc7c49e8dc913806f4b1dbd4cc075462dc84422a9b981b2556f9c9197d76da7ba3603e53e9300869c574d821c',
// this is needed so that smart contract signatures can be verified
provider,
})
console.log('is the sig valid: ', isValidSig)
}
run().catch(e => console.error(e))

FAQs

Can I juse use SIWE?

Since SIWE doesn't support ERC-6492 yet, it will only work if the user's contract account bas been deployed.

Therefore, if you want to validate signatures for even undeployed accounts, you would have to implement your own validation flow as decribed above.