EIPs
EIP-6492 — Signature validation for predeploy contracts
EIP-1271 validates a signature against a deployed contract. EIP-6492 extends that to contracts that aren’t deployed yet — the smart account address is known (via CREATE2), but the code isn’t on-chain.
The signature is wrapped: (factory, factory_calldata, inner_signature) || MAGIC_BYTES. A universal validator contract:
- Detects the wrapped form via the trailing magic bytes.
- If the address has no code, deploys it using the factory + calldata.
- Calls
isValidSignatureon the now-deployed contract.
import {
wrap_signature,
verify_hash,
} from "@ethernauta/eip/6492";
import { create_reader, encode_chain_id, http } from "@ethernauta/transport";
import { eip155_1 } from "@ethernauta/chain/eip155-1";
import { AddressSchema, BytesSchema, Hash32Schema } from "@ethernauta/core";
import { parse } from "valibot";
const CHAIN_ID = encode_chain_id({ namespace: "eip155", reference: eip155_1.chainId });
const reader = create_reader([
{ chainId: CHAIN_ID, transports: [http("https://ethereum-rpc.publicnode.com")] },
]);
const factory = parse(AddressSchema, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
const factory_calldata = parse(BytesSchema, "0x");
const inner_signature = parse(BytesSchema, "0x");
const counterfactual_account = parse(AddressSchema, "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC");
const digest = parse(Hash32Schema, "0x" + "00".repeat(32));
const wrapped = wrap_signature({
factory,
factoryData: factory_calldata,
signature: inner_signature,
});
const ok = await verify_hash({
address: counterfactual_account,
hash: digest,
signature: wrapped,
})(reader({ chain_id: CHAIN_ID }));
void ok; Surface
| Export | Type | Purpose |
|---|---|---|
MAGIC_BYTES | Bytes32 | 0x6492…6492 — sentinel suffix. |
VALIDATOR_BYTECODE | Bytes | Compiled universal validator. |
wrap_signature | (args) => Bytes | Produce a wrapped signature. |
unwrap_signature | (bytes) => UnwrappedSignature | Reverse wrap_signature. |
is_wrapped_signature | (bytes) => boolean | Detect via magic bytes. |
UnwrappedSignature | type | { factory, factory_calldata, inner_signature }. |
verify_hash | Readable<boolean> | Run the universal validator. |
How the universal validator works
The trick is that verify_hash deploys an ephemeral contract (via eth_call with the validator bytecode as to: null) that handles both the deployment and the isValidSignature call in a single state-less execution. No transaction is sent; nothing is persisted. Pure read.
This is what makes counterfactual signatures verifiable from a Readable<T> — no wallet, no gas.
Cross-EIP verification
In practice you rarely call this directly. The universal verifiers in @ethernauta/crypto walk the full hierarchy:
import { verify_message_universal } from "@ethernauta/crypto";
import { create_reader, encode_chain_id, http } from "@ethernauta/transport";
import { eip155_1 } from "@ethernauta/chain/eip155-1";
import { AddressSchema, BytesSchema } from "@ethernauta/core";
import { parse } from "valibot";
const CHAIN_ID = encode_chain_id({ namespace: "eip155", reference: eip155_1.chainId });
const reader = create_reader([
{ chainId: CHAIN_ID, transports: [http("https://ethereum-rpc.publicnode.com")] },
]);
const address = parse(AddressSchema, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
const message = "Hello";
const signature = parse(BytesSchema, "0x");
// works for: EOA, deployed smart account, counterfactual smart account
const ok = await verify_message_universal({
address,
message,
signature,
})(reader({ chain_id: CHAIN_ID }));
void ok; See also
- EIP-1014 — CREATE2 address derivation (the “counterfactual” half).
- EIP-1271 — deployed contract signatures (the inner case).
- @ethernauta/crypto — universal verifiers.