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#271
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
Close two test-coverage gaps in the limit-order park → claim lifecycle left after GitLab #263 (
CleanLimitBook) and #264 (match-time dust flush). Both are tests-only deliverables — no contract behavior changes unless a test exposes a regression.Bundled scope:
CleanLimitBookemits zero CW20/bank transfer submessages in the clean tx (refunds only onClaimExpiredLimitOrder).ClaimExpiredLimitOrderrejection integration test (mirror existing cancel batch guard).Current codebase
Park / clean path — no CW20 in park tx (L1, L15)
CleanLimitBook(limit_book_clean.rs→execute_clean_limit_bookincontract.rs) walks the book and callspark_limit_order_for_clean; response is attributes + wasm events only — no.add_message()CW20 transfers.EXPIRED_LIMIT_CLAIMSwithPENDING_ESCROW_*unchanged; maker CW20 refund happens only onClaimExpiredLimitOrder.clean_limit_book_parks_expired_head_default_config— parks, checks attrs, claim rows, order off book.clean_limit_book_force_dust_bid_then_claim_refunds— force-parks via governance threshold, then maker claims and balance increases — indirectly proves refund was deferred, but does not assert zero transfers / unchanged maker balance during the clean tx.expired_bid_parked_on_hybrid_walk_claim_refunds_makerdoes assert maker balance unchanged after park ("maker must not receive token1 until ClaimExpiredLimitOrder") — pattern to reuse for clean.orderbook::tests::park_expired_bid_unlinks_and_records_claim_without_pending_deltacovers taker-walk park, notCleanLimitBookexecute path.Claim owner guard (L1, L11)
execute_claim_expired_limit_order(contract.rs~L1222):if row.owner != info.sender { return Err(ContractError::Unauthorized {}) }.execute_claim_expired_limit_orders(limit_batch_withdraw.rs~L166): same per-row owner check; all-or-nothing revert.cancel_limit_order_non_owner_rejected— single cancel (L3).batch_cancel_foreign_owner_reverts_whole_tx— batch cancel foreign owner →Unauthorized, orders remain (L11).ClaimExpiredLimitOrdernon-owner rejection; also missing: batchClaimExpiredLimitOrdersforeign-owner twin (optional stretch — same guard, same pattern as cancel batch).batch_claim_expired_two_orders_one_tx,match_dust_flush_bid_hybrid_then_maker_claims,clean_limit_book_force_dust_bid_then_claim_refunds.Why this is needed
execute_clean_limit_bookor shared park helpers could accidentally attach a CW20Transfer(e.g. copying cancel/refund logic). Balance-delta checks after claim do not catch premature refunds in the clean tx itself.docs/contracts-security-audit.mdrows L1, L11, L15 should cite explicit integration tests for these guards on the clean and claim execute paths.Constraints and guardrails
execute_clean_limit_book,place_bid,place_expired_bids,query_cw20_balance,wasm_attr_in_action_event, hybrid park setup patterns.Responseare auto-executed; assert no CW20 balance change to maker during clean and/or scan tx events for absence of CW20transferwasm actions (see recommended direction).batch_claim_expired_foreign_owner_reverts_whole_tx— only if trivial once single-claim test exists.Relevant files
smartcontracts/contracts/pair/src/limit_book_clean.rs,contract.rs(execute_clean_limit_book)contract.rs(execute_claim_expired_limit_order),limit_batch_withdraw.rs(execute_claim_expired_limit_orders)smartcontracts/contracts/pair/src/orderbook.rs(park_limit_order_for_clean)smartcontracts/tests/src/limit_order_tests.rssmartcontracts/tests/src/helpers.rs(if adding shared assert helper)docs/contracts-security-audit.md(L1, L11, L15, L16)docs/limit-orders.md§ Permissionless limit book clean, § Claim expiredRecommended solution direction
1.
CleanLimitBookzero-transfer assertion (#263)assert_no_cw20_transfers_in_tx(app, &maker, &token, before_balance)orassert_events_have_no_cw20_transfer(events)in test helpers.clean_limit_book_emits_no_cw20_transfers(or extendclean_limit_book_force_dust_bid_then_claim_refunds):PendingEscrowquery before clean.CleanLimitBookas permissionless keeper.transferevents to maker in tx;PENDING_ESCROW_*unchanged;ExpiredLimitRefundrow exists; then claim moves balance (existing assertion).clean_limit_book_parks_expired_head_default_configscenario) — one test covering both force + time paths is sufficient if both park helpers share code path.docs/contracts-security-audit.md.2. Non-owner claim rejection (#264 context / L1 claim guard)
claim_expired_limit_order_non_owner_rejected:CleanLimitBook, or dust flush — simplest: reuse expired-bid hybrid park from existing tests).attackerexecutesClaimExpiredLimitOrder { order_id }→Unauthorized.ExpiredLimitRefundrow still present; maker balance unchanged; attacker balance unchanged.cancel_limit_order_non_owner_rejectedandbatch_cancel_foreign_owner_reverts_whole_tx.batch_claim_expired_foreign_owner_reverts_whole_txwith two parked ids owned byenv.user, batch submitted byattacker.Acceptance criteria
CleanLimitBooktx does not CW20-transfer to maker (balance +/or event scan) while parked claim row exists.ClaimExpiredLimitOrder→Unauthorized; claim row and balances unchanged.make test-contracts/cargo test -p cl8y-dex-tests limit_ordergreen.docs/contracts-security-audit.mdinvariant rows cite new test function names.Test plan — functional paths
Unauthorized; row persistsTest plan — attack / abuse / hack vectors
EXPIRED_LIMIT_CLAIMSPENDING_ESCROW_*unchanged across clean (query if helper exists)Verification criteria
cargo test -p cl8y-dex-tests clean_limit_book_emits_no_cw20(or chosen name) passes.cargo test -p cl8y-dex-tests claim_expired_limit_order_non_owner_rejectedpasses.marked as related to #263
marked as related to #264
mentioned in merge request !734
Knocked out #271 — both coverage gaps, tests-only, no wasm change. Branch qa/271-claim-clean-test-coverage off main, commit
6457bac, MR !734.Three new tests in smartcontracts/tests/src/limit_order_tests.rs:
Acceptance criteria:
remaining. Paying the FULL remaining also proves PENDING_ESCROW was untouched by the clean (no premature decrement) — covers the "premature pending decrement" abuse row without a pending query (none is exposed).Verification criteria:
Functional paths covered: force-dust clean (zero CW20 -> claim refunds); non-owner single claim rejected; owner claim after rejected attacker attempt still pays once; (stretch) foreign-owner batch claim reverts whole tx, both rows persist.
Attack/abuse vectors covered: permissionless keeper steals escrow via clean -> no CW20 out in clean tx; attacker claims victim's parked dust -> rejected, row remains; attacker claims after force-clean -> same rejection; double refund (clean + claim by different senders) -> clean never pays, only owner claim transfers; premature pending decrement -> claim pays full remaining (proves pending intact); batch claim partial grief -> foreign id reverts all, no partial CW20.
Scope note: covered the force-dust clean path only. Both force-clean and time-expiry park through the same park_limit_order_for_clean path (L15/L16), so per the issue one test is sufficient — not skipping the time-expired path, it's the same code path.
Needs your review/merge on !734, then close. @PlasticDigits
mentioned in commit
12308a3803mentioned in issue #246