I want to be able to call execTransaction
without gnosis infra (as a recovery measure), so I made a little signer web3.js app that takes all the parameters, hashes them exactly the way the safe contract does it in encodeTransactionData
, this produces safeTxHash
. I checked it against previous transactions I made through the Safe web UI, it matches.
I then use personal_sign
to prompt the user to sign the hash.
const sign = await ethereum.request({
method: 'personal_sign',
params: [safeTxHash, from, 'Random text'],
});
We can then send around the signatures with my colleagues in email and once we have enough signatures, we can call execTransaction
in eg. etherscan to interact with the safe without Gnosis servers.
However, calling execTransaction
fails with GS026 (which means some of the signatures are bad). OK maybe I got the nonce wrong, or something, so let's try calling checkNSignatures
directly to see which signature is bad. It turns out all of them are. Here's an example.
address: 0x360048390d7D967Bc634e1253fB9632290130ED7
data: 0x1901f575497ea4aae42517ffea2ac3cee51f6af01be4288b09746385e7ca8edb21900e9a43707f7f38353cc9a99de2dd46c6b41d91d425c2727e90d914785190cb7b
data hash: 0x3db1b18173909221b28b2a497995a26baef0712558a83f2755fda3799fbe93b0
signature: 0x1f48e4661e3adbb06c60c31291aa38265565ad72d87079bc07ce96cf9cbffabb7c5edefa071c108f9737930dad8085a33d0d5127c3fb8ddebc0be44c057c23711b
What drives me insane is that this is a transaction we've already signed and executed through the Safe Desktop app, and the signature matches the one that we see on the blockchain in the successful execTransaction
call!!
Sooo... what's wrong with my signature?
getTransactionHash
on the contract. Just sign that and you're fine