I am trying to sign a valid transaction hash (obtained from the onchain Gnosis Safe wallet itself) but when I sign the hash and then provide it to the multisig-transactions endpoint to propose the tx, the signing address that is recovered from the signature I provide does not match the address that I actually used to sign.
*note I unfortunately cannot use the SDK in this scenario
The signature is wrong because of some reason like ethersJS is prepending 'x19 Ethereum Signed Message' to the hash or because I am signing an ethers.utils.arrayify (ie bytes) version of the hexstring hash. I have tried all permutations I can think of to fix the invalid signature but I keep receiving response 422: "Signer=0xC2278C77001F5c5164ed97Ff945f6B0E6e006363 is not an owner or delegate. Current owners=[${owners}] The code in question:
const getAndSignTxHash = () => {
// get txhash from contract
const safe = new ethers.Contract(state.safeAddress, abiJson, signer);
// obtain txHash
const txHash = safe
.getTransactionHash(
state.recipient,
state.value,
"0x", //state.data,
state.operation,
state.safeTxGas,
state.baseGas,
state.gasPrice,
state.gasToken,
state.refundReceiver,
state.nonce
)
.then((res) => {
State.update({ txHash: res });
// sign contractTransactionHash using private key of Gnosis Safe owner (or deployer)
const signature = signer
.signMessage(ethers.utils.arrayify(res))
.then((sig) => {
State.update({ signature: sig });
console.log(sig);
});
});
};
const postToSafeApi = () => {
// craft transaction from state vars
const transaction = {
safe: state.safeAddress,
to: state.recipient,
value: state.value,
data: "0x", //state.data,
operation: state.operation,
gasToken: state.gasToken,
safeTxGas: state.safeTxGas,
baseGas: state.baseGas,
gasPrice: state.gasPrice,
refundReceiver: state.refundReceiver,
nonce: state.nonce,
contractTransactionHash: state.txHash,
sender: state.sender,
signature: state.signature,
origin: state.origin,
};
const transactionsUrl = state.baseUrl + `multisig-transactions/`;
const params = JSON.stringify(transaction);
const proposalOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
mode: "no-cors",
body: params,
};
// post to gnosis API backend
const proposed = asyncFetch(transactionsUrl, proposalOptions).then((res) =>
console.log(res)
);
};
If there is a better place to ask this question, please let me know since I have been stuck for a long time on this