Skip to content

safe:propose

Queue a Safe transaction, rejection or Safe message on the Safe Transaction Service: a command block, cancel or a message, signed by the wallet as an owner (its confirmation) or a delegate, or signed JSON.

⚗️ Experimental — available at next.evmcrispr.com.

Smart blocks: cannot be nested. This command performs an immediate wallet, RPC, external-service or control-flow operation and cannot run inside an atomic batch.

Accepts ordinary (...) and smart !(...) payload blocks. Smart blocks support explicit @helper! expressions and returned-value captures.

safe:propose <safe> <proposal>
NameTypeEvaluationDescription
safeaddressBuild timeSafe address
proposalblock | stringBuild timeCommands composing the transaction, cancel (with --nonce) to reject a pending one, a message (text or EIP-712 typed data), or signed Safe transaction or Safe message JSON
NameTypeEvaluationDescription
--saltbytes32Build timeSmart-batch storage salt for reproducible offline signing (block forms with !)
--noncenumberBuild timeSafe nonce for a command block (defaults to the next free service nonce), or of the pending transaction to cancel
--originstringBuild timeOrigin tag shown in the Safe UI
--viaaddressBuild timeOwner Safe to sign through, when you own several owner Safes
--allow-delegate-call-toaddress | arrayBuild timeContracts the transaction may delegatecall besides MultiSendCallOnly, SafeMigration, SignMessageLib and fully decoded MultiSend or ERC-8211 batches
--allow-new-ownersaddress | arrayBuild timeOwners the transaction may add
--allow-removed-ownersaddress | arrayBuild timeOwners the transaction may remove
--allow-change-threshold-tonumberBuild timeThreshold the transaction may leave the Safe with
--allow-new-modulesaddress | arrayBuild timeModules the transaction may enable
--allow-guard-toaddress | stringBuild timeTransaction guard the transaction may leave the Safe with (none removes it)
--allow-module-guard-toaddress | stringBuild timeModule guard the transaction may leave the Safe with (none removes it)
--allow-fallback-handler-toaddress | stringBuild timeFallback handler the transaction may leave the Safe with (none removes it)
--allow-gas-refundboolBuild timeSign or execute despite a gas refund (gasPrice, gasToken or refundReceiver set)
--allow-competingboolBuild timeSign or execute although other transactions are queued at the same nonce

Queues a new Safe transaction or Safe message on the Safe Transaction Service so the other owners can confirm it, here with safe:confirm or in the Safe web app. The service needs a signature, so the connected wallet signs it, and it is reviewed like safe:confirm before the wallet prompt: a blocking finding refuses it until the matching --allow-* option names what you reviewed.

  • As an owner, directly or through an owner Safe it completes alone (--via picks among several), its signature is the proposal's first confirmation.
  • As a delegate, added by an owner with safe:delegate, it signs a transaction as the proposer: the Safe web app shows it, but the service never counts it as a confirmation. A delegate cannot propose a Safe message.

On a 1-of-1 Safe, an owner's proposal is already fully confirmed, so its safe:execute is not reviewed again; safe:execute with the block proposes, confirms and executes in one step.

The Safe commands are named after where their result goes: the Safe Transaction Service (propose, confirm), a variable holding JSON (propose-offline, confirm-offline), or the chain (confirm-onchain, execute). See the Safe guide for the complete flows.

In the terminal and the CLI, the proposal stays open as a status box: Proposed (nonce 42) → 1/2 confirmations → Executed in 0x77…, where the hash links to the executing transaction on the chain's explorer (the full hash when the chain has none), Executed but reverted in 0x77… when the Safe ran it but its call failed (possible with a non-zero safeTxGas or gasPrice), or Replaced by another transaction at nonce 42 when another transaction uses the nonce first. The run waits until one of those happens; Cancel stops following without touching the proposal. A cancel rejection is followed the same way. Commands inside the block follow it too: a TWAP proposed here starts tracking once the Safe executes.

Propose a token transfer:

load safe
set $receiver 0x4F2083f5fBede34C2714aFfb3105539775f7FE64
safe:propose @ens(mysafe.eth) (
exec @token(DAI) transfer(address,uint256) $receiver 100e18
)

Batch several actions into one proposal (packed through MultiSendCallOnly) and manage the Safe itself from inside the block:

load safe
set $mySafe 0x5afe3855358e112b5647b952709e6165e1c1eeee
set $spender 0x4F2083f5fBede34C2714aFfb3105539775f7FE64
safe:propose $mySafe (
exec @token(DAI) approve(address,uint256) $spender 100e18
safe:add-owner 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 --threshold 2
) --origin "My app"

The nonce of a block defaults to the next free nonce: the on-chain nonce, skipping past trusted queued proposals. A consumed nonce is refused, and an proposal over transactions already queued at an explicit --nonce needs --allow-competing true, since only one of them can execute.

cancel in place of the block proposes a rejection: a zero-value call from the Safe to itself at the pending transaction's nonce, which is how the Safe web app rejects one. Once it is confirmed and executed, the pending transaction can never run.

load safe
set $mySafe 0x5afe3855358e112b5647b952709e6165e1c1eeee
safe:propose $mySafe cancel --nonce 42

--nonce is required. A quoted "cancel" is a text message instead.

A quoted string proposes an off-chain Safe message (EIP-191 text), and EIP-712 typed-data JSON proposes a typed message. Owners confirm it with safe:confirm <safe> <safeMessageHash> --message, and @safe:signature returns the signature a dapp asks for:

load safe
set $mySafe 0x5afe3855358e112b5647b952709e6165e1c1eeee
safe:propose $mySafe "I agree to the terms"

Safe transaction or Safe message JSON signed with safe:confirm-offline is posted as it is: its first owner signature proposes it and the rest become confirmations, so any account can post it without a wallet prompt. Posting adds no signature: its signers were reviewed by safe:confirm-offline when they signed.

safe:propose $mySafe $tx

Owner Safe signatures are posted once complete; those still collecting are kept out with a warning, and safe:confirm-offline continues them in the JSON.

Set $safe:apiKey to lift the anonymous rate limits of the Safe Transaction Service, or $safe:serviceUrl to target a self-hosted service.