Two-tx limit order sequence burns first gas fee when second tx fails #132

Closed
opened 2026-05-05 16:13:43 +00:00 by totdking · 12 comments
totdking commented 2026-05-05 16:13:43 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-05-05 16:18:53 +00:00 (Migrated from gitlab.com)

Issue Summary

Placing a limit order sends two sequential transactions: increase_allowance (CW20 approval, ~5.665 LUNC gas) followed by place_limit_order (~26.90875 LUNC gas). If the second tx fails for any reason, insufficient LUNC, user rejection, or on-chain error, the first tx has already gone through and burned its gas. The user loses ~5.665 LUNC with no order placed. The issue #130 fix guards against zero escrow token balance but does not validate that the wallet holds enough LUNC to cover both fees before starting the sequence.


Reproduction Steps

  1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running)
  2. Connect a Keplr wallet with sufficient escrow tokens but LUNC balance below the combined fee (~32.57375 LUNC total)
  3. Navigate to /limits, select a pair, enter a valid amount, click Place Limit
  4. Approve the first Keplr prompt (increase_allowance, ~5.665 LUNC fee)
  5. Second Keplr prompt appears (place_limit_order, ~26.90875 LUNC fee) — fails or is rejected due to insufficient LUNC
  6. Observe: first tx consumed gas, second tx never completed, no order placed, LUNC balance reduced

Expected Behavior

The frontend should validate that the wallet holds enough LUNC to cover both tx fees before sending the first transaction, not just that the escrow token balance is sufficient. If total LUNC balance is below the combined fee estimate, the Place Limit button should be disabled with a clear message.


Actual Behavior

The first tx (increase_allowance) is broadcast and burns ~5.665 LUNC even when the second tx cannot complete, leaving the user with no order placed and a reduced gas balance.

  1. Tx 1 (CW20 approval)

Screenshot 2026-05-05 at 15.41.10.png{width=900 height=585}

  1. Tx 2: place_limit_order

Screenshot 2026-05-05 at 15.41.25.png{width=900 height=585}


Root Cause

The two-tx sequence in LimitOrdersPage.tsx:122 has no total LUNC pre-flight check. The issue #130 fix added an escrow token balance gate but the same validation gap exists for native gas , the frontend does not check whether walletLuncBalance >= fee1 + fee2 before broadcasting the first tx.

Relevant files:

  • frontend-dapp/src/pages/LimitOrdersPage.tsx:122, two-tx sequence with no total LUNC pre-flight check

Environment Details

Field Value
OS macOS (Apple M1 Pro, 14-inch)
Browser Google Chrome (desktop)
Network localterra (local Docker)
Frontend VITE_NETWORK=local npm run dev
Indexer Running (make indexer-dev)
Contracts Deployed via make deploy-local

Wallet / Device Details

  • Wallet: Keplr browser extension
  • Network configured in Keplr: localterra — RPC http://localhost:26657

Severity / Impact

Medium. Users lose real LUNC to gas fees on a two-tx sequence that was never going to complete. The fix is low-effort: sum both estimated fees and compare against the wallet's native LUNC balance before broadcasting the first tx, mirroring the escrow token gate added in issue #130

CC: @PlasticDigits

### Issue Summary Placing a limit order sends two sequential transactions: `increase_allowance` (CW20 approval, \~5.665 LUNC gas) followed by `place_limit_order` (\~26.90875 LUNC gas). If the second tx fails for any reason, insufficient LUNC, user rejection, or on-chain error, the first tx has already gone through and burned its gas. The user loses \~5.665 LUNC with no order placed. The issue #130 fix guards against zero escrow token balance but does not validate that the wallet holds enough LUNC to cover both fees before starting the sequence. --- ### Reproduction Steps 1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running) 2. Connect a Keplr wallet with sufficient escrow tokens but LUNC balance below the combined fee (\~32.57375 LUNC total) 3. Navigate to `/limits`, select a pair, enter a valid amount, click **Place Limit** 4. Approve the first Keplr prompt (`increase_allowance`, \~5.665 LUNC fee) 5. Second Keplr prompt appears (`place_limit_order`, \~26.90875 LUNC fee) — fails or is rejected due to insufficient LUNC 6. Observe: first tx consumed gas, second tx never completed, no order placed, LUNC balance reduced --- ### Expected Behavior The frontend should validate that the wallet holds enough LUNC to cover both tx fees before sending the first transaction, not just that the escrow token balance is sufficient. If total LUNC balance is below the combined fee estimate, the Place Limit button should be disabled with a clear message. --- ### Actual Behavior The first tx (`increase_allowance`) is broadcast and burns \~5.665 LUNC even when the second tx cannot complete, leaving the user with no order placed and a reduced gas balance. 1. Tx 1 (CW20 approval) ![Screenshot 2026-05-05 at 15.41.10.png](/uploads/98caa654931a890efb5a3c2d0145d289/Screenshot_2026-05-05_at_15.41.10.png){width=900 height=585} 2. Tx 2: `place_limit_order` ![Screenshot 2026-05-05 at 15.41.25.png](/uploads/86a24c54614d70668b7162fd1671dfc5/Screenshot_2026-05-05_at_15.41.25.png){width=900 height=585} --- ### Root Cause The two-tx sequence in `LimitOrdersPage.tsx:122` has no total LUNC pre-flight check. The issue #130 fix added an escrow token balance gate but the same validation gap exists for native gas , the frontend does not check whether `walletLuncBalance >= fee1 + fee2` before broadcasting the first tx. Relevant files: - `frontend-dapp/src/pages/LimitOrdersPage.tsx:122`, two-tx sequence with no total LUNC pre-flight check --- ### Environment Details | Field | Value | |-------|-------| | OS | macOS (Apple M1 Pro, 14-inch) | | Browser | Google Chrome (desktop) | | Network | `localterra` (local Docker) | | Frontend | `VITE_NETWORK=local npm run dev` | | Indexer | Running (`make indexer-dev`) | | Contracts | Deployed via `make deploy-local` | --- ### Wallet / Device Details - **Wallet:** Keplr browser extension - **Network configured in Keplr:** localterra — RPC `http://localhost:26657` --- ### Severity / Impact **Medium.** Users lose real LUNC to gas fees on a two-tx sequence that was never going to complete. The fix is low-effort: sum both estimated fees and compare against the wallet's native LUNC balance before broadcasting the first tx, mirroring the escrow token gate added in issue #130 CC: @PlasticDigits
Brouie commented 2026-05-05 23:55:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #133

mentioned in issue #133
PlasticDigits commented 2026-05-06 08:49:50 +00:00 (Migrated from gitlab.com)

mentioned in commit b4ebc07ba5

mentioned in commit b4ebc07ba5f648827415a3cc236b05fc812f574e
PlasticDigits commented 2026-05-06 09:00:23 +00:00 (Migrated from gitlab.com)

Implemented native LUNC preflight for the two-transaction CW20 limit place path (increase_allowance then place_limit_order), so tx1 is not broadcast when the wallet cannot pay both fee envelopes.

What changed

  • Preflight: LimitOrdersPage and TradeOrderTicket require bank uluna ≥ estimateLimitOrderPlaceSequenceUlunaFeesTotal() (same gas limits and effectiveGasPriceUluna() as executeTerraContract) before enabling Place limit or broadcasting.
  • New: limitOrderNativeGasBalanceGate.ts, useNativeUlunaBalance (React Query key ['tokenBalance', address, 'uluna']), estimateLimitOrderPlaceSequenceUlunaFeesTotal in transactions.ts.
  • Docs / skills: docs/limit-orders.md, docs/frontend.md, skills/AGENTS_TERRACLASSIC_GAS.md, skills/AGENTS_LOCALNET_TRADING_SWARM.md; crosslinks from escrow gate + LimitOrderEscrowPlaceGuardMessage.
  • UX: Escrow guard message takes precedence; native LUNC message shows when escrow is clear (see doc invariants).

Verification checklist

  • LocalTerra: wallet with enough escrow CW20 but uluna below the combined fee (~32.57 LUNC at default 28.325 gas price) → Place limit disabled with clear inline copy (two txs / gas).
  • After topping up uluna to ≥ that sum → placement succeeds end-to-end.
  • Empty amount → no premature “add LUNC” line; button still disabled.
  • Same behaviour on /limits and /trade limit panel.
  • cd frontend-dapp && npx vitest run (297 tests).

@totdking Please re-run your repro and confirm; leaving the issue open until you verify.

Implemented **native LUNC preflight** for the two-transaction CW20 limit place path (`increase_allowance` then `place_limit_order`), so tx1 is not broadcast when the wallet cannot pay both fee envelopes. ### What changed - **Preflight:** `LimitOrdersPage` and `TradeOrderTicket` require bank **uluna** ≥ `estimateLimitOrderPlaceSequenceUlunaFeesTotal()` (same gas limits and `effectiveGasPriceUluna()` as `executeTerraContract`) before enabling **Place limit** or broadcasting. - **New:** `limitOrderNativeGasBalanceGate.ts`, `useNativeUlunaBalance` (React Query key `['tokenBalance', address, 'uluna']`), `estimateLimitOrderPlaceSequenceUlunaFeesTotal` in `transactions.ts`. - **Docs / skills:** `docs/limit-orders.md`, `docs/frontend.md`, `skills/AGENTS_TERRACLASSIC_GAS.md`, `skills/AGENTS_LOCALNET_TRADING_SWARM.md`; crosslinks from escrow gate + `LimitOrderEscrowPlaceGuardMessage`. - **UX:** Escrow guard message takes precedence; native LUNC message shows when escrow is clear (see doc invariants). ### Verification checklist - [ ] LocalTerra: wallet with enough escrow CW20 but **uluna** below the combined fee (~32.57 LUNC at default `28.325` gas price) → **Place limit** disabled with clear inline copy (two txs / gas). - [ ] After topping up **uluna** to ≥ that sum → placement succeeds end-to-end. - [ ] Empty amount → no premature “add LUNC” line; button still disabled. - [ ] Same behaviour on `/limits` and `/trade` limit panel. - [ ] `cd frontend-dapp && npx vitest run` (297 tests). @totdking Please re-run your repro and confirm; leaving the issue **open** until you verify.
PlasticDigits commented 2026-05-06 09:30:45 +00:00 (Migrated from gitlab.com)

mentioned in issue #115

mentioned in issue #115
totdking commented 2026-05-06 14:18:47 +00:00 (Migrated from gitlab.com)

Verification checklist

  • LocalTerra: wallet with enough escrow CW20 but uluna below the combined fee (~32.57 LUNC at default 28.325 gas price) → Place limit disabled with clear inline copy (two txs / gas).
  • After topping up uluna to ≥ that sum → placement succeeds end-to-end.
  • Empty amount → no premature “add LUNC” line; button still disabled.
  • Same behaviour on /limits and /trade limit panel.
  • cd frontend-dapp && npx vitest run (297 tests).

Good to close on dev side

cc : @PlasticDigits

### Verification checklist * [x] LocalTerra: wallet with enough escrow CW20 but **uluna** below the combined fee (\~32.57 LUNC at default `28.325` gas price) → **Place limit** disabled with clear inline copy (two txs / gas). * [x] After topping up **uluna** to ≥ that sum → placement succeeds end-to-end. * [x] Empty amount → no premature “add LUNC” line; button still disabled. * [x] Same behaviour on `/limits` and `/trade` limit panel. * [x] `cd frontend-dapp && npx vitest run` (297 tests). Good to close on dev side cc : @PlasticDigits
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-06 14:29:56 +00:00
totdking commented 2026-05-07 12:16:20 +00:00 (Migrated from gitlab.com)

mentioned in issue #147

mentioned in issue #147
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-29 03:15:18 +00:00 (Migrated from gitlab.com)

mentioned in issue #213

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

mentioned in issue #587

mentioned in issue #587
PlasticDigits commented 2026-08-25 06:09:48 +00:00 (Migrated from gitlab.com)

mentioned in commit 05451b201f

mentioned in commit 05451b201f40410c3624dc5d2386f5e1e7a76ded
PlasticDigits commented 2026-08-26 01:40:34 +00:00 (Migrated from gitlab.com)

mentioned in issue #629

mentioned in issue #629
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#132
No description provided.