LAUNCH-BLOCKER: Swap transactions fail with 'out of gas' — gas estimate too low for wasm contract execution #115

Closed
opened 2026-04-24 07:34:59 +00:00 by Brouie · 21 comments
Brouie commented 2026-04-24 07:34:59 +00:00 (Migrated from gitlab.com)

Found during #114 Visual UX verification (Section B — pool-only swap happy path) on fresh LocalTerra stack + latest main.

Repro

  1. Fresh DEX stack (docker compose up + deploy-dex-local.sh + indexer)
  2. Frontend: cd frontend-dapp && npm run dev
  3. Connect Station wallet (terra1...20k38v)
  4. Navigate to Swap. Default pair EMBER → CORAL.
  5. Enter 10 EMBER as YOU PAY amount
  6. Quote resolves cleanly: YOU RECEIVE 9.616 CORAL, price impact 0.00%, min received 9.568
  7. Slippage set to 1% (standard)
  8. Click SWAP button
  9. Station signing succeeds, transaction broadcast

Observed

Transaction fails on-chain with:

Transaction failed: out of gas in location: wasm contract;
gasWanted: 710000, gasUsed: 753321;
out of gas

Overshoot: ~43,000 gas units beyond estimate.

Why launch-blocker

Every pool swap will fail with this pattern — gas estimator is consistently under-provisioning by ~6% vs actual consumption for a simple pool-only swap. This is:

  • Not recoverable by user (no way to manually override gas from the frontend UI that I saw)
  • Reproducible on happy-path swap (no edge case, no hybrid complexity, no multi-hop)
  • Block on DEX mainnet launch: users lose gas fees on every attempted swap

Proposed fix scope

  • Increase gas estimation buffer / multiplier in swap submission code
  • Standard pattern: estimate → multiply by 1.3 or 1.5 → submit
  • Or: expose gas-override in Settings for power users (defer if added later)
  • OR check if the 710k is a hardcoded fallback that needs to be ~1M

Screenshots

Happy path quote (pre-submit) and failure toast attached via web UI.

cc @PlasticDigits urgent — blocks DEX launch

Found during #114 Visual UX verification (Section B — pool-only swap happy path) on fresh LocalTerra stack + latest main. ## Repro 1. Fresh DEX stack (docker compose up + deploy-dex-local.sh + indexer) 2. Frontend: `cd frontend-dapp && npm run dev` 3. Connect Station wallet (terra1...20k38v) 4. Navigate to Swap. Default pair EMBER → CORAL. 5. Enter 10 EMBER as YOU PAY amount 6. Quote resolves cleanly: YOU RECEIVE 9.616 CORAL, price impact 0.00%, min received 9.568 7. Slippage set to 1% (standard) 8. Click SWAP button 9. Station signing succeeds, transaction broadcast ## Observed Transaction fails on-chain with: ``` Transaction failed: out of gas in location: wasm contract; gasWanted: 710000, gasUsed: 753321; out of gas ``` Overshoot: ~43,000 gas units beyond estimate. ## Why launch-blocker Every pool swap will fail with this pattern — gas estimator is consistently under-provisioning by ~6% vs actual consumption for a simple pool-only swap. This is: - Not recoverable by user (no way to manually override gas from the frontend UI that I saw) - Reproducible on happy-path swap (no edge case, no hybrid complexity, no multi-hop) - Block on DEX mainnet launch: users lose gas fees on every attempted swap ## Proposed fix scope - Increase gas estimation buffer / multiplier in swap submission code - Standard pattern: estimate → multiply by 1.3 or 1.5 → submit - Or: expose gas-override in Settings for power users (defer if added later) - OR check if the 710k is a hardcoded fallback that needs to be ~1M ## Screenshots Happy path quote (pre-submit) and failure toast attached via web UI. cc @PlasticDigits urgent — blocks DEX launch
Brouie commented 2026-04-24 07:36:37 +00:00 (Migrated from gitlab.com)

image.png{width=711 height=600}

image.png{width=505 height=600}

![image.png](/uploads/4b7244b691ee13e5a9c26e1d257cff9d/image.png){width=711 height=600} ![image.png](/uploads/62fb577c04825c15969011f88106968a/image.png){width=505 height=600}
Brouie commented 2026-04-24 07:47:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #114

mentioned in issue #114
PlasticDigits commented 2026-04-24 12:23:47 +00:00 (Migrated from gitlab.com)

@brouie Could you re-verify on LocalTerra + Station when you have a moment?

What changed

  • Root cause: Pool-only router txs use `execute_swap_operations`; we set an explicit `Fee.gas` from `SWAP_GAS_PER_HOP × hops × SWAP_GAS_BUFFER` + per-hop padding (see `gasLimitForExecuteSwapOperations` in `frontend-dapp/src/services/terraclassic/transactions.ts`). At `SWAP_GAS_BUFFER = 1.1`, single-hop `gasWanted` was 710,000 — below your observed 753,321 `gasUsed` (glab#115).
  • Fix (merged to `main`, commit `ac9338e`): Raised `SWAP_GAS_BUFFER` from 1.1 → 1.2 in `frontend-dapp/src/utils/constants.ts`, so single-hop pool-only `gasWanted` is 770,000 (still below hybrid floors where applicable).
  • Docs: Invariants + formula in docs/frontend.md § Terra Classic gas limits; agent playbook skills/AGENTS_TERRACLASSIC_GAS.md; index links in `docs/README.md`.
  • Tests: `transactions.test.ts` updated + regression `gasLimit > 753321` for single-hop `execute_swap_operations`.

Verification checklist

  • Fresh stack: `docker compose up`, `deploy-dex-local.sh`, indexer as in #114.
  • `cd frontend-dapp && npm run dev`, connect Station, Swap default pair (EMBER → CORAL), amount 10 EMBER, 1% slippage.
  • Submit swap; tx succeeds (no `out of gas` in Station / block explorer).
  • Optional: note `gas_wanted` vs `gas_used` on success (wanted should remain comfortably above used).
  • Spot-check a 2-hop pool-only route if available (buffer change scales hop count).

Issue left open until you confirm. Thanks!

@brouie Could you re-verify on LocalTerra + Station when you have a moment? ## What changed - **Root cause:** Pool-only router txs use \`execute_swap_operations\`; we set an explicit \`Fee.gas\` from \`SWAP_GAS_PER_HOP × hops × SWAP_GAS_BUFFER\` + per-hop padding (see \`gasLimitForExecuteSwapOperations\` in \`frontend-dapp/src/services/terraclassic/transactions.ts\`). At \`SWAP_GAS_BUFFER = 1.1\`, single-hop \`gasWanted\` was **710,000** — below your observed **753,321** \`gasUsed\` (glab#115). - **Fix (merged to \`main\`, commit \`ac9338e\`):** Raised \`SWAP_GAS_BUFFER\` from **1.1 → 1.2** in \`frontend-dapp/src/utils/constants.ts\`, so single-hop pool-only \`gasWanted\` is **770,000** (still below hybrid floors where applicable). - **Docs:** Invariants + formula in [docs/frontend.md § Terra Classic gas limits](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md#terra-classic-gas-limits); agent playbook [skills/AGENTS_TERRACLASSIC_GAS.md](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_TERRACLASSIC_GAS.md); index links in \`docs/README.md\`. - **Tests:** \`transactions.test.ts\` updated + regression \`gasLimit > 753321\` for single-hop \`execute_swap_operations\`. ## Verification checklist - [ ] Fresh stack: \`docker compose up\`, \`deploy-dex-local.sh\`, indexer as in #114. - [ ] \`cd frontend-dapp && npm run dev\`, connect Station, **Swap** default pair (EMBER → CORAL), amount **10** EMBER, **1%** slippage. - [ ] Submit swap; tx **succeeds** (no \`out of gas\` in Station / block explorer). - [ ] Optional: note \`gas_wanted\` vs \`gas_used\` on success (wanted should remain comfortably above used). - [ ] Spot-check a **2-hop** pool-only route if available (buffer change scales hop count). Issue left **open** until you confirm. Thanks!
totdking commented 2026-05-04 17:02:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #127

mentioned in issue #127
Brouie commented 2026-05-05 23:55:34 +00:00 (Migrated from gitlab.com)

mentioned in issue #133

mentioned in issue #133
Brouie commented 2026-05-06 04:20:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #121

mentioned in issue #121
PlasticDigits commented 2026-05-06 09:29:56 +00:00 (Migrated from gitlab.com)

mentioned in commit 80a69f321d

mentioned in commit 80a69f321d8a8adb181bb21c02277ca0e0fe1dbc
PlasticDigits commented 2026-05-06 09:30:45 +00:00 (Migrated from gitlab.com)

#115 follow-up — swap gas buffer aligned with terrad --gas-adjustment 1.3

Earlier mitigation (buffer 1.1 → 1.2, ~770k gas_wanted single-hop) addressed the repro where 753,321 gas_used exceeded 710,000 wanted. This change tightens alignment with how we operate the chain in scripts:

  • SWAP_GAS_BUFFER = 1.3 in frontend-dapp/src/utils/constants.ts → single-hop pool-only execute_swap_operations gas_wanted = 830,000 (formula unchanged; see docs/frontend.md § Terra Classic gas limits).
  • packages/localnet-trading-swarm/src/gas.ts — same buffer so scripted LocalTerra swaps match wallet broadcasts (documented in swarm README.md + skills/AGENTS_LOCALNET_TRADING_SWARM.md).
  • Tests: frontend-dapp/src/services/terraclassic/__tests__/transactions.test.ts updated; npm ci + vitest --run …/transactions.test.ts passes; packages/localnet-trading-swarm npm run test:run passes.
  • Agent / 3rd-party playbooks: skills/AGENTS_TERRACLASSIC_GAS.md, docs/README.md crosslinks refreshed.

main: 80a69f3

Other issues on main (brief verification)

  • #127 (Station LocalTerra fee / cosmes patch) and #132 (native LUNC preflight for two-tx limit place) — reviewed for interaction with router swap gas; they use separate code paths (effectiveGasPriceUluna, limit gates vs gasLimitForExecuteSwapOperations). No merge conflict with this buffer change.

Checklist for @brouie (please re-verify; leaving issue open until you confirm):

  • Fresh LocalTerra stack + indexer (same flow as #114)
  • frontend-dapp dev server, Station wallet, Swap default pair EMBER → CORAL, amount 10 EMBER, 1% slippage
  • Submit swap → on-chain success (no out of gas); optional: note gas_wanted vs gas_used in explorer
  • Optional: 2-hop pool-only route if you have one in the UI

Thanks — tagging @brouie for verification.

## #115 follow-up — swap gas buffer aligned with `terrad --gas-adjustment 1.3` Earlier mitigation (buffer **1.1 → 1.2**, ~770k `gas_wanted` single-hop) addressed the repro where **753,321** `gas_used` exceeded **710,000** wanted. This change tightens alignment with how we operate the chain in scripts: - **`SWAP_GAS_BUFFER` = 1.3** in `frontend-dapp/src/utils/constants.ts` → single-hop pool-only `execute_swap_operations` **`gas_wanted` = 830,000** (formula unchanged; see `docs/frontend.md` § [Terra Classic gas limits](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md#terra-classic-gas-limits)). - **`packages/localnet-trading-swarm/src/gas.ts`** — same buffer so scripted LocalTerra swaps match wallet broadcasts (documented in swarm `README.md` + [`skills/AGENTS_LOCALNET_TRADING_SWARM.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_LOCALNET_TRADING_SWARM.md)). - **Tests:** `frontend-dapp/src/services/terraclassic/__tests__/transactions.test.ts` updated; `npm ci` + `vitest --run …/transactions.test.ts` passes; `packages/localnet-trading-swarm` `npm run test:run` passes. - **Agent / 3rd-party playbooks:** [`skills/AGENTS_TERRACLASSIC_GAS.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_TERRACLASSIC_GAS.md), [`docs/README.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/README.md) crosslinks refreshed. **`main`:** `80a69f3` ### Other issues on `main` (brief verification) - **#127** (Station LocalTerra fee / cosmes patch) and **#132** (native LUNC preflight for two-tx limit place) — reviewed for interaction with router swap gas; they use separate code paths (`effectiveGasPriceUluna`, limit gates vs `gasLimitForExecuteSwapOperations`). No merge conflict with this buffer change. --- **Checklist for @brouie** (please re-verify; leaving issue **open** until you confirm): - [ ] Fresh LocalTerra stack + indexer (same flow as #114) - [ ] `frontend-dapp` dev server, Station wallet, **Swap** default pair **EMBER → CORAL**, amount **10** EMBER, **1%** slippage - [ ] Submit swap → **on-chain success** (no `out of gas`); optional: note `gas_wanted` vs `gas_used` in explorer - [ ] Optional: 2-hop pool-only route if you have one in the UI Thanks — tagging **@brouie** for verification.
Brouie commented 2026-05-07 05:11:40 +00:00 (Migrated from gitlab.com)

@PlasticDigits @totdking — picking up verification on this. since totdking is now driving DEX visual QA, tagging him for the on-stack repro since he likely has the LocalTerra + Station setup running already. happy to walk it myself next time I have the DEX stack up if it makes more sense.

totdking — when you get a moment: fresh LocalTerra + DEX, frontend swap default EMBER → CORAL, 10 EMBER amount, 1% slippage. on commit 80a69f3 the buffer is 1.3 so single-hop gas_wanted should be ~830k. confirm tx lands without out-of-gas, ideally note gas_wanted vs gas_used from the explorer.

@PlasticDigits @totdking — picking up verification on this. since totdking is now driving DEX visual QA, tagging him for the on-stack repro since he likely has the LocalTerra + Station setup running already. happy to walk it myself next time I have the DEX stack up if it makes more sense. totdking — when you get a moment: fresh LocalTerra + DEX, frontend swap default EMBER → CORAL, 10 EMBER amount, 1% slippage. on commit `80a69f3` the buffer is 1.3 so single-hop `gas_wanted` should be ~830k. confirm tx lands without out-of-gas, ideally note gas_wanted vs gas_used from the explorer.
Brouie commented 2026-05-07 06:30:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #134

mentioned in issue #134
PlasticDigits commented 2026-05-27 03:27:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 3f6a2e5680

mentioned in commit 3f6a2e5680fe78766147165a23b5a8415d95454e
PlasticDigits commented 2026-05-27 03:27:26 +00:00 (Migrated from gitlab.com)

Verified on LocalTerra stack (commit 3f6a2e5):

Root cause (follow-up): After SWAP_GAS_BUFFER=1.3, single-hop gasWanted was exactly 830,000 but on-chain gasUsed was 830,102 (and up to 830,162 on retry) — failing by ~100 gas at the formula ceiling.

Fix: Added SWAP_GAS_SAFETY_MARGIN = 10_000 to gasLimitForExecuteSwapOperations (dApp + localnet-trading-swarm). Single-hop pool-only swap now broadcasts with 840,000 gas_wanted.

Verification (browser MCP, Simulated Wallet, EMBER→CORAL, 10 EMBER):

  • Tx 5059B88F…7ADE37 succeeded (code=0, gas_wanted=840000, gas_used=449963)
  • Unit tests: transactions.test.ts, extensionSignedFeeGuard.test.ts pass

Closing #115.

Verified on LocalTerra stack (commit 3f6a2e5): **Root cause (follow-up):** After SWAP_GAS_BUFFER=1.3, single-hop `gasWanted` was exactly **830,000** but on-chain `gasUsed` was **830,102** (and up to **830,162** on retry) — failing by ~100 gas at the formula ceiling. **Fix:** Added `SWAP_GAS_SAFETY_MARGIN = 10_000` to `gasLimitForExecuteSwapOperations` (dApp + localnet-trading-swarm). Single-hop pool-only swap now broadcasts with **840,000** `gas_wanted`. **Verification (browser MCP, Simulated Wallet, EMBER→CORAL, 10 EMBER):** - Tx **5059B88F…7ADE37** succeeded (`code=0`, `gas_wanted=840000`, `gas_used=449963`) - Unit tests: `transactions.test.ts`, `extensionSignedFeeGuard.test.ts` pass Closing #115.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-27 03:27:27 +00:00
PlasticDigits commented 2026-05-27 14:45:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #206

mentioned in issue #206
PlasticDigits commented 2026-05-31 12:21:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #249

mentioned in issue #249
PlasticDigits commented 2026-05-31 12:29:12 +00:00 (Migrated from gitlab.com)

mentioned in issue #252

mentioned in issue #252
PlasticDigits commented 2026-06-12 11:10:26 +00:00 (Migrated from gitlab.com)

mentioned in issue #372

mentioned in issue #372
PlasticDigits commented 2026-06-12 11:39:21 +00:00 (Migrated from gitlab.com)

mentioned in merge request !886

mentioned in merge request !886
PlasticDigits commented 2026-06-13 03:05:42 +00:00 (Migrated from gitlab.com)

mentioned in merge request !894

mentioned in merge request !894
PlasticDigits commented 2026-07-12 07:09:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #475

mentioned in issue #475
PlasticDigits commented 2026-08-21 11:29:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #587

mentioned in issue #587
PlasticDigits commented 2026-08-24 05:54:09 +00:00 (Migrated from gitlab.com)

mentioned in issue #621

mentioned in issue #621
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#115
No description provided.