Safer is a tool that helps you sign & submit transactions to a Safe, without requiring any interaction with Safe's backend or frontend.
Safer is a set of Foundry scripts that can be used as fallback in case Safe App is down and the blockchain is the only thing that can be trusted.
Safer enables submitting complex transactions without the need of intermediaries.
Safer unlocks true DAO resilience.
- Install Foundry.
- Run
maketo initialize the repository. - Create a
.envfile from the template.env.examplefile.- Set the environment variable
SENDERto the address used to execute the transaction on the Safe. If you don't execute the tx, you don't need to set it. - Use the environment variable
SAFE_NONCEto override a transaction's nonce. Remove it to use the default, latest Safe nonce. Leave it blank to use nonce 0. - Use the environment variable
FOUNDRY_ETH_RPC_URLto customize the RPC endpoint used. This is useful to interact with a Safe deployed on another chain than Ethereum mainnet (the default one).
- Set the environment variable
- Run
make txand follow the steps to create a Safe transaction using create-safe-tx; OR - Put the transaction's raw data in
data/tx.json
To create a batch of multiple transactions that will be executed atomically:
- Add the
MULTI_SEND_ADDRenvironment variable to your.envfile with the MultiSend contract address for your Safe version (e.g.,MULTI_SEND_ADDR=0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526for Safe 1.3.0 on Sepolia) - Create a
data/batch.jsonfile with an array of transaction objects - Run
make prepare-batchto encode the batch into a single Safe transaction
Each transaction in the batch should follow this format:
[
{
"operation": 0,
"to": "0x0000000000000000000000000000000000000000",
"value": "0",
"data": "0x"
},
{
"operation": 1,
"to": "0x0000000000000000000000000000000000000000",
"value": "1000000000000000000",
"data": "0x1234567890abcdef"
}
]Where:
operation:0for a call,1for a delegatecallto: target contract addressvalue: amount of ETH to send (as a string)data: transaction data (must start with0x)
The batch will be encoded using Safe's MultiSend contract and saved to data/tx.json for signing and execution.
- To sign the data with a Ledger, run:
make sign:ledger - Share the content of
data/signatures.txtwith the signer who will execute the transaction on the Safe
- Make sure at least
thresholdsignatures are available indata/signatures.txt, each one per line - To execute the transaction on the Safe with a Ledger, run:
make exec:ledger
With make sign & make exec, one can also use any other wallet provider available with cast:
make cmd:interactiveto input the private key to the command promptmake cmd:ledgerto use a Ledgermake cmd:trezorto use a Trezormake cmd:keystoreto use a keystoremake cmd:"private-key 0x..."if you really want to save your private key to your shell's history...
You can also append any cast parameter:
make sign:"ledger --mnemonic 1 --mnemonic-index 1"ormake exec:"ledger --mnemonics foo --mnemonic-indexes 1"to use another account than the default one at index0
{
"to": "0x0000000000000000000000000000000000000000",
"value": "0", // The tx value (in ETH), must be a string
"data": "0x", // The raw tx data, must start with 0x
"operation": 0, // 0 for a call, 1 for a delegatecall
"safeTxGas": 0,
"baseGas": 0,
"gasPrice": 0,
"gasToken": "0x0000000000000000000000000000000000000000", // Indicates the tx will consume the chain's default gas token (ETH on mainnet)
"refundReceiver": "0x0000000000000000000000000000000000000000" // Indicates the tx's refund receiver will be the address executing the tx
}