Place Limit submits two on-chain transactions and burns gas when user has zero escrow token balance #130
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#130
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?
Issue Summary
Placing a limit order with zero balance of the required escrow token submits two on-chain transactions before failing. The first transaction (
increase_allowanceCW20 approval) succeeds and consumes gas. The second transaction (place_limit_order) is rejected on-chain because the contract attempts atransfer_fromagainst a zero balance. Both transactions deduct LUNC gas fees from the wallet. The frontend performs no balance check before submission, so the user receives no warning and loses gas on a guaranteed-to-fail operation.Reproduction Steps
localhost:3000)/tradeand select any token pairincrease_allowance) succeeds, second tx (place_limit_order) is rejected on-chainExpected Behavior
Before submitting any transaction, the frontend should compare the entered amount against the user's escrow token balance (already fetched via
useLimitOrderEscrowBalance). If the balance is insufficient, the Place Limit button should be disabled and an "Insufficient balance" error should be shown inline. No transaction should be sent.Actual Behavior
The frontend skips balance validation and sends both transactions regardless of balance:
executeTerraContract→increase_allowanceon the CW20 escrow token — succeeds (allowance is a permission grant, does not require balance), gas consumedplaceLimitOrder→ contract callstransfer_from, finds zero balance — rejected on-chain, gas consumedThe wallet shows a net LUNC deduction across two gas payments with a final failed state. The UI displays a generic transaction error after the fact.
Screenshots
Pre funded
Carries out tx
3. Tx submitted but zero amount of bid/ask required tokens so it reverts.
4. Gas consumed, tx failed, user is left with deficit of gas carried out
Stages:
Root Cause
TradeOrderTicket.tsx:88–91,placeMutation.mutationFncallsexecuteTerraContract(allowance) thenplaceLimitOrderwithout checkingescrowBalanceQuery.dataagainst the entered amount. The balance data is already available in the component viauseLimitOrderEscrowBalance(line 59) but is only used to populate a display field, not to gate submission.Environment Details
localterra(local Docker)VITE_NETWORK=local npm run devatlocalhost:3000make indexer-dev)make deploy-localWallet / Device Details
http://localhost:26657Severity / Impact
Medium. Users lose real LUNC to gas fees when attempting a limit order they cannot afford. The gas loss from the unnecessary
increase_allowancetransaction is avoidable entirely, it should never be sent if balance validation fails. The fix is low-effort: add a pre-submission guard using the already-fetchedescrowBalanceQuery.datainTradeOrderTicket.tsx. The same validation gap exists on the/limitspage (LimitOrdersPage.tsx).cc: @PlasticDigits
We need a modularized, global utiltiy and component for balance validation wherever user is inputing amounts to spend.
mentioned in commit
0d645f7dffImplemented on
main(0d645f7)Summary: Added a shared preflight gate so the dApp never broadcasts
increase_allowancewhen the limit escrow amount (raw units) exceeds the wallet CW20 balance, or when the balance query is still loading / unreadable. This addresses the two-tx gas burn described in the issue.Code
frontend-dapp/src/utils/limitOrderEscrowBalanceGate.ts—evaluateLimitOrderEscrowPlaceGate(BigInt compare ontoRawAmountvs balance string; conservative when uncertain).frontend-dapp/src/components/trade/LimitOrderEscrowPlaceGuardMessage.tsx— inline status / error under Place limit.TradeOrderTicket.tsx(trade workspace) andLimitOrdersPage.tsx— disabled Place button +mutationFnguard (defense in depth).Docs / agent playbooks
docs/limit-orders.md— dApp retail section: #130 preflight invariants + links to code.skills/AGENTS_TERRACLASSIC_GAS.md— canonical table + rule of thumb for escrow vs balance.skills/AGENTS_LOCALNET_TRADING_SWARM.md— cross-link for localnet QA.Verification checklist (for QA / reviewers)
/tradeorder ticket and/limitspage both behave the same for bid/ask side switches.cd frontend-dapp && npm ci && npm run test:unitpasses (includeslimitOrderEscrowBalanceGate.test.ts).@totdking — could you confirm on your LocalTerra + Keplr setup that you no longer get a successful
increase_allowancewhen escrow balance is zero? Leaving the issue open until you verify.Status:
issue is fixed, on zero escrow balance, there is no increase_allowance() as the button to carry out limit orders is disabled.
Verification checklist (for QA / reviewers)
/tradeorder ticket and/limitspage both behave the same for bid/ask side switches.cd frontend-dapp && npm ci && npm run test:unitpasses (includeslimitOrderEscrowBalanceGate.test.ts).Fixed @PlasticDigits
mentioned in issue #132
mentioned in issue #133
mentioned in commit
b4ebc07ba5