security(pair): UpdateLimitOrderPrice skips F6 code-id gate #1234
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#1234
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
Closed #582 shipped invariant F6: pair write paths call
gate_asset_code_ids→asset_code_id_guard::assert_asset_code_idsso a listed CW20 that migrates off the factory whitelist (or off the listing-time pin) fail-closes. Live check is pin equality plus factoryIsCodeIdWhitelisted.ExecuteMsg::UpdateLimitOrderPriceis the maker limit execute arm that still skips that gate. Insmartcontracts/contracts/pair/src/contract.rsit runs pause + wallet blacklist, thenexecute_update_limit_order_price/relink_limit_order_price. Sibling limit arms (CancelLimitOrder(s),ClaimExpiredLimitOrder(s)) callgate_asset_code_ids. CW20Receive(swap / withdraw / place / batch / ladder) gates once before the hook match.This is not a reopen of #582. That ticket’s ACs (pin + whitelist re-check on swap / provide / withdraw / place+fill / cancel / claim, factory-then-pair migrate) are done. The merge note treated
UpdateLimitOrderPriceas ungated because the tx does not move CW20. That rationale does not match F6 as written: the playbook (skills/AGENTS_CW20_CODE_ID_PIN.md) requires a write-path re-check. Relink mutates the active bid/ask DLL (price, FIFO slot) while escrowremainingstays put. After code-id drift or a governance freeze (RemoveWhitelistedCodeId), makers can still reprice resting orders on a pair that must not accept book writes.Do not retarget #1227 (same-id FIFO leapfrog) or closed #393 (wallet-blacklist test coverage). Those share the message name only.
Bundle (same ticket, do not split):
CleanLimitBookis the other book-mutation execute that skipsgate_asset_code_ids(pause only). Decide whether keeper unlink during F6 freeze is allowed;UpdateLimitOrderPricemust be gated regardless. Admin-only config msgs (UpdateLimitOrderConfig,UpdateLimitCleanConfig) stay out of scope.Impact (Immunefi-style)
remaining/PENDING_ESCROW_*unchanged). The hole is freeze bypass: after pin drift or whitelist removal, swap / place / cancel / claim fail closed while the owner can still relink. Combined with #1227, a maker can also jump FIFO at the destination price on a pair that F6 says is frozen.executearm forUpdateLimitOrderPrice(+ decideCleanLimitBook). Docs/playbook F6 path list. Pin tests (asset_code_id_pin_tests). No indexer/frontend execute change unless they assume reprice works duringcode_id_frozen.Invariant that is broken: F6 write-path re-check. A pair whose live asset
code_iddrifted fromASSET_CODE_IDSor is no longer factory-whitelisted must not accept maker book mutation. “No CW20 in this tx” is not an exemption from pin/whitelist.Constraints / guardrails
LimitInsertStepsExceededstill all-or-nothing.gate_asset_code_ids/assert_asset_code_ids). Do not fork a second pin check. Fail closed on query errors (AssetCodeIdGuardUnavailable), same as other arms.remainingorPENDING_ESCROW_*. F6 reject must not half-detach the node.CleanLimitBook: if keepers must still park expired/dust during freeze, document that exception in F6 item 2 /cw20-code-id-ops.md. If freeze means no DLL writes, gate it too. Do not silently leave it as the only other hole without a written decision.ready.Relevant files
smartcontracts/contracts/pair/src/contract.rsExecuteMsg::UpdateLimitOrderPriceomitsgate_asset_code_ids; cancel/claim/receive already call itsmartcontracts/contracts/pair/src/asset_code_id_guard.rsassert_asset_code_ids— reuse, do not duplicatesmartcontracts/contracts/pair/src/orderbook.rsrelink_limit_order_price— mutation that must not run after a failed gatesmartcontracts/contracts/pair/src/limit_book_clean.rsCleanLimitBooksibling ungated writersmartcontracts/tests/src/asset_code_id_pin_tests.rs(or current pin-test module)skills/AGENTS_CW20_CODE_ID_PIN.mddocs/security-model.md,docs/runbooks/cw20-whitelist-policy.md,docs/runbooks/cw20-code-id-ops.mdRecommended direction
UpdateLimitOrderPriceexecute arm, callgate_asset_code_ids(deps.as_ref())?immediately after the existing pause + blacklist gates, beforeexecute_update_limit_order_price.UpdateLimitOrderPricereturnsAssetCodeIdDriftorAssetCodeIdNotWhitelisted(same error as swap/place). Order still linked at the old price; escrow unchanged. AfterRefreshAssetCodeIdson a still-whitelisted honest id (or restore whitelist + refresh per existing tests), reprice succeeds.CleanLimitBookdecision in the same docs edit.make verify-issue-582green; extend it or the pin suite so a missingUpdateLimitOrderPricegate fails CI.Acceptance criteria
UpdateLimitOrderPriceaborts with the existing asset-code-id errors. The resting order is not unlinked or repriced.remaining/PENDING_ESCROW_*unchanged.CleanLimitBookeither also callsgate_asset_code_ids, or docs explicitly keep it as a freeze-safe keeper exception. One written choice.UpdateLimitOrderPrice.make verify-issue-582(or the repo’s documented contract suite) pass.Verification (non-exploitative)
Do not publish a mainnet migrate + reprice recipe. Verify in multi-test only:
UpdateLimitOrderPriceon a resting order in the same setup and assert the F6 error, book price unchanged.RemoveWhitelistedCodeIdof the pin → reprice fails; swap/place still fail.GetLimitOrder/ book page still shows the old price and id.CleanLimitBookcoverage matches whatever AC4 chose.First-pass model recommendation
Recommendation: grok-high
Rationale: Founder-required CosmWasm pair / wasm and an F6 security control (code-id pin + factory whitelist). Even a one-arm
gate_asset_code_idscall still changes freeze semantics for Edit, must not half-detach on reject, and needs pin-test plus playbook/path-matrix updates. Composer is disallowed for security and for contracts/wasm. Verify with the pin tests above andmake verify-issue-582, not a live-chain migrate.Merged as PR #1288. AC1–AC6 are in tree (F6 gates
UpdateLimitOrderPriceandCleanLimitBook).Leftover: columbus-5 listed pairs still need a pair wasm store+migrate before the gate is live (cw2 stays 1.17.0). Tracked on #1300.
scripts/qa/verify-issue-1234.shheader still listsmake verify-issue-582as step 4, but the script does not invoke it. Pin tests for #1234 run; shared #582 green is a separatemake verify-issue-582. Optional leftover on #1300 if an implement wants the alias to actually call 582.Live pairs are still code 11664 (1.16.0). Factory is already 11629 / 1.10.0.
Inbox card filed (desktop): store 1.17.0 pair wasm and migrate. Use
UPGRADE582_SKIP_FACTORY_MIGRATE=1. Do notSKIP_STOREwith 11664.Leaving this issue open until the migrate tx lands.
On-chain leftover for F6 + named min remaining is done.
Live columbus-5 LCD:
terra1ejpg…chseacode 11629 / cw2 1.10.0 (unchanged)config.pair_code_id11672Operator inbox card Store and migrate pair wasm completed. Host
make verify-issue-1234already passed. Closing.