一行説明
初回送金(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 の反映タイミングの競合が原因だった。
発生の流れ
useDistributionTransfer.executeTransfer が approve を送信し、publicClient.waitForTransactionReceipt でレシートを待つ(Approval は block 50296569 で確定済み)
- 直後に
transferWithDistribution を送信。MetaMask など外部ウォレットはウォレット自身の RPC(Infura)でガス見積もりを行う
- その Infura ノードにまだ approve が反映されておらず、allowance 不足で
eth_estimateGas が revert
- MetaMask が見積もり失敗時のフォールバック値(ブロックガスリミット 400M × 0.35 = 140,000,000)を gas limit に設定
- Base の per-tx ガス上限 25M を超えるため Infura が送信を拒否
エラーが「transferWithDistribution reverted」と表示されるのは viem の表現で、実際に revert したのは見積もり呼び出し。同じ送金を allowance 確保後に再実行すると成功する(実際の必要ガスは 94,829)。
レシート確認にアプリ側の RPC(publicClient)を使い、送信・見積もりにウォレット側の RPC を使っているため、両者のノード間に反映ラグがあると必ず起こりうる。初回送金=approve が必要なケースでのみ発生するため、新規ユーザーが最初の送金で必ず踏む可能性がある。
要件
補足
5秒待機について
固定待機はノードの反映ラグが 5 秒を超えた場合に取りこぼす一方、通常時は待たなくてよい 5 秒を必ず待つことになる。より確実な代替として、allowance が必要額に達するまでポーリングする(上限つき)方法も検討の余地がある。まずは 5 秒待機で実装し、再発するようならポーリングに切り替える方針とする。
代替アプローチ(不採用)
EOA の場合にアプリ側 RPC で見積もったガスを writeContract に明示的に渡す案も検討したが、同じ問題への別アプローチであり二重に入れる必要がないため見送った。待機の追加で解決しない場合の選択肢として残しておく。
参考
- 該当コード:
packages/frontend/app/hooks/useDistributionTransfer.ts
- MetaMask のフォールバック: ブロックガスリミット × 0.35
- Base の per-tx ガス上限: 25,000,000
一行説明
初回送金(approve が必要なケース)で、approve がウォレット側 RPC に反映される前に
transferWithDistributionのガス見積もりが走り、送金が失敗する。詳細
Base 本番で初回送金を行った際、以下のエラーで送金が失敗した。
調査の結果、コントラクト側の問題ではなく、approve の反映タイミングの競合が原因だった。
発生の流れ
useDistributionTransfer.executeTransferがapproveを送信し、publicClient.waitForTransactionReceiptでレシートを待つ(Approval は block 50296569 で確定済み)transferWithDistributionを送信。MetaMask など外部ウォレットはウォレット自身の RPC(Infura)でガス見積もりを行うeth_estimateGasが revertエラーが「
transferWithDistributionreverted」と表示されるのは viem の表現で、実際に revert したのは見積もり呼び出し。同じ送金を allowance 確保後に再実行すると成功する(実際の必要ガスは 94,829)。レシート確認にアプリ側の RPC(
publicClient)を使い、送信・見積もりにウォレット側の RPC を使っているため、両者のノード間に反映ラグがあると必ず起こりうる。初回送金=approve が必要なケースでのみ発生するため、新規ユーザーが最初の送金で必ず踏む可能性がある。要件
approveのレシート確認後、transferWithDistributionを実行するまでに 5 秒の待機を挟む補足
5秒待機について
固定待機はノードの反映ラグが 5 秒を超えた場合に取りこぼす一方、通常時は待たなくてよい 5 秒を必ず待つことになる。より確実な代替として、
allowanceが必要額に達するまでポーリングする(上限つき)方法も検討の余地がある。まずは 5 秒待機で実装し、再発するようならポーリングに切り替える方針とする。代替アプローチ(不採用)
EOA の場合にアプリ側 RPC で見積もったガスを
writeContractに明示的に渡す案も検討したが、同じ問題への別アプローチであり二重に入れる必要がないため見送った。待機の追加で解決しない場合の選択肢として残しておく。参考
packages/frontend/app/hooks/useDistributionTransfer.ts