Frontend: thread estimateGas + 30% buffer through every wagmi writeContractAsync call site #176
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#176
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: P2 — defense-in-depth across all wagmi write paths
split out of #160 follow-up per @PlasticDigits — "We should estimate gas as some wallets do not correctly estimate gas, and this also allows us to add a gas buffer of 30% in case the contract state changes and consumes more gas than expected".
current state at HEAD
284c15c5 files contain wagmi write paths via
writeContractAsync:existing infrastructure (partially in place)
frontend/src/lib/estimateContractGas.tsexposesestimateGasUnits(...)— wraps viemestimateContractGas, returnsbigint | undefinedon best-effort basis. does not apply any buffer. used at 6 call sites inuseTimeCurveArenaModel.tsxfor display-only preflight (state varssetGasBuy,setGasWarbowSteal, etc.) — the estimated value is never passed towriteContractAsync.frontend/src/lib/simulateContractWrite.tsexposessimulateWriteContract(...)— wraps viemsimulateContract, used in Arena flow for revert-detection preflight.so:
writeContractAsync({ ..., gas })parameterwhat dev asked for
fix shape
option A — extend the existing helper
add
estimateGasWithBuffer(params, bufferPct = 30)tolib/estimateContractGas.ts:then thread the result into
writeContractAsync({ ..., gas: bufferedGas })at every write site that does not already pass an explicitgas. fallback: if the helper returnsundefined, omit thegasfield — wagmi falls back to wallet-provided estimation, same as today. no behavior regression on the happy-path RPC.option B — new wrapper helper
a wrapper
submitWithBufferedGas(writeContractAsync, params, bufferPct = 30)that internalizes the estimate + buffer + writeContractAsync call, with consistent error UX viafriendlyRevertFromUnknown. less code at call sites; more upfront migration cost across 39 call sites.where to apply
all 5 files listed above. priority order based on user-facing risk:
useTimeCurveArenaModel.tsx— buy paths, WarBow paths (path-dependent gas, dynamic args)TimeCurveProtocolWarbowRefreshSection.tsx— refreshWarbowPodium withaddress[](extreme state-dependence — see #172)useTimeCurveSaleSession.ts— multi-step approval + buy flowstimeCurveKumbayaSingleTx.ts— single-tx buy via Kumbaya routerReferralRegisterSection.tsx— referral registration (lowest risk, simple state mutation)interaction with #172
#172 is the CRITICAL gas-blowup design ticket on
refreshWarbowPodium/finalizeWarbowPodium. that ticket changes the architecture; this ticket protects every other write path today. they are independent — landing this does not close #172 (estimateGas + buffer cannot enable a 50B-gas tx; it just refuses to submit one that would fail).on
refreshWarbowPodiumspecifically, this ticket adds the soft-cap defense layer that #172 acceptance criterion 2 calls for ("single-tx submit path retired or soft-capped to protect callers from sending >5k candidates accidentally").acceptance criteria
bufferPctdefaulting to 30writeContractAsync({ ..., gas: ... })gas, let wagmi default)npm run typecheck+npm testcleanorigin
split from #160 follow-up per @PlasticDigits direct request. complementary to #172 (CRITICAL gas-blowup design), #173 (cosmetic double-call), #174 (silent truncation), #175 (Vitest coverage gap).
cc @PlasticDigits
mentioned in issue #160
mentioned in merge request !378
mentioned in commit
8eb5f34cfb