Skip to content

Commit 9df6845

Browse files
committed
wip: sign message
1 parent 3459b37 commit 9df6845

File tree

2 files changed

+84
-41
lines changed

2 files changed

+84
-41
lines changed

templates/chain-template/pages/api/verify-signature.ts

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -108,46 +108,82 @@ export default function handler(
108108
function verifyEthereumSignature(message: string, signature: string, expectedAddress: string): boolean {
109109
try {
110110
const secp256k1 = require('secp256k1');
111-
const { keccak256 } = require('keccak');
112-
113-
// Ethereum personal sign message format
114-
const prefix = '\x19Ethereum Signed Message:\n';
115-
const prefixedMessage = prefix + message.length + message;
116-
117-
// Hash the prefixed message
118-
const messageHash = keccak256(Buffer.from(prefixedMessage, 'utf8'));
119-
120-
// Remove 0x prefix if present and convert to buffer
121-
const sigHex = signature.startsWith('0x') ? signature.slice(2) : signature;
122-
const sigBuffer = Buffer.from(sigHex, 'hex');
123-
124-
if (sigBuffer.length !== 65) {
125-
throw new Error('Invalid signature length');
126-
}
127-
128-
// Extract r, s, v from signature
129-
const r = sigBuffer.slice(0, 32);
130-
const s = sigBuffer.slice(32, 64);
131-
let v = sigBuffer[64];
132-
133-
// Handle recovery id
134-
if (v < 27) {
135-
v += 27;
111+
const keccak = require('keccak');
112+
113+
console.log('Verifying Ethereum signature:');
114+
console.log('Message:', JSON.stringify(message));
115+
console.log('Signature:', signature);
116+
console.log('Expected address:', expectedAddress);
117+
118+
// Try different message formats that MetaMask might use
119+
const messageFormats = [
120+
message, // Original message
121+
message.replace(/\\n/g, '\n'), // Replace escaped newlines
122+
Buffer.from(message, 'utf8').toString(), // Ensure UTF-8 encoding
123+
];
124+
125+
for (let i = 0; i < messageFormats.length; i++) {
126+
const testMessage = messageFormats[i];
127+
console.log(`\nTrying message format ${i + 1}:`, JSON.stringify(testMessage));
128+
129+
// Ethereum personal sign message format
130+
const prefix = '\x19Ethereum Signed Message:\n';
131+
const messageBuffer = Buffer.from(testMessage, 'utf8');
132+
const prefixedMessage = prefix + messageBuffer.length + testMessage;
133+
134+
console.log('Prefixed message:', JSON.stringify(prefixedMessage));
135+
console.log('Message buffer length:', messageBuffer.length);
136+
137+
// Hash the prefixed message
138+
const messageHash = keccak('keccak256').update(Buffer.from(prefixedMessage, 'utf8')).digest();
139+
console.log('Message hash:', messageHash.toString('hex'));
140+
141+
// Remove 0x prefix if present and convert to buffer
142+
const sigHex = signature.startsWith('0x') ? signature.slice(2) : signature;
143+
const sigBuffer = Buffer.from(sigHex, 'hex');
144+
145+
if (sigBuffer.length !== 65) {
146+
continue;
147+
}
148+
149+
// Extract r, s, v from signature
150+
const r = sigBuffer.slice(0, 32);
151+
const s = sigBuffer.slice(32, 64);
152+
let v = sigBuffer[64];
153+
154+
console.log('Original v:', v);
155+
156+
// Try both recovery IDs
157+
for (const recoveryId of [0, 1]) {
158+
try {
159+
console.log(`Trying recovery ID: ${recoveryId}`);
160+
161+
// Combine r and s for secp256k1
162+
const signature65 = new Uint8Array([...r, ...s]);
163+
164+
// Recover public key
165+
const publicKey = secp256k1.ecdsaRecover(signature65, recoveryId, new Uint8Array(messageHash));
166+
167+
// Convert public key to address
168+
const publicKeyBuffer = Buffer.from(publicKey.slice(1));
169+
const publicKeyHash = keccak('keccak256').update(publicKeyBuffer).digest();
170+
const address = '0x' + publicKeyHash.slice(-20).toString('hex');
171+
172+
console.log(`Recovered address: ${address}`);
173+
174+
// Compare with expected address (case insensitive)
175+
if (address.toLowerCase() === expectedAddress.toLowerCase()) {
176+
console.log('✅ Signature verification successful!');
177+
return true;
178+
}
179+
} catch (e) {
180+
console.log(`❌ Failed with recovery ID ${recoveryId}:`, e);
181+
}
182+
}
136183
}
137-
const recoveryId = v - 27;
138-
139-
// Combine r and s for secp256k1
140-
const signature65 = new Uint8Array([...r, ...s]);
141184

142-
// Recover public key
143-
const publicKey = secp256k1.ecdsaRecover(signature65, recoveryId, new Uint8Array(messageHash));
144-
145-
// Convert public key to address
146-
const publicKeyHash = keccak256(publicKey.slice(1)); // Remove the 0x04 prefix
147-
const address = '0x' + publicKeyHash.slice(-20).toString('hex');
148-
149-
// Compare with expected address (case insensitive)
150-
return address.toLowerCase() === expectedAddress.toLowerCase();
185+
console.log('❌ All message formats and recovery IDs failed');
186+
return false;
151187

152188
} catch (error) {
153189
console.error('Error verifying Ethereum signature:', error);

templates/chain-template/pages/sign-message.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export default function SignMessage() {
6262
setSigningIn(true);
6363
let result: { signature: string };
6464
let publicKey: string;
65+
let messageToSign = message;
6566

6667
if (chain.chainType === 'eip155') {
6768
// Handle Ethereum chains
@@ -70,8 +71,14 @@ export default function SignMessage() {
7071
throw new Error('Ethereum wallet not found');
7172
}
7273

73-
// Sign the message using personal_sign
74-
const signature = await ethereumWallet.signMessage(message);
74+
// The message is already plain text, no need to decode
75+
console.log('Message to sign:', messageToSign);
76+
77+
// Sign the message using personal_sign (MetaMask accepts string directly)
78+
const signature = await ethereumWallet.ethereum.request({
79+
method: 'personal_sign',
80+
params: [messageToSign, address]
81+
});
7582
result = { signature };
7683

7784
// For Ethereum, we'll derive the public key from the signature during verification
@@ -102,7 +109,7 @@ export default function SignMessage() {
102109
'Content-Type': 'application/json',
103110
},
104111
body: JSON.stringify({
105-
message,
112+
message: messageToSign,
106113
signature: result.signature,
107114
publicKey,
108115
signer: address,

0 commit comments

Comments
 (0)