gnosis-safe – Using personal_sign with WalletConnect and Gnosis Safe: A Comprehensive Guide

gnosis-safewalletconnect

I'm developing a website that uses personal_sign to authenticate users. I send the "address" and "signature" to my server to verify the user owns the address. I'm currently adding WalletConnect support, and ran into an issue with Gnosis Safe. When signing with Gnosis Safe, the value of signature is just "0x" instead of the full signature:

const signature = await connector.signPersonalMessage([
  convertUtf8ToHex(message),
  address,
]);

Is personal_sign supported by Gnosis Safe? This technique works with WalletConnect when connecting with Ledger Live or the Metamask mobile app. Is there an alternative way to verify a user owns an address?

Thank you.

Best Answer

If safeProxyContract.isValidSignature(msgHash, signature) (See CompatibilityFallbackHandler.sol#L66) returns the EIP1271 magic value, then the message with the msgHash is signed. If it doesn't, then it isn't signed

const UPDATED_EIP1271_MAGIC_VALUE = '0x1626ba7e'

let isValidSignature = await safeProxyContract.isValidSignature(msgHash, signature)

// if isValidSignature() returns the EIP-1271 magic value, the signature is valid
if (isValidSignature == UPDATED_EIP1271_MAGIC_VALUE) {
  signatureValid = true
}

But what I couldn't figure out was when to make the call to isValidSignature(). Because the WalletConnect modal actually resolves 0x right after the user issues the txn, without waiting for the txn to be confirmed. So there is no way to know the txn hash, nor when/if the sign message txn was mined or not

But GnosisSafe contract emits an event during those txn. So I added a once event listener to the contract to listen for that event, and then check isValidSignature()

const msgHash = ethers.utils.hashMessage(rawMessage)
const getMessageHash = await wsSafeProxyContract.getMessageHash(msgHash)
// login() only after the _signMessage() txn is mined and SignMsg(msgHash) event emitted
wsSafeProxyContract.once(wsSafeProxyContract.filters.SignMsg(getMessageHash), async () => {
  await login()
})

Thanks @Richard for helping out!

Related Topic