Cancelled limit order remains in indexer placements list -> raw contract storage error surfaced on duplicate cancel attempt #135

Closed
opened 2026-05-06 14:25:49 +00:00 by totdking · 10 comments
totdking commented 2026-05-06 14:25:49 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-05-06 14:27:10 +00:00 (Migrated from gitlab.com)

Issue Summary

After a limit order is successfully cancelled, the order continues to appear in the indexer's recent placements list. A user who sees the order still listed may attempt to cancel it a second time. The second cancel attempt is rejected on-chain with a raw contract storage error containing a binary map key, this is completely unreadable to a user and provides no actionable guidance.


Reproduction Steps

  1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running)
  2. Connect wallet with sufficient LUNC and escrow token balance
  3. Navigate to /limits, place a limit order, and confirm placement
  4. Cancel the order. confirm cancellation succeeds
  5. Observe: the cancelled order still appears in the indexer's recent placements list
  6. Attempt to cancel the same order a second time using the still-visible entry
  7. Approve the transaction in the wallet
  8. Observe the on-chain rejection and the error message surfaced in the UI

Expected Behavior

Either:

  • The cancelled order is removed from the indexer's placements list promptly after cancellation so it is no longer selectable, or
  • If the order remains visible, the frontend should detect a duplicate cancel attempt client-side and show a clear human-readable message: "This order has already been cancelled."

In neither case should a raw contract storage key be shown to the user.


Actual Behavior

The cancelled order persists in the placements list. A second cancel attempt is submitted on-chain and rejected with the following raw error surfaced directly in the UI:

Transaction failed: Transaction failed: failed to execute message; message index: 0: 
type: cl8y_dex_pair::state::LimitOrder; 
key: [00, 0C, 6C, 69, 6D, 69, 74, 5F, 6F, 72, 64, 65, 72, 73, 00, 00, 00, 00, 00, 00, 00, 03] 
not found: execute wasm contract failed

The binary key ([00, 0C, 6C, ...]) is an internal contract storage reference with no meaning to a user. No human-readable "already cancelled" message is shown.


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 Station: localterra, LCD http://localhost:1317, RPC http://localhost:26657

Severity / Impact

P3 Nit. Does not block DEX usage or hinder normal user flow — no funds are at risk and the duplicate cancel fails safely. Two improvements warranted:

  1. Indexer cleanup: cancelled orders should be removed from or flagged in the placements list so they are not re-selectable
  2. Error copy : if a duplicate cancel does reach the chain, the raw contract key error should be caught and translated to a plain message such as "Order not foun; it may have already been cancelled"

cc @PlasticDigits

### Issue Summary After a limit order is successfully cancelled, the order continues to appear in the indexer's recent placements list. A user who sees the order still listed may attempt to cancel it a second time. The second cancel attempt is rejected on-chain with a raw contract storage error containing a binary map key, this is completely unreadable to a user and provides no actionable guidance. --- ### Reproduction Steps 1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running) 2. Connect wallet with sufficient LUNC and escrow token balance 3. Navigate to `/limits`, place a limit order, and confirm placement 4. Cancel the order. confirm cancellation succeeds 5. Observe: the cancelled order still appears in the indexer's recent placements list 6. Attempt to cancel the same order a second time using the still-visible entry 7. Approve the transaction in the wallet 8. Observe the on-chain rejection and the error message surfaced in the UI --- ### Expected Behavior Either: - The cancelled order is removed from the indexer's placements list promptly after cancellation so it is no longer selectable, **or** - If the order remains visible, the frontend should detect a duplicate cancel attempt client-side and show a clear human-readable message: _"This order has already been cancelled."_ In neither case should a raw contract storage key be shown to the user. --- ### Actual Behavior The cancelled order persists in the placements list. A second cancel attempt is submitted on-chain and rejected with the following raw error surfaced directly in the UI: ``` Transaction failed: Transaction failed: failed to execute message; message index: 0: type: cl8y_dex_pair::state::LimitOrder; key: [00, 0C, 6C, 69, 6D, 69, 74, 5F, 6F, 72, 64, 65, 72, 73, 00, 00, 00, 00, 00, 00, 00, 03] not found: execute wasm contract failed ``` The binary key (`[00, 0C, 6C, ...]`) is an internal contract storage reference with no meaning to a user. No human-readable "already cancelled" message is shown. --- ### 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 Station:** localterra, LCD `http://localhost:1317`, RPC `http://localhost:26657` --- ### Severity / Impact **P3 Nit.** Does not block DEX usage or hinder normal user flow — no funds are at risk and the duplicate cancel fails safely. Two improvements warranted: 1. **Indexer cleanup**: cancelled orders should be removed from or flagged in the placements list so they are not re-selectable 2. **Error copy** : if a duplicate cancel does reach the chain, the raw contract key error should be caught and translated to a plain message such as _"Order not foun; it may have already been cancelled"_ cc @PlasticDigits
PlasticDigits commented 2026-05-06 14:48:19 +00:00 (Migrated from gitlab.com)

mentioned in commit 2e77eede9b

mentioned in commit 2e77eede9baf8b046eb5e3bbfbbbcf9b0b1bd5f5
PlasticDigits commented 2026-05-06 14:48:37 +00:00 (Migrated from gitlab.com)

Update (implemented on main, merge c4bc1c2)

What changed

  • Indexer: GET /api/v1/pairs/{addr}/limit-placements now returns only placement rows whose (pair_id, order_id) has no matching row in limit_order_cancellations (SQL NOT EXISTS). Added (pair_id, order_id) index on cancellations for the anti-join. Full cancel history stays on .../limit-cancellations.
  • dApp: After a successful cancel, React Query invalidates both limitPlacements and pair-scoped limitCancellations. If the typed order id already appears in indexed cancellations, Cancel is disabled and the wallet is not invoked. CosmWasm LimitOrder map not found / binary key errors are humanized via tryHumanizeTerraTxMessage (with humanizeCosmwasmLimitOrderMissingMessage).
  • Merge note: handleTransactionError no longer treats any substring rejected as a wallet reject, so #134 max-spread copy (Trade rejected: ...) is not misclassified as user rejection.
  • docs/limit-orders.md, docs/indexer-invariants.md, skills/AGENTS_LOCALNET_TRADING_SWARM.md updated and cross-linked to #135.

Verification checklist (please confirm)

  • Run indexer with migrations applied; cancel a limit on LocalTerra; placements list for that pair no longer shows that order_id; cancellations endpoint still lists the cancel.
  • dApp /limits and Trade panel: after cancel, active placements refresh; duplicate cancel for the same id is blocked when indexed.
  • If you force an on-chain duplicate cancel (e.g. old indexer), UI shows the plain limit order no longer on the book message instead of the raw map key.
  • cd frontend-dapp && npx vitest run src/utils/__tests__/limitOrderCancelUserMessage.test.ts src/services/terraclassic/__tests__/transactions.test.ts
  • (Optional CI) cd indexer && cargo test --test api_pairs with Postgres for get_pair_limit_placements_and_cancellations.

@totdking — could you verify on your LocalTerra stack and confirm the checklist? Leaving the issue open as requested.

## Update (implemented on `main`, merge `c4bc1c2`) ### What changed - **Indexer:** `GET /api/v1/pairs/{addr}/limit-placements` now returns only placement rows whose `(pair_id, order_id)` has **no** matching row in `limit_order_cancellations` (SQL `NOT EXISTS`). Added `(pair_id, order_id)` index on cancellations for the anti-join. Full cancel history stays on `.../limit-cancellations`. - **dApp:** After a successful cancel, React Query invalidates **both** `limitPlacements` and pair-scoped `limitCancellations`. If the typed order id already appears in indexed cancellations, **Cancel** is disabled and the wallet is not invoked. CosmWasm `LimitOrder` map **not found** / binary key errors are humanized via `tryHumanizeTerraTxMessage` (with `humanizeCosmwasmLimitOrderMissingMessage`). - **Merge note:** `handleTransactionError` no longer treats any substring `rejected` as a wallet reject, so **#134** max-spread copy (`Trade rejected: ...`) is not misclassified as user rejection. ### Docs / agent crosslinks - `docs/limit-orders.md`, `docs/indexer-invariants.md`, `skills/AGENTS_LOCALNET_TRADING_SWARM.md` updated and cross-linked to **#135**. ### Verification checklist (please confirm) - [ ] Run indexer with migrations applied; cancel a limit on LocalTerra; **placements** list for that pair no longer shows that `order_id`; **cancellations** endpoint still lists the cancel. - [ ] dApp `/limits` and Trade panel: after cancel, **active placements** refresh; duplicate cancel for the same id is blocked when indexed. - [ ] If you force an on-chain duplicate cancel (e.g. old indexer), UI shows the plain **limit order no longer on the book** message instead of the raw map key. - [ ] `cd frontend-dapp && npx vitest run src/utils/__tests__/limitOrderCancelUserMessage.test.ts src/services/terraclassic/__tests__/transactions.test.ts` - [ ] (Optional CI) `cd indexer && cargo test --test api_pairs` with Postgres for `get_pair_limit_placements_and_cancellations`. @totdking — could you verify on your LocalTerra stack and confirm the checklist? Leaving the issue **open** as requested.
Brouie commented 2026-05-07 06:30:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #134

mentioned in issue #134
totdking commented 2026-05-22 13:58:56 +00:00 (Migrated from gitlab.com)

Verification checklist

  • Run indexer with migrations applied; cancel a limit on LocalTerra; placements list for that pair no longer shows that order_id; cancellations endpoint still lists the cancel.
  • dApp /limits and Trade panel: after cancel, active placements refresh; duplicate cancel for the same id is blocked when indexed.
  • If you force an on-chain duplicate cancel (e.g. old indexer), UI shows the plain limit order no longer on the book message instead of the raw map key.
  • cd frontend-dapp && npx vitest run src/utils/__tests__/limitOrderCancelUserMessage.test.ts src/services/terraclassic/__tests__/transactions.test.ts
  • (Optional CI) cd indexer && cargo test --test api_pairs with Postgres for get_pair_limit_placements_and_cancellations.

Final verdict

This is resolved, good to go

cc: @PlasticDigits

### Verification checklist * [x] Run indexer with migrations applied; cancel a limit on LocalTerra; **placements** list for that pair no longer shows that `order_id`; **cancellations** endpoint still lists the cancel. * [x] dApp `/limits` and Trade panel: after cancel, **active placements** refresh; duplicate cancel for the same id is blocked when indexed. * [x] If you force an on-chain duplicate cancel (e.g. old indexer), UI shows the plain **limit order no longer on the book** message instead of the raw map key. * [x] `cd frontend-dapp && npx vitest run src/utils/__tests__/limitOrderCancelUserMessage.test.ts src/services/terraclassic/__tests__/transactions.test.ts` * [x] (Optional CI) `cd indexer && cargo test --test api_pairs` with Postgres for `get_pair_limit_placements_and_cancellations`. ## Final verdict This is resolved, good to go cc: @PlasticDigits
Brouie commented 2026-05-25 01:26:19 +00:00 (Migrated from gitlab.com)

qa cleared, good to close @PlasticDigits

qa cleared, good to close @PlasticDigits
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-25 01:42:09 +00:00
PlasticDigits commented 2026-06-07 12:14:14 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
PlasticDigits commented 2026-06-25 14:12:44 +00:00 (Migrated from gitlab.com)

mentioned in issue #412

mentioned in issue #412
PlasticDigits commented 2026-06-25 14:12:57 +00:00 (Migrated from gitlab.com)

mentioned in issue #419

mentioned in issue #419
PlasticDigits commented 2026-08-16 07:14:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #530

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