1

I feel like I am missing something fairly basic here, hopefully this is a simple answer. I have done a ton of research on validating signatures from a gnosis safe. My safe is performing a transaction to store the fact that a signature was made by the owners on-chain. That part is all good. Now I need to verify the signature from my dApp smart contract and am running into VM execution errors. I decided to try and verify the signature from ethers just as a confirmation and ran into the same issue.

After reading about EIP-1271, my understanding is that safes should implement this EIP by default. I have a basic safe I created at https://gnosis-safe.io/app/ on the gnosis chain, and have signed a message from my dApp using the safe-apps-provider which is wrapped into an ethers Provider and then calls signMessage. A safe txn is performed to record the signature, and returns 0x to my dApp which I get means for this signature, I need to query the safe for signature validation, since smart contracts cannot generate ECDSA signatures like an EOA.

So now I am trying to verify the signature. I have the following code that just constructs an ethers Contract with just the EIP-1271 ABI so I can call isValidSignature. The call results in a VM error which to me, seems like the safe does not have the isValidSignature method. I could not find anywhere in the gnosis UI to enable this - my understanding is this should be enabled by default? I went down a rabbit hole looking at the safe code, but with all the libraries and fallback handlers, I wasn't able to confidently track down where the safe is actually implementing isValidSignature. The contract address below is the freshly created safe on gnosis which is version 1.3.0.

Shouldn't this work?

Code:

const ethers = require('ethers');

abi = [
    {
        "inputs": [
            {
                "internalType": "bytes32",
                "name": "hash",
                "type": "bytes32"
            },
            {
                "internalType": "bytes",
                "name": "signature",
                "type": "bytes"
            }
        ],
        "name": "isValidSignature",
        "outputs": [
            {
                "internalType": "bytes4",
                "name": "magicValue",
                "type": "bytes4"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    }
]

provider = new ethers.providers.JsonRpcProvider('https://rpc.gnosischain.com/')

safe = new ethers.Contract('0x22207860a2e5a50941c7ED99d20a18ADeCC93846', abi, provider);

msgHash = '0x220964afc8696c1bedbc4045ded3e62edca1bf83518f20121cfaf20347223d0b'; // message hash signed by safe

await safe.isValidSignature(msgHash, '0x');

and this results in VM execution errors:

Uncaught:
Error: missing revert data in call exception (error={"reason":"processing response error","code":"SERVER_ERROR","body":"{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"Reverted 0x48617368206e6f7420617070726f766564\"},\"id\":44}","error":{"code":-32015,"data":"Reverted 0x48617368206e6f7420617070726f766564"},"requestBody":"{\"method\":\"eth_call\",\"params\":[{\"to\":\"0x22207860a2e5a50941c7ed99d20a18adecc93846\",\"data\":\"0x1626ba7e220964afc8696c1bedbc4045ded3e62edca1bf83518f20121cfaf20347223d0b00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000\"},\"latest\"],\"id\":44,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"https://rpc.gnosischain.com/"}, data="0x", code=CALL_EXCEPTION, version=providers/5.5.3)
    at Logger.makeError (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/node_modules/@ethersproject/logger/lib/index.js:199:21)
    at Logger.throwError (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/node_modules/@ethersproject/logger/lib/index.js:208:20)
    at checkError (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:76:16)
    at JsonRpcProvider.<anonymous> (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:659:47)
    at step (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:48:23) {
  reason: 'missing revert data in call exception',
  code: 'CALL_EXCEPTION',
  error: Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"Reverted 0x48617368206e6f7420617070726f766564\"},\"id\":44}", error={"code":-32015,"data":"Reverted 0x48617368206e6f7420617070726f766564"}, requestBody="{\"method\":\"eth_call\",\"params\":[{\"to\":\"0x22207860a2e5a50941c7ed99d20a18adecc93846\",\"data\":\"0x1626ba7e220964afc8696c1bedbc4045ded3e62edca1bf83518f20121cfaf20347223d0b00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000\"},\"latest\"],\"id\":44,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="https://rpc.gnosischain.com/", code=SERVER_ERROR, version=web/5.5.1)
      at Logger.makeError (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/node_modules/@ethersproject/logger/lib/index.js:199:21)
      at Logger.throwError (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/node_modules/@ethersproject/logger/lib/index.js:208:20)
      at /Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:301:32
      at step (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:33:23)
      at Object.next (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:14:53)
      at fulfilled (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:5:58)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
    reason: 'processing response error',
    code: 'SERVER_ERROR',
    body: '{"jsonrpc":"2.0","error":{"code":-32015,"message":"VM execution error.","data":"Reverted 0x48617368206e6f7420617070726f766564"},"id":44}',
    error: Error: VM execution error.
        at getResult (/Users/masha/Projects/contracts/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:142:21)
        at processJsonFunc (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:344:22)
        at /Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:276:46
        at step (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:33:23)
        at Object.next (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:14:53)
        at fulfilled (/Users/masha/Projects/contracts/node_modules/@ethersproject/web/lib/index.js:5:58)
        at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
      code: -32015,
      data: 'Reverted 0x48617368206e6f7420617070726f766564'
    },
    requestBody: '{"method":"eth_call","params":[{"to":"0x22207860a2e5a50941c7ed99d20a18adecc93846","data":"0x1626ba7e220964afc8696c1bedbc4045ded3e62edca1bf83518f20121cfaf20347223d0b00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":44,"jsonrpc":"2.0"}',
    requestMethod: 'POST',
    url: 'https://rpc.gnosischain.com/'
  },
  data: '0x'
}
3
  • The revert here means the message was not signed
    – mikheevm
    Oct 26, 2022 at 13:09
  • That message hash is directly pulled from the SignMsg event that was triggered when it was signed. Oct 27, 2022 at 14:04
  • Safe performs additional hashing for security measurements, you should use the original hash of your message
    – mikheevm
    Oct 28, 2022 at 15:44

1 Answer 1

2

See my answer here how to validate the signature of a Gnosis Safe using ethers.js.

For me, the following code works:

import { Contract, utils, ethers } from "ethers";
...
const abi = ['function isValidSignature(bytes32 _message, bytes _signature) public view returns (bytes4)'];
const walletContract = new Contract("0xE1...", abi, provider);
let msg = "Your message";
let sig = "0x";
const hashMessage = utils.hashMessage(msg);
const response = await walletContract.isValidSignature(hashMessage, sig);

// Verify if the response matches the EIP-1271 magic value '0x1626ba7e'
...

To answer your questions:

  1. isValidSignature() is enabled by default on Gnosis Safe.
  2. This should be the contract code that is called.

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.