feat(#331): emit swap_index on limit_order_fill wasm events #817

Merged
PlasticDigits merged 1 commit from cursor/gitlab-issue-workflow-ed71 into main 2026-06-05 14:27:13 +00:00
PlasticDigits commented 2026-06-05 14:07:02 +00:00 (Migrated from gitlab.com)

Summary

Implements https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/331 (follow-up to #316).

  • Pair contract: Per-transaction swap ordinal (tx_swap_index) stamps swap_index on each limit_order_fill wasm event during hybrid execute_swap, so LCD replay can attribute fills without parser walk-order heuristics.
  • Indexer: parse_limit_order_fills prefers on-chain swap_index when present; legacy txs without the attr still use walk-order inference (#316).
  • Docs: limit-orders, integrators-hybrid-volume, indexer-invariants, contracts-security-audit (L10), agent skill.

Acceptance checklist

Criterion Verification Result
Every hybrid limit_order_fill includes swap_index matching parent swap ordinal cargo test -p cl8y-dex-tests hybrid_swap_emits_limit_order_fill PASS
Indexer prefers on-chain swap_index; inference for legacy cargo test --lib parse_limit_order_fills (incl. prefers_on_chain_swap_index_attr) PASS
limit_fill_swap_linkage extended cargo test --test limit_fill_swap_linkage (needs Postgres) SKIP (no test DB on agent VM)
make test-contracts green subset run on agent; full suite in CI PASS (subset)
Integrator / audit docs updated doc diff in MR PASS
Grep: fill events include swap_index tx_swap_index::stamp_swap_index_on_fill_events PASS
Manual LocalTerra LCD not run on agent VM SKIP

Verification for reviewers

cargo test -p cl8y-dex-tests hybrid_swap_emits_limit_order_fill
cargo test -p cl8y-dex-pair --lib
cd indexer && cargo test --lib parse_limit_order_fills
# with Postgres:
cd indexer && cargo test --test limit_fill_swap_linkage

After deploy: hybrid swap on LocalTerra → LCD tx query should show swap_index on limit_order_fill wasm attrs.

Issue stays open until MR merge + deploy verification.


Note

Medium Risk
Pair wasm adds new storage and changes emitted event attrs (requires deploy for on-chain benefit); indexer/parser changes are backward compatible. No auth or fund-movement logic changes, but incorrect ordinals could mis-link fills to swaps until fixed.

Overview
Hybrid execute_swap now assigns a per-transaction, per-pair 0-based swap_index (scoped by block height + tx index) and stamps it on each limit_order_fill wasm event, so multi-swap txs on the same pair can link fills to the correct parent swap without relying on parser walk order alone (#331, follow-up to #316).

The pair adds tx_swap_index storage (TX_SWAP_SCOPE / TX_SWAP_COUNTER) and wires current_tx_swap_index, stamp_swap_index_on_fill_events, and advance_tx_swap_index into hybrid swap execution. The indexer parses optional on-chain swap_index on fills (segment and columnar paths) and prefers it over inferred ordinals when resolving swap_event_id; legacy txs without the attr keep #316 behavior.

Docs/skills (L10, limit fills, integrator hybrid volume) and tests (parser unit test, contract assertion on swap_index, linkage integration test) are updated accordingly.

Reviewed by Cursor Bugbot for commit b6c3cae169. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Implements https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/331 (follow-up to #316). - **Pair contract:** Per-transaction swap ordinal (`tx_swap_index`) stamps `swap_index` on each `limit_order_fill` wasm event during hybrid `execute_swap`, so LCD replay can attribute fills without parser walk-order heuristics. - **Indexer:** `parse_limit_order_fills` prefers on-chain `swap_index` when present; legacy txs without the attr still use walk-order inference (#316). - **Docs:** limit-orders, integrators-hybrid-volume, indexer-invariants, contracts-security-audit (L10), agent skill. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Every hybrid `limit_order_fill` includes `swap_index` matching parent swap ordinal | `cargo test -p cl8y-dex-tests hybrid_swap_emits_limit_order_fill` | PASS | | Indexer prefers on-chain `swap_index`; inference for legacy | `cargo test --lib parse_limit_order_fills` (incl. `prefers_on_chain_swap_index_attr`) | PASS | | `limit_fill_swap_linkage` extended | `cargo test --test limit_fill_swap_linkage` (needs Postgres) | SKIP (no test DB on agent VM) | | `make test-contracts` green | subset run on agent; full suite in CI | PASS (subset) | | Integrator / audit docs updated | doc diff in MR | PASS | | Grep: fill events include `swap_index` | `tx_swap_index::stamp_swap_index_on_fill_events` | PASS | | Manual LocalTerra LCD | not run on agent VM | SKIP | ## Verification for reviewers ```bash cargo test -p cl8y-dex-tests hybrid_swap_emits_limit_order_fill cargo test -p cl8y-dex-pair --lib cd indexer && cargo test --lib parse_limit_order_fills # with Postgres: cd indexer && cargo test --test limit_fill_swap_linkage ``` After deploy: hybrid swap on LocalTerra → LCD tx query should show `swap_index` on `limit_order_fill` wasm attrs. Issue stays **open** until MR merge + deploy verification. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Pair wasm adds new storage and changes emitted event attrs (requires deploy for on-chain benefit); indexer/parser changes are backward compatible. No auth or fund-movement logic changes, but incorrect ordinals could mis-link fills to swaps until fixed. > > **Overview** > Hybrid **`execute_swap`** now assigns a per-transaction, per-pair **0-based `swap_index`** (scoped by block height + tx index) and stamps it on each **`limit_order_fill`** wasm event, so multi-swap txs on the same pair can link fills to the correct parent swap without relying on parser walk order alone ([#331](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/331), follow-up to #316). > > The pair adds **`tx_swap_index`** storage (`TX_SWAP_SCOPE` / `TX_SWAP_COUNTER`) and wires **`current_tx_swap_index`**, **`stamp_swap_index_on_fill_events`**, and **`advance_tx_swap_index`** into hybrid swap execution. The **indexer** parses optional on-chain **`swap_index`** on fills (segment and columnar paths) and **prefers it** over inferred ordinals when resolving **`swap_event_id`**; legacy txs without the attr keep #316 behavior. > > **Docs/skills** (L10, limit fills, integrator hybrid volume) and **tests** (parser unit test, contract assertion on `swap_index`, linkage integration test) are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b6c3cae16914356aad3f22ae7b81debc7d8fe500. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-05 14:07:09 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 14:07:09 +00:00 (Migrated from gitlab.com)

mentioned in issue #331

mentioned in issue #331
ghost1 commented 2026-06-05 14:07:14 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 14:07:24 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 14:08:55 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: b6c3cae16914356aad3f22ae7b81debc7d8fe500
Scope: Pair tx_swap_index state + execute_swap event stamping; indexer parse_limit_order_fills preference for on-chain swap_index; docs/tests only elsewhere.

Outcome: FINDINGS: 0 medium+ — Security review: no medium+ findings on this diff.

Summary

This MR adds deterministic per-tx swap ordinals on limit_order_fill wasm events and teaches the indexer to prefer the on-chain swap_index attribute when present. Review focused on injection, authn/authz, permission boundaries, and whether attacker-controlled input reaches a sensitive sink.

Pair contract (tx_swap_index.rs, contract.rs)

  • swap_index is derived from internal TX_SWAP_SCOPE / TX_SWAP_COUNTER state keyed by (block.height, tx.index) — not from user-supplied execute args.
  • Counter advances only on successful execute_swap completion (after book match, pool leg, and invariants), before hook submessages run — consistent with multi-swap-in-one-tx ordering.
  • No fund-movement, access-control, or hook semantics changes.

Indexer (parser.rs)

  • On-chain swap_index is parsed as i32 and used only to resolve optional swap_event_id via parameterized SQL (swap_id_for_tx_pair_index) — no injection surface.
  • Forged limit_order_fill / swap_index attrs cannot attribute rows to a victim pair: emitter scoping remains _contract_address-only (GitLab #285; existing tests unchanged). A malicious contract can only affect indexer rows scoped to its own address.
  • swap_event_id is off-chain linkage metadata (API/CSV); mis-linkage does not affect on-chain balances, trading gates, or auth.

Inline threads: none (no medium+ findings).

## Security review **Commit reviewed:** `b6c3cae16914356aad3f22ae7b81debc7d8fe500` **Scope:** Pair `tx_swap_index` state + `execute_swap` event stamping; indexer `parse_limit_order_fills` preference for on-chain `swap_index`; docs/tests only elsewhere. **Outcome:** `FINDINGS: 0` medium+ — **Security review: no medium+ findings on this diff.** ### Summary This MR adds deterministic per-tx swap ordinals on `limit_order_fill` wasm events and teaches the indexer to prefer the on-chain `swap_index` attribute when present. Review focused on injection, authn/authz, permission boundaries, and whether attacker-controlled input reaches a sensitive sink. **Pair contract (`tx_swap_index.rs`, `contract.rs`)** - `swap_index` is derived from internal `TX_SWAP_SCOPE` / `TX_SWAP_COUNTER` state keyed by `(block.height, tx.index)` — not from user-supplied execute args. - Counter advances only on successful `execute_swap` completion (after book match, pool leg, and invariants), before hook submessages run — consistent with multi-swap-in-one-tx ordering. - No fund-movement, access-control, or hook semantics changes. **Indexer (`parser.rs`)** - On-chain `swap_index` is parsed as `i32` and used only to resolve optional `swap_event_id` via parameterized SQL (`swap_id_for_tx_pair_index`) — no injection surface. - Forged `limit_order_fill` / `swap_index` attrs cannot attribute rows to a victim pair: emitter scoping remains `_contract_address`-only (GitLab #285; existing tests unchanged). A malicious contract can only affect indexer rows scoped to its own address. - `swap_event_id` is off-chain linkage metadata (API/CSV); mis-linkage does not affect on-chain balances, trading gates, or auth. **Inline threads:** none (no medium+ findings).
PlasticDigits (Migrated from gitlab.com) merged commit 13be1a3398 into main 2026-06-05 14:27:14 +00:00
PlasticDigits commented 2026-06-05 14:27:15 +00:00 (Migrated from gitlab.com)

mentioned in commit 13be1a3398

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

mentioned in commit 91e3c83823

mentioned in commit 91e3c838235639bc1552970e7afaa5bca7262bdc
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 21f6eb6ada

mentioned in commit 21f6eb6ada6ea0d62108b565591dab3c07546194
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 21f6eb6ada

mentioned in commit 21f6eb6ada6ea0d62108b565591dab3c07546194
Sign in to join this conversation.
No reviewers
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!817
No description provided.