I am using the guide How to verify Gnosis Safe transactions on a hardware wallet in order to verify what I am signing on my hardware wallet.

However, the guide explains that I will get a single hash on my Ledger wallet but I actually get two. First it says I am signing a “Typed message”, and then I get a “Domain” hash followed by a “Message” hash, neither of these match the expected hash.

When I reject this transaction, Metamask pops up with another transaction and when I sent this to my Ledger I do get the expected message hash, but this does not seem like the proper process.

What is this “Typed message” exactly, and how can I verify that these two hashes match with what I am expecting to sign?

  • Did you find a solution to easily verify the hashes that a ledger is showing?
    – Kev
    Aug 30, 2022 at 13:25

2 Answers 2


The typed message is based on EIP-712. The Safe transaction hash (safeTxHash) is based on the domain hash and the message hash. The logic for this can be found here.

To verify these value you would have to perform an additional hashing on these to values (same as in the linked contract) and then compare it to the hash returned via Etherscan.

  • Could you give a more detailed explanation? How does one "perform an additional hashing of the two values"?
    – Kev
    Aug 30, 2022 at 14:10
  • The link in this answer is a 404. The full details of the answer should be included in the Stack Exchange answer, rather than linked externally, for this exact reason. Dec 8, 2023 at 10:36

Signing a typed message with SAFE and validating it is a bit of a nightmare at the time of this writing. The SAFE UI shows a Message field with some text, and two hashes, but the message field doesn't hash into either of them. If you ignore that and then go forward with the signing, you are asked to sign the SafeMessage (not the original message) and MetaMask will show that. But then your ledger will receive a request for a signature over a Domain Hash and Message Hash, but the Domain Hash isn't presented anywhere, nor is the message that is shown.

You can get the Domain Hash by reading the domainSeparator value off of your SAFE contract

You can calculate the message hash presented on the ledger with the following TypeScript:

const safeMessage = '0x...' // whatever is shown in SAFE UI
const prefix = keccak256('SafeMessage(bytes message)')
const postfix = keccak256(safeMessage)
const messageHash = keccak256(`0x${prefix}${postfix}`)

I don't know how the Message is turned into a SafeMessage, and this is a critical bit of information that someone can hopefully fill in one day.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.