Batch cancel and batch claim expired limit orders (on-chain + frontend) #246

Closed
opened 2026-05-31 12:21:20 +00:00 by PlasticDigits · 19 comments
PlasticDigits commented 2026-05-31 12:21:20 +00:00 (Migrated from gitlab.com)

Summary

Add on-chain CancelLimitOrders { order_ids: Vec<u64> } and ClaimExpiredLimitOrders { order_ids: Vec<u64> } so makers can unlink many resting or parked-expiry orders in one transaction, with at most two CW20 refund transfers (token0 + token1), instead of N separate cancel/claim txs.

Current codebase

  • Single cancel only: ExecuteMsg::CancelLimitOrder { order_id } and ExecuteMsg::ClaimExpiredLimitOrder { order_id } in smartcontracts/packages/dex-common/src/pair.rs. Handlers: execute_cancel_limit_order / execute_claim_expired_limit_order in smartcontracts/contracts/pair/src/contract.rs (~1169–1230, ~1103–1167).
  • Each cancel: load order → orderbook::unlink_order → read/write PENDING_ESCROW_TOKEN0|1 → one CW20 Transfer submessage per order.
  • No batch cancel message exists (grep confirms no CancelLimitOrders).
  • Frontend “Cancel all mine” loops one tx per order:
    for (const id of myActiveOrderIds) {
      try {
        await cancelLimitOrderMutation.mutateAsync(id)
  • Gas model: CANCEL_LIMIT_ORDER_GAS_LIMIT = 450_000 per tx (frontend-dapp/src/services/terraclassic/terraGas.ts). Ten cancels ≈ 4.5M gas + 10 signatures.
  • Batch placement precedent: PlaceLimitOrderBatch aggregates maker fees into one treasury transfer and refunds skipped rungs once (smartcontracts/contracts/pair/src/limit_placement.rs). Cap pattern: MAX_LIMIT_BATCH_RUNGS_HARD_CAP = 30 (dex-common/src/limit_placement.rs).
  • Indexer already exposes active placements + cancellations; client knows order_ids without an on-chain owner index.

Why this is needed

Cancel-all and bulk cleanup are common for market makers and ladder traders. Today each order costs a full tx overhead (sig verify, wasm spin-up, pair loads, escrow item R/W, CW20 execute). Collapsing N cancels into one tx targets ~1.3–1.8M gas for 10 orders vs ~4.5M today, plus one wallet approval flow.

Constraints / guardrails

  • Hard cap: order_ids.len() ≤ MAX_LIMIT_BATCH_RUNGS_HARD_CAP (30), same ceiling as batch placement. Reuse clamp_max_batch_rungs semantics or add parallel constants in dex-common.
  • Owner-only: Every id must belong to info.sender; any failure → whole tx reverts (all-or-nothing, unlike batch placement’s partial skip for insert steps).
  • Pause (L6): Same assert_not_paused gate as single cancel/claim (contract.rs dispatcher).
  • Claim batch: Only ids with rows in EXPIRED_LIMIT_CLAIMS; cancel batch only ids in active ORDERS map (not already parked).
  • Refund aggregation: Sum remaining per side (token0 asks / token1 bids); emit ≤ 2 CW20 transfers total. Do not change escrow accounting invariants (L1 / L5 — docs/contracts-security-audit.md).
  • No owner index: Do not add new storage maps keyed by owner; client supplies ids from indexer.
  • Indexer: Emit batch summary wasm attrs + per-id attrs (mirror place_limit_order_batch columnar pattern) so indexer/src/indexer/parser.rs can index cancellations/claims without N separate txs.

Relevant files

Area Files
Messages / types smartcontracts/packages/dex-common/src/pair.rs
Execute handlers smartcontracts/contracts/pair/src/contract.rs
Orderbook unlink smartcontracts/contracts/pair/src/orderbook.rs
State smartcontracts/contracts/pair/src/state.rs
Errors smartcontracts/contracts/pair/src/error.rs
Integration tests smartcontracts/tests/src/limit_order_tests.rs
Frontend service frontend-dapp/src/services/terraclassic/pair.ts
Cancel UI frontend-dapp/src/components/trade/OrderBookPanel.tsx
Cancel mutation frontend-dapp/src/hooks/useLimitOrderCancelMutation.ts
Gas frontend-dapp/src/services/terraclassic/terraGas.ts
Docs docs/limit-orders.md
  1. dex-common: Add CancelLimitOrders { order_ids: Vec<u64> }, ClaimExpiredLimitOrders { order_ids: Vec<u64> } to ExecuteMsg.
  2. pair contract: Implement execute_cancel_limit_orders / execute_claim_expired_limit_orders:
    • Validate cap, dedupe ids (reject duplicates).
    • Load PAIR_INFO, token addrs once.
    • Loop: authorize owner, unlink or load claim row, accumulate refunds per token, update escrow once per token at end.
    • Build ≤ 2 CW20 transfer messages.
    • Attributes: action=cancel_limit_orders_batch, batch_count, then per-id limit_order_cancelled (or claim equivalent).
  3. Frontend: Add cancelLimitOrders(wallet, pair, orderIds[]) and claimExpiredLimitOrders(...) in pair.ts. Replace onCancelAllMyResting loop with single batch call (keep confirm dialog). Add gasLimitForLimitOrderCancelBatch(n) ≈ CANCEL_LIMIT_ORDER_GAS_LIMIT base + marginal per id (measure on localterra).
  4. Indexer: Extend parser for batch cancel/claim attrs if columnar layout used.

Acceptance criteria

  • Batch cancel of N orders (N ≤ 30, same owner) succeeds in one tx with ≤ 2 CW20 transfers.
  • Batch claim of N expired rows succeeds in one tx with ≤ 2 CW20 transfers.
  • Duplicate order_id in vec → revert.
  • Any id not owned by sender → revert (no partial cancel).
  • N > 30 → revert with clear error.
  • Paused pair → revert.
  • Escrow invariants hold: sum of list remaining == PENDING_ESCROW_* after batch (existing prop tests pattern).
  • Frontend cancel-all uses batch API; gas hint reflects batch model.
  • Indexer records all N cancellations from one tx.

Test plan — functional paths

  • Cancel 1, 5, 30 orders (same side and mixed bid/ask) in one batch.
  • Claim 1, 5 expired rows in one batch.
  • Empty vec → revert.
  • Mix valid + foreign-owned id → revert, state unchanged.
  • Cancel id already cancelled → revert.
  • Claim id with no expired row → revert.
  • Refund amounts match sum of individual cancels (property test vs loop of singles).
  • Frontend e2e: cancel-all mine on /trade order book (extend frontend-dapp/e2e/limit-orders-tx.spec.ts or order-book spec).
  • Unit: gasLimitForLimitOrderCancelBatch monotonic in N.

Test plan — attack / abuse vectors

  • Unauthorized batch: Include another user’s order_id → entire tx fails; no escrow leak.
  • Duplicate ids: Same id twice → revert (prevent double-refund attempt).
  • Cap griefing: Submit 31 ids → revert; no gas bomb beyond cap.
  • Pause bypass: Batch cancel/claim while paused → blocked.
  • Escrow drain: Batch cancel with inflated internal remaining (invariant tests) → underflow revert, no over-refund.
  • Indexer spoofing: Batch attrs parsed correctly; no duplicate cancellation rows for one order.

Verification criteria

  • make test-contracts passes with new integration tests.
  • Manual localterra: 10-place ladder → cancel-all one tx; LCD shows single tx, 10 indexed cancellations.
  • Gas used for 10-batch cancel < 50% of 10× single cancel (document measured numbers in PR).
  • docs/limit-orders.md updated with batch cancel/claim messages and gas table.
## Summary Add on-chain **`CancelLimitOrders { order_ids: Vec<u64> }`** and **`ClaimExpiredLimitOrders { order_ids: Vec<u64> }`** so makers can unlink many resting or parked-expiry orders in **one transaction**, with **at most two CW20 refund transfers** (token0 + token1), instead of N separate cancel/claim txs. ## Current codebase - **Single cancel only:** `ExecuteMsg::CancelLimitOrder { order_id }` and `ExecuteMsg::ClaimExpiredLimitOrder { order_id }` in `smartcontracts/packages/dex-common/src/pair.rs`. Handlers: `execute_cancel_limit_order` / `execute_claim_expired_limit_order` in `smartcontracts/contracts/pair/src/contract.rs` (~1169–1230, ~1103–1167). - Each cancel: load order → `orderbook::unlink_order` → read/write `PENDING_ESCROW_TOKEN0|1` → **one CW20 `Transfer` submessage** per order. - **No batch cancel message** exists (grep confirms no `CancelLimitOrders`). - **Frontend “Cancel all mine”** loops one tx per order: ```394:401:frontend-dapp/src/components/trade/OrderBookPanel.tsx for (const id of myActiveOrderIds) { try { await cancelLimitOrderMutation.mutateAsync(id) ``` - Gas model: `CANCEL_LIMIT_ORDER_GAS_LIMIT = 450_000` per tx (`frontend-dapp/src/services/terraclassic/terraGas.ts`). Ten cancels ≈ **4.5M gas + 10 signatures**. - **Batch placement precedent:** `PlaceLimitOrderBatch` aggregates maker fees into one treasury transfer and refunds skipped rungs once (`smartcontracts/contracts/pair/src/limit_placement.rs`). Cap pattern: `MAX_LIMIT_BATCH_RUNGS_HARD_CAP = 30` (`dex-common/src/limit_placement.rs`). - Indexer already exposes active placements + cancellations; client knows `order_id`s without an on-chain owner index. ## Why this is needed Cancel-all and bulk cleanup are common for market makers and ladder traders. Today each order costs a full tx overhead (sig verify, wasm spin-up, pair loads, escrow item R/W, CW20 execute). Collapsing N cancels into one tx targets **~1.3–1.8M gas** for 10 orders vs **~4.5M** today, plus one wallet approval flow. ## Constraints / guardrails - **Hard cap:** `order_ids.len()` ≤ `MAX_LIMIT_BATCH_RUNGS_HARD_CAP` (30), same ceiling as batch placement. Reuse `clamp_max_batch_rungs` semantics or add parallel constants in `dex-common`. - **Owner-only:** Every id must belong to `info.sender`; any failure → **whole tx reverts** (all-or-nothing, unlike batch placement’s partial skip for insert steps). - **Pause (L6):** Same `assert_not_paused` gate as single cancel/claim (`contract.rs` dispatcher). - **Claim batch:** Only ids with rows in `EXPIRED_LIMIT_CLAIMS`; cancel batch only ids in active `ORDERS` map (not already parked). - **Refund aggregation:** Sum `remaining` per side (token0 asks / token1 bids); emit **≤ 2** CW20 transfers total. Do not change escrow accounting invariants (L1 / L5 — `docs/contracts-security-audit.md`). - **No owner index:** Do not add new storage maps keyed by owner; client supplies ids from indexer. - **Indexer:** Emit batch summary wasm attrs + per-id attrs (mirror `place_limit_order_batch` columnar pattern) so `indexer/src/indexer/parser.rs` can index cancellations/claims without N separate txs. ## Relevant files | Area | Files | |------|-------| | Messages / types | `smartcontracts/packages/dex-common/src/pair.rs` | | Execute handlers | `smartcontracts/contracts/pair/src/contract.rs` | | Orderbook unlink | `smartcontracts/contracts/pair/src/orderbook.rs` | | State | `smartcontracts/contracts/pair/src/state.rs` | | Errors | `smartcontracts/contracts/pair/src/error.rs` | | Integration tests | `smartcontracts/tests/src/limit_order_tests.rs` | | Frontend service | `frontend-dapp/src/services/terraclassic/pair.ts` | | Cancel UI | `frontend-dapp/src/components/trade/OrderBookPanel.tsx` | | Cancel mutation | `frontend-dapp/src/hooks/useLimitOrderCancelMutation.ts` | | Gas | `frontend-dapp/src/services/terraclassic/terraGas.ts` | | Docs | `docs/limit-orders.md` | ## Recommended solution direction 1. **dex-common:** Add `CancelLimitOrders { order_ids: Vec<u64> }`, `ClaimExpiredLimitOrders { order_ids: Vec<u64> }` to `ExecuteMsg`. 2. **pair contract:** Implement `execute_cancel_limit_orders` / `execute_claim_expired_limit_orders`: - Validate cap, dedupe ids (reject duplicates). - Load `PAIR_INFO`, token addrs once. - Loop: authorize owner, unlink or load claim row, accumulate refunds per token, update escrow once per token at end. - Build ≤ 2 CW20 transfer messages. - Attributes: `action=cancel_limit_orders_batch`, `batch_count`, then per-id `limit_order_cancelled` (or claim equivalent). 3. **Frontend:** Add `cancelLimitOrders(wallet, pair, orderIds[])` and `claimExpiredLimitOrders(...)` in `pair.ts`. Replace `onCancelAllMyResting` loop with single batch call (keep confirm dialog). Add `gasLimitForLimitOrderCancelBatch(n)` ≈ `CANCEL_LIMIT_ORDER_GAS_LIMIT` base + marginal per id (measure on localterra). 4. **Indexer:** Extend parser for batch cancel/claim attrs if columnar layout used. ## Acceptance criteria - [ ] Batch cancel of N orders (N ≤ 30, same owner) succeeds in **one tx** with ≤ 2 CW20 transfers. - [ ] Batch claim of N expired rows succeeds in one tx with ≤ 2 CW20 transfers. - [ ] Duplicate `order_id` in vec → revert. - [ ] Any id not owned by sender → revert (no partial cancel). - [ ] N > 30 → revert with clear error. - [ ] Paused pair → revert. - [ ] Escrow invariants hold: sum of list remaining == `PENDING_ESCROW_*` after batch (existing prop tests pattern). - [ ] Frontend cancel-all uses batch API; gas hint reflects batch model. - [ ] Indexer records all N cancellations from one tx. ## Test plan — functional paths - [ ] Cancel 1, 5, 30 orders (same side and mixed bid/ask) in one batch. - [ ] Claim 1, 5 expired rows in one batch. - [ ] Empty vec → revert. - [ ] Mix valid + foreign-owned id → revert, state unchanged. - [ ] Cancel id already cancelled → revert. - [ ] Claim id with no expired row → revert. - [ ] Refund amounts match sum of individual cancels (property test vs loop of singles). - [ ] Frontend e2e: cancel-all mine on `/trade` order book (extend `frontend-dapp/e2e/limit-orders-tx.spec.ts` or order-book spec). - [ ] Unit: `gasLimitForLimitOrderCancelBatch` monotonic in N. ## Test plan — attack / abuse vectors - [ ] **Unauthorized batch:** Include another user’s order_id → entire tx fails; no escrow leak. - [ ] **Duplicate ids:** Same id twice → revert (prevent double-refund attempt). - [ ] **Cap griefing:** Submit 31 ids → revert; no gas bomb beyond cap. - [ ] **Pause bypass:** Batch cancel/claim while paused → blocked. - [ ] **Escrow drain:** Batch cancel with inflated internal remaining (invariant tests) → underflow revert, no over-refund. - [ ] **Indexer spoofing:** Batch attrs parsed correctly; no duplicate cancellation rows for one order. ## Verification criteria - [ ] `make test-contracts` passes with new integration tests. - [ ] Manual localterra: 10-place ladder → cancel-all one tx; LCD shows single tx, 10 indexed cancellations. - [ ] Gas used for 10-batch cancel < 50% of 10× single cancel (document measured numbers in PR). - [ ] `docs/limit-orders.md` updated with batch cancel/claim messages and gas table.
PlasticDigits commented 2026-05-31 12:56:34 +00:00 (Migrated from gitlab.com)

mentioned in commit c93bb3c208

mentioned in commit c93bb3c208ce9cfba7f039cd9125c611f6d46927
PlasticDigits commented 2026-05-31 12:56:44 +00:00 (Migrated from gitlab.com)

Implementation summary (merged to main @ c93bb3c)

Added on-chain batch maker withdrawal paths and wired the dApp cancel-all flow to use a single transaction.

Contract (limit_batch_withdraw.rs)

  • CancelLimitOrders { order_ids } — all-or-nothing owner checks, dedupe enforced, cap = pair max_batch_rungs (≤30)
  • ClaimExpiredLimitOrders { order_ids } — same rules for parked-expiry rows
  • Refunds aggregate per token side → ≤ 2 CW20 transfers per tx
  • Wasm attrs: columnar cancel_limit_order / claim_expired_limit_order + batch summary attrs for indexer

Frontend

  • cancelLimitOrders / claimExpiredLimitOrders in pair.ts
  • Cancel all mine → one batch tx via useLimitOrderCancelMutation (number | number[])
  • Gas model: gasLimitForLimitOrderCancelBatch(n) = 400k + 80k×N

Indexer

  • Columnar parser for batch cancel/claim wasm attrs (mirrors batch placement pattern)

Docs / invariants

  • L11 in docs/contracts-security-audit.md
  • docs/limit-orders.md § batch cancel/claim + gas table
  • skills/AGENTS_TERRACLASSIC_GAS.md crosslink

Verification checklist

  • make test-contracts (323 tests incl. 6 new batch cancel/claim tests)
  • cargo test -p cl8y-dex-indexer --lib parse_limit_order_cancellations_batch_columnar
  • Localterra: place 5+ limits → Cancel all mine on /trade order book → one tx, all orders cancelled
  • LCD: batch tx emits cancel_limit_orders_batch + N limit_order_cancelled attrs
  • Indexer: N rows in limit_order_cancellations from one tx
  • Mixed bid+ask batch cancel refunds correct token0/token1 amounts
  • Duplicate id / foreign owner / empty vec / paused pair → whole tx reverts
  • Park 2 expired orders → claim_expired_limit_orders refunds both in one tx
  • Vitest: terraGas.batchCancel.test.ts (monotonic gas formula)

Follow-ups (optional): UI “Claim all parked” batch button on LimitOrderMyPlacementsPanel (service fn exists; per-row claim unchanged).

Request: @qa-agent-team please verify on LocalTerra + indexer ingestion per checklist above. Leaving issue open until QA sign-off.

## Implementation summary (merged to `main` @ c93bb3c) Added on-chain batch maker withdrawal paths and wired the dApp cancel-all flow to use a single transaction. ### Contract (`limit_batch_withdraw.rs`) - **`CancelLimitOrders { order_ids }`** — all-or-nothing owner checks, dedupe enforced, cap = pair `max_batch_rungs` (≤30) - **`ClaimExpiredLimitOrders { order_ids }`** — same rules for parked-expiry rows - Refunds aggregate per token side → **≤ 2 CW20 transfers** per tx - Wasm attrs: columnar `cancel_limit_order` / `claim_expired_limit_order` + batch summary attrs for indexer ### Frontend - `cancelLimitOrders` / `claimExpiredLimitOrders` in `pair.ts` - **Cancel all mine** → one batch tx via `useLimitOrderCancelMutation` (`number | number[]`) - Gas model: `gasLimitForLimitOrderCancelBatch(n)` = 400k + 80k×N ### Indexer - Columnar parser for batch cancel/claim wasm attrs (mirrors batch placement pattern) ### Docs / invariants - **L11** in `docs/contracts-security-audit.md` - `docs/limit-orders.md` § batch cancel/claim + gas table - `skills/AGENTS_TERRACLASSIC_GAS.md` crosslink --- ## Verification checklist - [ ] `make test-contracts` (323 tests incl. 6 new batch cancel/claim tests) - [ ] `cargo test -p cl8y-dex-indexer --lib parse_limit_order_cancellations_batch_columnar` - [ ] Localterra: place 5+ limits → **Cancel all mine** on `/trade` order book → **one tx**, all orders cancelled - [ ] LCD: batch tx emits `cancel_limit_orders_batch` + N `limit_order_cancelled` attrs - [ ] Indexer: N rows in `limit_order_cancellations` from one tx - [ ] Mixed bid+ask batch cancel refunds correct token0/token1 amounts - [ ] Duplicate id / foreign owner / empty vec / paused pair → whole tx reverts - [ ] Park 2 expired orders → `claim_expired_limit_orders` refunds both in one tx - [ ] Vitest: `terraGas.batchCancel.test.ts` (monotonic gas formula) --- **Follow-ups (optional):** UI “Claim all parked” batch button on `LimitOrderMyPlacementsPanel` (service fn exists; per-row claim unchanged). **Request:** @qa-agent-team please verify on LocalTerra + indexer ingestion per checklist above. Leaving issue **open** until QA sign-off.
PlasticDigits commented 2026-05-31 13:07:56 +00:00 (Migrated from gitlab.com)

mentioned in issue #253

mentioned in issue #253
PlasticDigits commented 2026-05-31 13:10:23 +00:00 (Migrated from gitlab.com)

mentioned in commit 0be09de77c

mentioned in commit 0be09de77c28c09b9e5d5a52089a05226532085e
PlasticDigits commented 2026-05-31 13:52:01 +00:00 (Migrated from gitlab.com)

mentioned in issue #259

mentioned in issue #259
Brouie commented 2026-06-02 17:23:02 +00:00 (Migrated from gitlab.com)

Heads up — main npm run build (tsc -b) is red, and it traces back to this batch-cancel change (c93bb3c).

c93bb3c introduced LimitOrderCancelInput = number | number[] in useLimitOrderCancelMutation (so "Cancel all mine" can pass an id array), but the cancel-mutation PROP types on the consuming components stayed UseMutationResult<..., number, ...>:

  • OrderBookPanel.tsx (cancelLimitOrderMutation + the BookSideColumn cancelMutation props)
  • TradeOrderTicket.tsx (two prop decls)

So the components are wired to a number|number[] mutation through props typed number-only. tsc -b fails with 6 TS2322/TS2345 errors across OrderBookPanel, TradeOrderTicket, TradePage, LimitOrdersPage (e.g. "number[] is not assignable to number"). It wasn't caught because CI/local checks here run vitest + eslint, neither of which type-checks; only tsc -b / npm run build does.

I found this while verifying #268 (its "npm run typecheck clean" criterion failed for this reason, not for anything in the ladder code).

Fix (type-only): widen the cancelLimitOrderMutation / cancelMutation prop types to LimitOrderCancelInput across OrderBookPanel + TradeOrderTicket. After the change tsc -b exits clean and the OrderBookPanel/TradeOrderTicket/LimitOrdersPage tests stay green (30 passed). MR incoming.

Worth adding tsc -b (or npm run build) to CI so a type-only break like this doesn't slip through again. @PlasticDigits

Heads up — main npm run build (tsc -b) is red, and it traces back to this batch-cancel change (c93bb3c). c93bb3c introduced LimitOrderCancelInput = number | number[] in useLimitOrderCancelMutation (so "Cancel all mine" can pass an id array), but the cancel-mutation PROP types on the consuming components stayed UseMutationResult<..., number, ...>: - OrderBookPanel.tsx (cancelLimitOrderMutation + the BookSideColumn cancelMutation props) - TradeOrderTicket.tsx (two prop decls) So the components are wired to a number|number[] mutation through props typed number-only. tsc -b fails with 6 TS2322/TS2345 errors across OrderBookPanel, TradeOrderTicket, TradePage, LimitOrdersPage (e.g. "number[] is not assignable to number"). It wasn't caught because CI/local checks here run vitest + eslint, neither of which type-checks; only tsc -b / npm run build does. I found this while verifying #268 (its "npm run typecheck clean" criterion failed for this reason, not for anything in the ladder code). Fix (type-only): widen the cancelLimitOrderMutation / cancelMutation prop types to LimitOrderCancelInput across OrderBookPanel + TradeOrderTicket. After the change tsc -b exits clean and the OrderBookPanel/TradeOrderTicket/LimitOrdersPage tests stay green (30 passed). MR incoming. Worth adding tsc -b (or npm run build) to CI so a type-only break like this doesn't slip through again. @PlasticDigits
Brouie commented 2026-06-02 17:23:32 +00:00 (Migrated from gitlab.com)

mentioned in merge request !737

mentioned in merge request !737
Brouie commented 2026-06-02 17:23:55 +00:00 (Migrated from gitlab.com)

mentioned in issue #268

mentioned in issue #268
Brouie commented 2026-06-02 18:00:12 +00:00 (Migrated from gitlab.com)

#246 verified — good to close. Both batch withdrawal paths proven live, plus the full test matrix.

Live (deployed wasm):

  • Batch CANCEL, mixed side, one tx: cancel_limit_orders [127 (ask), 122 (bid)] -> code 0, single tx, batch_count=2, wasm actions [cancel_limit_orders_batch, cancel_limit_order x2, transfer x2]. Exactly 2 CW20 transfers (EMBER token0 for the ask + CORAL token1 for the bid = mixed sides, <= 2). Both orders gone afterward. gas_used 323,967 for 2 (vs the 450k single-cancel envelope x2 = ~900k) — the batch saving holds.
  • Batch CLAIM, one tx: verified live on #253 — claim_expired_limit_orders[128,129] -> one claim_expired_limit_orders_batch tx, both expired_limit_refund rows released, refunds returned.

Contract / indexer / frontend tests:

  • Contract batch cancel/claim integration: 21 tests pass (incl. duplicate/foreign-owner/empty/cap/paused reverts; the foreign-owner and non-owner-claim guards landed via #271).
  • Indexer columnar parser: parse_limit_order_cancellations_batch_columnar passes (N cancellations indexed from one tx).
  • Frontend gas: terraGas.batchCancel vitest 2/2; gasLimitForLimitOrderCancelBatch(n) = 400k + 80k x N (monotonic).
  • Escrow invariant L1/L11 holds across batch (prop_escrow + the per-side <=2 transfer aggregation).

Acceptance criteria all covered: N<=30 one tx <=2 CW20 (live + tests); duplicate / foreign / N>30 / paused -> whole tx reverts (tests); mixed bid+ask refunds correct token0/token1 (live); frontend cancel-all uses the batch API with the batch gas model.

One frontend note already filed above: c93bb3c left the cancel-mutation PROP types as number while the hook is number|number[], so tsc -b / npm run build was red. Fixed type-only in MR !737; with that the cancel-all wiring type-checks clean.

Browser "Cancel all mine" on /trade is the UI wrapper over the same cancelLimitOrders batch path proven live above. Good to close. @PlasticDigits

#246 verified — good to close. Both batch withdrawal paths proven live, plus the full test matrix. Live (deployed wasm): - [x] Batch CANCEL, mixed side, one tx: cancel_limit_orders [127 (ask), 122 (bid)] -> code 0, single tx, batch_count=2, wasm actions [cancel_limit_orders_batch, cancel_limit_order x2, transfer x2]. Exactly 2 CW20 transfers (EMBER token0 for the ask + CORAL token1 for the bid = mixed sides, <= 2). Both orders gone afterward. gas_used 323,967 for 2 (vs the 450k single-cancel envelope x2 = ~900k) — the batch saving holds. - [x] Batch CLAIM, one tx: verified live on #253 — claim_expired_limit_orders[128,129] -> one claim_expired_limit_orders_batch tx, both expired_limit_refund rows released, refunds returned. Contract / indexer / frontend tests: - [x] Contract batch cancel/claim integration: 21 tests pass (incl. duplicate/foreign-owner/empty/cap/paused reverts; the foreign-owner and non-owner-claim guards landed via #271). - [x] Indexer columnar parser: parse_limit_order_cancellations_batch_columnar passes (N cancellations indexed from one tx). - [x] Frontend gas: terraGas.batchCancel vitest 2/2; gasLimitForLimitOrderCancelBatch(n) = 400k + 80k x N (monotonic). - [x] Escrow invariant L1/L11 holds across batch (prop_escrow + the per-side <=2 transfer aggregation). Acceptance criteria all covered: N<=30 one tx <=2 CW20 (live + tests); duplicate / foreign / N>30 / paused -> whole tx reverts (tests); mixed bid+ask refunds correct token0/token1 (live); frontend cancel-all uses the batch API with the batch gas model. One frontend note already filed above: c93bb3c left the cancel-mutation PROP types as number while the hook is number|number[], so tsc -b / npm run build was red. Fixed type-only in MR !737; with that the cancel-all wiring type-checks clean. Browser "Cancel all mine" on /trade is the UI wrapper over the same cancelLimitOrders batch path proven live above. Good to close. @PlasticDigits
PlasticDigits commented 2026-06-03 01:59:19 +00:00 (Migrated from gitlab.com)

mentioned in commit 90fca1be04

mentioned in commit 90fca1be04de0517abdb43441fab0f2e45109de7
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-03 02:05:12 +00:00
Brouie commented 2026-06-08 00:20:37 +00:00 (Migrated from gitlab.com)

mentioned in merge request !834

mentioned in merge request !834
Brouie commented 2026-06-08 00:32:39 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
ghost1 commented 2026-06-08 05:24:17 +00:00 (Migrated from gitlab.com)

mentioned in commit f875d5388a

mentioned in commit f875d5388a17e2467de35f7dc805ee7d77e6cea7
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 0e3afcaef3

mentioned in commit 0e3afcaef332b416792e99676407524ae3be2ef3
PlasticDigits commented 2026-06-08 13:42:30 +00:00 (Migrated from gitlab.com)

mentioned in commit 65876e17c7

mentioned in commit 65876e17c74fed89111b3928c9e2229ded5eb4de
Brouie commented 2026-06-29 07:52:30 +00:00 (Migrated from gitlab.com)

mentioned in merge request !953

mentioned in merge request !953
Brouie commented 2026-06-29 07:53:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #421

mentioned in issue #421
PlasticDigits commented 2026-08-17 10:26:07 +00:00 (Migrated from gitlab.com)

mentioned in issue #546

mentioned in issue #546
PlasticDigits commented 2026-08-24 03:15:17 +00:00 (Migrated from gitlab.com)

mentioned in issue #617

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