Safeの取引が進まない時の確認手順:署名・threshold・nonce・実行失敗を分ける
Safe multisigが署名待ち、nonce競合、実行失敗になるとき、proposal、owner confirmations、Safe nonce、guard、target revertを証拠ごとに確認します。

Safeの画面に「Awaiting confirmations」「Queued」「Execution failed」などと出ても、同じ原因とは限りません。最初に分けるのは、proposalが作られたこと、owner signaturesが集まったこと、別のEthereum transactionでon-chain executionが試されたことの3段階です。
2-of-3で署名が2件見えても、現在のowners・threshold、署名対象のSafe transaction hash、Safe nonce、guard、target callが一致しなければ実行成功は確定しません。反対に、Transaction Serviceの表示が遅れていても、chain上ではすでにSafe nonceが進んでいる場合があります。
この記事は、Safe addressやchainを確認せずに再署名・再実行する手順ではありません。公開dataはread-onlyで扱い、掲載する再現結果はlocal chainだけで動かしています。実在Safeへの接続、署名要求、module・guard変更、transaction送信、資産移動は行いません。
先に止める操作と保存する値
原因が分かるまでは、同じ内容への再署名、nonceだけを変えた再提案、未知のexecutorやrelayerへの送信、guard・module・thresholdの変更、検索結果やDMから開く「recovery」接続を止めます。ownerであっても、内容を確認していないhashへ署名しません。
一件の調査メモへ次を保存します。
| 項目 | 保存する値 | 分けたいもの |
|---|---|---|
| Safe identity | chain ID、Safe address、implementation、VERSION()、確認block |
別chain・別proxy・別version |
| authorization | owners、threshold、current Safe nonce | 現在の署名条件 |
| proposal | to、value、data、operation、gas関連field、nonce、safeTxHash |
署名対象の内容 |
| confirmations | signer address、signature type、確認時刻、対応safeTxHash | 件数表示と有効署名 |
| execution | Ethereum tx hash、sender、EOA nonce、receipt、logs、trace | proposalとon-chain attempt |
| extensions | modules、transaction guard、module guard、fallback handler | owner経路以外の実行・拒否 |
| service | Transaction Service URL、response、indexing status、確認時刻 | off-chain recordとchain state |
Safe addressとchain IDを固定できない場合はそこで停止します。addressの文字列が同じでもchainが違えば別のcontract stateです。proxy implementationの読み方はERC-1967 proxyの確認手順も参照してください。Safe proxyはERC-1967 slotを使うとは限らないため、一般的なproxy判定をそのまま当てはめず、対象versionの公式sourceと照合します。
proposal・confirmations・executionの3段階
1. proposal
proposalは、Safe transactionのfieldとSafe nonceをまとめ、EIP-712のsafeTxHashを作った段階です。Safe Transaction Serviceへ登録されたproposalや、別のcoordinatorが保持するproposalはoff-chain recordです。proposalが一覧にあるだけでは、Safe contractのstateは変わりません。
2. confirmations
ownerは、表示ラベルではなく同じsafeTxHashへ署名します。Safe v1.5.0の通常のEOA署名は、recovered owner addressの昇順に連結して検証されます。2-of-3なら現在のowner 3名のうち2名が必要ですが、削除済みowner、別hash、重複owner、順序不正、threshold未満は有効な2件になりません。
ownerがcontract accountならERC-1271など別のsignature validationが関係します。EOA signatureとcontract signatureの違いはERC-1271の検証手順、wallet promptでtyped dataのdomain・chain・contract・nonceを読む方法は署名要求の安全確認へ分けてください。
3. on-chain execution
thresholdへ到達しても自動実行とは限りません。executorが別のEthereum transactionでSafeのexecTransactionを呼びます。このouter transactionにはEthereum tx hashとexecutor EOA nonceがあり、Safe transactionにはsafeTxHashとSafe nonceがあります。
receiptのstatus: 1はouter callがrevertせず終わったことを示します。しかしSafeがtarget failureをcatchしてExecutionFailureをemitし、execTransactionがfalseを返す構成では、outer receiptが成功でもSafe内部callは失敗し得ます。receipt、ExecutionSuccess / ExecutionFailure event、return value、traceを同じEthereum tx hashへ対応させます。
safeTxHashとEthereum tx hashは別物
| identifier | いつ作られるか | 主な入力 | 何を証明しないか |
|---|---|---|---|
| Safe transaction hash | proposal作成時 | chain ID、Safe address、to、value、data、operation、gas / refund field、Safe nonce |
broadcast、mining、target success |
| Ethereum transaction hash | executorがnetworkへ送る時 | outer transaction、executor、EOA nonce、gas、chain | Safe内部callの成功、署名内容の妥当性 |
Safe v1.5.0のgetTransactionHashへ渡すfieldは次の10個です。
to, value, data, operation,
safeTxGas, baseGas, gasPrice, gasToken, refundReceiver,
nonce
どれか1つが変われば別のSafe transactionです。Safe addressとchain IDもEIP-712 domainへ入るため、別Safe・別chainのhashへ署名を流用できません。公開検証JSONは、架空Safe 0x0000…5000、chain ID 31337、Safe nonce 7を固定し、value 41と42のproposalが異なるsafeTxHashになることをoffline計算しています。generatorはprivate key、wallet、RPC、signature、transactionを使いません。
Transaction ServiceのsafeTxHashがある場合も、取得したtransaction fieldと対象SafeのgetTransactionHashから再計算して一致を確認します。見た目が同じ送金先やamountでも、data、operation、refundReceiver、nonceが違えば同じhashではありません。
Safe nonceとexecutorのEOA nonceを分ける
Safe nonceは、Safeがowner-authorized transactionを順序付けしてreplayを防ぐ値です。executor EOA nonceは、outer transactionを送るaccount自身のnetwork nonceです。同じ7と表示されても、所属するaccountと役割が違います。
同じSafe nonce Nでproposal AとBが作られることはあります。AとBはdataが異なるのでsafeTxHashも別です。Aが先に成功またはSafeがfailureをcatchしてnonceを消費すると、current Safe nonceはN + 1になります。Bへ集めた署名はnonce Nのhashへ固定されているため、そのままN + 1へ付け替えられません。
UIの「reject」「replace」は、元proposalを消去する魔法ではありません。どのSafe transactionがどのnonceを使い、どのhashがon-chainで実行され、current nonceがいくつになったかを確認します。新しいnonceへ内容を移すなら新しいsafeTxHashとなるため、ownersは新しい全fieldを再確認します。
executor側でnonce too lowが出た場合は、Safe nonceではなくexecutor EOAのpending transaction競合かもしれません。outer sender、EOA nonce、replacement fee、Ethereum tx hashを別列で調べます。
owners・threshold・modules・guards・versionをread-onlyで確認する
UIやTransaction Serviceのcacheより先に、対象blockのSafe contractをread-onlyで確認します。RPC、Explorerのverified contract read、または監査済みscriptを使い、wallet接続やwrite methodは不要です。
| 対象 | Safe v1.5.0で読む入口 | 注意点 |
|---|---|---|
| version | proxy経由のVERSION() |
implementationが違えば挙動を一般化しない |
| owners | getOwners() |
表示名ではなくaddressを保存 |
| threshold | getThreshold() |
confirmations数と同じ時点で読む |
| Safe nonce | nonce() |
proposalのnonceとcurrent値を分ける |
| modules | getModulesPaginated(0x…01, pageSize) |
sentinelからpaginationし、全pageを確認 |
| transaction guard | getStorageAt(GUARD_STORAGE_SLOT, 1) |
v1.5.0はpublic getterを持たない |
| module guard | getStorageAt(MODULE_GUARD_STORAGE_SLOT, 1) |
owner transaction guardとは別 |
| implementation | Safe proxyのmasterCopy()またはstorage slot 0 |
対象proxy typeを公式sourceで固定 |
Safe v1.5.0のtransaction guard slotは次です。
0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8
module guard slotは次です。
0xb104e0b93118902c651344349b610029d694cfdec91c589c91ebafbcd0289947
getStorageAt(uint256(slot), 1)が返す32 bytesの末尾20 bytesをaddressとして読みます。これらはSafe v1.5.0のpinned sourceで確認した値です。別versionへ無条件に流用しません。guardやmoduleを「確認のため」に無効化・交換しないでください。設定変更自体がowner-authorized writeであり、資産controlの境界を変えます。
moduleは、通常のowner threshold transactionとは別のexecTransactionFromModule経路を使えます。有効なmoduleが実行したtransactionでは、通常proposalのconfirmation件数を原因にしません。呼び出し元module、module guard、module event、traceを確認します。悪意あるmoduleは任意実行につながり得るため、名称やUI iconではなくaddress、code、設定transactionを記録します。
failureを止まった場所で分類する
threshold不足・invalid owner・署名順序
Safeはnonceをpost-incrementしてからsignature検証へ進みますが、signature検証がrevertすればouter call全体がrollbackするため、Safe nonceは消費されません。次を同じblockとsafeTxHashで確認します。
- current ownersとthreshold
- 各signatureからrecoveryしたowner、またはcontract signature owner
- signatureが同じsafeTxHashへ対応するか
- EOA signaturesがowner address昇順か
- prevalidated signatureやERC-1271などsignature typeの解釈
件数だけ合わせるために追加署名を依頼せず、まず既存signatureがどのhashへ対応するかを固定します。
transaction guard reject
transaction guardはexecTransactionのtarget call前後で検査を実行できます。事前検査がrevertするとtargetは呼ばれず、outer callがrevertするためnonce incrementもrollbackします。guard revert data、guard address、guard code version、blocked conditionを保存します。
guardを外せば通るという案内はしません。Safe公式も、壊れたguardや悪意あるguardがtransactionをblockできると注意しています。guard変更はSafe自身からのauthorized callが必要で、別の運用・security reviewです。
target revertとExecutionFailure
signatureとguardを通過しても、target contractがrevertする場合があります。Safe v1.5.0ではsigned gas fieldによりouter結果が変わります。
safeTxGas > 0またはgasPrice > 0でtarget failureをSafeがcatchした場合、execTransactionはfalseを返してExecutionFailureをemitし、Safe nonceは消費されますsafeTxGas == 0かつgasPrice == 0ではtarget failureをbubbleするため、outer transactionがrevertし、Safe nonce incrementもrollbackします
したがって「target revertならnonce未消費」「receipt successならSafe success」のどちらも一般化できません。signed field、Safe event、trace、current nonceを一緒に読みます。
target revertの原因はSafeではなく、target側のallowance、role、deadline、slippage、paused state、calldata、value、delegatecall contextなどにある場合があります。revert dataとtraceを保存し、同じcallを実資産環境で闇雲に再実行しません。
execution gas・refund・relayer
safeTxGas、baseGas、gasPrice、gasToken、refundReceiverはsafeTxHashに含まれます。画面でgas estimateだけを更新したつもりでも、signed Safe transactionが変わる場合があります。
gasPrice > 0ならSafeは実装の計算に基づきrefund paymentを試みます。native refundやtoken transferが失敗するとouter executionもrevertし得ます。executorが払うnetwork fee、Safeが設定に基づき返すpayment、relayer serviceの料金は別項目です。refundReceiverやgasTokenを推測で変えず、署名対象field、Safe balance、token behavior、outer receiptを確認します。
Transaction Service表示とon-chain stateがずれる場合
Safe Transaction Serviceはoff-chain proposalとconfirmationsを提供し、chainのtraceやeventsをindexします。便利なcoordination layerですが、Safe contractそのものではありません。indexer lag、unsupported chain、trace取得失敗、reorg、service endpointの違いにより、一時的に表示とchain stateがずれる可能性があります。
次の順で照合します。
- RPCでchain ID、Safe code、implementation、versionを固定する
- owners、threshold、current Safe nonce、modules、guardsを同じblockで読む
- service responseのtransaction fieldsからsafeTxHashを再計算する
- execution tx hashがあればRPCでtransactionとreceiptを取得する
- Safe eventとtraceを読み、target callのsuccess / revertを確認する
- 最後にTransaction Serviceのindexing status、response時刻、再取得結果を比較する
serviceにproposalがないことは、on-chain executionがなかった証拠ではありません。反対に、serviceにconfirmationsが揃っていることも、実行済みの証拠ではありません。on-chain stateを先に固定し、Transaction Serviceのstatusは最後に照合することが切り分けの基準です。
local 2-of-3で再現した結果
公式@safe-global/[email protected]をlocal Foundry chainへdeployし、公開された検証専用keyだけを使って次の条件を再現しました。外部RPCやwalletへは接続していません。
| 条件 | local実行の結果 |
|---|---|
| 2-of-3 | owner 2名のsorted ECDSA signaturesでtarget stateを更新し、Safe nonceが1進む |
| threshold不足 | 1 signatureでrevertし、target stateとSafe nonceは変わらない |
| invalid owner | owner + outsiderでrevertし、Safe nonceはrollbackする |
| nonce競合 | 同じnonceのAを実行後、Bの元signatureはcurrent nonceと合わず実行できない |
| target revert | non-zero safeTxGasでfalseを返し、target stateは変わらずSafe nonceは進む |
| guard reject | Safe self-callで設定したguardがtarget前にrevertし、Safe nonceはrollbackする |
同じlocal実行でtransaction guardを公式storage slotからread-only確認し、module一覧が空であること、VERSION()が1.5.0であることも確かめました。この結果はSafe v1.5.0の限定条件を再現したもので、任意のSafe、module、guard、target、relayerで同じ結果を保証しません。
support・運用担当へ渡すpackage
問い合わせには、screenshotだけでなく次のmachine-readableな値を渡します。seed phrase、private key、full signature blobを公開ticketへ貼りません。
- chain ID、Safe address、implementation address、Safe version、確認block
- owners、threshold、current Safe nonce
- proposalの全transaction fieldsとsafeTxHash
- signer addressesとconfirmation時刻。signature本体は必要性と安全な共有先を確認する
- execution Ethereum tx hash、outer sender、EOA nonce、receipt、Safe event、trace、revert data
- modules、transaction guard、module guard、fallback handler
- Transaction Service endpoint、response、indexing status、取得時刻
- 期待した結果と実際の結果、最初に不一致になった段階
この順に揃えると、「署名が足りない」「同じnonceの別proposalが先に進んだ」「guardが拒否した」「targetがrevertした」「service表示だけ遅れている」を混ぜずに相談できます。safeTxHashとEthereum tx hash、Safe nonceとexecutor EOA nonceを別欄にすることが、再署名や再実行を判断する前提です。
最終チェック
- chain ID、Safe address、implementation、
VERSION()を固定した - owners、threshold、Safe nonce、modules、transaction guard、module guardを同じblockで読んだ
- proposalの全fieldからsafeTxHashを再計算した
- confirmationsが同じhashと現在のownersへ対応することを確認した
- 競合proposalごとにnonceとsafeTxHashを分けた
- execution tx hash、executor EOA nonce、receipt、Safe event、traceを保存した
- target revert、guard reject、refund failure、service lagのどこで止まったかを分類した
- 原因確定前の再署名、再提案、module・guard変更、資産操作を止めた
この8項目が揃うまで、UIのstatusだけを根拠に「署名を追加すれば進む」「rejectすれば置換できる」「もう一度実行すれば直る」と判断しません。
確認した一次情報
- Safe Transaction Service API overview確認日: 2026/08/31
- Safe off-chain transaction guide確認日: 2026/08/31
- Safe Protocol Kit transaction signatures確認日: 2026/08/31
- Safe Protocol Kit transaction execution確認日: 2026/08/31
- Safe Smart Account guard tutorial確認日: 2026/08/31
- Safe Smart Account v1.5.0 release確認日: 2026/08/31
- Safe.sol at pinned v1.5.0 commit確認日: 2026/08/31
- GuardManager.sol at pinned v1.5.0 commit確認日: 2026/08/31
- ERC-1271 contract signature validation確認日: 2026/08/31



