Contracts: HybridSimulation CL8Y fee discount parity with execute path (H1) #238
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#238
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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 reducingfee_bpsbydiscount_bps.HybridSimulation/simulate_hybrid_swap(contract.rs:1890-2000) usesfee_config.fee_bpsonly (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
HybridSimulationResponseschema.ceil_div, book commission math).GetDiscountfails (Err), execute charges full fee — sim must match that fallback.trader/senderin sim query if discount is wallet-specific — audit all callers (router sim, indexer LCD queries, frontend).Relevant files
smartcontracts/contracts/pair/src/contract.rseffective_fee_bps_with_discount_msgs,simulate_hybrid_swap, execute swap discountsmartcontracts/contracts/pair/src/limit_placement.rssmartcontracts/contracts/router/src/contract.rsHybridSimulationsmartcontracts/packages/dex-common/src/pair.rsHybridSimulationquery msg + response typessmartcontracts/tests/src/limit_order_tests.rssmartcontracts/tests/src/lib.rsdocs/adr/0001-hybrid-quoting-and-routing.mdRecommended direction
Route
simulate_hybrid_swapthrougheffective_fee_bps_with_discount_msgs(or a sim-safe variant that returns effective bps without emitting msgs). Add optionaltrader: Option<String>toHybridSimulationquery 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
HybridSimulationoutput matches executed swap output for a discounted trader (same block snapshot).fee_bps(matches execute).traderprovided.Test plan — all paths
Err(mock failing registry)needs_deregistertraderAdd dedicated test in
limit_order_tests.rsorlib.rscomparing sim vs execute with registered discount wallet.Run:
make test-contractsTest plan — attack / abuse vectors
traderin sim queryVerification criteria
make test-contractsgreen.mentioned in commit
3adf2b43d2Implementation complete (pushed to
main@3adf2b4)Summary:
HybridSimulation/HybridReverseSimulationnow 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). Optionaltrader/senderfields were added to pair hybrid sim queries and routerSimulateSwapOperations/ReverseSimulateSwapOperations. Omittraderfor backward-compatible full-fee quotes.Code: consolidated execute + limit-placement + sim discount math in
pair/src/contract.rs; helpers index_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-linkedskills/AGENTS_HYBRID_QUOTING.mdandskills/AGENTS_FEE_DISCOUNT_TIERS.md. FrontendsimulateHybridSwapaccepts 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_exceededstill fails on main (pre-existing, unrelated).QA verification checklist
HybridSimulationwith registered discount wallet +traderset: output matches executed swap on same snapshot (pool-only, book-only, hybrid split)HybridSimulationwithouttrader: unchanged full-fee behaviorfee_bps(matches execute)traderprovidedSimulateSwapOperationswithtrader: multi-hop output reflects per-hop discountHybridReverseSimulationwithtrader: reverse offer amount consistent with forward discounted feescargo test -p cl8y-dex-tests hybrid_simulation_matches_execute_with_fee_discountgreentraderonhybrid_simulationfor tier holders (follow-up wiring if not yet in UI)traderthrough LCDhybrid_simulationwhen 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.
mentioned in issue #245
Verification report (agent, 2026-05-31)
Verified GitLab #238 on branch
verify/issue-238(worktree) againstorigin/main.Contract implementation (already on main —
3adf2b4)simulate_hybrid_swapuseseffective_fee_bps_for_sim(sharedlookup_effective_fee_bpswith execute; no deregister side-effects in queries).effective_fee_bps.HybridSimulation/HybridReverseSimulationaccept optionaltrader/sender; omit → fullfee_bps.SimulateSwapOperationsforwardstrader/senderper hop.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
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.mdcross-link #238 / #245.Tests run
make test-contracts— green (316 tests) after merging small test fix841c321(batch placement may revert withbook-walk capas well asmax adjust steps).hybrid_simulation_matches_execute_with_fee_discount— ok.Local E2E smoke — blocked (environment)
Running LocalTerra pair
terra146ypnd…still serves pre-#238 WASM: LCDhybrid_simulationwithtraderreturnsunknown field trader, expected offer_asset or hybrid. IndexerGET /api/v1/route/solvereturns 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
main:841c321(test assertion fix only; contract fix was already merged).Checklist for @brouie (post WASM refresh)
HybridSimulationwithtraderon a tier-registered wallet returns higherreturn_amountthan withouttrader.return_amount(same block snapshot).GET /api/v1/route/solve?...&trader=<addr>estimated_amount_outmatches routerSimulateSwapOperationswith sametrader.make test-contractsgreen on CI/main.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.
mentioned in commit
0a232781f6Verification complete (agent, 2026-05-31) —
main@0a23278Note: GitLab issue #2385 does not exist in this repo; this work tracks gap H1 / #238.
What was verified
Contract fix landed on
mainin3adf2b4(fix(contracts): hybrid sim CL8Y fee discount parity with execute (#238)). This pass re-verified source + tests and updated docs:HybridSimulation/HybridReverseSimulationuseeffective_fee_bps_for_sim→ sharedlookup_effective_fee_bps(read-only; no deregister side-effects).trader/senderon pair hybrid sim + routerSimulateSwapOperations/ReverseSimulateSwapOperations; omit → fullfee_bps.traderis set.Docs / invariants / skills (cross-linked)
docs/contracts-security-audit.mddocs/adr/0001-hybrid-quoting-and-routing.mdsmartcontracts/contracts/pair/src/lib.rsgaps/GAP_1780200149.md(0a23278)skills/AGENTS_HYBRID_QUOTING.md,skills/AGENTS_FEE_DISCOUNT_TIERS.md,skills/AGENTS_INDEXER_HYBRID_BEST_EXECUTION.mdTests run (green)
make test-contracts— 316 passedcargo 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, okfee_discount_tests::test_swap_via_router_with_discount— included in suite, okWorktree
verify/issue-238merged tomain, pushed, branch + worktree removed.QA verification checklist (@qa agent team — please confirm)
mainartifacts (prior verification blocked on stale WASM rejectingtraderfield)HybridSimulationwithtraderon tier-registered wallet → higherreturn_amountthan withouttraderreturn_amount(same block snapshot) for pool-only, book-only, and hybrid splitHybridReverseSimulationwithtrader: reverse offer consistent with forward discounted feesSimulateSwapOperationswithtrader: multi-hop output reflects per-hop discountGET /api/v1/route/solve?...&trader=<addr>estimated_amount_outmatches router sim with sametradertraderon preflight / route-solve for tier holders (#245)fee_bpsmake test-contractsgreen on CI/mainFollow-up (out of scope for #238): Swap page
min_receivedparseFloatprecision (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.
mentioned in commit
c745d66a9eOn-chain verification complete (agent, 2026-05-31) —
main@c745d66Brought 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 rejectingtrader— this redeploy resolves that, and the live checks now pass.Bug found & fixed during verification
HybridReverseSimulationwithtraderran out of gas on the deployed contract: it re-queried the fee-discount registry inside its exponential+binary search loop (one cross-contractGetDiscountper 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 coresimulate_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).limit_order_tests::hybrid_simulation_matches_execute_with_fee_discountwith a reverse-sim discount assertion.docs/contracts-security-audit.md), gap H1 (gaps/GAP_1780200149.md), and skills (AGENTS_HYBRID_QUOTING.md,AGENTS_QA_DEPLOY_VERIFY.md) all document the bounded-gas behavior and the live check.Verification checklist — all green
Contracts / tests
make test-contracts— 316 integration + crate units, 0 failures (incl.hybrid_simulation_matches_execute_with_fee_discountfwd + reverse,swap_uses_full_fee_when_discount_registry_query_fails).cargo fmt --check+cargo clippy --workspace -D warningsclean.On-chain E2E (
make verify-issue-238, freshdeploy-local)hybrid_simulationaccepts optionaltrader— nounknown field trader(prior blocker resolved).discount_bps=9500for the registered dev wallet.return_amount=968357635> undiscounted951783803.return_amount=968357635== discounted simreturn_amount=968357635on the same reserves (quote == execution; L8).simulate_swap_operationswithtrader:948594728> without932359146.hybrid_reverse_simulationwithtrader: needs less offer (524538138<533722411) and no longer OOG.GET /api/v1/route/solve?…&trader=is trader-aware:98916710830≥ undiscounted97190334993.Issue body acceptance criteria
traderomitted) sim unchanged / fullfee_bps.fee_bpsin sim and execute (swap_uses_full_fee_when_discount_registry_query_fails).traderprovided (router sim + indexer route/solve).trader/senderquery shape.Prior QA comment checklist (post-WASM-refresh) — all confirmed on this fresh localnet, except the frontend
traderwiring, 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.
mentioned in issue #257
mentioned in issue #292
mentioned in issue #319
mentioned in merge request !768
mentioned in issue #361
mentioned in issue #476
mentioned in issue #615