I'm trying to understand toEthSignedMessageHash in the documentation. I understand that this creates a signed message from a digest of 32 bytes. However, I was under the impression that a signature was required to produce that signed message. Where does that signature come from? My only guess that this signature is coming from msg or some other similar global. Any help here would be greatly appreciated. Thanks.
I think I fundamentally didn't understand how toEthSignedMessageHash and recover works. toEthSignedMessageHash simply builds a hash and recover will return the address from a digest and a signature.
I have written some pseudo code to help understand:
// Client.
hash = hash(userId, token)
// Creates a digest with RSA private key to build an authentic signed message.
signature = signMessage(hash)
verify(userId, token, signature) // Call contract function.
// Contract.
verify (userId, token, signature) {
hash = hash(userId, token) // Duplicate of the hash made on the client.
digest = toEthSignedMessageHash(hash) // Creates a signed message digest.
// Returns the address of the signer from the client’s signed message.
addr = recover(digest, signature)
if (!isRoleMinter(addr)) throw new Error()
}
I have one more question, why go through the process of creating the address from the message recovery when I can use msg.sender?
toEthSignedMessageHash produces a eth message hash from any bytes32 value (which itself might be a hash). This is an operation that is required by ERC191.
recover takes (1) a signed message that can either be produced using toEthSignedMessageHash (for ERC191 messages) or by toTypedDataHash (for ERC712 typed structs) and (2) a signature of this signed message by an EOA. It returns the address of the EOA that produced the signature.
This is very different from msg.sender, which is the sender of the call (can be an EOA, or a contract that is relaying it). I encourage you read ERC191 and ERC712!