fix(pair): UpdateLimitOrderPrice same-id relink jumps FIFO at the new price #1227

Closed
opened 2026-09-11 07:35:54 +00:00 by PlasticDigits · 5 comments

Summary

ExecuteMsg::UpdateLimitOrderPrice detaches a resting limit and relinks it at the new price without minting a new order_id. Equal-price FIFO on the pair book is the composite key (price, order_id) (DLL insert via bid_before / ask_before; match walks that list). A maker who quoted a different price earlier therefore keeps a globally older id, moves onto a level other makers already occupy, and sorts ahead of those makers.

That is a price-time / FIFO violation at the destination level. Price priority across different prices is unchanged and must stay.

Closed #247 shipped price-only Edit → UpdateLimitOrderPrice with an explicit AC of “same order_id” (gas: no cancel+replace, no second maker fee, no CW20). That identity choice is the mechanism. #247 did not specify time-priority at the new level.

Closed #424 independently recorded the same fairness quirk (relink_limit_order_price keeps the original id → leapfrog) and closed the audit as docs + Reprice fuzz, not a matching-engine fix. This ticket is the matching-engine fix. Do not reopen #424. #42 QA FIFO (fifo_two_bids_same_price_older_filled_first) only covers two new placements at the same price, where id ≈ arrival-at-that-price.

Not a pool drain: escrow remaining and PENDING_ESCROW_* stay put on relink (#247 L1 / #424 reprice note). The defect is fill order among honest makers at one price.

Current codebase

  • smartcontracts/packages/dex-common/src/pair.rs — ExecuteMsg::UpdateLimitOrderPrice { order_id, price, hint_after_order_id, max_adjust_steps, … }
  • smartcontracts/contracts/pair/src/contract.rs — execute_update_limit_order_price: owner-only, pause/expiry/blacklist gates, then orderbook::relink_limit_order_price
  • smartcontracts/contracts/pair/src/orderbook.rs — relink_limit_order_price unlinks and reinserts with the same id; find_insert_bid / find_insert_ask place by (price, order_id)
  • smartcontracts/tests/src/limit_order_tests.rs — fifo_two_bids_same_price_older_filled_first (new places only); no reprice-then-match FIFO case
  • Frontend Edit (#247): updateLimitOrderPrice in frontend-dapp/src/services/terraclassic/pair.ts — product path that exercises this msg on every price-only edit
  • Docs: docs/limit-orders.md (Edit → update, same id); docs/contracts-security-audit.md (L12 id monotonicity, FIFO notes). #266 requires equal-price batch rungs to resolve ascending id — that rule is for one batch’s new ids, not for a later relink into someone else’s level.

Expected vs actual

Expected At one limit price, makers match in the order they quoted that price (arrival-at-level). Reprice onto a populated level joins the tail of that price group. A same-price no-op update must not move the node. Aggressive reprice to a better price still goes ahead of worse prices (price priority).
Actual Relink keeps order_id. Insert at the new price uses that id, so a low id lands at the head of the equal-price run and matches before makers who have been on that price longer.

Repro

Given a pair with two makers on the same side: maker A already resting at price P with order_id = A_id, and maker B resting at a different in-band price with order_id = B_id where B_id < A_id (B placed globally earlier)
When B’s owner executes UpdateLimitOrderPrice to P (valid hint / max_adjust_steps; remaining and side unchanged)
Then the book at P must match A before B on the next hybrid/book take that walks from the head of that side
And B’s remaining / PENDING_ESCROW_* are unchanged; no second maker fee; no CW20 on the update tx
And today, without a fix, B sorts before A at P because B_id < A_id

Constraints / guardrails

  • Do not reopen #247 or #424. Keep #247 gas properties: owner-only, no maker fee, no token movement, pause/expiry/blacklist unchanged, LimitInsertStepsExceeded still all-or-nothing (order not half-detached).
  • L1 escrow: relink still must not change remaining or PENDING_ESCROW_*.
  • L5 / L14: hints stay advisory; stale hint cannot corrupt sort; step budget still bounds the walk.
  • L12: new placements and batch id reservation stay contiguous / monotonic. If the fix mints a new id on reprice, consume ORDER_NEXT_ID once, never reuse, and keep batch_placement_order_ids_match_sequential_singles green. If the fix keeps the id, do not punch holes in the id space.
  • #266 equal-price batch rungs still insert in ascending id (input-index ids). Do not invert that.
  • Simulation parity (L8): simulate_match_* / indexer db_orderbook_sim must see the same FIFO after relink as execute.
  • Indexer: if order_id is kept, placements/book pages stay keyed the same; if id changes, update parse/upsert so the old row does not remain as a ghost live order.
  • Frontend: Edit may keep showing one row. If id changes, invalidate limitBookPage / limitPlacements and do not leave the ticket pointed at a canceled id.
  • Same-price update (new price == old price): must not jump to the head of the level (no-op or reinsert at the same relative slot / tail — pick one and test it).
  • Bid and ask. Ladder / batch place is out of scope except that a later UpdateLimitOrderPrice on one rung must not jump a level another maker already occupies.
  • No public mainnet griefing recipe. Tests are in-tree multi-test only.
  • Founder-required CosmWasm pair matching. First pass is advisory grok-high (below). Do not add ready from intake.

Relevant files

Path Why
smartcontracts/contracts/pair/src/orderbook.rs relink_limit_order_price, find_insert_bid / find_insert_ask, equal-price compare
smartcontracts/contracts/pair/src/contract.rs execute_update_limit_order_price
smartcontracts/packages/dex-common/src/pair.rs UpdateLimitOrderPrice msg
smartcontracts/tests/src/limit_order_tests.rs New FIFO-after-reprice tests; existing fifo_two_bids_same_price_older_filled_first must stay
Indexer orderbook ingest / db_orderbook_sim Live book + sim must not advertise the jumper as first at P if execute will not fill them first (or vice versa)
frontend-dapp/src/services/terraclassic/pair.ts + Edit ticket Only if id identity changes; otherwise docs
docs/limit-orders.md, docs/contracts-security-audit.md, docs/integrators.md Document lose-priority-on-reprice (or explicit time-at-level FIFO) vs #247 “same id”

Prefer keep order_id for cancel/edit identity (preserves #247 UX) and change insert position at equal price for relink:

  1. In relink_limit_order_price, after unlink, insert as a new arrival at that price: walk/place after every existing node with the same side + same price (tail of the equal-price run), not by comparing the preserved id. Cross-price ordering stays the existing bid/ask price sort.
  2. Equivalent formulation: positioning key for relink is (price, sentinel_last) while storage key / ORDERS map key stays the original id.
  3. Alternative (only if DLL + match actually re-sort by id on every walk): mint a fresh order_id on reprice (next_order_id / one ORDER_NEXT_ID write), leave the old id unused, emit attributes the indexer already understands for cancel+place identity. Heavier: indexer + frontend + L12 docs. Use this only if tail-insert cannot be made match-equivalent.
  4. Tests first (below). Add a Reprice op to prop_escrow_dll as #424 asked, asserting escrow + DLL integrity and equal-price FIFO after random reprices.

Do not “fix” this by charging a second maker fee or by forcing cancel+place in the dApp while the chain msg still jumps. The chain is the source of truth; any owner can call the msg.

Acceptance criteria

  • AC1. Repro above: after B reprices to A’s P, a taker that fills one maker at P fills A, not B. Remaining on B unchanged until A is gone.
  • AC2. Symmetric for asks (and bids). Both sides covered by tests.
  • AC3. New placements at the same price still FIFO by ascending order_id (fifo_two_bids_same_price_older_filled_first and the ask twin stay green).
  • AC4. Relink to a better price still sorts ahead of worse-priced resters (price priority). Relink to a worse price sorts behind better prices.
  • AC5. Relink with new_price == old_price does not move the order ahead of later same-price makers who were already behind it (no free bump).
  • AC6. Failed relink (LimitInsertStepsExceeded, expired, pause, non-owner) leaves the order linked at the old price with the same remaining (atomicity).
  • AC7. L1: PENDING_ESCROW_* and order.remaining unchanged on success. No CW20 messages on the update tx.
  • AC8. simulate_match_* + indexer sim agree with execute FIFO after relink.
  • AC9. Docs: docs/limit-orders.md states time-priority at the quoted price (reprice joins the tail). Security matrix notes the #424 quirk is closed by this behavior, not merely documented as “by design.”
  • AC10. Focused cargo test for pair orderbook / cl8y-dex-tests limit FIFO + make test-contracts (or the repo’s documented contract suite) pass.

Test plan (functional)

# Path Expect
T1 Bid: A at P, B older id at P', B → P, take 1 maker Fills A
T2 Ask: same as T1 on the ask book Fills A
T3 Two new bids same P (no reprice) Lower id first (existing test)
T4 B reprices through A’s price to a strictly better price B is new head (price priority)
T5 B reprices to a worse price than A A still ahead
T6 Three makers at P; middle one reprices away and back to P Returns at tail, not original slot
T7 Same-price “update” Does not leapfrog later same-price orders
T8 Partial fill on A then B after T1 Remaining math / escrow L1
T9 hint_after_order_id pointing at A when B joins P Still cannot place B before A at P; hint cannot invert FIFO
T10 Indexer sim / simulate_match_* on T1 book Same fill order as execute
T11 Frontend price-only Edit still one tx, no CW20, no maker fee #247 gas path; book order matches AC1 after refresh

Test plan (attack / hack / abuse)

# Vector Expect
A1 Repeat reprice P' → P → P' → P to climb a level Each arrival at P joins tail; cannot grind to head
A2 Stale / wrong-side hint_after_order_id on relink Bounded fallback; no unlink-without-relink; no insert before earlier same-price makers
A3 Tiny max_adjust_steps mid-relink Full revert; order still at old price (A6)
A4 Non-owner / paused / expired / blacklisted Reject; book unchanged
A5 Relink to MIN_LIMIT_PRICE / band edge Existing #467 / #529 / #1225 gates still apply; FIFO fix must not skip those validators
A6 Relink remaining that cannot pay cost ≥ 1 at the new price Same reject/park policy as place; do not plant an unfillable head (#1225)
A7 Id overflow if minting a new id Existing u64::MAX revert; no wrap to 0

Verification criteria

  • New unit/integration tests T1–T10 in limit_order_tests (or pair orderbook tests). Name them so fifo_*_after_update_limit_order_price is grepable.
  • Existing FIFO, batch id, escrow prop, pause, blacklist, and #247 update-price tests stay green.
  • Optional: prop_escrow_dll gains a Reprice op that never lets a repriced node sit before a same-price node that was already on that price.
  • Docs greps in docs/limit-orders.md for reprice / FIFO-at-level.
  • No live-chain placement script in the issue or the PR.

Out of scope

  • Charging a second maker fee on Edit.
  • Changing cancel+replace for amount/side/expiry (already not UpdateLimitOrderPrice).
  • Grid vault / MM bot product (#546, #597).
  • Reopening the #424 audit umbrella or #247 gas work.
  • Indexer hint API shape (#267) except sim parity.

First-pass model recommendation

Recommendation: grok-high

Rationale: CosmWasm pair matching and order-book FIFO (founder-required: contracts / wasm). The change is a protocol time-priority rule in relink_limit_order_price plus insert/match/sim/indexer agreement, not a local helper. It collides with shipped #247 “keep order_id” UX and with #266 composite-key insertion. Composer fails the contracts/wasm criterion and the “no cross-cutting state/protocol change” criterion even if the Rust edit is small. Verify with the FIFO-after-reprice tests above plus existing equal-price FIFO and escrow props — not a mainnet book walk.

## Summary `ExecuteMsg::UpdateLimitOrderPrice` detaches a resting limit and relinks it at the new price **without minting a new `order_id`**. Equal-price FIFO on the pair book is the composite key `(price, order_id)` (DLL insert via `bid_before` / `ask_before`; match walks that list). A maker who quoted a *different* price earlier therefore keeps a globally older id, moves onto a level other makers already occupy, and sorts **ahead** of those makers. That is a price-time / FIFO violation at the destination level. Price priority across *different* prices is unchanged and must stay. Closed [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) shipped price-only Edit → `UpdateLimitOrderPrice` with an explicit AC of “same `order_id`” (gas: no cancel+replace, no second maker fee, no CW20). That identity choice is the mechanism. [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) did not specify time-priority at the new level. Closed [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424) independently recorded the same fairness quirk (`relink_limit_order_price` keeps the original id → leapfrog) and closed the audit as **docs + `Reprice` fuzz**, not a matching-engine fix. This ticket **is** the matching-engine fix. Do not reopen [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424). [#42](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/42) QA FIFO (`fifo_two_bids_same_price_older_filled_first`) only covers two *new* placements at the same price, where id ≈ arrival-at-that-price. Not a pool drain: escrow `remaining` and `PENDING_ESCROW_*` stay put on relink ([#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) L1 / [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424) reprice note). The defect is fill *order* among honest makers at one price. ## Current codebase - `smartcontracts/packages/dex-common/src/pair.rs` — `ExecuteMsg::UpdateLimitOrderPrice { order_id, price, hint_after_order_id, max_adjust_steps, … }` - `smartcontracts/contracts/pair/src/contract.rs` — `execute_update_limit_order_price`: owner-only, pause/expiry/blacklist gates, then `orderbook::relink_limit_order_price` - `smartcontracts/contracts/pair/src/orderbook.rs` — `relink_limit_order_price` unlinks and reinserts with the **same** id; `find_insert_bid` / `find_insert_ask` place by `(price, order_id)` - `smartcontracts/tests/src/limit_order_tests.rs` — `fifo_two_bids_same_price_older_filled_first` (new places only); no reprice-then-match FIFO case - Frontend Edit ([#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247)): `updateLimitOrderPrice` in `frontend-dapp/src/services/terraclassic/pair.ts` — product path that exercises this msg on every price-only edit - Docs: `docs/limit-orders.md` (Edit → update, same id); `docs/contracts-security-audit.md` (L12 id monotonicity, FIFO notes). [#266](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/266) requires equal-price *batch rungs* to resolve ascending id — that rule is for one batch’s new ids, not for a later relink into someone else’s level. ### Expected vs actual | | | | --- | --- | | **Expected** | At one limit price, makers match in the order they **quoted that price** (arrival-at-level). Reprice onto a populated level joins the **tail** of that price group. A same-price no-op update must not move the node. Aggressive reprice to a *better* price still goes ahead of worse prices (price priority). | | **Actual** | Relink keeps `order_id`. Insert at the new price uses that id, so a low id lands at the **head** of the equal-price run and matches before makers who have been on that price longer. | ## Repro Given a pair with two makers on the same side: maker A already resting at price `P` with `order_id = A_id`, and maker B resting at a different in-band price with `order_id = B_id` where `B_id < A_id` (B placed globally earlier) When B’s owner executes `UpdateLimitOrderPrice` to `P` (valid hint / `max_adjust_steps`; remaining and side unchanged) Then the book at `P` must match A before B on the next hybrid/book take that walks from the head of that side And B’s `remaining` / `PENDING_ESCROW_*` are unchanged; no second maker fee; no CW20 on the update tx And today, without a fix, B sorts before A at `P` because `B_id < A_id` ## Constraints / guardrails - Do not reopen [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) or [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424). Keep [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) gas properties: owner-only, no maker fee, no token movement, pause/expiry/blacklist unchanged, `LimitInsertStepsExceeded` still all-or-nothing (order not half-detached). - L1 escrow: relink still must not change `remaining` or `PENDING_ESCROW_*`. - L5 / L14: hints stay advisory; stale hint cannot corrupt sort; step budget still bounds the walk. - L12: new placements and batch id reservation stay contiguous / monotonic. If the fix mints a **new** id on reprice, consume `ORDER_NEXT_ID` once, never reuse, and keep `batch_placement_order_ids_match_sequential_singles` green. If the fix keeps the id, do not punch holes in the id space. - [#266](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/266) equal-price **batch** rungs still insert in ascending id (input-index ids). Do not invert that. - Simulation parity (L8): `simulate_match_*` / indexer `db_orderbook_sim` must see the same FIFO after relink as execute. - Indexer: if `order_id` is kept, placements/book pages stay keyed the same; if id changes, update parse/upsert so the old row does not remain as a ghost live order. - Frontend: Edit may keep showing one row. If id changes, invalidate `limitBookPage` / `limitPlacements` and do not leave the ticket pointed at a canceled id. - Same-price update (new price == old price): must not jump to the head of the level (no-op or reinsert at the same relative slot / tail — pick one and test it). - Bid **and** ask. Ladder / batch place is out of scope except that a later `UpdateLimitOrderPrice` on one rung must not jump a level another maker already occupies. - No public mainnet griefing recipe. Tests are in-tree multi-test only. - Founder-required CosmWasm pair matching. First pass is advisory `grok-high` (below). Do not add `ready` from intake. ## Relevant files | Path | Why | | --- | --- | | `smartcontracts/contracts/pair/src/orderbook.rs` | `relink_limit_order_price`, `find_insert_bid` / `find_insert_ask`, equal-price compare | | `smartcontracts/contracts/pair/src/contract.rs` | `execute_update_limit_order_price` | | `smartcontracts/packages/dex-common/src/pair.rs` | `UpdateLimitOrderPrice` msg | | `smartcontracts/tests/src/limit_order_tests.rs` | New FIFO-after-reprice tests; existing `fifo_two_bids_same_price_older_filled_first` must stay | | Indexer orderbook ingest / `db_orderbook_sim` | Live book + sim must not advertise the jumper as first at `P` if execute will not fill them first (or vice versa) | | `frontend-dapp/src/services/terraclassic/pair.ts` + Edit ticket | Only if id identity changes; otherwise docs | | `docs/limit-orders.md`, `docs/contracts-security-audit.md`, `docs/integrators.md` | Document lose-priority-on-reprice (or explicit time-at-level FIFO) vs [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) “same id” | ## Recommended direction Prefer **keep `order_id` for cancel/edit identity** (preserves [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) UX) and change **insert position at equal price for relink**: 1. In `relink_limit_order_price`, after unlink, insert as a **new arrival at that price**: walk/place after every existing node with the same side + same price (tail of the equal-price run), not by comparing the preserved id. Cross-price ordering stays the existing bid/ask price sort. 2. Equivalent formulation: positioning key for relink is `(price, sentinel_last)` while storage key / `ORDERS` map key stays the original id. 3. Alternative (only if DLL + match actually re-sort by id on every walk): mint a fresh `order_id` on reprice (`next_order_id` / one `ORDER_NEXT_ID` write), leave the old id unused, emit attributes the indexer already understands for cancel+place identity. Heavier: indexer + frontend + L12 docs. Use this only if tail-insert cannot be made match-equivalent. 4. Tests first (below). Add a `Reprice` op to `prop_escrow_dll` as [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424) asked, asserting escrow + DLL integrity **and** equal-price FIFO after random reprices. Do not “fix” this by charging a second maker fee or by forcing cancel+place in the dApp while the chain msg still jumps. The chain is the source of truth; any owner can call the msg. ## Acceptance criteria - AC1. Repro above: after B reprices to A’s `P`, a taker that fills one maker at `P` fills **A**, not B. Remaining on B unchanged until A is gone. - AC2. Symmetric for asks (and bids). Both sides covered by tests. - AC3. New placements at the same price still FIFO by ascending `order_id` (`fifo_two_bids_same_price_older_filled_first` and the ask twin stay green). - AC4. Relink to a **better** price still sorts ahead of worse-priced resters (price priority). Relink to a **worse** price sorts behind better prices. - AC5. Relink with `new_price == old_price` does not move the order ahead of later same-price makers who were already behind it (no free bump). - AC6. Failed relink (`LimitInsertStepsExceeded`, expired, pause, non-owner) leaves the order linked at the **old** price with the same remaining (atomicity). - AC7. L1: `PENDING_ESCROW_*` and `order.remaining` unchanged on success. No CW20 messages on the update tx. - AC8. `simulate_match_*` + indexer sim agree with execute FIFO after relink. - AC9. Docs: `docs/limit-orders.md` states time-priority **at the quoted price** (reprice joins the tail). Security matrix notes the [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424) quirk is closed by this behavior, not merely documented as “by design.” - AC10. Focused `cargo test` for pair orderbook / `cl8y-dex-tests` limit FIFO + `make test-contracts` (or the repo’s documented contract suite) pass. ## Test plan (functional) | # | Path | Expect | | --- | --- | --- | | T1 | Bid: A at `P`, B older id at `P'`, B → `P`, take 1 maker | Fills A | | T2 | Ask: same as T1 on the ask book | Fills A | | T3 | Two new bids same `P` (no reprice) | Lower id first (existing test) | | T4 | B reprices **through** A’s price to a strictly better price | B is new head (price priority) | | T5 | B reprices to a worse price than A | A still ahead | | T6 | Three makers at `P`; middle one reprices away and back to `P` | Returns at tail, not original slot | | T7 | Same-price “update” | Does not leapfrog later same-price orders | | T8 | Partial fill on A then B after T1 | Remaining math / escrow L1 | | T9 | `hint_after_order_id` pointing at A when B joins `P` | Still cannot place B *before* A at `P`; hint cannot invert FIFO | | T10 | Indexer sim / `simulate_match_*` on T1 book | Same fill order as execute | | T11 | Frontend price-only Edit still one tx, no CW20, no maker fee | [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) gas path; book order matches AC1 after refresh | ## Test plan (attack / hack / abuse) | # | Vector | Expect | | --- | --- | --- | | A1 | Repeat reprice `P' → P → P' → P` to climb a level | Each arrival at `P` joins tail; cannot grind to head | | A2 | Stale / wrong-side `hint_after_order_id` on relink | Bounded fallback; no unlink-without-relink; no insert before earlier same-price makers | | A3 | Tiny `max_adjust_steps` mid-relink | Full revert; order still at old price (A6) | | A4 | Non-owner / paused / expired / blacklisted | Reject; book unchanged | | A5 | Relink to `MIN_LIMIT_PRICE` / band edge | Existing [#467](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/467) / [#529](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/529) / [#1225](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1225) gates still apply; FIFO fix must not skip those validators | | A6 | Relink remaining that cannot pay `cost ≥ 1` at the new price | Same reject/park policy as place; do not plant an unfillable head ([#1225](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1225)) | | A7 | Id overflow if minting a new id | Existing `u64::MAX` revert; no wrap to 0 | ## Verification criteria - New unit/integration tests T1–T10 in `limit_order_tests` (or pair `orderbook` tests). Name them so `fifo_*_after_update_limit_order_price` is grepable. - Existing FIFO, batch id, escrow prop, pause, blacklist, and [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) update-price tests stay green. - Optional: `prop_escrow_dll` gains a `Reprice` op that never lets a repriced node sit before a same-price node that was already on that price. - Docs greps in `docs/limit-orders.md` for reprice / FIFO-at-level. - No live-chain placement script in the issue or the PR. ## Out of scope - Charging a second maker fee on Edit. - Changing cancel+replace for amount/side/expiry (already not `UpdateLimitOrderPrice`). - Grid vault / MM bot product ([#546](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/546), [#597](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/597)). - Reopening the [#424](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/424) audit umbrella or [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) gas work. - Indexer hint API shape ([#267](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/267)) except sim parity. ## First-pass model recommendation Recommendation: grok-high Rationale: CosmWasm pair matching and order-book FIFO (founder-required: contracts / wasm). The change is a protocol time-priority rule in `relink_limit_order_price` plus insert/match/sim/indexer agreement, not a local helper. It collides with shipped [#247](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/247) “keep `order_id`” UX and with [#266](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/266) composite-key insertion. Composer fails the contracts/wasm criterion and the “no cross-cutting state/protocol change” criterion even if the Rust edit is small. Verify with the FIFO-after-reprice tests above plus existing equal-price FIFO and escrow props — not a mainnet book walk.
Author
Owner

cl8y-agent-control: queued implement job e10fc52c-42fb-4d75-8b0e-154779c3a954 (not executed; no Hetzner VM).

cl8y-agent-control: queued `implement` job `e10fc52c-42fb-4d75-8b0e-154779c3a954` (not executed; no Hetzner VM).
Author
Owner

Merged onto origin/main via #1235. Pair + docs steps of make verify-issue-1227 were 8/8. Relink joins the equal-price FIFO tail (RELINK_EQUAL_PRICE_SORT_ID); indexer snapshot stores walk_index.

Problems:

  1. Indexer step auto-ran because indexer/.env exists (VERIFY1227_INDEXER is optional; presence of .env also enables it). Postgres timed out on resting_book_walk_index_preserves_reprice_fifo. That is host DB reachability, not a missing FIFO fix. Re-run with reachable Postgres, or without .env to skip.
  2. Coolify/indexer must apply indexer/migrations/20260911120000_resting_orders_walk_index.sql or live db_orderbook_sim can disagree with execute after reprice.
  3. Pair wasm store+migrate is still ops (columbus-5 listed pairs still cw2 1.15.0 until that lands). Bundled with #1230 / #1231 pair leftover in a new ops issue. Not #1232.

CI: Woodpecker did not post live statuses; merge used local gitleaks + Forgejo status.

Merged onto `origin/main` via #1235. Pair + docs steps of `make verify-issue-1227` were 8/8. Relink joins the equal-price FIFO tail (`RELINK_EQUAL_PRICE_SORT_ID`); indexer snapshot stores `walk_index`. Problems: 1. Indexer step auto-ran because `indexer/.env` exists (`VERIFY1227_INDEXER` is optional; presence of `.env` also enables it). Postgres timed out on `resting_book_walk_index_preserves_reprice_fifo`. That is host DB reachability, not a missing FIFO fix. Re-run with reachable Postgres, or without `.env` to skip. 2. Coolify/indexer must apply `indexer/migrations/20260911120000_resting_orders_walk_index.sql` or live `db_orderbook_sim` can disagree with execute after reprice. 3. Pair wasm store+migrate is still ops (columbus-5 listed pairs still cw2 **1.15.0** until that lands). Bundled with #1230 / #1231 pair leftover in a new ops issue. Not #1232. CI: Woodpecker did not post live statuses; merge used local gitleaks + Forgejo status.
Author
Owner

Follow-up ops ticket: #1246. Woodpecker enablement: #1247.

Follow-up ops ticket: #1246. Woodpecker enablement: #1247.
Author
Owner

columbus-5 wasm for this ticket is not live. Ops tracker: #1246.

Live pairs are 11639 / 1.16.0 (#712). LCD HybridSimulation belief_price: "0" still 200 (same output as omitted belief) — #1230 / #1227 / #1231 execute/query wasm still needs a 1.17.0 store+migrate (git CONTRACT_VERSION is still 1.15.0). Tax listed pin is 11630 (not 11611/11619); ALPHA terra1x6e64… is 1.0.0 and needs a tax cw2 bump + CMM migrate for #1228 / #1237.

columbus-5 wasm for this ticket is **not** live. Ops tracker: [#1246](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1246). Live pairs are **11639 / 1.16.0** (#712). LCD `HybridSimulation` `belief_price: "0"` still **200** (same output as omitted belief) — #1230 / #1227 / #1231 execute/query wasm still needs a **1.17.0** store+migrate (git `CONTRACT_VERSION` is still 1.15.0). Tax listed pin is **11630** (not 11611/11619); ALPHA `terra1x6e64…` is 1.0.0 and needs a tax cw2 bump + CMM migrate for #1228 / #1237.
Author
Owner

columbus-5 pair wasm is live: 11664 / cw2 1.17.0 (store DB35943A4925059E770A63C9ADDF35622696088A4DFFC8A91110466034995961). Factory pair_code_id=11664, GetPairCount=20. LCD UST1/cUSTC HybridSimulation belief_price:"0" → Invalid belief_price 0. Ops #1246.

columbus-5 pair wasm is live: **11664 / cw2 1.17.0** (store `DB35943A4925059E770A63C9ADDF35622696088A4DFFC8A91110466034995961`). Factory `pair_code_id=11664`, `GetPairCount=20`. LCD UST1/cUSTC `HybridSimulation` `belief_price:"0"` → `Invalid belief_price 0`. Ops [#1246](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1246).
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#1227
No description provided.