feat(community-tax): autoregister CL8Y pairs on create + Manage catch-up + manager tax skip #633

Closed
opened 2026-08-25 02:04:13 +00:00 by PlasticDigits · 13 comments
PlasticDigits commented 2026-08-25 02:04:13 +00:00 (Migrated from gitlab.com)

Template #592 (T592-1, T592-7, T592-9). Create/Manage #593. ExemptionDirectory #609 (E609-1–E609-7). AutoLP factory pair #610 (M610-1). Migrate-adopt #626 (M626-10 — do not register Terraport/GDEX). LocalTerra seed already registers QATax/EMBER (#620 L620-4). Router hops #607. H-01: no pair/router FoT math.

Product (2026-08-25): every CL8Y factory pair that holds a community-tax CW20 must be RegisterListedPair'd. The manager wallet must not pay buy / sell / transfer tax when they add LP or trade. Catch-up lives on Manage: if a managed tax token still has no registered factory pair, show a highly visible alert and one button that registers the highest-LP unregistered factory pair. Hide the alert when registration is not needed.

This ticket is one product change. Shipping autoregister without the manager tax skip taxes the manager on the newly listed markets. Do not split those workstreams across merges.


Current codebase

Buy/sell tax is per pair address, not per token. LISTED_PAIRS is written only by ExecuteMsg::RegisterListedPair { pair } on the token (pair_registry.rs). The execute is permissionless and add-only. It verifies:

  1. Pair Pair {} contract_addr matches the argument.
  2. One asset is this token.
  3. config.factory Pair { asset_infos } returns the same address.

On success it writes LISTED_PAIRS + PROTOCOL_EXEMPT. There is no unregister. Terraport/GDEX addrs fail the factory lookup (T592-9 / M626-10).

Nothing in the retail path calls it:

Surface Today
Launcher CreateToken / adopt migrate Stamps factory/router. No pair. No register. Manager is not written to MANAGER_EXEMPT.
/create CreatePairPage.tsx Factory CreatePair only. createPair returns a tx hash. No follow-up.
Factory execute_create_pair Instantiates the pair. Does not talk to either asset CW20.
ManageTokenPage.tsx Links to /create. No register alert/button. registerListedPair exists but is unused.
AutoLP pair.rs Same factory lookup as RegisterListedPair, then stores cfg.pair. Does not execute register on the token. Skim Send+Swap + provide assumes the pair is already listed for retail tax; AutoLP itself is protocol-exempt so its own pull stays 1:1.
LocalTerra deploy-community-tax-local.sh / #601 smoke Does register after CreatePair (ops-only).
IsProtocolExempt protocol is true for registered pairs (and factory/router/AutoLP/self). manager is only MANAGER_EXEMPT, not config.manager.

Classification (tax.rs):

  • Registered pair + Send+Swap → sell extra-debit. Pair → non-exempt → buy split. TransferFrom to a registered pair → Honest.
  • Unregistered factory pair → no buy/sell. If TransferTax is on, Transfer / TransferFrom to that pair is Transfer FoT. Pair provide_liquidity credits RESERVES from the declared amount (pair/src/contract.rs ~1711–1746). That is P2 / H-01 reserve desync (High when TransferTax is on). Crate fixture comment already says “List before seed so TransferTax SKU does not tax the pair fund.”
  • Official router → user is buy even when the previous hop was unregistered.

Manager tax skip today is paid SKU only (E609-5). config.manager is instantiate/adopt-only (SettingsBatch cannot rotate it). Extra directory wallets stay on exemption_directory + 50 UST1. Launch guards still use economic kind (E609-2).

Indexer GET /api/v1/tokens/{addr}/pairs lists factory-ingested pairs without reserves / listed / USD TVL. Highest-LP must come from LCD Pool (getPool) plus optional hub USD. Catalog GET /api/v1/community-tokens?manager= powers MyCommunityTokensPage.tsx.

Swap/Trade Max uses token-level sell_bps and IsProtocolExempt.manager — it does not check whether the hop pair is registered.


Why this is needed

Product is not “some pairs tax-off forever.” Managers create (and after migrate, catch up) CL8Y markets and expect:

  1. Those markets are listed-pair tax markets (buy/sell apply for retail).
  2. The manager can seed LP and trade without paying that tax.
  3. They are not left to remember a permissionless CosmWasm execute.

Today a manager who follows Create Token → Create Pair gets a tax-off pool. Retail quotes still say “listed-pair swap.” If they later enable TransferTax and provide before registering, inbound FoT desyncs reserves. AutoLP can be bound to a factory pair that is still unregistered, so skim LP works but retail buy/sell on that market never starts. Adopted tokens with existing CL8Y pairs stay unregistered until someone runs terrad.


Constraints / guardrails

  1. Do not change pair/router swap math (H-01). No balance-delta FoT on pair/router.
  2. Do not RegisterListedPair Terraport / GDEX / non-factory addrs (M626-10). Factory Pair lookup stays the gate (T592-9).
  3. Do not factory-whitelist 8654 or launcher / AutoLP code ids (O601-2).
  4. Register is add-only. No unregister API. Idempotent re-register stays already: true.
  5. Factory must not blindly execute register_listed_pair on both assets. Honest CW20s reject the unknown variant and would revert CreatePair. Gate on cw2 ∈ community-tax token crate name(s) (11611 / 11619 / LocalTerra store), or an equivalent GetConfig probe that honest templates do not implement.
  6. Manager tax skip is role-based, not a new paid SKU. Treat config.manager like MANAGER_EXEMPT for Buy / Sell / Transfer (and official-router hop trader). Do not make the manager protocol-exempt (that would drop them as a cooldown subject — E609-2 / T592-11 stay on). Extra wallets still require exemption_directory.
  7. Manager cannot remove themselves via remove_exempt to “opt into tax” in a way that breaks the product rule — skip is addr == config.manager || MANAGER_EXEMPT. Protocol entries still cannot be removed.
  8. C593-8: Manage register chrome only when LCD code_id is the community-tax pin (VITE_COMMUNITY_TAX_CODE_ID / LocalTerra tax store). 6036 / 10184 / 8266 / 8654 must not see it.
  9. C593-6 / C593-10: CTA is manager-wallet gated from LCD GetConfig.manager. No ?payee= / ?manager= / ?pair=.
  10. C593-11 / M626-12: Do not dump the token into Swap defaults. After register, stay on Manage (optional link to /pool for that pair).
  11. Copy (#489): human words. No LISTED_PAIRS / VITE_* / RegisterListedPair on the alert. Something like: this market is not collecting buy/sell tax yet; register the largest CL8Y pool.
  12. #596: do not turn hybrid off.
  13. Live columbus-5 11611 / 11619 need a CMM token migrate for the manager-role skip. Factory autoregister needs a factory migrate. dApp sequential register + Manage catch-up must work before those migrates (already-permissionless execute).
  14. Unregistered + TransferTax provide FoT is in scope to close by registering before LP, not by adding pair FoT math.

Relevant files

Area Path
Token register smartcontracts/contracts/community-tax-token/src/pair_registry.rs, tax.rs, contract.rs, msg.rs, adopt.rs, multitest.rs
AutoLP bind smartcontracts/contracts/community-tax-autolp/src/pair.rs, contract.rs
Factory create smartcontracts/contracts/factory/src/contract.rs
dApp Create Pair frontend-dapp/src/pages/CreatePairPage.tsx, services/terraclassic/factory.ts
dApp Manage frontend-dapp/src/pages/ManageTokenPage.tsx, ManageTokenPage.test.tsx
Client helper frontend-dapp/src/services/terraclassic/communityTaxToken.ts (registerListedPair, queryCommunityTaxIsExempt)
Pools / rank frontend-dapp/src/services/terraclassic/pair.ts (getPool), services/indexer/client.ts (getTokenPairs, getCommunityTokens, getPairStats)
Seed (already registers) scripts/lib/deploy-community-tax-local.sh, scripts/qa/localterra-community-tax-smoke.sh
Docs / playbooks docs/contracts-terraclassic.md § Classification, skills/AGENTS_COMMUNITY_TAX_CW20.md, AGENTS_COMMUNITY_TAX_AUTOLP.md, AGENTS_COMMUNITY_TAX_EXEMPT.md, AGENTS_FRONTEND_CREATE_TOKEN.md, AGENTS_FRONTEND_TOKEN_MIGRATE.md

A — Manager role is always tax-skip (on-chain)

In is_manager_exempt / is_manager_directory_tax_skip / hop-trader skip / IsProtocolExempt.manager / GetExemptions.manager: treat config.manager as exempt in addition to MANAGER_EXEMPT. Same Honest skip as #609. Launch guards unchanged. Instantiate/adopt do not need to write MANAGER_EXEMPT (role is enough). Swap/Trade Max already zeros extra-debit when manager === true — query must start returning that for the manager without the SKU.

Crate + migrate 11619 (and LocalTerra tax wasm). Keep 11611 listed until Refresh (F6); disclose 11611 instances stay pre-skip until CMM migrate.

B — Autoregister on CL8Y CreatePair

B1 (retail, ships without factory migrate). After a successful /create tx, query factory Pair { asset_infos }. For each asset whose LCD code_id is the community-tax pin, register_listed_pair from the same wallet. UX is one flow (sequential txs or a follow-up the page runs automatically). Toast only after register succeeds or already. If register fails, show a hard error and point at Manage catch-up — do not pretend the market is listed.

B2 (all creators, including terrad / other UIs). Factory instantiate-reply (or equivalent post-pair persist): cw2/code-id gate, then WasmMsg::Execute register_listed_pair on that asset. Fail-closed if the token is tax wasm and register fails (except already). Honest assets: no execute. Requires factory migrate + docs. Do not call unknown CW20 executes.

C — AutoLP bind registers

When AutoLP pair is set (instantiate or manager UpdateConfig), also execute register_listed_pair on cfg.token for the factory-returned pair addr. Same lookup as M610-1. Idempotent. Skim still never runs from token Transfer/Send (T592-10). Manage AutoLP pair field: after save, pair must query IsProtocolExempt.protocol == true.

D — Manage catch-up (highest LP)

On /token/:addr/manage, when the connected wallet is GetConfig.manager and the token is the tax template:

  1. Load factory pairs that include this token (getTokenPairs and/or factory pagination + LCD Pair verify). Drop non-factory.
  2. For each, IsProtocolExempt { address: pair } (or equivalent).
  3. Hide the alert when there are no factory pairs, or every factory pair is already registered, or the template is not tax (C593-8). Registration is still required at 0 bps (prepares later rate enable); do not hide only because buy_bps/sell_bps/transfer_bps are 0.
  4. If any factory pair is unregistered: highly visible alert (not a dim hint). One button: register the highest-LP unregistered factory pair.
  5. Highest LP: LCD Pool reserves. Prefer hub/oracle USD TVL when both sides price; else rank by tax-token reserve, then other-side reserve. Tie: lower pair address. Skip pairs that fail factory verify.
  6. Button label includes the pair identity (symbols + truncated addr) and “largest pool”. Calls existing registerListedPair. After success, refetch; if more unregistered remain, keep the alert and retarget the button at the next highest (still one button).
  7. Any managed token: also query GET /api/v1/community-tokens?manager=. If another attested tax token has an unregistered factory pair, a second line links to that token’s Manage. No extra register buttons on this page.

/tokens may show a compact “needs pool registration” mark; not a substitute for the Manage alert.

E — Docs / seed

Document that retail markets are listed-pair tax once registered; manager role skips tax; Terraport stays 1:1. LocalTerra seed already registers — keep that; add an assert that IsProtocolExempt is true for the seed pair and IsProtocolExempt.manager is true for test1 as manager without ExemptionDirectory.


Acceptance criteria

  • AC1. Official dApp Create Pair for a community-tax asset ends with that new factory pair registered (IsProtocolExempt.protocol true on the pair). Honest-only pairs unchanged (no extra execute).
  • AC2. Factory CreatePair (after factory migrate) autoregisters tax assets via cw2/code-id gate. Creating an honest/honest pair does not call tax executes. Creating tax/honest registers only the tax token. Creating tax/tax (if ever allowed) registers both.
  • AC3. AutoLP set-pair registers that pair on the token. Re-bind of the same pair is idempotent.
  • AC4. Manage (manager wallet, tax template) shows a highly visible alert iff this token has ≥1 factory pair and ≥1 of those is unregistered. Hidden when no factory pair, all registered, wrong code id, or disconnected/non-manager.
  • AC5. Single CTA registers the highest-LP unregistered factory pair. After that, leftover unregistered pairs keep the alert aimed at the next highest. Never offers a Terraport/GDEX addr.
  • AC6. If the connected manager has another catalogued tax token with an unregistered factory pair, Manage shows a link to that token’s Manage. No ?pair= / ?payee= prefill.
  • AC7. config.manager skips buy, sell, and transfer tax (pair-direct and official-router hop trader). TaxPreview matches execute. Pair inbound stays 1:1. Extra-debit Max is 0 for the connected manager.
  • AC8. Launch guards still apply to the manager (trading_enabled, cooldown, max_wallet on user-side buys/transfers). Manager sell-to-listed-pair still bypasses max_wallet (T592-11).
  • AC9. Non-manager retail on a registered pair still pays buy/sell. TransferTax still hits non-exempt wallet↔wallet.
  • AC10. Adopt/migrate does not register Terraport/GDEX. Existing CL8Y pairs are caught by Manage / permissionless register, not by the migrate tx.
  • AC11. Copy is retail (#489). Hybrid stays on (#596). No Swap default dump.

Test plan — happy / functional paths

  1. Free create + Create Pair (dApp). 0 SKU token, /create vs UST1 or EMBER. After the flow, LCD IsProtocolExempt on the new pair is protocol true. Provide 1:1. Retail Send+Swap extra-debits when sell_bps > 0; manager Send+Swap Honest.
  2. Paid create with buy/sell. Same as (1); retail extra-debit / buy split match TaxPreview. Manager provide + swap Honest.
  3. TransferTax + new pair. Register happens before first provide (dApp order). Provide 1:1 (P2 reserves == CW20). Control: if register is skipped in a unit test, TransferFrom to the unregistered pair must still show the FoT desync so we do not “fix” it with pair math.
  4. Factory CLI CreatePair (after B2). terrad create tax/EMBER without dApp; pair is registered in the same tx (or documented factory reply). Honest/honest create unchanged.
  5. Idempotent register. Second RegisterListedPair already: true; Manage alert gone once all factory pairs are listed.
  6. Two factory pairs. Seed A (low LP) and B (high LP), neither registered. Alert button targets B. After register B, button targets A. After A, alert hidden.
  7. AutoLP. Create with auto_v2_lp, Create Pair, Manage bind pair → token IsProtocolExempt.protocol true and AutoLP GetConfig.pair set. SkimToLp still permissionless; not called from token transfer. Floor unchanged (M610-3).
  8. Migrate honest 10184 analogue. Adopt tax-off zeros. Existing CL8Y pair (if any) is not registered by adopt. Manage alert offers that factory pair (not Terraport). Manager of adopted token is tax-skip without ExemptionDirectory SKU.
  9. Cross-token alert. Wallet manages token T1 (all registered) and T2 (unregistered factory pair). On T1 Manage, secondary link to T2. On T2, primary alert + button.
  10. Non-manager. Manage is read-only; no register CTA. Retail swap on registered pair still taxed.
  11. Wrong template. Manage of 10184/8266/6036 does not show the alert.
  12. No factory pair. New token, no /create yet: no alert (nothing to register).
  13. Swap/Trade Max. Connected manager: no extra-debit cap. Other wallet: extra-debit when selling into a registered pair (pair-direct and router).
  14. LocalTerra seed. Existing register + new manager-role query without ExemptionDirectory.
  15. Vitest. Manage alert visibility matrix; highest-LP picker (USD tie-break / reserve fallback / factory-only filter); Create Pair follow-up calls register_listed_pair only for tax code ids.
  16. Crates. Manager role skip without MANAGER_EXEMPT row; AutoLP set-pair emits token register; factory create tax asset registers / honest does not; Terraport-shaped addr rejected.

Test plan — attack / abuse / hack vectors

  1. Fake pair / wrong factory. Register or button must reject a random CW20, a pair that does not hold this token, and a pair from another factory (T592-9). AutoLP bind same.
  2. Terraport/GDEX spoof. Paste ALPHA/Open Terraport pair into any new UI or AutoLP field → reject. Adopt must not register those addrs.
  3. Blind factory execute. Factory CreatePair of honest/honest must not register_listed_pair (would revert). Tax/honest must not execute on the honest side.
  4. Permissionless register grief. Anyone can still register a real factory pair (already true). That is now the desired end state. They cannot register a non-factory pool to turn on tax. They cannot unregister. They cannot register a pair for a different token.
  5. Manager spoof via URL. ?manager= / ?pair= / ?payee= must not change CTA target or invoice payee.
  6. Manager protocol-exempt smuggle. Manager must remain a cooldown / trading_enabled subject. remove_exempt must not strip factory/router/pairs. Adding the pair to MANAGER_EXEMPT stays forbidden (E609-3).
  7. Self-trader / protocol trader on router hop. Missing / protocol-exempt / self Swap.trader still fail-closed (T592-13). Manager-as-trader is Honest tax, not fail-closed.
  8. CreatePair fee / pending pair. Factory one-per-block (F1) and uluna fee (F2) unchanged. Register follow-up must not skip the fee or double-instantiate.
  9. F6 freeze. Registering a pair does not Refresh pins and does not unpause. Frozen hops stay out of route/solve (#585). Alert may still register a frozen factory pair (listing ≠ thaw).
  10. TransferTax race. Third party CreatePairs a second quote asset and immediately LPs before dApp/factory register. After B2 this should be closed for factory creates. Until B2, Manage catch-up + docs; do not add pair FoT math. Test that unregistered + TransferTax provide still desyncs if register is omitted (invariant alarm).
  11. Two tax tokens in one pair. Register must be invoked on each tax asset; one success and one skip/fail must not leave a half-listed market without error UX.
  12. Catalog unattested. Cross-token alert uses attested manager catalog only (CMM + origin). Rogue instantiate with this wallet as manager must not appear (O601-4).
  13. Reentrancy / AutoLP. Register execute from AutoLP bind must not call SkimToLp. SKIMMING residual M610-8 unchanged.
  14. ExemptionDirectory bypass. Non-manager must not gain skip by appearing in a spoofed query. Fail-closed Max when exempt status unknown (E609-7).

Verification criteria

Close only when all of the following pass:

cd smartcontracts && cargo test -p cl8y-community-tax-token -p cl8y-community-tax-autolp -p cl8y-dex-factory
make verify-issue-593
make verify-issue-609
make verify-issue-610
make verify-issue-626
# add make verify-issue-<this> covering: manager-role skip crate, AutoLP register-on-bind,
# Manage alert/highest-LP Vitest, Create Pair follow-up Vitest
  • LocalTerra: make deploy-local seed pair still registered; new dApp Create Pair for a second tax/EMBER (or tax/UST1) pair is registered without a hand-rolled terrad execute; manager test1 provide + swap are Honest; a second wallet pays sell extra-debit on that pair.
  • LCD: IsProtocolExempt on the new pair protocol: true; on the manager manager: true without ExemptionDirectory SKU.
  • Manage: no alert when all factory pairs registered; alert + one button when not; button never shows a non-factory addr; non-manager sees no CTA.
  • Docs/playbooks updated: listed-pair tax is the default for new CL8Y pools; manager role skip; Terraport still not registered; TransferTax + unregistered provide remains the High residual only for pairs that escaped B1/B2 (should be none on official create).

Do not close if factory B2 is skipped without an explicit leftover ticket and dApp B1 + Manage D are green — or the inverse (factory only, no Manage catch-up for adopt leftovers).


Out of scope

  • Pair/router FoT math or un-whitelisting 11611/11619.
  • Registering Terraport/GDEX or factory-listing 8654.
  • Paid ExemptionDirectory for other wallets (stays #609).
  • Turning hybrid off, Swap default injection, RefreshPairAssetCodeIds from the token admin.
  • Unregister / per-pair tax-off markets (rejected product).
## Parent / related Template [#592](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/592) (**T592-1**, **T592-7**, **T592-9**). Create/Manage [#593](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/593). ExemptionDirectory [#609](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/609) (**E609-1–E609-7**). AutoLP factory pair [#610](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/610) (**M610-1**). Migrate-adopt [#626](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/626) (**M626-10** — do **not** register Terraport/GDEX). LocalTerra seed already registers QATax/EMBER ([#620](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/620) **L620-4**). Router hops [#607](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/607). H-01: no pair/router FoT math. Product (2026-08-25): **every CL8Y factory pair** that holds a community-tax CW20 must be `RegisterListedPair`'d. The **manager** wallet must not pay buy / sell / transfer tax when they add LP or trade. Catch-up lives on Manage: if a managed tax token still has no registered factory pair, show a highly visible alert and **one** button that registers the **highest-LP** unregistered factory pair. Hide the alert when registration is not needed. This ticket is one product change. Shipping autoregister **without** the manager tax skip taxes the manager on the newly listed markets. Do not split those workstreams across merges. --- ## Current codebase Buy/sell tax is **per pair address**, not per token. `LISTED_PAIRS` is written only by `ExecuteMsg::RegisterListedPair { pair }` on the **token** ([`pair_registry.rs`](smartcontracts/contracts/community-tax-token/src/pair_registry.rs)). The execute is **permissionless** and add-only. It verifies: 1. Pair `Pair {}` `contract_addr` matches the argument. 2. One asset is this token. 3. `config.factory` `Pair { asset_infos }` returns the same address. On success it writes `LISTED_PAIRS` + `PROTOCOL_EXEMPT`. There is **no unregister**. Terraport/GDEX addrs fail the factory lookup (**T592-9** / **M626-10**). Nothing in the retail path calls it: | Surface | Today | |---------|--------| | Launcher `CreateToken` / adopt migrate | Stamps factory/router. No pair. No register. Manager is **not** written to `MANAGER_EXEMPT`. | | `/create` [`CreatePairPage.tsx`](frontend-dapp/src/pages/CreatePairPage.tsx) | Factory `CreatePair` only. [`createPair`](frontend-dapp/src/services/terraclassic/factory.ts) returns a tx hash. No follow-up. | | Factory `execute_create_pair` | Instantiates the pair. Does not talk to either asset CW20. | | [`ManageTokenPage.tsx`](frontend-dapp/src/pages/ManageTokenPage.tsx) | Links to `/create`. No register alert/button. [`registerListedPair`](frontend-dapp/src/services/terraclassic/communityTaxToken.ts) exists but is unused. | | AutoLP [`pair.rs`](smartcontracts/contracts/community-tax-autolp/src/pair.rs) | Same factory lookup as `RegisterListedPair`, then stores `cfg.pair`. Does **not** execute register on the token. Skim `Send+Swap` + provide assumes the pair is already listed for retail tax; AutoLP itself is protocol-exempt so its own pull stays 1:1. | | LocalTerra [`deploy-community-tax-local.sh`](scripts/lib/deploy-community-tax-local.sh) / `#601` smoke | **Does** register after `CreatePair` (ops-only). | | `IsProtocolExempt` | `protocol` is true for registered pairs (and factory/router/AutoLP/self). `manager` is **only** `MANAGER_EXEMPT`, not `config.manager`. | Classification ([`tax.rs`](smartcontracts/contracts/community-tax-token/src/tax.rs)): - Registered pair + `Send+Swap` → sell extra-debit. Pair → non-exempt → buy split. `TransferFrom` to a registered pair → Honest. - Unregistered factory pair → no buy/sell. If **TransferTax** is on, `Transfer` / `TransferFrom` to that pair is **Transfer FoT**. Pair `provide_liquidity` credits `RESERVES` from the **declared** amount ([`pair/src/contract.rs`](smartcontracts/contracts/pair/src/contract.rs) ~1711–1746). That is P2 / H-01 reserve desync (**High** when TransferTax is on). Crate fixture comment already says *“List before seed so TransferTax SKU does not tax the pair fund.”* - Official router → user is **buy** even when the previous hop was unregistered. Manager tax skip today is **paid SKU only** (**E609-5**). `config.manager` is instantiate/adopt-only (`SettingsBatch` cannot rotate it). Extra directory wallets stay on `exemption_directory` + 50 UST1. Launch guards still use economic kind (**E609-2**). Indexer `GET /api/v1/tokens/{addr}/pairs` lists factory-ingested pairs **without** reserves / `listed` / USD TVL. Highest-LP must come from LCD `Pool` ([`getPool`](frontend-dapp/src/services/terraclassic/pair.ts)) plus optional hub USD. Catalog `GET /api/v1/community-tokens?manager=` powers [`MyCommunityTokensPage.tsx`](frontend-dapp/src/pages/MyCommunityTokensPage.tsx). Swap/Trade Max uses token-level `sell_bps` and `IsProtocolExempt.manager` — it does not check whether the hop pair is registered. --- ## Why this is needed Product is **not** “some pairs tax-off forever.” Managers create (and after migrate, catch up) CL8Y markets and expect: 1. Those markets **are** listed-pair tax markets (buy/sell apply for retail). 2. The **manager** can seed LP and trade without paying that tax. 3. They are not left to remember a permissionless CosmWasm execute. Today a manager who follows Create Token → Create Pair gets a **tax-off** pool. Retail quotes still say “listed-pair swap.” If they later enable TransferTax and provide before registering, inbound FoT desyncs reserves. AutoLP can be bound to a factory pair that is still unregistered, so skim LP works but retail buy/sell on that market never starts. Adopted tokens with existing CL8Y pairs stay unregistered until someone runs terrad. --- ## Constraints / guardrails 1. **Do not change pair/router swap math** (H-01). No balance-delta FoT on pair/router. 2. **Do not `RegisterListedPair` Terraport / GDEX / non-factory addrs** (**M626-10**). Factory `Pair` lookup stays the gate (**T592-9**). 3. **Do not factory-whitelist 8654** or launcher / AutoLP code ids (**O601-2**). 4. **Register is add-only.** No unregister API. Idempotent re-register stays `already: true`. 5. **Factory must not blindly execute `register_listed_pair` on both assets.** Honest CW20s reject the unknown variant and would revert `CreatePair`. Gate on cw2 ∈ community-tax token crate name(s) (11611 / 11619 / LocalTerra store), or an equivalent `GetConfig` probe that honest templates do not implement. 6. **Manager tax skip is role-based**, not a new paid SKU. Treat `config.manager` like `MANAGER_EXEMPT` for Buy / Sell / Transfer (and official-router hop `trader`). **Do not** make the manager protocol-exempt (that would drop them as a cooldown subject — **E609-2** / **T592-11** stay on). Extra wallets still require `exemption_directory`. 7. **Manager cannot remove themselves** via `remove_exempt` to “opt into tax” in a way that breaks the product rule — skip is `addr == config.manager || MANAGER_EXEMPT`. Protocol entries still cannot be removed. 8. **C593-8:** Manage register chrome only when LCD `code_id` is the community-tax pin (`VITE_COMMUNITY_TAX_CODE_ID` / LocalTerra tax store). 6036 / 10184 / 8266 / 8654 must not see it. 9. **C593-6 / C593-10:** CTA is manager-wallet gated from LCD `GetConfig.manager`. No `?payee=` / `?manager=` / `?pair=`. 10. **C593-11 / M626-12:** Do not dump the token into Swap defaults. After register, stay on Manage (optional link to `/pool` for that pair). 11. **Copy (#489):** human words. No `LISTED_PAIRS` / `VITE_*` / `RegisterListedPair` on the alert. Something like: this market is not collecting buy/sell tax yet; register the largest CL8Y pool. 12. **#596:** do not turn hybrid off. 13. Live columbus-5 **11611** / **11619** need a **CMM token migrate** for the manager-role skip. Factory autoregister needs a **factory migrate**. dApp sequential register + Manage catch-up must work **before** those migrates (already-permissionless execute). 14. Unregistered + TransferTax provide FoT is in scope to **close** by registering before LP, not by adding pair FoT math. --- ## Relevant files | Area | Path | |------|------| | Token register | `smartcontracts/contracts/community-tax-token/src/pair_registry.rs`, `tax.rs`, `contract.rs`, `msg.rs`, `adopt.rs`, `multitest.rs` | | AutoLP bind | `smartcontracts/contracts/community-tax-autolp/src/pair.rs`, `contract.rs` | | Factory create | `smartcontracts/contracts/factory/src/contract.rs` | | dApp Create Pair | `frontend-dapp/src/pages/CreatePairPage.tsx`, `services/terraclassic/factory.ts` | | dApp Manage | `frontend-dapp/src/pages/ManageTokenPage.tsx`, `ManageTokenPage.test.tsx` | | Client helper | `frontend-dapp/src/services/terraclassic/communityTaxToken.ts` (`registerListedPair`, `queryCommunityTaxIsExempt`) | | Pools / rank | `frontend-dapp/src/services/terraclassic/pair.ts` (`getPool`), `services/indexer/client.ts` (`getTokenPairs`, `getCommunityTokens`, `getPairStats`) | | Seed (already registers) | `scripts/lib/deploy-community-tax-local.sh`, `scripts/qa/localterra-community-tax-smoke.sh` | | Docs / playbooks | `docs/contracts-terraclassic.md` § Classification, `skills/AGENTS_COMMUNITY_TAX_CW20.md`, `AGENTS_COMMUNITY_TAX_AUTOLP.md`, `AGENTS_COMMUNITY_TAX_EXEMPT.md`, `AGENTS_FRONTEND_CREATE_TOKEN.md`, `AGENTS_FRONTEND_TOKEN_MIGRATE.md` | --- ## Recommended direction ### A — Manager role is always tax-skip (on-chain) In `is_manager_exempt` / `is_manager_directory_tax_skip` / hop-trader skip / `IsProtocolExempt.manager` / `GetExemptions.manager`: treat **`config.manager` as exempt** in addition to `MANAGER_EXEMPT`. Same Honest skip as #609. Launch guards unchanged. Instantiate/adopt do **not** need to write `MANAGER_EXEMPT` (role is enough). Swap/Trade Max already zeros extra-debit when `manager === true` — query must start returning that for the manager without the SKU. Crate + migrate **11619** (and LocalTerra tax wasm). Keep 11611 listed until Refresh (**F6**); disclose 11611 instances stay pre-skip until CMM migrate. ### B — Autoregister on CL8Y `CreatePair` **B1 (retail, ships without factory migrate).** After a successful `/create` tx, query factory `Pair { asset_infos }`. For each asset whose LCD `code_id` is the community-tax pin, `register_listed_pair` from the same wallet. UX is one flow (sequential txs or a follow-up the page runs automatically). Toast only after register succeeds or `already`. If register fails, show a hard error and point at Manage catch-up — do **not** pretend the market is listed. **B2 (all creators, including terrad / other UIs).** Factory instantiate-reply (or equivalent post-pair persist): cw2/code-id gate, then `WasmMsg::Execute` `register_listed_pair` on that asset. Fail-closed if the token is tax wasm and register fails (except `already`). Honest assets: no execute. Requires factory migrate + docs. Do **not** call unknown CW20 executes. ### C — AutoLP bind registers When AutoLP `pair` is set (instantiate or manager `UpdateConfig`), also execute `register_listed_pair` on `cfg.token` for the factory-returned pair addr. Same lookup as **M610-1**. Idempotent. Skim still never runs from token `Transfer`/`Send` (**T592-10**). Manage AutoLP pair field: after save, pair must query `IsProtocolExempt.protocol == true`. ### D — Manage catch-up (highest LP) On `/token/:addr/manage`, when the connected wallet is `GetConfig.manager` and the token is the tax template: 1. Load factory pairs that include this token (`getTokenPairs` and/or factory pagination + LCD `Pair` verify). Drop non-factory. 2. For each, `IsProtocolExempt { address: pair }` (or equivalent). 3. **Hide** the alert when there are **no** factory pairs, or **every** factory pair is already registered, or the template is not tax (**C593-8**). Registration is still required at 0 bps (prepares later rate enable); do not hide only because `buy_bps`/`sell_bps`/`transfer_bps` are 0. 4. If any factory pair is unregistered: **highly visible** alert (not a dim hint). One button: register the **highest-LP** unregistered factory pair. 5. Highest LP: LCD `Pool` reserves. Prefer hub/oracle USD TVL when both sides price; else rank by tax-token reserve, then other-side reserve. Tie: lower pair address. Skip pairs that fail factory verify. 6. Button label includes the pair identity (symbols + truncated addr) and “largest pool”. Calls existing `registerListedPair`. After success, refetch; if more unregistered remain, keep the alert and retarget the button at the next highest (still one button). 7. **Any managed token:** also query `GET /api/v1/community-tokens?manager=`. If another attested tax token has an unregistered factory pair, a second line links to that token’s Manage. No extra register buttons on this page. `/tokens` may show a compact “needs pool registration” mark; not a substitute for the Manage alert. ### E — Docs / seed Document that retail markets are listed-pair tax once registered; manager role skips tax; Terraport stays 1:1. LocalTerra seed already registers — keep that; add an assert that `IsProtocolExempt` is true for the seed pair **and** `IsProtocolExempt.manager` is true for test1 as manager without ExemptionDirectory. --- ## Acceptance criteria - [ ] **AC1.** Official dApp Create Pair for a community-tax asset ends with that new factory pair registered (`IsProtocolExempt.protocol` true on the pair). Honest-only pairs unchanged (no extra execute). - [ ] **AC2.** Factory `CreatePair` (after factory migrate) autoregisters tax assets via cw2/code-id gate. Creating an honest/honest pair does not call tax executes. Creating tax/honest registers **only** the tax token. Creating tax/tax (if ever allowed) registers both. - [ ] **AC3.** AutoLP set-pair registers that pair on the token. Re-bind of the same pair is idempotent. - [ ] **AC4.** Manage (manager wallet, tax template) shows a highly visible alert iff this token has ≥1 factory pair and ≥1 of those is unregistered. Hidden when no factory pair, all registered, wrong code id, or disconnected/non-manager. - [ ] **AC5.** Single CTA registers the highest-LP unregistered factory pair. After that, leftover unregistered pairs keep the alert aimed at the next highest. Never offers a Terraport/GDEX addr. - [ ] **AC6.** If the connected manager has another catalogued tax token with an unregistered factory pair, Manage shows a link to that token’s Manage. No `?pair=` / `?payee=` prefill. - [ ] **AC7.** `config.manager` skips buy, sell, and transfer tax (pair-direct and official-router hop `trader`). `TaxPreview` matches execute. Pair inbound stays 1:1. Extra-debit Max is 0 for the connected manager. - [ ] **AC8.** Launch guards still apply to the manager (`trading_enabled`, cooldown, `max_wallet` on user-side buys/transfers). Manager sell-to-listed-pair still bypasses `max_wallet` (**T592-11**). - [ ] **AC9.** Non-manager retail on a registered pair still pays buy/sell. TransferTax still hits non-exempt wallet↔wallet. - [ ] **AC10.** Adopt/migrate does **not** register Terraport/GDEX. Existing CL8Y pairs are caught by Manage / permissionless register, not by the migrate tx. - [ ] **AC11.** Copy is retail (#489). Hybrid stays on (#596). No Swap default dump. --- ## Test plan — happy / functional paths 1. **Free create + Create Pair (dApp).** 0 SKU token, `/create` vs UST1 or EMBER. After the flow, LCD `IsProtocolExempt` on the new pair is protocol true. Provide 1:1. Retail `Send+Swap` extra-debits when `sell_bps > 0`; manager `Send+Swap` Honest. 2. **Paid create with buy/sell.** Same as (1); retail extra-debit / buy split match `TaxPreview`. Manager provide + swap Honest. 3. **TransferTax + new pair.** Register happens **before** first provide (dApp order). Provide 1:1 (P2 reserves == CW20). Control: if register is skipped in a unit test, TransferFrom to the unregistered pair **must** still show the FoT desync so we do not “fix” it with pair math. 4. **Factory CLI CreatePair** (after B2). `terrad` create tax/EMBER without dApp; pair is registered in the same tx (or documented factory reply). Honest/honest create unchanged. 5. **Idempotent register.** Second `RegisterListedPair` `already: true`; Manage alert gone once all factory pairs are listed. 6. **Two factory pairs.** Seed A (low LP) and B (high LP), neither registered. Alert button targets B. After register B, button targets A. After A, alert hidden. 7. **AutoLP.** Create with `auto_v2_lp`, Create Pair, Manage bind pair → token `IsProtocolExempt.protocol` true **and** AutoLP `GetConfig.pair` set. `SkimToLp` still permissionless; not called from token transfer. Floor unchanged (**M610-3**). 8. **Migrate honest 10184 analogue.** Adopt tax-off zeros. Existing CL8Y pair (if any) is **not** registered by adopt. Manage alert offers that factory pair (not Terraport). Manager of adopted token is tax-skip without ExemptionDirectory SKU. 9. **Cross-token alert.** Wallet manages token T1 (all registered) and T2 (unregistered factory pair). On T1 Manage, secondary link to T2. On T2, primary alert + button. 10. **Non-manager.** Manage is read-only; no register CTA. Retail swap on registered pair still taxed. 11. **Wrong template.** Manage of 10184/8266/6036 does not show the alert. 12. **No factory pair.** New token, no `/create` yet: no alert (nothing to register). 13. **Swap/Trade Max.** Connected manager: no extra-debit cap. Other wallet: extra-debit when selling into a **registered** pair (pair-direct and router). 14. **LocalTerra seed.** Existing register + new manager-role query without ExemptionDirectory. 15. **Vitest.** Manage alert visibility matrix; highest-LP picker (USD tie-break / reserve fallback / factory-only filter); Create Pair follow-up calls `register_listed_pair` only for tax code ids. 16. **Crates.** Manager role skip without `MANAGER_EXEMPT` row; AutoLP set-pair emits token register; factory create tax asset registers / honest does not; Terraport-shaped addr rejected. --- ## Test plan — attack / abuse / hack vectors 1. **Fake pair / wrong factory.** Register or button must reject a random CW20, a pair that does not hold this token, and a pair from another factory (**T592-9**). AutoLP bind same. 2. **Terraport/GDEX spoof.** Paste ALPHA/Open Terraport pair into any new UI or AutoLP field → reject. Adopt must not register those addrs. 3. **Blind factory execute.** Factory CreatePair of honest/honest must not `register_listed_pair` (would revert). Tax/honest must not execute on the honest side. 4. **Permissionless register grief.** Anyone can still register a real factory pair (already true). That is now the desired end state. They **cannot** register a non-factory pool to turn on tax. They **cannot** unregister. They **cannot** register a pair for a different token. 5. **Manager spoof via URL.** `?manager=` / `?pair=` / `?payee=` must not change CTA target or invoice payee. 6. **Manager protocol-exempt smuggle.** Manager must remain a cooldown / `trading_enabled` subject. `remove_exempt` must not strip factory/router/pairs. Adding the pair to `MANAGER_EXEMPT` stays forbidden (**E609-3**). 7. **Self-trader / protocol trader on router hop.** Missing / protocol-exempt / self `Swap.trader` still fail-closed (**T592-13**). Manager-as-trader is Honest tax, not fail-closed. 8. **CreatePair fee / pending pair.** Factory one-per-block (**F1**) and uluna fee (**F2**) unchanged. Register follow-up must not skip the fee or double-instantiate. 9. **F6 freeze.** Registering a pair does not Refresh pins and does not unpause. Frozen hops stay out of `route/solve` (**#585**). Alert may still register a frozen factory pair (listing ≠ thaw). 10. **TransferTax race.** Third party CreatePairs a second quote asset and immediately LPs before dApp/factory register. After B2 this should be closed for factory creates. Until B2, Manage catch-up + docs; do not add pair FoT math. Test that unregistered + TransferTax provide still desyncs if register is omitted (invariant alarm). 11. **Two tax tokens in one pair.** Register must be invoked on **each** tax asset; one success and one skip/fail must not leave a half-listed market without error UX. 12. **Catalog unattested.** Cross-token alert uses attested manager catalog only (CMM + origin). Rogue instantiate with this wallet as manager must not appear (**O601-4**). 13. **Reentrancy / AutoLP.** Register execute from AutoLP bind must not call `SkimToLp`. `SKIMMING` residual **M610-8** unchanged. 14. **ExemptionDirectory bypass.** Non-manager must not gain skip by appearing in a spoofed query. Fail-closed Max when exempt status unknown (**E609-7**). --- ## Verification criteria Close only when **all** of the following pass: ```bash cd smartcontracts && cargo test -p cl8y-community-tax-token -p cl8y-community-tax-autolp -p cl8y-dex-factory make verify-issue-593 make verify-issue-609 make verify-issue-610 make verify-issue-626 # add make verify-issue-<this> covering: manager-role skip crate, AutoLP register-on-bind, # Manage alert/highest-LP Vitest, Create Pair follow-up Vitest ``` - LocalTerra: `make deploy-local` seed pair still registered; **new** dApp Create Pair for a second tax/EMBER (or tax/UST1) pair is registered without a hand-rolled terrad execute; manager test1 provide + swap are Honest; a second wallet pays sell extra-debit on that pair. - LCD: `IsProtocolExempt` on the new pair `protocol: true`; on the manager `manager: true` **without** ExemptionDirectory SKU. - Manage: no alert when all factory pairs registered; alert + one button when not; button never shows a non-factory addr; non-manager sees no CTA. - Docs/playbooks updated: listed-pair tax is the default for new CL8Y pools; manager role skip; Terraport still not registered; TransferTax + unregistered provide remains the High residual **only** for pairs that escaped B1/B2 (should be none on official create). Do **not** close if factory B2 is skipped without an explicit leftover ticket **and** dApp B1 + Manage D are green — or the inverse (factory only, no Manage catch-up for adopt leftovers). --- ## Out of scope - Pair/router FoT math or un-whitelisting 11611/11619. - Registering Terraport/GDEX or factory-listing 8654. - Paid ExemptionDirectory for *other* wallets (stays #609). - Turning hybrid off, Swap default injection, RefreshPairAssetCodeIds from the token admin. - Unregister / per-pair tax-off markets (rejected product).
PlasticDigits commented 2026-08-25 02:08:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #634

mentioned in issue #634
PlasticDigits commented 2026-08-25 02:08:39 +00:00 (Migrated from gitlab.com)

Adopt leftovers (existing CL8Y pairs + Terraport/GDEX) are not this ticket. See #634: migrate-page venue inventory, governance-refresh instructions, and CL8Y-only register tool after pins match. This issue stays new Create Pair / AutoLP bind / Manage highest-LP / manager tax skip.

Adopt leftovers (existing CL8Y pairs + Terraport/GDEX) are **not** this ticket. See [#634](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/634): migrate-page venue inventory, governance-refresh instructions, and CL8Y-only register tool after pins match. This issue stays new Create Pair / AutoLP bind / Manage highest-LP / manager tax skip.
PlasticDigits commented 2026-08-25 02:23:34 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1137

mentioned in merge request !1137
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-25 02:27:27 +00:00
PlasticDigits commented 2026-08-25 02:27:28 +00:00 (Migrated from gitlab.com)

mentioned in commit bb0194082c

mentioned in commit bb0194082c86d2d028fa07db1c0ece86533886e7
PlasticDigits commented 2026-08-25 02:29:30 +00:00 (Migrated from gitlab.com)

mentioned in issue #635

mentioned in issue #635
PlasticDigits commented 2026-08-25 02:29:31 +00:00 (Migrated from gitlab.com)

marked as related to #635

marked as related to #635
PlasticDigits commented 2026-08-25 02:29:41 +00:00 (Migrated from gitlab.com)

!1137 merge note (no CI wait)

Merged !1137 into main as bb019408 (source 8b55d4fd). GitLab reported no conflicts (can_be_merged); local git merge-tree against current main also produced a clean tree (MR was 0 behind, 1 ahead).

Sanity / AC

make verify-issue-633 on the source branch: 6/6 PASS (token + AutoLP + factory crates, Manage/Create Pair Vitest, R633 docs; twice).

AC Result
AC1 dApp Create Pair follow-up Code + Vitest. Live LocalTerra not run.
AC2 factory cw2-gated register Crate tests green. Needs factory migrate before CLI CreatePair autoregisters.
AC3 AutoLP bind register Crate tests green. Live bind not run.
AC4–AC6 Manage catch-up Vitest visibility / highest-LP / other-token link. Live UI not run.
AC7 manager role skip Crate: skip without MANAGER_EXEMPT; TaxPreview matches. Live 11611/11619 still pre-skip until CMM token migrate.
AC8 launch guards stay on Crate: cooldown / max_wallet / trading_enabled still apply to manager.
AC9 retail still taxed Crate: non-manager sell extra-debit on registered pair.
AC10 no Terraport/GDEX register Factory lookup + picker filter. Adopt register stays out of this ticket (#634).
AC11 retail copy / hybrid Alert copy is human words; no Swap dump.

GitLab CI on !1137 failed with ci_quota_exceeded (frontend/contracts/audit/gitleaks) — same quota class as !1136, not a code defect.

Leftovers (do not reopen this issue)

Tracked on #635: factory migrate (LocalTerra + columbus-5), CMM token migrate for live 11611/11619 manager-role skip, LocalTerra Create Pair + Manage live checks.

Migrate-page venue inventory stays on #634.

## !1137 merge note (no CI wait) Merged [!1137](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/419) into `main` as `bb019408` (source `8b55d4fd`). GitLab reported **no conflicts** (`can_be_merged`); local `git merge-tree` against current `main` also produced a clean tree (MR was 0 behind, 1 ahead). ### Sanity / AC `make verify-issue-633` on the source branch: **6/6 PASS** (token + AutoLP + factory crates, Manage/Create Pair Vitest, R633 docs; twice). | AC | Result | |----|--------| | AC1 dApp Create Pair follow-up | Code + Vitest. Live LocalTerra not run. | | AC2 factory cw2-gated register | Crate tests green. **Needs factory migrate** before CLI CreatePair autoregisters. | | AC3 AutoLP bind register | Crate tests green. Live bind not run. | | AC4–AC6 Manage catch-up | Vitest visibility / highest-LP / other-token link. Live UI not run. | | AC7 manager role skip | Crate: skip without `MANAGER_EXEMPT`; TaxPreview matches. Live **11611/11619** still pre-skip until CMM token migrate. | | AC8 launch guards stay on | Crate: cooldown / `max_wallet` / `trading_enabled` still apply to manager. | | AC9 retail still taxed | Crate: non-manager sell extra-debit on registered pair. | | AC10 no Terraport/GDEX register | Factory lookup + picker filter. Adopt register stays out of this ticket ([#634](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/634)). | | AC11 retail copy / hybrid | Alert copy is human words; no Swap dump. | GitLab CI on !1137 failed with `ci_quota_exceeded` (frontend/contracts/audit/gitleaks) — same quota class as !1136, not a code defect. ### Leftovers (do not reopen this issue) Tracked on **[#635](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/635)**: factory migrate (LocalTerra + columbus-5), CMM token migrate for live 11611/11619 manager-role skip, LocalTerra Create Pair + Manage live checks. Migrate-page venue inventory stays on [#634](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/634).
PlasticDigits commented 2026-08-25 02:48:33 +00:00 (Migrated from gitlab.com)

Adopt leftovers (venue inventory, F6/Refresh copy, post-refresh CL8Y register on /token/migrate) are implemented in #634 / !1138. This issue stays Manage + new Create Pair / AutoLP register — do not stretch Manage-only copy to cover migrate inventory.

Adopt leftovers (venue inventory, F6/Refresh copy, post-refresh CL8Y register on `/token/migrate`) are implemented in #634 / !1138. This issue stays Manage + new Create Pair / AutoLP register — do not stretch Manage-only copy to cover migrate inventory.
PlasticDigits commented 2026-08-25 03:50:57 +00:00 (Migrated from gitlab.com)

mentioned in commit 67a8bdb16c

mentioned in commit 67a8bdb16c7e33581784a3825d70fb9878c4060d
PlasticDigits commented 2026-08-25 03:51:22 +00:00 (Migrated from gitlab.com)

LocalTerra verify (not columbus-5)

Pushed to main as 67a8bdb1 (scripts/qa/localterra-633-autoregister.sh + VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633). Fresh LocalTerra deploy (current-wasm factory — no separate leftover factory migrate on this chain). Do not reopen this issue — columbus-5 leftovers stay on #635.

Ran

  • VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633 → 7/7 PASS (token + AutoLP + factory crates, Manage/Create Pair Vitest, R633 docs, LocalTerra live).
  • Factory CreatePair tax/UST1 autoregistered in the same create path (no hand-rolled register_listed_pair).
  • Honest/honest CreatePair succeeded (no blind tax execute).
  • Seed tax pair still IsProtocolExempt.protocol on the pair.
  • test1 IsProtocolExempt.manager true without ExemptionDirectory.
  • Manager provide + Send+Swap Honest; third wallet (test3) sell extra-debit on the new registered pair.
  • AutoLP UpdateConfig { pair } idempotent on an already-registered pair.

Checklist (issue body + comments)

  • LocalTerra seed pair still registered after deploy-local
  • New factory CreatePair tax/UST1 registered without a hand-rolled terrad register
  • Honest/honest CreatePair does not revert
  • LCD: new pair protocol: true; manager manager: true without ExemptionDirectory
  • Manager provide + swap Honest; second wallet extra-debit
  • AutoLP re-bind does not break an already-registered pair
  • Crates + Manage/Create Pair Vitest + docs (make verify-issue-633)
  • Live Manage UI (alert / one highest-LP button / hide when done / non-manager / wrong template) — Vitest only; not Playwright
  • make verify-issue-593 / 609 / 610 / 626 not re-run in this session (merge-time gates)
  • columbus-5 factory migrate
  • columbus-5 CMM token migrate for live 11611 / 11619 manager-role skip

Close decision

Leave closed. LocalTerra R633 live rungs are now green on main. Remaining body items (Manage live UI, sibling verify targets, columbus-5 migrates) stay on #635. No R633 invariant was wrong.

How to re-run: make setup-cloud-localterra (or make deploy-local on a healthy chain), then VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633.

## LocalTerra verify (not columbus-5) Pushed to `main` as `67a8bdb1` (`scripts/qa/localterra-633-autoregister.sh` + `VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633`). Fresh LocalTerra deploy (current-wasm factory — no separate leftover factory migrate on this chain). **Do not reopen this issue** — columbus-5 leftovers stay on #635. ### Ran - `VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633` → **7/7 PASS** (token + AutoLP + factory crates, Manage/Create Pair Vitest, R633 docs, LocalTerra live). - Factory `CreatePair` tax/UST1 **autoregistered** in the same create path (no hand-rolled `register_listed_pair`). - Honest/honest `CreatePair` succeeded (no blind tax execute). - Seed tax pair still `IsProtocolExempt.protocol` on the pair. - test1 `IsProtocolExempt.manager` **true** without ExemptionDirectory. - Manager provide + `Send+Swap` Honest; third wallet (test3) sell extra-debit on the new registered pair. - AutoLP `UpdateConfig { pair }` idempotent on an already-registered pair. ### Checklist (issue body + comments) - [x] LocalTerra seed pair still registered after `deploy-local` - [x] New factory CreatePair tax/UST1 registered without a hand-rolled terrad register - [x] Honest/honest CreatePair does not revert - [x] LCD: new pair `protocol: true`; manager `manager: true` without ExemptionDirectory - [x] Manager provide + swap Honest; second wallet extra-debit - [x] AutoLP re-bind does not break an already-registered pair - [x] Crates + Manage/Create Pair Vitest + docs (`make verify-issue-633`) - [ ] Live Manage UI (alert / one highest-LP button / hide when done / non-manager / wrong template) — Vitest only; not Playwright - [ ] `make verify-issue-593` / `609` / `610` / `626` not re-run in this session (merge-time gates) - [ ] columbus-5 factory migrate - [ ] columbus-5 CMM token migrate for live 11611 / 11619 manager-role skip ### Close decision **Leave closed.** LocalTerra R633 live rungs are now green on `main`. Remaining body items (Manage live UI, sibling verify targets, columbus-5 migrates) stay on #635. No R633 invariant was wrong. How to re-run: `make setup-cloud-localterra` (or `make deploy-local` on a healthy chain), then `VERIFY633_REQUIRE_CHAIN=1 make verify-issue-633`.
PlasticDigits commented 2026-08-25 05:24:07 +00:00 (Migrated from gitlab.com)

Columbus-5 leftover verify #635 is closed (factory 11629, token 11630, AutoLP 11633, Coolify 11630). Do not reopen this issue unless an R633 invariant is wrong.

Columbus-5 leftover verify [#635](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/635) is closed (factory **11629**, token **11630**, AutoLP **11633**, Coolify 11630). Do not reopen this issue unless an **R633** invariant is wrong.
PlasticDigits commented 2026-08-25 05:24:39 +00:00 (Migrated from gitlab.com)

mentioned in commit 4379639ceb

mentioned in commit 4379639ceb45ef414076d0760acdf93f7a97ac91
PlasticDigits commented 2026-08-26 07:36:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #558

mentioned in issue #558
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#633
No description provided.