-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Background
I've been using safe-utils to write a solidity script that involves batching a few transactions and proposing them to a safe wallet like so:
function addToBatch(address target, bytes memory callData) internal {
batchTargets.push(target);
batchData.push(callData);
}
function proposeBatchTransaction() internal returns bytes32{
//Generate transaction target and data arrays for signing.
bytes memory transactionDataContract1 = abi.encodeCall(ownable2StepContract1.acceptOwnership, ());
bytes memory transactionDataContract2 = abi.encodeCall(ownable2StepContract2.acceptOwnership, ());
bytes memory transactionDataContract3 = abi.encodeCall(ownable2StepContract3.acceptOwnership, ());
addToBatch(address(contract1), transactionDataContract1);
addToBatch(address(contract2), transactionDataContract2);
addToBatch(address(contract3), transactionDataContract3);
//Get composed transaction data
(address to, bytes memory data) = safe.getProposeTransactionsTargetAndData(batchTargets, batchData);
// Get signature over transaction so we can propose it to the multisig wallet.
bytes memory signature = safe.sign(to, data, Enum.Operation.Call, proposerAddress, derivationPath);
//Use signature to propose transaction to the safe wallet
bytes32 txHash = safe.proposeTransactionsWithSignature(
batchTargets,
batchData,
proposerAddress,
signature
);
return txHash;
}
The script uses several contract level variables. Namely, batchTargets, batchData, proposerAddress, and derivationPath.
The types associated with these are as follows.
address[] internal batchTargets;
bytes[] internal batchData;
// The following are read in via vm.env* cheatcodes.
address proposerAddress; // This will be the address of the account stored in the ledger at derivationPath
string derivationPath;
Issue
From my understanding this should mean while running the script, a user would be using their ledger wallet to sign this batch of transactions, and then have it proposed to the multi-sig wallet, making it visible on their UI.
However, when running the script, I get the following error message from the safe-ui service:
ProposeTransactionFailed(422, "{\"nonFieldErrors\":[\"Signer=0x9999999999999999999999999999999999999999 is not an owner or delegate. Current owners=['0x1111111111111111111111111111111111111111', '0x2222222222222222222222222222222222222222', '0x3333333333333333333333333333333333333333']. Delegates=set()\"]}")
The signer address returned is notably not the address present in the ledger wallet at the derivation path used to sign; furthermore, the signer address isn't present on the ledger at all.
At first I assumed that this was because the script executes some transactions before this step with a different address, so I might have been constructing the signature wrong. However, the first address used for broadcasting in the script is also not the address listed as a signer.
I found a similar issue someone had with a javascript framework for interacting with the safe API. The solution they later posted implies that the signature being generated wrong might cause this issue, but it's not immediately obvious to me how I would be doing that wrong here.