1

I am trying to propose a transaction on a nested safe setup programmatically. I am testing a very basic setup for simplicity, my final setup will involve more than one inner safe.

Setup

Safe setup

To clarify ownership:

  • Top Safe owned by Inner safe
  • Inner Safe owned by EOA 1 and EOA 2

My desired flow is for one of the Inner safe owners (EOA 1) to programmatically propose a transaction on Top Safe. I then want the other EOAs on the Inner safe to sign that transaction using the Safe UI. The key is for the transaction to be proposed programmatically by one signer and to be signed in the UI by the other signers, as I only have access to one of the EOAs for programmatic signing.

Based on similar questions, I have followed to docs and attempted to use the protocol kit to create a transaction, collect a signature of behalf of Inner safe from EOA 1 and propose the transaction.

Here is a gist of my attempt.

I run into this error:

Error: Signature=0x000000000000000000000000371afe2b31dd5bd45fe2b07348d434e1d6cd90d1000000000000000000000000000000000000000000000000000000000000004100 for owner=0x371aFE2B31dd5bD45fE2B07348d434E1D6CD90d1 is not valid 

I believe this is happening because my script is not producing a valid/complete signature for the inner safe as I do not have a signature from EOA 2.

Is there a way I can propose a TX without having all the signatures? To restate my goal, I want to propose the transaction programmatically and collect the signatures from the other EOAs in the safe UI. I am open to different approaches to achieve this.

1 Answer 1

1

Answer

For your top safe to propose it, you'd need to have all the signatures from your inner safe first, except the top safe itself.

Instead of the image you have, it might be more helpful to think of it like this:

enter image description here

Where the top safe is initializing the transaction, and the inner safe is performing validation on that transaction.

So, the flow would need to be:

  1. Inner safe proposes transfer innerTxProposal
  2. Signer 1 signs innerTxProposal
  3. Signer 2 signs innerTxProposal

This creates all the calldata needed for the top safe to execute.

  1. Top safe then proposes innerTxProposal. It needs to set the recipient to the inner safe because the inner safe is the safe with the signature calldata.
  2. Top safe sends proposal, which sends to inner safe, which makes the transfer

Why?

When you propose a multi-sig transaction, you need all the calldata to propose it.

If you have foundry, to generate the calldata to for the inner safe send someone 10000000000000 wei of ETH you could run this:

cast calldata-encode "execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)" 0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba 10000000000000 0x 0 0 0 0 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 <valid signatures> 

However, as you can see, you'd need the final signatures to generate the final calldata. Without it, the top safe can't propose anything.

How to programmatically do this

Essentially, your code (pseudocode) would look like this:

innerSafeTx = innerSafe.createTx(send_money_from_top_safe) innerSafeTx.sign(keyOne) innerSafeTx.sign(keyTwo) innerSafeTx.send(topSafe) // topsafe has innersafe as the signer. The way top safe does verification, is it checks that the sender is the inner safe 
3
  • I have been able to propose/execute Transaction A on Top Safe using an Inner Safe. I did this by proposing an approveHash transaction for Transaction A on Inner Safe, I then collect signatures for this approveHash transaction from the signers (EOA 1 and 2) on Inner Safe. Finally, I can propose Transaction A on Top Safe with Inner Safe as a proposer using a pre-validated signature. Gist. Is this what you had in mind? Commented Mar 27 at 10:00
  • In step 4, why would the recipient need to be the inner safe? Commented Mar 27 at 10:35
  • I've updated my answer, does that help? It might be helpful to think in reverse order. Commented Apr 4 at 22:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.