Contracts: HybridSimulation CL8Y fee discount parity with execute path (H1) #238

Closed
opened 2026-05-31 04:41:18 +00:00 by PlasticDigits · 15 comments
PlasticDigits commented 2026-05-31 04:41:18 +00:00 (Migrated from gitlab.com)

Reference

Gap analysis: gaps/GAP_1780200149.md — finding H1.

Current codebase

The pair contract applies CL8Y fee-tier discounts on execute via effective_fee_bps_with_discount_msgs (smartcontracts/contracts/pair/src/contract.rs:45-86), querying the fee-discount registry and reducing fee_bps by discount_bps.

HybridSimulation / simulate_hybrid_swap (contract.rs:1890-2000) uses fee_config.fee_bps only (line 1924) — no discount lookup. Limit placement already reuses the shared helper (limit_placement.rs:17-89).

The router's multi-hop simulation calls pair HybridSimulation (router/src/contract.rs:426+), so off-chain quotes and indexer route solver inherit the same gap.

Why this is needed

Integrators, the frontend route solver, and ADR-0001 hybrid quoting assume simulation matches execution. Discounted CL8Y holders see under-quoted output in sims while execution applies lower fees → failed txs (min_receive too high) or misleading UX. This breaks quote=execution trust for hybrid-as-default retail UX.

Constraints / guardrails

  • Simulation must remain a read-only query — no state changes from discount deregister side-effects in sim (execute path may emit deregister msgs; sim should mirror fee math only).
  • Preserve backward-compatible HybridSimulationResponse schema.
  • Match execute-path rounding (pool-favorable ceil_div, book commission math).
  • If GetDiscount fails (Err), execute charges full fee — sim must match that fallback.
  • Requires trader / sender in sim query if discount is wallet-specific — audit all callers (router sim, indexer LCD queries, frontend).
  • Wasm gas for sim queries must stay bounded.

Relevant files

Path Role
smartcontracts/contracts/pair/src/contract.rs effective_fee_bps_with_discount_msgs, simulate_hybrid_swap, execute swap discount
smartcontracts/contracts/pair/src/limit_placement.rs Reference implementation using shared helper
smartcontracts/contracts/router/src/contract.rs Multi-hop sim via HybridSimulation
smartcontracts/packages/dex-common/src/pair.rs HybridSimulation query msg + response types
smartcontracts/tests/src/limit_order_tests.rs Existing hybrid sim tests
smartcontracts/tests/src/lib.rs Broad integration coverage
docs/adr/0001-hybrid-quoting-and-routing.md Quoting ADR

Route simulate_hybrid_swap through effective_fee_bps_with_discount_msgs (or a sim-safe variant that returns effective bps without emitting msgs). Add optional trader: Option<String> to HybridSimulation query if not already plumbed — default to full fee when absent (document for integrators).

Consolidate the duplicated discount lookup (noted in gap doc §2.3) to prevent future sim/execute drift.

Acceptance criteria

  • HybridSimulation output matches executed swap output for a discounted trader (same block snapshot).
  • Undiscounted trader: sim unchanged from current behavior.
  • Registry query failure: sim uses full fee_bps (matches execute).
  • Book leg and pool leg both use discounted effective fee.
  • Router multi-hop sim reflects per-hop discount when trader provided.
  • ADR/docs updated if query shape changes.

Test plan — all paths

Path Test
Zero discount tier Sim == execute output
25% / 50% / max tier discount Sim == execute for pool-only, book-only, hybrid split
No registry configured Full fee in sim
Registry Err (mock failing registry) Full fee in sim and execute
needs_deregister trader Execute emits deregister; sim fee still correct
Zero input Zero output (unchanged)
Hybrid split mismatch Error (unchanged)

Add dedicated test in limit_order_tests.rs or lib.rs comparing sim vs execute with registered discount wallet.

Run: make test-contracts

Test plan — attack / abuse vectors

Vector Expected
Spoofed trader in sim query Sim reflects that wallet's tier only (informational; no funds at risk)
Expired registration epoch Full fee after deregister on execute; sim should match pre-deregister snapshot
Discount > 10000 bps (invalid) Saturating math; no underflow

Verification criteria

  • New integration test: sim vs execute within same block for discounted trader.
  • make test-contracts green.
  • Indexer route-solve quotes (if passing trader) align with on-chain execution in local E2E smoke.
## Reference Gap analysis: [`gaps/GAP_1780200149.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/gaps/GAP_1780200149.md) — finding **H1**. ## Current codebase The pair contract applies CL8Y fee-tier discounts on **execute** via `effective_fee_bps_with_discount_msgs` (`smartcontracts/contracts/pair/src/contract.rs:45-86`), querying the fee-discount registry and reducing `fee_bps` by `discount_bps`. `HybridSimulation` / `simulate_hybrid_swap` (`contract.rs:1890-2000`) uses **`fee_config.fee_bps` only** (line 1924) — no discount lookup. Limit placement already reuses the shared helper (`limit_placement.rs:17-89`). The router's multi-hop simulation calls pair `HybridSimulation` (`router/src/contract.rs:426+`), so off-chain quotes and indexer route solver inherit the same gap. ## Why this is needed Integrators, the frontend route solver, and ADR-0001 hybrid quoting assume simulation matches execution. Discounted CL8Y holders see **under-quoted output** in sims while execution applies lower fees → failed txs (min_receive too high) or misleading UX. This breaks quote=execution trust for hybrid-as-default retail UX. ## Constraints / guardrails - Simulation must remain a **read-only query** — no state changes from discount deregister side-effects in sim (execute path may emit deregister msgs; sim should mirror fee math only). - Preserve backward-compatible `HybridSimulationResponse` schema. - Match execute-path rounding (pool-favorable `ceil_div`, book commission math). - If `GetDiscount` fails (`Err`), execute charges full fee — sim must match that fallback. - Requires `trader` / `sender` in sim query if discount is wallet-specific — audit all callers (router sim, indexer LCD queries, frontend). - Wasm gas for sim queries must stay bounded. ## Relevant files | Path | Role | |------|------| | `smartcontracts/contracts/pair/src/contract.rs` | `effective_fee_bps_with_discount_msgs`, `simulate_hybrid_swap`, execute swap discount | | `smartcontracts/contracts/pair/src/limit_placement.rs` | Reference implementation using shared helper | | `smartcontracts/contracts/router/src/contract.rs` | Multi-hop sim via `HybridSimulation` | | `smartcontracts/packages/dex-common/src/pair.rs` | `HybridSimulation` query msg + response types | | `smartcontracts/tests/src/limit_order_tests.rs` | Existing hybrid sim tests | | `smartcontracts/tests/src/lib.rs` | Broad integration coverage | | `docs/adr/0001-hybrid-quoting-and-routing.md` | Quoting ADR | ## Recommended direction Route `simulate_hybrid_swap` through `effective_fee_bps_with_discount_msgs` (or a sim-safe variant that returns effective bps without emitting msgs). Add optional `trader: Option<String>` to `HybridSimulation` query if not already plumbed — default to full fee when absent (document for integrators). Consolidate the duplicated discount lookup (noted in gap doc §2.3) to prevent future sim/execute drift. ## Acceptance criteria - [ ] `HybridSimulation` output matches executed swap output for a discounted trader (same block snapshot). - [ ] Undiscounted trader: sim unchanged from current behavior. - [ ] Registry query failure: sim uses full `fee_bps` (matches execute). - [ ] Book leg and pool leg both use discounted effective fee. - [ ] Router multi-hop sim reflects per-hop discount when `trader` provided. - [ ] ADR/docs updated if query shape changes. ## Test plan — all paths | Path | Test | |------|------| | Zero discount tier | Sim == execute output | | 25% / 50% / max tier discount | Sim == execute for pool-only, book-only, hybrid split | | No registry configured | Full fee in sim | | Registry `Err` (mock failing registry) | Full fee in sim and execute | | `needs_deregister` trader | Execute emits deregister; sim fee still correct | | Zero input | Zero output (unchanged) | | Hybrid split mismatch | Error (unchanged) | Add dedicated test in `limit_order_tests.rs` or `lib.rs` comparing sim vs execute with registered discount wallet. Run: `make test-contracts` ## Test plan — attack / abuse vectors | Vector | Expected | |--------|----------| | Spoofed `trader` in sim query | Sim reflects that wallet's tier only (informational; no funds at risk) | | Expired registration epoch | Full fee after deregister on execute; sim should match pre-deregister snapshot | | Discount > 10000 bps (invalid) | Saturating math; no underflow | ## Verification criteria - [ ] New integration test: sim vs execute within same block for discounted trader. - [ ] `make test-contracts` green. - [ ] Indexer route-solve quotes (if passing trader) align with on-chain execution in local E2E smoke.
PlasticDigits commented 2026-05-31 04:52:16 +00:00 (Migrated from gitlab.com)

mentioned in commit 3adf2b43d2

mentioned in commit 3adf2b43d287a98dc8dbf19d8e0141e96875b9ea
PlasticDigits commented 2026-05-31 04:52:24 +00:00 (Migrated from gitlab.com)

Implementation complete (pushed to main @ 3adf2b4)

Summary: HybridSimulation / HybridReverseSimulation now apply CL8Y fee-tier discounts via the same shared lookup as execute (lookup_effective_fee_bps). Sim queries are read-only (no deregister side-effects). Optional trader / sender fields were added to pair hybrid sim queries and router SimulateSwapOperations / ReverseSimulateSwapOperations. Omit trader for backward-compatible full-fee quotes.

Code: consolidated execute + limit-placement + sim discount math in pair/src/contract.rs; helpers in dex_common::pair (hybrid_simulation_with_trader, hybrid_simulation_undiscounted, etc.).

Docs / skills: L8 invariant updated (docs/contracts-security-audit.md), ADR 0001, integrators, contracts reference; cross-linked skills/AGENTS_HYBRID_QUOTING.md and skills/AGENTS_FEE_DISCOUNT_TIERS.md. Frontend simulateHybridSwap accepts optional { trader, sender }.

Tests: new limit_order_tests::hybrid_simulation_matches_execute_with_fee_discount (pool-only, book-only, hybrid split). make test-contracts — 312 pass; place_limit_insert_steps_exceeded still fails on main (pre-existing, unrelated).


QA verification checklist

  • HybridSimulation with registered discount wallet + trader set: output matches executed swap on same snapshot (pool-only, book-only, hybrid split)
  • HybridSimulation without trader: unchanged full-fee behavior
  • Registry query failure / no registry: sim uses full fee_bps (matches execute)
  • Book leg commission uses discounted effective fee when trader provided
  • Router SimulateSwapOperations with trader: multi-hop output reflects per-hop discount
  • HybridReverseSimulation with trader: reverse offer amount consistent with forward discounted fees
  • cargo test -p cl8y-dex-tests hybrid_simulation_matches_execute_with_fee_discount green
  • Frontend preflight: pass connected wallet as trader on hybrid_simulation for tier holders (follow-up wiring if not yet in UI)
  • Indexer route-solve: pass trader through LCD hybrid_simulation when wallet known (follow-up if not yet wired)

Request: @qa team / QA agents — please run the checklist above on localnet or staging and confirm quote=execution for discounted traders before closing this issue.

## Implementation complete (pushed to `main` @ 3adf2b4) **Summary:** `HybridSimulation` / `HybridReverseSimulation` now apply CL8Y fee-tier discounts via the same shared lookup as execute (`lookup_effective_fee_bps`). Sim queries are read-only (no deregister side-effects). Optional `trader` / `sender` fields were added to pair hybrid sim queries and router `SimulateSwapOperations` / `ReverseSimulateSwapOperations`. Omit `trader` for backward-compatible full-fee quotes. **Code:** consolidated execute + limit-placement + sim discount math in `pair/src/contract.rs`; helpers in `dex_common::pair` (`hybrid_simulation_with_trader`, `hybrid_simulation_undiscounted`, etc.). **Docs / skills:** L8 invariant updated (`docs/contracts-security-audit.md`), ADR 0001, integrators, contracts reference; cross-linked `skills/AGENTS_HYBRID_QUOTING.md` and `skills/AGENTS_FEE_DISCOUNT_TIERS.md`. Frontend `simulateHybridSwap` accepts optional `{ trader, sender }`. **Tests:** new `limit_order_tests::hybrid_simulation_matches_execute_with_fee_discount` (pool-only, book-only, hybrid split). `make test-contracts` — 312 pass; `place_limit_insert_steps_exceeded` still fails on main (pre-existing, unrelated). --- ### QA verification checklist - [ ] `HybridSimulation` with registered discount wallet + `trader` set: output matches executed swap on same snapshot (pool-only, book-only, hybrid split) - [ ] `HybridSimulation` without `trader`: unchanged full-fee behavior - [ ] Registry query failure / no registry: sim uses full `fee_bps` (matches execute) - [ ] Book leg commission uses discounted effective fee when `trader` provided - [ ] Router `SimulateSwapOperations` with `trader`: multi-hop output reflects per-hop discount - [ ] `HybridReverseSimulation` with `trader`: reverse offer amount consistent with forward discounted fees - [ ] `cargo test -p cl8y-dex-tests hybrid_simulation_matches_execute_with_fee_discount` green - [ ] Frontend preflight: pass connected wallet as `trader` on `hybrid_simulation` for tier holders (follow-up wiring if not yet in UI) - [ ] Indexer route-solve: pass `trader` through LCD `hybrid_simulation` when wallet known (follow-up if not yet wired) --- **Request:** @qa team / QA agents — please run the checklist above on localnet or staging and confirm quote=execution for discounted traders before closing this issue.
PlasticDigits commented 2026-05-31 04:53:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #245

mentioned in issue #245
PlasticDigits commented 2026-05-31 06:57:02 +00:00 (Migrated from gitlab.com)

Verification report (agent, 2026-05-31)

Verified GitLab #238 on branch verify/issue-238 (worktree) against origin/main.

Contract implementation (already on main — 3adf2b4)

  • simulate_hybrid_swap uses effective_fee_bps_for_sim (shared lookup_effective_fee_bps with execute; no deregister side-effects in queries).
  • Pool and book legs both receive discounted effective_fee_bps.
  • HybridSimulation / HybridReverseSimulation accept optional trader / sender; omit → full fee_bps.
  • Router SimulateSwapOperations forwards trader / sender per hop.
  • Integration test: limit_order_tests::hybrid_simulation_matches_execute_with_fee_discount (pool-only, book-only, hybrid split; discounted sim > undiscounted sim; sim output == execute balance delta).

Docs / skills / invariants

  • ADR-0001, docs/contracts-security-audit.md (L8), smartcontracts/contracts/pair/src/lib.rs, skills/AGENTS_HYBRID_QUOTING.md, skills/AGENTS_FEE_DISCOUNT_TIERS.md, skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md cross-link #238 / #245.

Tests run

  • make test-contracts — green (316 tests) after merging small test fix 841c321 (batch placement may revert with book-walk cap as well as max adjust steps).
  • Targeted: hybrid_simulation_matches_execute_with_fee_discount — ok.

Local E2E smoke — blocked (environment)

Running LocalTerra pair terra146ypnd… still serves pre-#238 WASM: LCD hybrid_simulation with trader returns unknown field trader, expected offer_asset or hybrid. Indexer GET /api/v1/route/solve returns 400 (router simulation failed) for the same reason. Did not restart infra per instructions.

After pair/router WASM is upgraded or localnet redeployed from current artifacts, re-run the checklist below.

Merge

  • Pushed to main: 841c321 (test assertion fix only; contract fix was already merged).

Checklist for @brouie (post WASM refresh)

  • LCD: HybridSimulation with trader on a tier-registered wallet returns higher return_amount than without trader.
  • Same wallet: hybrid swap execute output == sim return_amount (same block snapshot).
  • GET /api/v1/route/solve?...&trader=<addr> estimated_amount_out matches router SimulateSwapOperations with same trader.
  • make test-contracts green on CI/main.
  • Registry query failure: sim and execute both use full fee_bps (audit_invariant_tests::swap_uses_full_fee_when_discount_registry_query_fails).

Status: leaving open until local on-chain WASM matches main and indexer route-solve E2E passes. Contract + integration criteria are satisfied in source.

/cc @brouie — please confirm after localnet WASM upgrade.

## Verification report (agent, 2026-05-31) Verified GitLab **#238** on branch `verify/issue-238` (worktree) against `origin/main`. ### Contract implementation (already on main — `3adf2b4`) - `simulate_hybrid_swap` uses `effective_fee_bps_for_sim` (shared `lookup_effective_fee_bps` with execute; no deregister side-effects in queries). - Pool and book legs both receive discounted `effective_fee_bps`. - `HybridSimulation` / `HybridReverseSimulation` accept optional `trader` / `sender`; omit → full `fee_bps`. - Router `SimulateSwapOperations` forwards `trader` / `sender` per hop. - Integration test: `limit_order_tests::hybrid_simulation_matches_execute_with_fee_discount` (pool-only, book-only, hybrid split; discounted sim > undiscounted sim; sim output == execute balance delta). ### Docs / skills / invariants - ADR-0001, `docs/contracts-security-audit.md` (L8), `smartcontracts/contracts/pair/src/lib.rs`, `skills/AGENTS_HYBRID_QUOTING.md`, `skills/AGENTS_FEE_DISCOUNT_TIERS.md`, `skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md` cross-link **#238** / **#245**. ### Tests run - `make test-contracts` — **green** (316 tests) after merging small test fix `841c321` (batch placement may revert with `book-walk cap` as well as `max adjust steps`). - Targeted: `hybrid_simulation_matches_execute_with_fee_discount` — **ok**. ### Local E2E smoke — **blocked (environment)** Running LocalTerra pair `terra146ypnd…` still serves **pre-#238 WASM**: LCD `hybrid_simulation` with `trader` returns `unknown field trader, expected offer_asset or hybrid`. Indexer `GET /api/v1/route/solve` returns **400** (`router simulation failed`) for the same reason. **Did not restart infra** per instructions. After pair/router WASM is upgraded or localnet redeployed from current artifacts, re-run the checklist below. ### Merge - Pushed to `main`: `841c321` (test assertion fix only; contract fix was already merged). --- ### Checklist for @brouie (post WASM refresh) - [ ] LCD: `HybridSimulation` with `trader` on a tier-registered wallet returns higher `return_amount` than without `trader`. - [ ] Same wallet: hybrid swap execute output == sim `return_amount` (same block snapshot). - [ ] `GET /api/v1/route/solve?...&trader=<addr>` `estimated_amount_out` matches router `SimulateSwapOperations` with same `trader`. - [ ] `make test-contracts` green on CI/main. - [ ] Registry query failure: sim and execute both use full `fee_bps` (`audit_invariant_tests::swap_uses_full_fee_when_discount_registry_query_fails`). **Status:** leaving **open** until local on-chain WASM matches main and indexer route-solve E2E passes. Contract + integration criteria are satisfied in source. /cc @brouie — please confirm after localnet WASM upgrade.
PlasticDigits commented 2026-05-31 07:47:46 +00:00 (Migrated from gitlab.com)

mentioned in commit 0a232781f6

mentioned in commit 0a232781f6149ed5c458db612c074ffcb07b73b1
PlasticDigits commented 2026-05-31 07:48:06 +00:00 (Migrated from gitlab.com)

Verification complete (agent, 2026-05-31) — main @ 0a23278

Note: GitLab issue #2385 does not exist in this repo; this work tracks gap H1 / #238.

What was verified

Contract fix landed on main in 3adf2b4 (fix(contracts): hybrid sim CL8Y fee discount parity with execute (#238)). This pass re-verified source + tests and updated docs:

  • HybridSimulation / HybridReverseSimulation use effective_fee_bps_for_sim → shared lookup_effective_fee_bps (read-only; no deregister side-effects).
  • Optional trader / sender on pair hybrid sim + router SimulateSwapOperations / ReverseSimulateSwapOperations; omit → full fee_bps.
  • Pool leg, book leg, and hybrid split all use discounted effective fee when trader is set.
  • Off-chain wiring for connected wallets: #245 (frontend + indexer route-solve).

Docs / invariants / skills (cross-linked)

Artifact Update
Invariant L8 docs/contracts-security-audit.md
ADR-0001 docs/adr/0001-hybrid-quoting-and-routing.md
Pair crate header smartcontracts/contracts/pair/src/lib.rs
Gap H1 marked fixed gaps/GAP_1780200149.md (0a23278)
Agent skills skills/AGENTS_HYBRID_QUOTING.md, skills/AGENTS_FEE_DISCOUNT_TIERS.md, skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md

Tests run (green)

  • make test-contracts — 316 passed
  • cargo test -p cl8y-dex-tests hybrid_simulation_matches_execute_with_fee_discount — ok (pool-only, book-only, hybrid split; discounted sim > undiscounted; sim == execute balance delta)
  • audit_invariant_tests::swap_uses_full_fee_when_discount_registry_query_fails — included in suite, ok
  • fee_discount_tests::test_swap_via_router_with_discount — included in suite, ok

Worktree verify/issue-238 merged to main, pushed, branch + worktree removed.


QA verification checklist (@qa agent team — please confirm)

  • Redeploy / upgrade localnet pair + router WASM from current main artifacts (prior verification blocked on stale WASM rejecting trader field)
  • LCD: HybridSimulation with trader on tier-registered wallet → higher return_amount than without trader
  • Same wallet: hybrid swap execute output == sim return_amount (same block snapshot) for pool-only, book-only, and hybrid split
  • HybridReverseSimulation with trader: reverse offer consistent with forward discounted fees
  • Router SimulateSwapOperations with trader: multi-hop output reflects per-hop discount
  • Indexer GET /api/v1/route/solve?...&trader=<addr> estimated_amount_out matches router sim with same trader
  • Frontend: connected wallet forwarded as trader on preflight / route-solve for tier holders (#245)
  • Registry query failure / no registry: sim and execute both use full fee_bps
  • make test-contracts green on CI/main

Follow-up (out of scope for #238): Swap page min_received parseFloat precision (gap H2); indexer ingestion hardening (C1–C3).

Status: leaving open until QA confirms on-chain WASM + E2E quote=execution for discounted traders.

/cc @brouie @qa — please run the checklist above on localnet/staging and report back.

## Verification complete (agent, 2026-05-31) — `main` @ `0a23278` **Note:** GitLab issue **#2385** does not exist in this repo; this work tracks gap **H1** / [**#238**](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/238). ### What was verified Contract fix landed on `main` in `3adf2b4` (`fix(contracts): hybrid sim CL8Y fee discount parity with execute (#238)`). This pass re-verified source + tests and updated docs: - **`HybridSimulation` / `HybridReverseSimulation`** use `effective_fee_bps_for_sim` → shared `lookup_effective_fee_bps` (read-only; no deregister side-effects). - Optional **`trader` / `sender`** on pair hybrid sim + router `SimulateSwapOperations` / `ReverseSimulateSwapOperations`; omit → full `fee_bps`. - Pool leg, book leg, and hybrid split all use discounted effective fee when `trader` is set. - Off-chain wiring for connected wallets: [#245](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/245) (frontend + indexer route-solve). ### Docs / invariants / skills (cross-linked) | Artifact | Update | |----------|--------| | Invariant **L8** | [`docs/contracts-security-audit.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/contracts-security-audit.md) | | ADR-0001 | [`docs/adr/0001-hybrid-quoting-and-routing.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/adr/0001-hybrid-quoting-and-routing.md) | | Pair crate header | [`smartcontracts/contracts/pair/src/lib.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/smartcontracts/contracts/pair/src/lib.rs) | | Gap **H1** marked fixed | [`gaps/GAP_1780200149.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/gaps/GAP_1780200149.md) (`0a23278`) | | Agent skills | [`skills/AGENTS_HYBRID_QUOTING.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_HYBRID_QUOTING.md), [`skills/AGENTS_FEE_DISCOUNT_TIERS.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FEE_DISCOUNT_TIERS.md), [`skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md) | ### Tests run (green) - `make test-contracts` — **316 passed** - `cargo test -p cl8y-dex-tests hybrid_simulation_matches_execute_with_fee_discount` — **ok** (pool-only, book-only, hybrid split; discounted sim > undiscounted; sim == execute balance delta) - `audit_invariant_tests::swap_uses_full_fee_when_discount_registry_query_fails` — included in suite, **ok** - `fee_discount_tests::test_swap_via_router_with_discount` — included in suite, **ok** Worktree `verify/issue-238` merged to `main`, pushed, branch + worktree removed. --- ### QA verification checklist (@qa agent team — please confirm) - [ ] Redeploy / upgrade localnet pair + router WASM from current `main` artifacts (prior verification blocked on stale WASM rejecting `trader` field) - [ ] LCD: `HybridSimulation` with `trader` on tier-registered wallet → higher `return_amount` than without `trader` - [ ] Same wallet: hybrid swap **execute output == sim `return_amount`** (same block snapshot) for pool-only, book-only, and hybrid split - [ ] `HybridReverseSimulation` with `trader`: reverse offer consistent with forward discounted fees - [ ] Router `SimulateSwapOperations` with `trader`: multi-hop output reflects per-hop discount - [ ] Indexer `GET /api/v1/route/solve?...&trader=<addr>` `estimated_amount_out` matches router sim with same `trader` - [ ] Frontend: connected wallet forwarded as `trader` on preflight / route-solve for tier holders ([#245](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/245)) - [ ] Registry query failure / no registry: sim and execute both use full `fee_bps` - [ ] `make test-contracts` green on CI/main **Follow-up (out of scope for #238):** Swap page `min_received` `parseFloat` precision (gap **H2**); indexer ingestion hardening (**C1–C3**). **Status:** leaving **open** until QA confirms on-chain WASM + E2E quote=execution for discounted traders. /cc @brouie @qa — please run the checklist above on localnet/staging and report back.
PlasticDigits commented 2026-05-31 08:46:38 +00:00 (Migrated from gitlab.com)

mentioned in commit c745d66a9e

mentioned in commit c745d66a9e67846d5e286e0b42e8084f3d42ff9c
PlasticDigits commented 2026-05-31 08:47:36 +00:00 (Migrated from gitlab.com)

On-chain verification complete (agent, 2026-05-31) — main @ c745d66

Brought up the full local stack from a clean slate (fresh volumes → LocalTerra devnet → rebuilt optimized wasm → deploy-local → indexer → 30-worker bot swarm; no frontend) and verified #238 end-to-end on-chain. The prior pass was blocked on stale on-chain wasm rejecting trader — this redeploy resolves that, and the live checks now pass.

Bug found & fixed during verification

HybridReverseSimulation with trader ran out of gas on the deployed contract: it re-queried the fee-discount registry inside its exponential+binary search loop (one cross-contract GetDiscount per iteration), exceeding the LCD 3M smart-query gas cap. This violated the issue guardrail "Wasm gas for sim queries must stay bounded."

Fix (c745d66): resolve the discount once per quote, then reuse it across all search iterations via a new fee-parameterized core simulate_hybrid_swap_with_fee. Forward sim / router sim / execute parity are unchanged (those already resolved the discount once). Reverse sim is now bounded and correct.

Reproducible artifacts

Verification checklist — all green

Contracts / tests

  • make test-contracts — 316 integration + crate units, 0 failures (incl. hybrid_simulation_matches_execute_with_fee_discount fwd + reverse, swap_uses_full_fee_when_discount_registry_query_fails).
  • cargo fmt --check + cargo clippy --workspace -D warnings clean.

On-chain E2E (make verify-issue-238, fresh deploy-local)

  • (1) Deployed pair hybrid_simulation accepts optional trader — no unknown field trader (prior blocker resolved).
  • (2) Fee-discount registry returns discount_bps=9500 for the registered dev wallet.
  • (3) Discounted forward sim return_amount=968357635 > undiscounted 951783803.
  • (4) Executed swap return_amount=968357635 == discounted sim return_amount=968357635 on the same reserves (quote == execution; L8).
  • (5) Router simulate_swap_operations with trader: 948594728 > without 932359146.
  • (5b) hybrid_reverse_simulation with trader: needs less offer (524538138 < 533722411) and no longer OOG.
  • (6) Indexer GET /api/v1/route/solve?…&trader= is trader-aware: 98916710830 ≥ undiscounted 97190334993.

Issue body acceptance criteria

  • Sim == executed output for a discounted trader (same snapshot).
  • Undiscounted (trader omitted) sim unchanged / full fee_bps.
  • Registry query failure → full fee_bps in sim and execute (swap_uses_full_fee_when_discount_registry_query_fails).
  • Book leg + pool leg both use discounted effective fee (pool-only, book-only, hybrid split covered by the integration test).
  • Router multi-hop sim reflects per-hop discount when trader provided (router sim + indexer route/solve).
  • ADR/docs updated for the trader/sender query shape.

Prior QA comment checklist (post-WASM-refresh) — all confirmed on this fresh localnet, except the frontend trader wiring, which is tracked separately in #245 (off-chain, out of scope for #238).

Result

All #238 acceptance + verification criteria and all in-scope comment checklist items pass against freshly-built, freshly-deployed contracts. Closing. Off-chain dApp/indexer wallet forwarding continues under #245.

## On-chain verification complete (agent, 2026-05-31) — `main` @ `c745d66` Brought up the **full local stack from a clean slate** (fresh volumes → LocalTerra devnet → **rebuilt optimized wasm** → `deploy-local` → indexer → 30-worker bot swarm; **no frontend**) and verified #238 end-to-end on-chain. The prior pass was blocked on **stale on-chain wasm rejecting `trader`** — this redeploy resolves that, and the live checks now pass. ### Bug found & fixed during verification `HybridReverseSimulation` with `trader` **ran out of gas** on the deployed contract: it re-queried the fee-discount registry **inside** its exponential+binary search loop (one cross-contract `GetDiscount` per iteration), exceeding the LCD 3M smart-query gas cap. This violated the issue guardrail *"Wasm gas for sim queries must stay bounded."* **Fix (`c745d66`):** resolve the discount **once per quote**, then reuse it across all search iterations via a new fee-parameterized core `simulate_hybrid_swap_with_fee`. Forward sim / router sim / execute parity are unchanged (those already resolved the discount once). Reverse sim is now bounded and correct. ### Reproducible artifacts - `scripts/qa/verify-issue-238.sh` (`make verify-issue-238`) — on-chain E2E (mints CL8Y, registers a tier, asserts parity). - Extended `limit_order_tests::hybrid_simulation_matches_execute_with_fee_discount` with a reverse-sim discount assertion. - Invariant **L8** ([`docs/contracts-security-audit.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/contracts-security-audit.md)), gap **H1** ([`gaps/GAP_1780200149.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/gaps/GAP_1780200149.md)), and skills ([`AGENTS_HYBRID_QUOTING.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_HYBRID_QUOTING.md), [`AGENTS_QA_DEPLOY_VERIFY.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_QA_DEPLOY_VERIFY.md)) all document the bounded-gas behavior and the live check. ### Verification checklist — all green **Contracts / tests** - [x] `make test-contracts` — **316** integration + crate units, **0 failures** (incl. `hybrid_simulation_matches_execute_with_fee_discount` fwd + reverse, `swap_uses_full_fee_when_discount_registry_query_fails`). - [x] `cargo fmt --check` + `cargo clippy --workspace -D warnings` clean. **On-chain E2E (`make verify-issue-238`, fresh `deploy-local`)** - [x] **(1)** Deployed pair `hybrid_simulation` accepts optional `trader` — no `unknown field trader` (prior blocker resolved). - [x] **(2)** Fee-discount registry returns `discount_bps=9500` for the registered dev wallet. - [x] **(3)** Discounted forward sim `return_amount=968357635` > undiscounted `951783803`. - [x] **(4)** Executed swap `return_amount=968357635` **== discounted sim `return_amount=968357635`** on the same reserves (quote == execution; L8). - [x] **(5)** Router `simulate_swap_operations` with `trader`: `948594728` > without `932359146`. - [x] **(5b)** `hybrid_reverse_simulation` with `trader`: needs **less** offer (`524538138` < `533722411`) and no longer OOG. - [x] **(6)** Indexer `GET /api/v1/route/solve?…&trader=` is trader-aware: `98916710830` ≥ undiscounted `97190334993`. **Issue body acceptance criteria** - [x] Sim == executed output for a discounted trader (same snapshot). - [x] Undiscounted (`trader` omitted) sim unchanged / full `fee_bps`. - [x] Registry query failure → full `fee_bps` in sim and execute (`swap_uses_full_fee_when_discount_registry_query_fails`). - [x] Book leg + pool leg both use discounted effective fee (pool-only, book-only, hybrid split covered by the integration test). - [x] Router multi-hop sim reflects per-hop discount when `trader` provided (router sim + indexer route/solve). - [x] ADR/docs updated for the `trader`/`sender` query shape. **Prior QA comment checklist (post-WASM-refresh)** — all confirmed on this fresh localnet, except the **frontend `trader` wiring**, which is tracked separately in **[#245](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/245)** (off-chain, out of scope for #238). ### Result All #238 acceptance + verification criteria and all in-scope comment checklist items pass against freshly-built, freshly-deployed contracts. **Closing.** Off-chain dApp/indexer wallet forwarding continues under #245.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-31 08:47:42 +00:00
PlasticDigits commented 2026-05-31 13:45:55 +00:00 (Migrated from gitlab.com)

mentioned in issue #257

mentioned in issue #257
Brouie commented 2026-06-04 02:35:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #292

mentioned in issue #292
PlasticDigits commented 2026-06-05 04:19:52 +00:00 (Migrated from gitlab.com)

mentioned in issue #319

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

mentioned in merge request !768

mentioned in merge request !768
PlasticDigits commented 2026-06-12 04:46:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #361

mentioned in issue #361
PlasticDigits commented 2026-07-12 07:14:20 +00:00 (Migrated from gitlab.com)

mentioned in issue #476

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

mentioned in issue #615

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