Ethers.js: How to Verify Signature in Backend with Web3.py

ethers.jsmetamaskweb3js

I'm trying to implement a 'Login with Metamask' button on my dapp.

On the frontend I'm using ethers.js code:

 const provider = new ethers.providers.Web3Provider(window.ethereum);
    var [account] = await ethereum.request({
        method: 'eth_requestAccounts'
    });

    
 const signer = provider.getSigner(account);
 signature = await signer.signMessage("Hello World");

This as expected, generates a signed message hash (lets assume its: 0xec325c188547379c92df21225c624206ba68bb2a87994c7e2937375ad6fbe609109780a5ed6e9633c132708fd66d6edf2bd993e9ce346797e7e33448639f751d1c)

On the backend, I want to use web3.py to verify this address.

message_hash = web3.keccak(text="Hello World")
signature = 0xec325c188547379c92df21225c624206ba68bb2a87994c7e2937375ad6fbe609109780a5ed6e9633c132708fd66d6edf2bd993e9ce346797e7e33448639f751d1c
web3.eth.account.recoverHash(message_hash, signature=signature)

However, this doesnt quite work, and the address I receive back is different to the address that signed the original message.

>>> web3.eth.account.recoverHash(message, signature=signature)
'0xAA1A56093f7Dd7a8Df755c616ccdc295e0a2af5f'
>>> 

How do I correctly verify the signature in web3.py and return the correct address that signed 'Hello World' in the frontend ethers.js code?

Best Answer

Thank you to the wonderful chinese website that explained this well and I figured it out.

from web3 import Web3, HTTPProvider
import sys
from eth_account.messages import defunct_hash_message

w3 = Web3() 

signature = sys.argv[1]

original_message = "Hello World"
message_hash = defunct_hash_message(text=original_message)

signer = w3.eth.account.recoverHash(message_hash, signature=signature)
return signer
Related Topic