with one click
safe-multisig
// Guide the user through Safe multisig operations -- managing owners, preparing arbitrary transactions, collecting signatures, and executing on-chain. Supports Ledger hardware wallets and Timelock interactions.
// Guide the user through Safe multisig operations -- managing owners, preparing arbitrary transactions, collecting signatures, and executing on-chain. Supports Ledger hardware wallets and Timelock interactions.
| name | safe-multisig |
| description | Guide the user through Safe multisig operations -- managing owners, preparing arbitrary transactions, collecting signatures, and executing on-chain. Supports Ledger hardware wallets and Timelock interactions. |
| user-invocable | true |
| allowed-tools | Read, Edit, Write, Bash, Grep, Glob, AskUserQuestion |
| argument-hint | [manage-owners | prepare-tx | sign | execute] |
You are helping the user interact with a Gnosis Safe multisig wallet. The toolkit lives in tools/safeMultisig/.
The workflow always follows: Prepare -> Sign -> Execute.
Ask the user (or determine from $ARGUMENTS) which operation they need:
manageOwners.ts)tools/safeMultisig/manageOwners.tsprepareTransaction.ts)tools/safeMultisig/prepareTransaction.tssignSafeTransaction.ts)transactions.json and needs more signaturestools/safeMultisig/signSafeTransaction.tsexecuteSafeTransaction.ts)tools/safeMultisig/executeSafeTransaction.tsIf the user says something generic like "I want to use the multisig", ask them which operation they need.
mainnet, sepolia, custom). Ask: "Which network should we use?".env has:
CUSTOM_PROVIDER (RPC URL, if using --network custom)LEDGER_ACCOUNT (their Ledger address, if using Ledger)MNEMONIC for software wallet signingAsk the user for:
At least one of ownersToAdd, ownersToRemove, or newThreshold must be provided.
Ask the user for:
0x)0, "1.5 ether", "10 gwei", or wei as stringIf the user wants to schedule or execute a Timelock operation, help them encode the calldata:
Schedule:
function schedule(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt, uint256 delay)
Execute:
function execute(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt)
The Timelock address for mainnet is: 0xEf1462451C30Ea7aD8555386226059Fe837CA4EF
"true" to bypass nonce mismatch (only if user confirms)For Options A and B, write the configuration to tools/safeMultisig/parameters.json.
{
"safeAddress": "<safe-address>",
"ownersToAdd": ["<address1>", "<address2>"],
"ownersToRemove": ["<address>"],
"newThreshold": 3
}
Only include the fields that are relevant. Omit ownersToAdd if not adding, omit ownersToRemove if not removing.
{
"safeAddress": "<safe-address>",
"to": "<target-contract>",
"data": "<encoded-calldata>",
"value": 0,
"description": "<human-readable-description>"
}
All commands run from the repository root.
npx hardhat run tools/safeMultisig/manageOwners.ts --network <network>
npx hardhat run tools/safeMultisig/prepareTransaction.ts --network <network>
SIGNER_INDEX=<index> npx hardhat run tools/safeMultisig/signSafeTransaction.ts --network <network>
EXECUTOR_INDEX=<index> npx hardhat run tools/safeMultisig/executeSafeTransaction.ts --network <network>
Or with force execute:
FORCE_EXECUTE=true EXECUTOR_INDEX=<index> npx hardhat run tools/safeMultisig/executeSafeTransaction.ts --network <network>
After preparing, remind the user of the remaining steps:
signSafeTransaction.ts from their own machine with their own Ledger (SIGNER_INDEX stays at 0 for everyone). After each owner signs, they share the updated transactions.json with the next owner until threshold is met.executeSafeTransaction.ts.If using Ledger, remind the user:
If the user hits an error, check these common issues:
| Error | Cause | Fix |
|---|---|---|
| "Nonce mismatch" | A previous tx was executed or prepared tx is stale | Re-run the preparation script |
| "Insufficient signatures" | Not enough owners have signed | More owners need to run signSafeTransaction.ts |
| "Not an owner" / "Signer is not a Safe owner" | The signer address is not a Safe owner | Check SIGNER_INDEX or LEDGER_ACCOUNT |
| "Already signed" | This signer already signed | Another owner needs to sign |
| "Gas estimation failed" | Transaction would revert | Check calldata, permissions; try FORCE_EXECUTE=true |
| Ledger not detected | USB or app issue | Reconnect, unlock, open Ethereum app |
| Transaction rejected on Ledger | Blind signing disabled | Enable blind signing in Ledger Ethereum app settings |
.env.transactions.json file is auto-generated -- do not manually create it.