Skip to content

初回送金時に approve 反映前の見積もりで送金が失敗する #170

Description

@yu23ki14

一行説明

初回送金(approve が必要なケース)で、approve がウォレット側 RPC に反映される前に transferWithDistribution のガス見積もりが走り、送金が失敗する。

詳細

Base 本番で初回送金を行った際、以下のエラーで送金が失敗した。

The contract function "transferWithDistribution" reverted with the following reason:
RPC 0x2105 Infura eth_sendRawTransaction: exceeds maximum per-tx gas limit: 140000000 > 25000000

Contract Call:
  address:   0xD34318dD4BE709E3017ACd2138d321D5b962cEbb
  function:  transferWithDistribution(address from, address recipient, uint256 amount, string message)
  sender:    0x86036f29855181C4d72a67428f6cdFAdE157381b

調査の結果、コントラクト側の問題ではなく、approve の反映タイミングの競合が原因だった。

発生の流れ

  1. useDistributionTransfer.executeTransferapprove を送信し、publicClient.waitForTransactionReceipt でレシートを待つ(Approval は block 50296569 で確定済み)
  2. 直後に transferWithDistribution を送信。MetaMask など外部ウォレットはウォレット自身の RPC(Infura)でガス見積もりを行う
  3. その Infura ノードにまだ approve が反映されておらず、allowance 不足で eth_estimateGas が revert
  4. MetaMask が見積もり失敗時のフォールバック値(ブロックガスリミット 400M × 0.35 = 140,000,000)を gas limit に設定
  5. Base の per-tx ガス上限 25M を超えるため Infura が送信を拒否

エラーが「transferWithDistribution reverted」と表示されるのは viem の表現で、実際に revert したのは見積もり呼び出し。同じ送金を allowance 確保後に再実行すると成功する(実際の必要ガスは 94,829)。

レシート確認にアプリ側の RPC(publicClient)を使い、送信・見積もりにウォレット側の RPC を使っているため、両者のノード間に反映ラグがあると必ず起こりうる。初回送金=approve が必要なケースでのみ発生するため、新規ユーザーが最初の送金で必ず踏む可能性がある。

要件

  • approve のレシート確認後、transferWithDistribution を実行するまでに 5 秒の待機を挟む
  • 待機中であることがユーザーに分かる UI 表示にする(無反応に見えないようにする)
  • approve が不要なケース(allowance が十分な場合)では待機を挟まない
  • 初回送金(allowance 0 の状態)で送金が成功することを実機で確認する

補足

5秒待機について

固定待機はノードの反映ラグが 5 秒を超えた場合に取りこぼす一方、通常時は待たなくてよい 5 秒を必ず待つことになる。より確実な代替として、allowance が必要額に達するまでポーリングする(上限つき)方法も検討の余地がある。まずは 5 秒待機で実装し、再発するようならポーリングに切り替える方針とする。

代替アプローチ(不採用)

EOA の場合にアプリ側 RPC で見積もったガスを writeContract に明示的に渡す案も検討したが、同じ問題への別アプローチであり二重に入れる必要がないため見送った。待機の追加で解決しない場合の選択肢として残しておく。

参考

  • 該当コード: packages/frontend/app/hooks/useDistributionTransfer.ts
  • MetaMask のフォールバック: ブロックガスリミット × 0.35
  • Base の per-tx ガス上限: 25,000,000

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfrontendFrontend development

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions