test: greedy pause/blacklist, AfterSwap L7, community-tax extra-debit (!480 leftover) #710
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#710
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?
Summary
#708 / !1198 added an opt-in greedy book-first swap and a
greedy_book_first_708multitest module. That suite covers G1–G3/G5/G8 happy paths. It does not replay three invariants that #708 required to “behave as Pattern C hybrid”:traderspoof (A9 / A14).return_asset/ commission = book net + pool net on a greedy fill (path 16).This ticket is tests (and only the minimal product code if a test finds a real greedy-specific hole). Do not change G1 (pool-only default), the official dApp solver path, or Pattern C.
Correctness leftovers (query mutex,
greedy_stop=empty,Decimal::from_ratiopanic) are a separate issue. Land or coordinate with that MR so greedy execute used here is the post-fix matcher.Related: #708, #607 (router tax option 2), #196 (L7 commission), #120 (pause), #468 (blacklist).
Current codebase
Greedy execute (what tests must drive)
On !1198,
SwapHybridMode::Greedysetspool_leg = 0,book_leg = offer, then leftover offer aftermatch_*rolls into the AMM (G9). Hook string staysCw20HookMsg::Swap(greedy: Some(...)). Pause is stillassert_not_pausedonReceive. Blacklist still skips makers inmatch_bids/match_asks. AfterSwap still runs after settlement withreturn_asset= book net + pool net (same as Pattern C). Community-taxis_swap_send_hookmatches anyCw20HookMsg::Swap(including greedy) viafrom_json.There is no greedy-specific pause, blacklist, AfterSwap, or tax test. Existing tests pass
greedy: None:pause_blocks_swap_and_place_cancel_refunds_escrow(limit_order_tests.rs~L2968)greedy: Noneblacklisted_maker_resting_limit_not_filled_taker_can_still_swap(blacklist_tests.rs~L711)book_inputhybrid_hook_commission_includes_pool_and_book(limit_order_tests.rs~L3670)sell_extra_debit_on_swap_send(community-tax-token/src/multitest.rs~L493)greedy: Nonerouter_sell_extra_debits_authenticated_trader(~L2356)greedy: Nonemake verify-issue-708runs dex-common + pairgreedy+greedy_book_first_708+ gas vitest + docs greps. It does not run community-tax, blacklist, or L7 hybrid hook tests.Tax hook detection (why greedy should work)
community-tax-token/src/tax.rs:is_swap_send_hook—from_json::<Cw20HookMsg>isSwap { .. }(anyhybrid/greedy).is_router_sell_hop— listed pair + swap hook +fromis official router.hop_trader_addr— honorSwap.traderonly whenfromis the stamped official router; pair-direct extra-debitsfrom.#[serde(default)]onCw20HookMsg::Swap.greedykeeps old JSON decoding. A greedy sell is still aSwapsend. If tests fail, that is a product bug (serde / hook / trader), not “coverage optional.”AfterSwap L7 (Pattern C reference)
hybrid_hook_commission_includes_pool_and_bookquotesHybridSimulation, executes declared hybrid, and checks treasury / hookcommission_amount= pool commission + book taker half,return_asset= book net + pool net. Greedy remainder (G9) is the same two legs; the hook must not see book-only or pool-only.Why this is needed
#708 acceptance:
Attack table A9 / A12 / A13 / A14 and functional paths 14, 16, 18 were listed and are untested on greedy. Bots will send
greedyon listed tax pairs and through the official router. A silent tax skip, a paused pair that still greedy-fills, a blacklisted maker that gets paid, or AfterSwapreturn_assetthat omits the book (or pool) leg would be a mainnet-class failure that Pattern C tests would not catch (greedy: None).These paths are the difference between “matcher reuse (G10) on paper” and “we proved pause/tax/hooks still bind.”
Constraints / guardrails
hybrid: None+greedy: Noneon a paused / tax / hooked pair still pool-only (no book fill).belief_priceormin_return. Tests must pass a floor (min_return = 1is acceptable for invariant tests; add one tight-floor fail if cheap).match_*viagreedy: Some(GreedySwapParams { … }).greedyon the sell hop, not auto-upgradehybrid: null.Swap.traderstamped by router). Pair-direct extra-debits the CW20from. Greedy must not loosenhop_trader_addr.return_asset.amount= book net + pool net;commission_amount= pool commission + book taker commission (ask asset).trader: Some(whale)must not grant a fee tier or change tax subject.Out of scope: G11 query mutex /
greedy_stopremainder / Decimal panic (sibling issue); expired-prefix scan cap; reverse sim; columbus-5 migrate; e2e Playwright (nice-to-have, not this ticket unless already cheap).Relevant files
smartcontracts/tests/src/limit_order_tests.rsgreedy_book_first_708, pause,hybrid_hook_commission_includes_pool_and_booksmartcontracts/tests/src/blacklist_tests.rssmartcontracts/contracts/community-tax-token/src/multitest.rssell_extra_debit_on_swap_send,router_sell_extra_debits_authenticated_tradersmartcontracts/contracts/community-tax-token/src/tax.rsis_swap_send_hook,hop_trader_addrsmartcontracts/contracts/pair/src/contract.rsreturn_asset), pause,execute_swapgreedysmartcontracts/contracts/pair/src/orderbook.rsmatch_*smartcontracts/contracts/router/src/contract.rstrader; greedy hopsmartcontracts/tests/src/adversarial_token.rsgreedy: Nonetoday)scripts/qa/verify-issue-708.shverify-issue-<iid>skills/AGENTS_GREEDY_BOOK_FIRST.md,skills/AGENTS_COMMUNITY_TAX_ROUTER.mdRecommended direction
Reuse fixtures, swap the hook field. Copy the Pattern C / pool-only setups (seed pool, better bid/ask so greedy actually touches the book). Replace
hybrid: Some(declared)/greedy: Nonewithhybrid: None+greedy: Some(greedy_swap_params(n, None))and a G8 floor. Prefer extendingmod greedy_book_first_708plus tax multitest siblings named*_greedy_*socargo test greedy/verify-issue-*can filter.Tax:
sell_extra_debit_on_swap_send.trader, not the router (router_sell_extra_debits_authenticated_traderanalogue).greedy: Noneon the same pair still extra-debits (regression).Pause: factory
SetPairPaused { paused: true }→ greedySend+Swaperrors; unpause → greedy fill works (better bid). QueryHybridSimulationgreedy may still succeed while paused (pin current pause-on-execute-only behavior; do not newly pause queries unless product already does).Blacklist:
AfterSwap L7: Seed better bid + leftover offer so both legs exist. Assert hook
return_assetandcommission_amountagainst simreturn_amount/commission_amount(or treasury delta like the Pattern C test). Query must not park or fire AfterSwap.Trader spoof (pair-direct): greedy swap with
trader: Some(high-tier)from a non-router CW20 sender → fee/tax as sender, not whale.If a test fails because greedy never hits the book (G3 stop), fix the fixture (price strictly better than pool after fees), not the matcher.
Add names to
make verify-issue-<iid>(tax crate +cl8y-dex-testsfilters). Do not requiremake test-contractsentire tree unless already cheap.Acceptance criteria
from(same economic extra-debit as pool-only/hybrid sell on that fixture).Swap.trader), not the router contract (T592-13).trader: Some(other)does not apply that wallet’s fee tier or tax exemption (A9 / A14).return_asset= book net + pool net; commission = pool + book taker half (L7). Query does not fire the hook / does not park.greedyon the same tax/pause fixtures still does not fill the book.greedy: None).make verify-issue-<iid>runs the new test names (and greps G1/L7/T592-13 if docs updated).Test plan (functional paths)
Community tax (listed pair, sell of tax CW20)
trader; router CW20 balance not the tax subject.hybrid: null(no greedy) → unchanged extra-debit (regression).trader: Some(victim)spoof → extra-debit from, not victim.Pause / blacklist / trader
IsPausedtrue; unpause then greedy fills better bid.limit_order_fillfor that id; maker token0/1 not increased from fill; taker return from pool (and/or other makers).traderhigh CL8Y tier →effective_fee_bps/ treasury commission as unregistered sender (or existing pair-direct rule).AfterSwap L7
return_asset.amount== book_return + pool_return (net);commission_amount== pool_commission + book_commission (matchHybridSimulationgreedy quote).HybridSimulationgreedy on the same state: no AfterSwap message, no park, amounts equal execute when book has no expired prefix.Optional if cheap
Test plan (attack, hack, abuse)
tradertraderfor fee discount and for taxhop_trader_addr. Router-only stamp remains.Receive/ execute entry, not mid-match. Paused pair: no greedy fills, no extra-debit success, no AfterSwap. Unpause does not retroactively fill.WorseThanPoolin a way that stops the walk and then pays that maker via another path. Remainder → pool.Send+Swapgreedy on the same pair to mint extra fills or double extra-debit. Same allowlist as Pattern C.traderon pair-direct greedy to steal a whale tier (pool + book legs both use authenticated trader).is_swap_send_hookmust still matchSwap { greedy: Some(_) }. A serde miss (deny_unknown_fields/ missingdefault) that makes tax treat greedy as not a swap would skip extra-debit — fail this ticket.return_assetmust not be pool-only (hides book) or book-only (hides AMM remainder).HookFeeExceedsReturnstill guards.Verification criteria
cd smartcontracts && cargo test -p cl8y-dex-community-tax-token greedy -- --test-threads=1(or the exact new test filter) green, including pair-direct + router extra-debit.cd smartcontracts && cargo test -p cl8y-dex-tests greedy_book_first_708 -- --test-threads=1green, including new pause / L7 tests in that module or clearly namedgreedy_*tests inlimit_order_tests/blacklist_tests.cargo test -p cl8y-dex-tests greedy_blacklistor equivalent).return_asseton greedy remainder = book net + pool net.make verify-issue-<iid>lists those cargo filters (and does not claim they ran if they did not).AGENTS_GREEDY_BOOK_FIRST.mdTests section mentions tax / pause / L7 / blacklist commands.No LocalTerra required. If a test finds a real greedy-specific tax/pause/hook bug, fix it in the same MR as the test (do not file-and-forget).
marked as related to #708
mentioned in commit
83bccc2838mentioned in merge request !1198
mentioned in commit
56e4c4f513mentioned in commit
f54de4fd4bmentioned in issue #712
marked as related to #712
mentioned in issue #708
!1198 merged to
main(f54de4fd). Merge-time verify:make verify-issue-710PASS.Covered: greedy tax sell extra-debit (pair-direct + official router T592-13), pause L6, blacklist maker/taker L19, pair-direct
traderspoof A9/A14, AfterSwap book+pool L7.Not in this MR (optional follow-up on #712): community-tax greedy buy analogue; AfterSwap re-entrancy A13 greedy-specific test. Do not reopen this issue for those.
mentioned in issue #718