# EIP-191: Signed Data Standard

Source: https://www.eipsfordesigners.com/standards/EIP-191
Agent brief: https://www.eipsfordesigners.com/standards/EIP-191/agent.md
Machine-readable JSON: https://www.eipsfordesigners.com/api/standards/EIP-191
Last reviewed: 2026-04-05
Last updated: 2026-04-05

| Field | Value |
| --- | --- |
| Status | Final |
| Chain | both |
| Category | Security & Trust |
| Journey stages | Authentication & Identity |
| Detailed guide | Yes |
| Official specification | https://eips.ethereum.org/EIPS/eip-191 |
| Discussion search | https://ethereum-magicians.org/search?q=EIP-191 |

## UX Impact

Users sign off-chain messages to authorize actions without gas — login, approve listings, multisig confirmations. Design implications: show clear 'Sign Message' vs 'Approve Transaction' distinction, display human-readable message content before signing, indicate which dApp/contract will validate the signature. Design decisions: balance security warnings (phishing risk) against friction — too many warnings cause blindness, too few enable exploits.

## Summary

EIP-191 standardizes how messages are signed by wallets, adding a prefix that prevents signed messages from being replayed as transactions. This is the foundation of "Sign-In with Ethereum" and all safe off-chain signing.

## For Designers

- You can design UI that delivers prefix "\x19Ethereum Signed Message:" makes it invalid as a transaction.
- You can standard prefix + version byte = consistent.
- You can design UI that delivers version byte indicates: personal message.

## Applicability

### When to Use

- Your product addresses: signed messages could be replayed as transactions.
- Your product addresses: no standard format for signed data.
- The flow should deliver: prefix "\x19Ethereum Signed Message:" makes it invalid as a transaction.
- You are designing a personal message signing experience with visible states and recovery paths.

### When to Avoid

- Always show human-readable message with clear purpose.
- Include timestamp and/or nonce, enforce expiration.
- Wallet should warn if message looks like encoded function call.
- Wrong-address or approval mistakes are not recoverable in your product context.

## Problems It Solves

### Signed messages could be replayed as transactions

Impact: critical

Old way: Sign a message, attacker replays it as a transaction draining funds

New way: Prefix "\x19Ethereum Signed Message:" makes it invalid as a transaction

### No standard format for signed data

Impact: high

Old way: Each app invented own signing format, security varied wildly

New way: Standard prefix + version byte = consistent, auditable signing

### Can't verify what type of signature it is

Impact: high

Old way: Raw signature could be anything, hard to validate

New way: Version byte indicates: personal message, typed data, or validator

### Signing requests look the same regardless of purpose

Impact: medium

Old way: User signs hex blob, no idea if it's login or permission grant

New way: Different prefixes enable different wallet UI treatments

### Cross-protocol signature collision

Impact: medium

Old way: Signature for App A might be valid for unrelated use in App B

New way: Version 0x45 includes validator address for protocol-specific signing

## Anti-Patterns

### Asking users to sign raw hex data

Severity: critical

Users can't verify what they're signing, easy to trick them

Instead: Always show human-readable message with clear purpose

### No timestamp or nonce in signed messages

Severity: critical

Signature can be replayed indefinitely

Instead: Include timestamp and/or nonce, enforce expiration

### Signing messages that look like transaction data

Severity: critical

Could be tricking user into signing malicious permit/approval

Instead: Wallet should warn if message looks like encoded function call

### Not explaining what signing does vs doesn't do

Severity: high

Users fear any signature might drain their wallet

Instead: Clearly state "This will NOT approve transactions or spend funds"

### Same UI for login signatures and permits

Severity: high

Permit signatures ARE dangerous, login signatures are safe

Instead: Use EIP-712 for permits with different, scarier UI

### Not showing the requesting origin

Severity: high

Phishing sites can pretend to be legitimate

Instead: Always show full URL of requesting site prominently

## UI Components

### MessageDisplay

Render signed message content
States: readable, hex, mixed, suspicious
Props: message, encoding, maxLength, expanded

### SignatureTypeIndicator

Show what type of signature this is
States: personal, typed, login, unknown
Props: type, version, tooltip

### OriginBadge

Show requesting site with trust level
States: trusted, unknown, suspicious, known-malicious
Props: origin, trustLevel, previousInteractions

### ScopeExplainer

Explain what signature grants and doesn't grant
States: collapsed, expanded
Props: grants[], doesNotGrant[], expiresAt

### NonceDisplay

Show nonce/timestamp for replay protection
States: valid, expired, missing
Props: nonce, timestamp, expiresAt

## On Monad

### Signature Format

Ethereum: EIP-191 is chain-agnostic, works everywhere

Monad: Same EIP-191 format, full compatibility

Design implication: No changes needed for basic signing on Monad

### Verification Speed

Ethereum: Signature verification is fast (off-chain)

Monad: On-chain verification also fast due to precompiles

Design implication: Can do on-chain sig verification without UX penalty

### Domain Binding

Ethereum: Messages should include chain ID for multi-chain apps

Monad: Include Monad chain ID when signature is chain-specific

Design implication: Multi-chain apps need chain-aware message formats

### Smart Wallet Signing

Ethereum: EIP-191 works with ERC-1271 for smart wallets

Monad: Same compatibility, verify via isValidSignature()

Design implication: Support both EOA and smart wallet signatures

## Key Takeaways

- EIP-191 prefix prevents message-to-transaction replay attacks
- Always show human-readable message content
- Include timestamp/nonce for replay protection
- Clearly explain what signing does and doesn't do
- Warn loudly about hex/encoded messages

## UX Patterns

### Personal Message Signing

Standard wallet UI for human-readable message signing

User flow:

- dApp calls personal_sign with message
- Wallet shows readable message content
- User reads and understands what they're signing
- User clicks Sign
- Wallet prepends EIP-191 prefix and signs
- Signature returned to dApp

Mockup registry key: `concept/typed-data` (React UI on the live standard page).

### Login Signature

Sign-in authentication flow

User flow:

- User clicks "Connect" or "Sign In"
- Wallet explains what signature does and doesn't do
- User understands this is just authentication
- User signs
- Backend verifies signature, creates session

Mockup registry key: `concept/siwe-sign-in` (React UI on the live standard page).

### Proof of Ownership

Verify wallet ownership for external systems

User flow:

- External service needs wallet verification
- Presents message with context (what, why)
- User understands linking purpose
- User signs message
- Service verifies signature, grants access

Mockup registry key: `concept/typed-data` (React UI on the live standard page).

### Dangerous Signature Warning

Wallet warns about suspicious signing requests

User flow:

- Suspicious site requests signature
- Wallet detects non-readable content
- Shows warning about potential attack
- User encouraged to reject
- If user proceeds, extra confirmation required

Mockup registry key: `concept/typed-data` (React UI on the live standard page).

## Technical Notes

EIP-191 format: 0x19 <version> <data>. Version 0x01 = structured data (EIP-712). Version 0x00 = validator address + data. Version 0x45 (E) = personal_sign with "Ethereum Signed Message:\n" + length + message. The 0x19 byte is invalid as transaction start, preventing replay.
