スマートウォレットの登録完了率を正しく測る|再送で水増しされない数え方

コラム

/約18分で読めます

コラム

/約18分

スマートウォレットの登録完了率を正しく測る|再送で水増しされない数え方
目次(タップで折りたたみ)

    あるアプリが、スマートウォレットを使った新規登録の導線を公開しました。スマートウォレットとは、アカウントの検証・実行の仕組みをスマートコントラクトで動かすウォレットです。プロダクト責任者は、利用を始めた人の割合(利用開始率)をダッシュボードで追っています。

    ところが、数字がどうもおかしい。「完了」の件数は伸びているのに、実際に最初の購入まで済ませた人は増えていません。調べると、原因は数え方にありました。手数料の変動で処理が遅れると、SDKは同じ操作を自動で送り直します。ダッシュボードはこの送信の件数を「完了」として数えていたので、送り直すたびに件数が増えていたのです。

    逆の失敗もあります。ブロックチェーン上で取引が確定した件数だけを見るやり方です。これだと、ログイン画面やパスキー作成でやめてしまった人が、最初から数に入りません。

    どちらも、画面の操作とチェーン上の結果が、別々に数えられていることが原因です。そこで、利用者が始めるたびに「試行ID」を振り、ログイン、署名、送信の受付、実行結果、最初の購入までを同じ試行として結びます。そうすれば、途中でやめた人と、処理の失敗や再送を見分けられます。

    以下では、このアプリのプロダクト責任者と開発チームが、計測を組み直す順に見ていきます。前半は「何を数えるか」を決める話です。イベントの形式やエラーコードといった細部は、後半の「開発チームが決める実装の詳細」にまとめました。AAの仕組みそのものはERC-4337の解説が基礎になります。

    この記事で使う言葉

    • AA(Account Abstraction):アカウントの検証・実行ロジックをスマートコントラクトへ移す仕組み。ERC-4337が代表的な規格
    • UserOperation:スマートウォレットが送る「やりたい操作」の単位。ふつうの取引の代わりに使う
    • Bundler:UserOperationを受け付け、まとめてチェーンへ送る事業者・サーバー
    • Paymaster:利用者の代わりにガス代(手数料)を補助する仕組み
    • 試行ID:利用者が導線を始めるたびに振る、その1回を表すID

    どこを「利用開始」のゴールにするか

    「登録できた」「ウォレットのアドレスが出た」をゴールにすると、その人が本当に使えたかは分かりません。送金、購入、mint、権限付与などを済ませたかどうかが見えないからです。

    ゴールは「ウォレット作成」ではなく、そのプロダクトで最初の価値に届いた時点にします。このアプリなら、最初の購入の成立です。そこまでの段階は次の7つです。

    1. 開始:導線が表示されただけでなく、利用者が開始の操作をした
    2. 本人認証:メール、OAuth、パスキーなど、選んだ方式でログインが成立した
    3. アカウント準備:使う予定のチェーンのアドレスと、署名できることをアプリが確認した
    4. 操作の承認:これから行う操作の内容を見せ、利用者の署名を得た
    5. 送信の受付:BundlerがUserOperationを受け付けた
    6. チェーン上での実行:実行結果を取得し、成功を確認した
    7. 価値到達:注文成立、mint完了など、プロダクトごとの業務の結果が確定した

    注意したいのは5と6の違いです。ERC-4337では、アプリ側がUserOperationをBundlerへ送ります。Bundlerは検証したうえで、複数の操作をまとめてチェーンへ送ります。受付、まとめ送信への採用、チェーン上での実行は、それぞれ別の状態です(ERC-4337仕様)。ですから「送信APIが成功した」を完了として数えてはいけません。

    「ウォレット作成済み」の意味も、方式によって変わります。

    • 最初の操作でアカウントがデプロイされる方式
    • デプロイ前に計算したアドレス(counterfactual address)を先に使える方式
    • EIP-7702で、既存のアカウント(EOA)のアドレスをそのまま使う方式

    製品をまたいで比べるなら、3のアカウント準備は「アドレスが払い出された」ではなく「対象の操作を署名・送信できる状態」と定めます。方式の選び方はスマートコントラクトウォレットのスタック比較 2026、AA全体で誰が何を担うかはAA完全マップ2026で扱っています。

    1回の「やってみた」にIDを振り、画面から取引結果までつなぐ

    ログインの前には、まだユーザーIDがありません。また、同じ人がやり直したら、その1回ずつを別に数えたいところです。そこで集計の軸には、ユーザーIDやウォレットアドレスではなく、開始のたびに発行する試行IDを使います。推測されにくい値にします。

    • 同じ人がやり直したら、別の試行として記録する
    • 同じ試行の中でSDKが送り直した分は、重複として1回にまとめる

    ログインの前は、ブラウザやアプリ単位の匿名IDだけを使います。ログインが成立した後、内部のユーザーIDとの対応をサーバー側で管理します。

    個人情報の扱いにも気をつけます。ウォレットアドレスとUserOperationのハッシュ(userOpHash)は、公開情報になりえます。これを、メールアドレス、電話番号、OAuthの利用者識別子(subject)、端末の生体情報と結ぶ対応表があるとします。その対応表を、分析基盤やブロックチェーンへむやみに複製してはいけません。

    なお、パスキー(WebAuthn)は認証器が作る署名を使う仕組みです。生体情報そのものをWebサイトへ渡すわけではありません(W3C WebAuthn Level 3)。秘密鍵、署名の材料、パスキーの認証情報に含まれる秘密情報は、どのイベントにも入れず、分析基盤へ送りません。

    「人」「試行」「送信」を別々に数える

    冒頭のアプリで件数が水増しされたのは、この3つを混ぜて数えていたからです。

    同じ利用者がログインをやり直したとき、新しい試行として扱うかどうか。これは、再開できる期限と画面の作りで決めます。一方、ガス代の見積もり直しやBundlerへの再送は、利用者が新しく決めたことではありません。同じ試行の中の送信として記録します。

    数える単位は次の5つです。

    • 利用者数(unique users):ログイン後の内部ユーザーIDで数える。ログイン前は匿名IDによる推定値だと明記する。
    • オンボーディング試行数(onboarding attempts):開始から有効期限までの、一連の利用者の操作。再訪を同じ試行に戻す条件は固定しておく。
    • 送信試行数(submission attempts):UserOperationの組み立て、シミュレーション、署名、送信、差し替え(replacement)を記録する。ハッシュが変わっても、親の試行はそのまま。
    • 受付件数(accepted operations):Bundlerが返したハッシュごとに数える。同じ操作の差し替えを、別のコンバージョンにしない。
    • 利用開始ユーザー数(activated users):最初の価値到達を1人1回だけ数える。

    SDKによっては、UserOperationの価格の調整と再送を自動で行います。たとえばAlchemyは、手数料の変動で処理が遅れた場合の設定を案内しています。再試行の間隔や回数を決める方法と、dropAndReplaceUserOperationによる差し替えです(Alchemy Wallet APIs FAQ、2026年9月24日確認)。ハッシュの件数をそのまま「完了ユーザー数」にすると、この再送の分だけコンバージョンが水増しされます。

    「来なかった」を全部「離脱」にしない

    次のイベントが来なかったものを、すべて離脱として数えたとします。すると、まだ処理中のもの、記録が遅れているもの、利用者が断ったもの、システムの障害が1つに混ざります。

    そこで試行には、「いまどの段階にいるか」という状態を持たせます。途中で止まったものは、次の3つに分けます。

    • 利用者が取りやめた
    • 技術的に失敗したが、同じ試行でやり直せる
    • やり直せず、人の対応が要る

    受付済みでも安心はできません。Bundlerは、受付の前、まとめ送信を作るとき、チェーンへ送る前にそれぞれ検証します。条件を満たさないUserOperationは、そこで破棄(drop)されることがあります。受付の時刻、チェーンに取り込まれた時刻、確定した時刻は、別々に記録します。

    失敗の種類ごとに、誰が直すか・利用者に何を見せるかを決める

    失敗を分類するのは、直す人と、利用者への見せ方を決めるためです。主な分類は次の8つです。コード名は後半の表にまとめています。

    失敗の種類(例)主な担当利用者への見せ方
    利用者の取りやめ(認証・署名を明示的に拒否)プロダクト・画面設計理由を推測せず、再開できる地点を示す
    認証の失敗(OTPの期限切れ、WebAuthnのchallenge不一致)認証基盤challengeを使い回さず、安全に再発行
    アプリ側の失敗(SDKの例外、未対応ブラウザー、チェーン切替の失敗)フロントエンド環境情報を最小限集め、別の手段を示す
    検証での拒否(署名、nonce、factory、シミュレーション)ウォレット・Bundler同じ内容の無限再送を止め、原因ごとに処理
    ガス代補助の拒否(Paymasterの補助方針、回数上限、残高不足)決済・運用自己負担へ切り替えられるかを明示する
    取り込みの時間切れ(受付後も期限内に受領記録がない)Bundler・チェーン運用処理中と表示し、差し替えと照会を続ける
    実行時の取り消し(対象コントラクトの条件不成立)アプリケーション・コントラクト確定した失敗として、やり直しの条件を示す
    業務処理の失敗(チェーン上は成功したが、注文・権限の反映に失敗)バックエンド・運用埋め合わせの処理をし、問い合わせ用IDを出す

    OTPはワンタイムパスワード、challengeはパスキー認証で毎回サーバーが出す使い捨ての値です。

    分類できない失敗を「その他」に入れっぱなしにはしません。件数の多いものから定期的に分類し直します。

    Paymasterを使う場合は、予算の上限、補助方針による拒否、提供元の障害を分けます。そのうえで、利用開始の質とガス代補助の費用を同時に追います。補助の上限をどう段階的に設け、使い切ったときにどう止めて再開するかはPaymasterの不正利用・ガス枯渇対策で扱っています。

    ダッシュボードに何を並べるか

    各段階の転換率だけでは、見落とすものがあります。時間はかかったが成功した処理や、再試行でやっと成功した処理です。そこで転換率に、時間・品質・費用を並べます。

    • 転換率:開始→認証→ウォレット準備→受付→取り込み→利用開始の、試行単位の転換率
    • 所要時間:各区間と全体のp50/p95/p99(半分・95%・99%が収まる時間)、受付から取り込みまでのブロック数
    • 信頼性:失敗の種類ごとの失敗率、再試行後の成功率、処理中のまま期限を超えた件数、記録の欠落率
    • 費用:利用開始ユーザー1人あたりの補助したガス代、Bundler・APIの費用、失敗したUserOperationを含む費用
    • 整合性:対応する試行がないイベント、重複イベント、受領記録との食い違い、チェーン再編後の補正件数

    数字は、次の切り口で分けて見られるようにします。

    • 導線の版(flow version)、アプリの版
    • OS・ブラウザー、認証方式
    • チェーン、ウォレット実装、Bundler、Paymasterの補助方針

    ただし、人数の少ない区分から個人を推定できないよう、表示は制限します。

    改善の実験をする間は、同じ導線の版の中でイベントの定義を変えません。段階を足したり削ったりするときは、イベントの形式(schema)と導線の版を更新します。旧版と新版の数字は混ぜません。

    成功率が上がっても、補助の費用や不正利用が急に増えることがあります。悪くしてはいけない指標(ガードレール指標)も、同じ期間で確かめます。

    ここで集めた転換率・費用・問い合わせの数字を、A/Bテストや総保有コストにどうつなげるか。採用・限定採用・不採用をどう決めるか。それはAAの導入効果の測り方で扱っています。

    本番の前に、わざと欠落・重複・遅延を起こして試す

    「分析画面にイベントが出た」では合格になりません。わざと障害を起こして、数字が正しく残るかを確かめます。

    1. ログイン前の離脱、署名の拒否、タブを閉じる操作を起こす。次のイベントが来ないことが、利用者側の理由として正しく区別されるか確認する。
    2. アプリ側のイベントを二重に送り、アプリ側のイベントIDで一度だけ保存されるか確認する。
    3. Bundlerのシミュレーション拒否、Paymasterの回数上限超え、nonceの競合を起こし、決まった失敗の種類に振り分けられるか確認する。
    4. 受領記録の取得を遅らせたり止めたりする。受付済みを成功扱いせず、処理中のまま照会し直せるか確認する。
    5. 同じ操作を差し替えて送り、複数のハッシュが1つの試行と利用開始にまとまるか確認する。
    6. チェーン上の成功の後で業務処理を失敗させ、埋め合わせの処理と監査ログから元に戻せるか確認する。
    7. Indexerを止めてから戻す。ブロック範囲を読み直しても二重に数えず、チェーン再編のときに集計を直せるか確認する。

    合格の条件は3つです。試験用の試行について、各所のログとチェーン上の受領記録から同じ状態を組み立て直せること。欠落と重複の件数を説明できること。障害の後に、安全に追いつけることです。

    採用の前に決めておくこと

    • オンボーディングの開始と、最初の業務価値到達を文章で定義した
    • 試行ID、イベントID、内部ユーザーID、ウォレットアドレス、userOpHashの用途と保存先を分けた
    • イベントごとに、発行する主体、時刻、形式の版、重複の除き方を決めた
    • 受付、取り込み、実行の成功、業務の成功を別の状態にした
    • 利用者の拒否、技術的な失敗、時間切れ、記録の欠落を区別し、担当と利用者への見せ方を決めた
    • 個人情報をブロックチェーンへ置かず、分析データの同意・保持期間・アクセス権を確認した

    この6つを決めずに計測SDKだけを入れると、数字は表示できても、どこを直せばよいか判断できません。

    全イベントをチェーン上に書き込むと、費用がかさみ、中身が公開され、消すのも難しくなります。しかも署名の前にやめた人は、チェーンからは見えません。ですから、この作りを選ぶ理由はありません。

    開発チームが決める実装の詳細

    ここからは、さきほどのアプリで計測を実装する開発チームの話です。イベントの名前と形式、誰がどのイベントを出すか、状態とエラーコードを見ていきます。

    段階ごとのイベントと完了条件

    前半の7段階を、イベント名と完了条件に置き換えると次のとおりです。

    段階成功イベント完了条件主な離脱・失敗
    開始onboarding_started導線を表示しただけでなく、利用者が開始操作をした価値説明不足、対象外端末
    本人認証auth_succeededメール、OAuth、パスキー等の選択方式でセッションが成立したキャンセル、ワンタイムパスワード(OTP)の期限切れ、WebAuthnエラー
    アカウント準備wallet_ready利用予定チェーンのアドレスと署名能力をアプリが確認したSDK、ネットワーク、counterfactual address(デプロイ前に事前計算したアドレス)の不一致
    操作承認signature_approved対象操作の内容を表示し、ユーザー署名を得た拒否、画面閉鎖、署名対象の不一致
    送信受付userop_acceptedBundlerがeth_sendUserOperationを受理し、userOpHashを返したシミュレーション、Paymaster、nonce、署名のエラー
    オンチェーン実行userop_included受領記録(receipt)を取得し、対象UserOperationのsuccessを確認した未包含、期限切れ、実行時のリバート
    価値到達activation_completed注文成立、mint完了等、プロダクト固有の業務結果が確定したオンチェーン成功後の業務連携失敗

    Bundlerは、複数の操作をEntryPoint(UserOperationを実行する共通コントラクト)のhandleOpsへまとめて送ります。

    イベントの形式

    主キーは onboarding_attempt_id(試行ID)です。同じ試行内のSDKによる再送は、同じ idempotency_key(同じ要求を1回分として扱うための識別子)で重複を除きます。

    {
      "event_name": "userop_accepted",
      "event_version": 1,
      "occurred_at": "2026-08-12T12:34:56.789Z",
      "onboarding_attempt_id": "01J...",
      "anonymous_id": "browser-scoped-id",
      "internal_user_id": "opaque-user-id",
      "chain_id": 8453,
      "wallet_address": "0x...",
      "user_op_hash": "0x...",
      "flow_version": "smart-wallet-v3",
      "provider": "configured-provider",
      "result": "accepted",
      "error_class": null
    }

    どのイベントを、誰が出すか

    すべてをフロントエンドから送ると、タブを閉じたり通信が切れたりしたときに成功イベントが抜けます。好きなイベントを偽造されるおそれもあります。反対にブロックチェーンだけでは、署名前の離脱や画面上のエラーが見えません。そこで、その事実を最も確実に見られる所がイベントを出します。

    主体記録する事実信頼上の限界結合キー
    アプリ側(画面)開始、画面表示、方式選択、署名画面での承認・キャンセル送信欠落・改ざんがあり、確定事実には使わない試行ID、アプリ側のイベントID
    認証バックエンドchallenge発行、認証成功、セッション成立ウォレット操作の確定までは分からない試行ID、内部ユーザーID
    Bundler / Paymaster受付、シミュレーション結果、補助の可否判定、再送受付はオンチェーン確定を保証しない試行ID、userOpHash
    Indexer / 受領記録の取得処理包含ブロック、成否、ガス、リバート、ファイナリティの観測チェーン再編を考慮し、観測時点を持つチェーンID、EntryPoint、userOpHash
    業務バックエンド注文、mint、権限付与等の業務成果オンチェーン成功と業務成功を混同しない試行ID、業務ID、userOpHash

    ファイナリティは、取引が覆らないと見なせる確定のことです。チェーン再編は、直近のブロックが組み替わり、いったん取り込まれた取引の位置が変わることです。

    受領記録とエラーコード

    RPCメソッドのeth_getUserOperationReceiptは、次の項目を返します。userOpHash、entryPoint、sender、nonce、paymaster、実際のガス代(actualGasCost)、success、関連する取引の受領記録などです。

    送信時のエラーには、原因を見分けるコードが定義されています。

    • ウォレット署名の検証失敗:-32507
    • EntryPointの検証で拒否(アカウント作成の失敗を含む):-32500
    • Paymasterに起因する拒否:-32501〜-32505

    これらを定めるERC-7769は、2026年9月24日時点でDraft(草案)の段階です(ERC-7769: JSON-RPC API for ERC-4337)。ベンダーSDK独自の状態値だけに頼らず、この項目にそろえて保存します。そうすれば、提供元を切り替えた後も時系列を比べられます。

    エラー本文を、そのまま分析の属性にはしません。標準のAAエラーコード、提供元独自のコード、自社の安定したerror_classを、別々の項目にします。未知のエラーをOTHERへずっとまとめ続けることもしません。

    状態の遷移

    試行は、単調に増える番号ではなく、状態の遷移として保存します。

    STARTED → AUTHENTICATED → WALLET_READY → SIGNED → ACCEPTED → INCLUDED → ACTIVATED

    各状態 → USER_CANCELED | RETRYABLE_FAILURE → 同じ試行で再試行 | TERMINAL_FAILURE → 手動対応

    受付済みでも後の段階で失敗しうるため、accepted_at、included_at、finalized_atを分けます(ERC-4337: Bundler behavior)。運用の指標には、受付数、検証失敗の分類、受付から取り込みまでの遅延、EntryPointでの実行の成否を含めます(ERC-4337 Documentation: Monitoring and Metrics)。

    失敗分類のコード名

    前半の8つの失敗の種類は、次のコード名でerror_classに入れます。

    分類失敗の種類
    USER_CANCEL利用者の取りやめ
    AUTH_FAILURE認証の失敗
    CLIENT_FAILUREアプリ側の失敗
    VALIDATION_FAILURE検証での拒否
    SPONSOR_FAILUREガス代補助の拒否
    INCLUSION_TIMEOUT取り込みの時間切れ
    EXECUTION_REVERT実行時の取り消し
    BUSINESS_FAILURE業務処理の失敗

    導入効果を測るなら、同じ試行に足す項目

    このファネルをAAの投資判断(A/Bテストや総保有コストの比較)に使う場合もあります。そのときは上のイベントに次の項目を足しておきます。後から実験群・費用・問い合わせを突き合わせられます。

    イベント必須属性成功条件主な診断用途
    aa_eligibleコホート、チェーン、端末、流入経路、実験群、experiment_id実験対象へ割当済み分母の確定、実験群の割当比率の想定外の偏り(sample ratio mismatch)の検知
    intent_created操作種別、金額帯、必要な呼び出し、intent_id業務上の意図を一意に採番再試行を同じ操作意図へ集約
    sponsorship_decidedガス代補助の方針の版、承認・拒否、理由、推定ガス判断理由を保存補助対象・拒否・予算消化
    userop_finalizedトランザクションハッシュ、ブロック、成否、実ガス、補助コスト定義したファイナリティへ到達成功率、実費、実行失敗の原因
    support_case_linked試行IDまたは操作意図ID、分類、対応時間、解決結果問い合わせ対応終了サポートコストと技術失敗の対応

    関連して読む

    XTELAができること

    私たちは、現行オンボーディングの状態整理から、スマートウォレット・Bundler・Paymasterの責任分界、イベント形式、Indexer、ダッシュボード、障害注入試験までを設計し、PoCと実装を一緒に進めます。試行IDで画面操作とオンチェーンの結果を結ぶところから始めれば、貴社のどの段階で人が止まっているかを実データで示せます。導入効果と運用費を自社データで確かめたい場合は、お問い合わせください。

    主要参考資料

    資料の確認日と注意

    仕様は2026年8月12日時点の公開資料にもとづいています。ERC-7769とAlchemyの記述は、2026年9月24日に確認し直しました。ここで述べたのは公開仕様にもとづく技術設計の整理です。特定の方式によるKPIの改善を保証するものではなく、個人情報保護に関する法的な判断も含みません。実装時は、採用するバージョンの公式資料を確認してください。

    お問い合わせ

    どんなフェーズからでも、お持ちのアイデアや企画をもとにご提案可能です。
    まずはお気軽にご相談下さい!