Hybrid swap gas: benchmark and tune dApp constants under warm bot load (#248 follow-up) #252
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#252
Loading…
Add table
Add a link
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?
Summary
After contract-side CW20 aggregation lands (#248,
main@4f26d11), run a LocalTerra gas benchmark campaign and recalibrate dApp (and swarm) gas constants so retail swaps never hitout of gas— including when the DEX is actively traded by the localnet bot swarm (“bots warm”: resting book depth, concurrent swaps, indexer/tape moving).This issue is the measurement + floor-tuning track. Quote-driven dynamic limits are tracked separately in #249; both must share the same calibrated baselines.
Current codebase
frontend-dapp/src/utils/constants.tsSWAP_GAS_PER_HOP(600k),SWAP_GAS_BUFFER(1.3),EXECUTE_SWAP_OPS_MIN_GAS_PER_HOP(661k), padding / safety marginfrontend-dapp/src/services/terraclassic/terraGas.tsHYBRID_SWAP_GAS_LIMIT(1.2M/hop),gasLimitForExecuteSwapOperations,getGasLimitForTxpackages/localnet-trading-swarm/src/gas.tsfrontend-dapp/src/services/terraclassic/__tests__/transactions.test.tsFee.gasLimitscripts/bots/launch-swarm.sh/make swarm-localskills/AGENTS_TERRACLASSIC_GAS.mdskills/AGENTS_LOCALNET_TRADING_SWARM.mdToday: Hybrid execute gas dropped on-chain post-#248, but the dApp still budgets flat 1.2M/hop hybrid floor and conservative pool hop math from pre-aggregation measurements (#115). Users overpay LUNC (unused gas not refunded on Classic), while under-tuning risks OOG when the book is deep or chain is hot.
Why this is needed
gas_usedabove shallow-book measurements taken on a cold chain.Constraints / guardrails
gas_used≤gas_wantedwith margin: keepSWAP_GAS_SAFETY_MARGIN+ buffer ≥ observed peak under warm load (document p50 / p95 / max).transactions.test.tswith measured values, do not delete tests.SWAP_GAS_BUFFER, hybrid base, or per-hop floors must touch dApp +localnet-trading-swarmin one PR.Recommended solution direction
make swarm-local/launch-swarm.sh, then samplegas_usedfrom:Record block height, maker count, and whether swarm was active.
HYBRID_BASE, optionalHYBRID_PER_MAKER, updateHYBRID_SWAP_GAS_LIMITand/orEXECUTE_SWAP_OPS_MIN_GAS_PER_HOPonly where benchmarks show headroom; add warm-load peak + safety margin.transactions.test.ts,docs/frontend.md§ Terra Classic gas limits,docs/limit-orders.md, crosslink L10 / #248 inskills/AGENTS_TERRACLASSIC_GAS.md.make verify-issue-248-gasscript mirroringverify-issue-238pattern for repeatable LCD tx gas assertions.Acceptance criteria
gas_usedand proposedgas_limit.terraGas.tsupdated; swarmgas.tsmatches.npm test—transactions.test.ts/terraGastests reflect new floors./tradeand Swap page succeeds with warm swarm running; noout of gas.MAX_MAKER_FILLS_HARD_CAP).Test plan — functional paths
gas_usedlogged.gas_used≤ new limit.Test plan — attack / abuse vectors
max_maker_fillsbuffer (see #249) or conservative floor prevents truncation/OOG.Verification criteria
@qa-agent-teamruns checklist on LocalTerra withmake swarm-localactive.Related
marked as related to #248
marked as related to #249
mentioned in issue #248
mentioned in commit
0be09de77cmentioned in issue #249
Follow-up from #249 (merged
main@d587048)#249 landed quote-driven hybrid gas and single-hop direct-to-pair routing. The formula constants are calibrated to issue targets, not yet field-measured on LocalTerra under warm swarm load:
HYBRID_SWAP_BASE_GASfrontend-dapp/src/utils/constants.tsHYBRID_SWAP_PER_MAKER_GASHYBRID_SWAP_MAKER_GAS_BUFFERHYBRID_SWAP_GAS_FLOORhybridSwapGas.tsThis issue (#252) should record measured
gas_usedvsgas_wantedfor representative swaps (M = 0, 1, 2, 3, 5 maker fills; pool-only vs split book+pool) with bots warm (make swarm-local/launch-swarm.sh), then adjust the table above + keeppackages/localnet-trading-swarm/src/gas.tsin lockstep.Suggested doc sink after benchmark:
docs/limit-orders.md§ Execution order (hybrid gas paragraph added in #249) andskills/AGENTS_TERRACLASSIC_GAS.md.Regression: update shallow-book cases in
transactions.test.tsonly when new floors are proven above warm-loadgas_usedpeaks — do not delete #115 floors without evidence.Cross-link: #249 implementation note.
mentioned in issue #250
Follow-up from #250 — expired park cap (merged
main@ff7a680)Contract-side hybrid match walks now cap
park_expired_limit_order_for_claimatMAX_EXPIRED_PARKS_PER_SWAP = 5permatch_bids/match_asksinvocation; additional expired head orders are skipped without storage writes. This bounds taker gas griefing when many expired limits stack at best prices.Add to warm-load benchmark matrix (#252)
Please include a 10-expired-head scenario when sampling
gas_usedunder swarm load:limit_order_expired_parkedevents + 5 skipped; swap attrsexpired_parks_used=5,expired_parks_capped=true,expired_parks_skipped=5gas_usedvs shallow 1-maker hybridGoal: confirm post-#250
gas_usedfor the 10-expired-head case is ≤ 5 × (park cost) + walk/skip reads + any fill cost, and decide whetherHYBRID_SWAP_*/ per-maker constants inconstants.tsneed a separate expired-park component or if the existing hybrid base + per-maker floor already covers capped parks.Baseline comparison (optional): if a pre-#250 wasm artifact is still available locally, one cold measurement of uncapped 10-park walk would quantify savings; not blocking if only post-cap wasm is deployed.
Docs / invariants already updated (#250)
docs/limit-orders.md§ Expiry — cap + skip semanticsdocs/contracts-security-audit.mdskills/AGENTS_TERRACLASSIC_GAS.mdcross-linkQA note
When running the #252 warm matrix, verify hybrid swaps still succeed with warm swarm + stacked expired head (not just M=1/3/5 live makers). Skipped expired orders may remain visible on indexer/LCD book APIs until a later park — expected; not a gas regression signal.
/cc @qa-agent-team — fold the rows above into the #252 acceptance checklist when benchmarking.
mentioned in issue #251
mentioned in issue #254
mentioned in issue #260
marked as related to #260
mentioned in issue #255
Ran the absolute gas profile on the current build (
6b22feb), live on-chain against LocalTerra. Taker sells T0 into resting maker bids on the EMBER/CORAL dual-CW20 pair; gas_used is the executed-tx value, fills verified per scenario (M=1→1, M=3→3, M=5→5, expiry park confirmed with a refund row).Verdict: practical, no redesign needed. Top number is the cold M=1 at ~626k gas — well within block limits.
On fees: the chain's fee check required 20,989,137 uluna (~21 LUNC) for that cold M=1 in my run — that's the observed required amount straight from the ante (code=13 insufficient-fee), not a derived rate, and it's trivial at current LUNC. I'm deliberately not quoting a uluna/gas price: the fee tracks gas_wanted (the simulated limit), not the 626k gas_used, and it ran roughly flat near 21M uluna across scenarios — so don't back-derive a per-gas rate from gas_used. Reconcile against the node's min-gas-price config for the exact figure.
Scaling is linear and cheap:
Cold/warm: the first hybrid swap in each ~5-min window costs ~145k more (625,896 vs 481,066). That's #251's CL8Y fee-discount cache (300s TTL) populating on the first fee-bearing op — a cross-contract registry query + a storage write that warm ops within the window skip. Source-confirmed; details on #251.
On the ">=30% reduction" acceptance criterion — being straight: I can't demonstrate it. There's no clean pre-wave (
ff7a680) baseline, and the one data point we do have (~615k for an M=1 cross) is essentially the current cold M=1 (~626k), so the simple single-swap case did not drop ~30%. The real win this wave delivers isn't a simple-case reduction — it's bounded worst-case gas (#254) plus cheap linear scaling, and #251 shaving ~145k off repeat swaps by the same trader inside the 5-min window.@PlasticDigits — how do you want to handle the criterion? Either accept this reframing (bounded worst case + linear scaling + #251 warm-path win, in place of a flat % on the simple case), or I run a proper
ff7a680baseline with the same cold/warm split so we can state a real apples-to-apples %.Layer: live on-chain on
6b22febon the current LocalTerra. If your LocalTerra update lands these absolute numbers shift — the rig is parametrized so I can re-run in one command. Needs your call on the criterion before this is closed.Dropping the arbitrary >=30% reduction criteria
At current terraclassic gas fee rates, 100k gas is 2.835 LUNC, about $0.000242 at todays prices. Gas fee rates below $0.1 are acceptable, at these prices that is ~400m gas. From above table marginal on placing limit orders is 22.5k and marginal on takes is 19k, acceptable - however griefing the orderbook is still theoretically possible by an agent willing to spend enough funds to do so due to the gas cap - not gas costs. The gas cap would be reached with 15k makers + orders, however our onchain limits would hit before then increasing the slippage.
(1) We need to raise limits for the loops, given the low additional gas cost of processing additional orders, we should raise the limit to 1k orders for takers and 100 for makers.
(2) We need to add a "sweep" method that expires orders under a governance set size (ideally less than $0.01 but should be configurable per pair in either side of the token). It should both expire and clean expired orders. By default if the sweep is set to 0 tokens for both side (default) should only clean book of expired orders, up to X at a time per call to avoid the 30M gas cap.
(3) We need review permissionlessly sweeping expired orders out of the book. The gas costs are likely minimal. An onchain method for now should be sufficient, but could be useful in the future to have a watcher that sweeps expired orders. This should be documentation only as long as the method already exists, for a future update.
Once issues for 1,2,3 are created this issue can be clsoed
mentioned in issue #262
mentioned in issue #256
mentioned in issue #257
#252 — the close condition is met; good to close.
Recap of where this landed:
6b22feb): hybrid M=1/3/5 + pool-only + place/batch + cancel single/batch + claim, with the cold->warm #251 cache delta (~145k on the first fee-bearing op per 5-min window), ~19.2k gas per extra maker fill (dead linear), and worst case bounded by #254's scan cap. Conclusion at the time: practical, no redesign needed.So the measurement track is complete, the criterion is settled, and the three follow-up issues are created and closed. Note that the offline gas LIMITS were subsequently raised for safety by #260/#262 (book-leg sizes for the 500-step worst case) — the measured gas_USED numbers above still inform the floors; #249/#260 verified those separately. Good to close. @PlasticDigits