Skip to content

Instantly share code, notes, and snippets.

@ezesundayeze
Last active June 3, 2026 19:03
Show Gist options
  • Select an option

  • Save ezesundayeze/05b1dadead9ce13332985b76ad4a0c7d to your computer and use it in GitHub Desktop.

Select an option

Save ezesundayeze/05b1dadead9ce13332985b76ad4a0c7d to your computer and use it in GitHub Desktop.
Signature Method Comparison
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Signature Comparison: Raw vs EIP-191 vs EIP-712</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h2 {
color: #333;
text-align: center;
}
.button-group {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
button {
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
flex: 1;
min-width: 200px;
}
#signRaw {
background-color: #ffcccc;
}
#signEIP191 {
background-color: #ccffcc;
}
#signEIP712 {
background-color: #ccffff;
}
pre {
background-color: #f5f5f5;
padding: 15px;
border-radius: 5px;
white-space: pre-wrap;
word-wrap: break-word;
min-height: 180px;
}
.signature-type {
font-weight: bold;
margin-bottom: 5px;
}
.danger {
color: #d32f2f;
}
.safe {
color: #388e3c;
}
.enhanced {
color: #0288d1;
}
</style>
</head>
<body>
<h2>Signature Method Comparison</h2>
<div class="button-group">
<button id="signRaw" onclick="signWithoutEIP191()">
⚠️ Sign Raw Hash
</button>
<button id="signEIP191" onclick="signWithEIP191()">
✅ Sign with EIP-191
</button>
<button id="signEIP712" onclick="signWithEIP712()">
✨ Sign with EIP-712
</button>
</div>
<pre id="output"></pre>
<script src="https://cdn.jsdelivr.net/npm/ethers@5.7.2/dist/ethers.umd.min.js"></script>
<script>
const output = document.getElementById("output");
async function getConnectedAccount() {
if (!window.ethereum) {
throw new Error("MetaMask is not installed.");
}
const accounts = await window.ethereum.request({
method: "eth_requestAccounts"
});
const account = accounts[0];
if (!account) {
throw new Error("No MetaMask account is connected.");
}
return account;
}
async function signWithoutEIP191() {
try {
const account = await getConnectedAccount();
const message = "Withdraw 1 ETH from treasury";
const messageHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(message)
);
const signature = await window.ethereum.request({
method: "personal_sign",
params: [messageHash, account]
});
output.innerHTML = `<div class="signature-type danger">⚠️ Raw Hash Signature via personal_sign</div>
Original message:
"${message}"
Keccak-256 hash (signed directly):
${messageHash}
Signature:
${signature}
This signs the raw hash using personal_sign.
eth_sign was deprecated by MetaMask — it allowed signing arbitrary hashes with no user-readable context.
personal_sign still lets you sign a hash directly, but MetaMask will show a warning.`;
} catch (err) {
output.textContent = `Error: ${err.message}`;
}
}
async function signWithEIP191() {
try {
const account = await getConnectedAccount();
const message = "Withdraw 1 ETH from treasury";
const messageHex = ethers.utils.hexlify(
ethers.utils.toUtf8Bytes(message)
);
const signature = await window.ethereum.request({
method: "personal_sign",
params: [messageHex, account]
});
output.innerHTML = `<div class="signature-type safe">✅ EIP-191 Signed Message via personal_sign</div>
Message:
"${message}"
Hex-encoded message sent to MetaMask:
${messageHex}
Signature:
${signature}
personal_sign applies the EIP-191 prefix before hashing and signing.
MetaMask can also display the readable message to the user.`;
} catch (err) {
output.textContent = `Error: ${err.message}`;
}
}
async function signWithEIP712() {
try {
const account = await getConnectedAccount();
const chainIdHex = await window.ethereum.request({
method: "eth_chainId"
});
const chainId = Number.parseInt(chainIdHex, 16);
const typedData = {
domain: {
name: "SignatureDemo",
version: "1",
chainId,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
primaryType: "Transaction",
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
Transaction: [
{ name: "action", type: "string" },
{ name: "amount", type: "uint256" },
{ name: "currency", type: "string" },
{ name: "recipient", type: "address" }
]
},
message: {
action: "Withdraw",
amount: ethers.utils.parseEther("1").toString(),
currency: "ETH",
recipient: account
}
};
const signature = await window.ethereum.request({
method: "eth_signTypedData_v4",
params: [account, JSON.stringify(typedData)]
});
output.innerHTML = `<div class="signature-type enhanced">✨ EIP-712 Structured Signature</div>
Typed data:
${JSON.stringify(typedData, null, 2)}
Signature:
${signature}
EIP-712 signs structured typed data.
MetaMask can display the action, amount, recipient, and signing domain more clearly.`;
} catch (err) {
output.textContent = `Error: ${err.message}`;
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment