fix(community-tax): SettingsBatch autolp no-op still charges 50 UST1 #1237
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#1237
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
Community-tax
UpdateSettingsis supposed to charge one 50 UST1 invoice only when aSettingsBatchactually mutates state (T592-4). Other keys already compare on-chain values (buy_bps,sell_bps,treasury,transfer_bps,sinks, exemptions,launch_guards) and returnNoOpSettings(UST1 not kept) when nothing differs.apply_autolp_settingsdoes not compare. Any batch that includesautolpsetschanged = trueand queues a sisterUpdateConfig, so a manager can pay 50 UST1 for a no-op AutoLP save.Retail Manage Token compounds this: Auto liquidity fields are included whenever any of pair / threshold / recipient is non-empty, without reading sister
GetConfig. Empty threshold defaults to raw1; empty recipient defaults to the connected wallet. Together, typing the already-bound pair (or any AutoLP field) is enough to attachautolpand take the invoice.Parent invariant: #592 T592-4. Sister write path / merge: #610 M610-6. Manage Token: #593. Indexer ingest #1210 already assumes on-chain no-ops revert (do not expand that ticket).
Given / When / Then
GetConfigshowing pairP, thresholdT,lp_recipientR, and current skim floor.UpdateSettingswhoseautolprepeatsP/T/R(and omitted skim fields), and no other batch key differs from token state.NoOpSettings, CMM does not receive 50 UST1, sister config is unchanged, and noupdate_settings/invoicesuccess attrs are emitted.Current behavior
community-tax-tokeninvoice.rsupdate_settings:NoOpSettings.if !changed { return Err(NoOpSettings) }thenCONFIG.save+forward_ust1(50e6) + optional extra msgs.apply_autolp_settings(same file):cfg.autolp(bound sister). Unbound → error, fee not kept.lp_recipient(andpairif present).*changed = trueunconditionally.update_configto the sister (thresholdandlp_recipientalwaysSome;pair/ skim fields forwarded as in the batch).Sister
UpdateConfigmerges omitted fields (M610-6). Re-sending the samepairstill runs factory listing +register_listed_pair. The invoice decision never asks sisterGetConfig.NoOpSettingserror text is “empty or identical to on-chain state”. There is no token test that sends an identicalautolppayload and expects that error.Expected vs actual
autolponlyNoOpSettings; UST1 not keptchanged = true; 50 UST1 forwarded; sisterUpdateConfigqueuedautolpplus a realbuy_bpschangeautolpWhy this is needed
T592-4: unpaid / no-op / non-manager / unactivated SKU fail closed; fee not kept. AutoLP is the only settings key that cannot be compared from token
GetConfig(those fields are not stored on the token). The implementation skipped the sister query and treated “key present” as “changed”.Managers who re-save Auto liquidity (or whose UI attaches
autolpwhenever a field is non-empty) pay CMM for no mutation. #1210 would then index asettings_feefor a no-op if this path stays green.Constraints / guardrails
EnableFeatureinto the batch.SkimToLpstays permissionless and is not a settings invoice. Pair still must be factory-listed with this token; skim floor unchanged. Do not add pair/router FoT math (H-01).autolpmust query sisterGetConfig(or equivalent), not invent token-local copies of those fields.pair/ skim fields are not a change.Nonepair in the batch must not clear a configured pair. Compare only fields the batch actually sets (same merge rules asUpdateConfig).UpdateConfig(or re-register_listed_pair) when the effective sister config is unchanged.cfg.autolpNone) still errors; do not charge.buy_bps !== cfg.buy_bps) but must not be the only fix. Invoice integrity is on-chain.1or empty recipient to the connected wallet unless those values are the user’s intended delta versus sister state.apply_mint_settingssets*changed = trueaftermintereven whenMinterData.minteris already that address. Cover identicalminterasNoOpSettingsin the same MR if it is still unconditional. Revoke mint remains a real change.Relevant files
smartcontracts/contracts/community-tax-token/src/invoice.rsupdate_settings,apply_autolp_settings,apply_mint_settingssmartcontracts/contracts/community-tax-token/src/msg.rsSettingsBatch,AutoLpConfig,INVOICE_UST1smartcontracts/contracts/community-tax-token/src/error.rsNoOpSettingssmartcontracts/contracts/community-tax-token/src/multitest.rssmartcontracts/contracts/community-tax-autolp/src/msg.rsGetConfig/UpdateConfigmergesmartcontracts/contracts/community-tax-autolp/src/contract.rsexecute_update,GetConfigfrontend-dapp/src/pages/ManageTokenPage.tsxfrontend-dapp/src/utils/communityTaxInvoice.tsbuildSettingsBatchInvoice/settingsBatchIsEmptyfrontend-dapp/src/services/terraclassic/communityTaxToken.ts(or AutoLP query helper)GetConfigfor dirty compare / prefillskills/AGENTS_COMMUNITY_TAX_CW20.mdskills/AGENTS_COMMUNITY_TAX_AUTOLP.mdskills/AGENTS_FRONTEND_CREATE_TOKEN.mddocs/contracts-security-audit.md/docs/contracts-terraclassic.mdRecommended direction
apply_autolp_settings,query_wasm_smartsisterGetConfig. Normalize batch vs response:pair:Someonly if it differs from current (after factory-canonical addr);None= omit.threshold/lp_recipient: change iff present and not equal.skim_max_spread/skim_min_return: change iff the batch sets them and the effective sister value would change (respect clamp / zero-clears-min_return).changedfrom this key; returnNone(no extra msg). If that was the only key,update_settingsalready returnsNoOpSettings.changed, emitUpdateConfigwith only the differing fields asSome(keep merge; do not rewrite pair when the batch omitted it).NoOpSettingsand CMM UST1 unchanged; delta pair/threshold/recipient/skim → invoice + sister config; mixed batch (bps change + identical autolp) → one invoice, no sister execute.cfg.autolpis set; includesettings.autolponly on a real delta; do not substitute threshold1or wallet recipient for blank fields. RTL: filled-but-equal AutoLP does not enable Save / does not build an invoice.Acceptance criteria
UpdateSettings { autolp: <exact current sister pair, threshold, recipient, omitted skim> }and no other dirty keys →NoOpSettings; CMM UST1 balance unchanged; sisterGetConfigunchanged.buy_bpsactually changes → one 50 UST1 invoice; sister notUpdateConfig’d; tokenbuy_bpsupdates.autolp.threshold(or recipient, or listed pair, or skim floor) differs → one 50 UST1; sister config matches; pair still M610-1.autolpin batch → error, fee not kept.auto_v2_lp+autolp→SkuNotUnlocked; fee not kept.NoOpSettings. Identicallaunch_guardsstill no-op (no regression).minterdoes not by itself take the invoice (if that branch is still unconditional).GetConfigdo not attachautolpand do not enable Save. A real AutoLP delta still builds a 50 UST1 token-payee invoice.make verify-issue-592/verify-issue-610stay green.Test plan (functional paths)
autolpidentical toGetConfig; no other keysNoOpSettings; no CMM creditbuy_bpsdeltaupdate_configautolp.thresholdonly deltaautolp.pairnew factory-listed tax pairautolp.pairomitted, other AutoLP fields equalcfg.autolpSkuNotUnlocked; fee not keptlaunch_guardsonlyNoOpSettingsminteronlyNoOpSettingsVitest/RTL for T11–T12. CosmWasm multitest for T1–T10. Playwright not required unless Manage Save enablement is only covered in e2e today.
Test plan (attack, hack, and abuse)
autolpto a no-op tax batch so the key presence forces invoiceautolp.pair= random CW20 / wrong listed pairpair: null/ omitUpdateSettingswith autolpUnauthorized; fee not keptSkuNotUnlocked; fee not keptUpdateConfigspoof from a non-authorized senderregister_listed_pairskim_max_spreadabove 200 bps1/ recipient = connected wallet without user intentInvoiceToken/ T592-12Verification criteria
cd smartcontracts && cargo test -p cl8y-community-tax-tokenincluding new identical-autolp / mixed-batch cases.cargo test -p cl8y-community-tax-autolp(merge / pair gate unchanged).make verify-issue-592andmake verify-issue-610green; addmake verify-issue-<this>grepping T592-4 AutoLP no-op + the new tests.update_settings; delta does.GetConfigupdates.Out of scope
INVOICE_UST1or per-field pricing.settings_feeingest (#1210).SkimToLpfrom taxTransfer/Send.First-pass model recommendation
Recommendation: grok-high
Rationale: Wasm invoice + sister-query dirty detection on
community-tax-token/ AutoLP (invoice.rs, multitest, Manage Token batch builder). Founder-required contracts / wasm / UST1 billing. Wrong compare can either skip a paid sister write or keep charging no-ops. Verification is multitest plus LocalTerra; live instances need a later migrate. That fails the Composer bar (not a local ≤3-file helper with deterministic non-wasm tests).cl8y-agent-control: queued
implementjob0c864769-c040-4089-b493-5afca0d64433(not executed; no Hetzner VM).PR #1239 was marked merged in Forgejo but the recorded merge commit was not an ancestor of
origin/main(force_mergecan do that when required status/review checks are unsatisfied). Relanded via #1242 (e4b8c218/ merge7a37e776).That #1242 union truncated
Makefileafterhelp(droppedbuild-optimized,test-contracts, most recipes). Restored from837b4229plusverify-issue-1237in #1244 (37317336onorigin/main). Do not re-run a naive conflict-union on Makefile.After restore,
make verify-issue-1237was 8/8. AutoLP settings no-op via sisterGetConfigis onmain.Leftover: listed community-tax token wasm store+migrate (same 11611/11619 leftover as #1228). Tracked in a new ops issue.
CI: Woodpecker did not post live statuses. Later merges used
Do: mergewithoutforce_mergeafter dismissingmaintainersand posting a local-gitleaks status. That path does updateorigin/main.Follow-up ops ticket: #1246. Woodpecker enablement: #1247.
columbus-5 wasm for this ticket is not live. Ops tracker: #1246.
Live pairs are 11639 / 1.16.0 (#712). LCD
HybridSimulationbelief_price: "0"still 200 (same output as omitted belief) — #1230 / #1227 / #1231 execute/query wasm still needs a 1.17.0 store+migrate (gitCONTRACT_VERSIONis still 1.15.0). Tax listed pin is 11630 (not 11611/11619); ALPHAterra1x6e64…is 1.0.0 and needs a tax cw2 bump + CMM migrate for #1228 / #1237.Tax wasm stored and listed as 11666 (tx
5A45A84A…, whitelistA9E19924…). Live ALPHA instance is still 11630 / 1.0.0 (CMM admin; no treasury migrate execute). Instance leftover #1250 + ustr-cmm #43. Trading is not frozen: 11630 stays on the whitelist and pair pins still match.