I have a gnosis safe which I am interacting with directly (no sdk here). It has a threshold of 2 and 3 signers. I am attempting to execute a txn by calling execTransaction()
directly. It is failing with the GS026 error for incorrectly formatted signatures, but when I call checkNsignatures
directly with the same inputs, it doesn't fail.
My script is written in python using a combination of web3 & apeWorx
First I get the txn_hash
with:
txn_hash = my_safe_master_abi.getTransactionHash(
to,
value,
calldata.data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce
)
I then sign the txn hash and convert the signature as described in the gnosis docs
from web3.auto import w3
from eth_account.messages import encode_defunct
encoded_hash = encode_defunct(txn_hash)
signed_message1 = w3.eth.account.sign_message(encoded_hash, private_key=owner1.private_key)
ecdsa_signature1 = hex(signed_message1.r) + hex(signed_message1.s)[2:] + hex(signed_message1.v + 4)[2:]
I repeat this process with the 2 other owners to create 3 signatures.
ecdsa_signature2 = hex(signed_message2.r) + hex(signed_message2.s)[2:] + hex(signed_message2.v + 4)[2:]
ecdsa_signature3 = hex(signed_message3.r) + hex(signed_message3.s)[2:] + hex(signed_message3.v + 4)[2:]
To test that the individual signatures work, I call checkNsignatures
with the threshold set to 1. This way I can test if the signatures are formatted properly individually before concatenating. my_safe_master_abi.checkNSignatures(txnHash, datahash, ecdsa_signature1, threshold)
Strangely, the checkNsignatures
successfully executes for signatures 1 & 3 but not for 2
I continued with signatures 1 and 3 and concatenated them, also per the docs, checking that they are in ascending order: signatures = ecda_signature1 + ecda_signature3[2:]
and called checkNsignatures
successfully
When I then call my_safe_master_abi.execTransaction()
with the same signatures
variable, it fails and throws error GS026 which is inside of the checkNsignatures
function which passed when called directly
Would appreciate help on both why signature 2 is failing separately from 1 & 3 AND why checkNsignatures
is failing when called within execTransaction
Full source code (note: local hardhat chain with a fork of eth mainnet). Not really calling this as a script, but executing line by line in ape console to sort out where I'm going wrong
txn_hash = my_safe_master_abi.getTransactionHash(
to,
value,
calldata.data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce
)
from web3.auto import w3
from eth_account.messages import encode_defunct
encoded_hash = encode_defunct(txn_hash)
signed_message1 = w3.eth.account.sign_message(encoded_hash, private_key=owner1.private_key)
signed_message2 = w3.eth.account.sign_message(encoded_hash, private_key=owner2.private_key)
signed_message3 = w3.eth.account.sign_message(encoded_hash, private_key=owner3.private_key)
## signatures1 is working
## >>> '0xf4f681475a9a03ef457c2fcf85e82f52872fc3c7ad10dd74245e6e898ad0c8d84c441b7adea575f5e10ccf3d25d80fa7efc878078ded98995ca1fa7be70a8e9720'
ecdsa_signature1 = hex(signed_message1.r) + hex(signed_message1.s)[2:] + hex(signed_message1.v + 4)[2:]
## signatures2 is not working
## >>> 0x15c81d3a62b1635e4dedb594e2b009e6943498d83cf38a89c3efaf819fc855e7a8f8cd3a13968de8ed8718c05af49e26c9b871c42325e91bb0d344b3cfdeb341f
ecdsa_signature2 = hex(signed_message2.r) + hex(signed_message2.s)[2:] + hex(signed_message2.v + 4)[2:]
## signature3 is working
## >>> 0x1183ab034b94fb9ff69e3a81abc057e23485bd2b8766491d639526367ac19a4727dd0235c6b948cd9fd3d35b436b06358f8d2e1d481c4fd544ae5f20b510fb6b20
ecdsa_signature3 = hex(signed_message3.r) + hex(signed_message3.s)[2:] + hex(signed_message3.v + 4)[2:]
## >>>'0xf4f681475a9a03ef457c2fcf85e82f52872fc3c7ad10dd74245e6e898ad0c8d84c441b7adea575f5e10ccf3d25d80fa7efc878078ded98995ca1fa7be70a8e97201183ab034b94fb9ff69e3a81abc057e23485bd2b8766491d639526367ac19a4727dd0235c6b948cd9fd3d35b436b06358f8d2e1d481c4fd544ae5f20b510fb6b20'
signatures = ecdsa_signature1 + ecdsa_signature3[2:]
## Check signature with checkN signatures
## need encoded dat
datahash = my_safe_master_abi.encodeTransactionData(
to,
value,
calldata.data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce
)
## need hashed data
txnHash = my_safe_master_abi.getTransactionHash(
to,
value,
calldata.data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce
)
## Set threshold to 1 to check individual signatures
threshold = 1
## check signature, works with signature 1, 3, & 1+3
my_safe_master_abi.checkNSignatures(txnHash, datahash, ecdsa_signature1, threshold)
theshold = 2
my_safe_master_abi.checkNSignatures(txnHash, datahash, signatures, threshold)
## try to execute a transaction
my_safe_master_abi.execTransaction(
to,
value,
calldata.data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
signatures,
sender = owner1
)