feat(create-token): SKU initialization fields and retail percent tax inputs #605
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#605
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?
Parent / related
Create Token #593 · template #592 · invoices #595 · identity/wallet defaults (sibling issue, same Create Token surface). Do not wait on #603 migrate-adopt.
Live routes:
/token/create,/token/:addr/manage. There is no/token/migratepage.Current codebase
Paid SKUs are checkboxes on create. Only Minting reveals an extra field (optional raw mint cap). Every other SKU is a boolean in
features[]with no init payload, even though the launcher and token already accept most of those fields.transfer_taxCreateTokenMsg.transfer_bpssplit_routerCreateTokenMsg.sinks(SinkKind+bps, max 4, must sum 10000)auto_v2_lpautolp_threshold,autolp_lp_recipient; tokenautolplet _ = (code_id, autolp_init)). Manage shows Skim only ifcfg.autolpis bound.exemption_directoryadd_exempt/remove_exemptafter create.variable_ratesmax_buy_bps/max_sell_bps/max_transfer_bps(combined ≤ 2500, C593-13)instantiateTaxCaps(slack split). User cannot set max %.launch_guardsLaunchGuardsConfig { max_wallet, cooldown_blocks, trading_enabled }. If SKU on and field omitted, contract defaultstrading_enabled: true, cooldown 0, no max wallet.mint_controlmint: { minter, cap }Tax inputs are labeled Buy tax (bps) / Sell tax (bps) (and manage Buy bps / Sell bps).
parseTaxBpsrequires a whole number of basis points, max 2500. Most retail users do not know bps;100is read as “100%” and then either bricks trading or hits the 25% cap error.CreateTokenHookArgshastransferBps?but create page never sets it, and has nosinks/launch_guards/autolp_*/initial_exempt/ max-% fields.On-chain money is still
u16bps. This issue is display + parse + wire-up, not a denom change.Why this is needed
Paying 50 UST1 per SKU with no way to set the SKU’s initial parameters means:
transfer_bps = 0until a second 50 UST1 settings batch.BPS labels cause dangerous mis-entry (10 bps vs 10%). Percent with 2 decimal places maps 1:1 to bps (
2.50%= 250 bps).Constraints / guardrails
bps = round(percent × 100)with exactly 2 decimal places (0.01% = 1 bp). Reject 3+ fraction digits (2.501). Reject> 25.00per leg when that would exceedMAX_TAX_BPS/ combined cap.max_buy + max_sell + max_transfer ≤ 2500. Current buy+sell+transfer likewise. Never default each max to 2500.transfer_bps/sinks/launch_guardsfor unpaid SKUs). Contract already errors if SKU data is present without the feature.create_token. Post-create changes stay 50 UST1 settings batch (or AutoLP sisterUpdateConfigafter bind).autolp_code_idis set (pair may beNoneat create — pair usually does not exist yet), bindcfg.autolpon the token, or (b) refuse the AutoLP SKU at create with copy to unlock + bind on Manage. Fail closed if AutoLP SKU is selected andautolp_code_idis unset (do not take 50 UST1 for a no-op).SkimToLpstays permissionless and is never called fromTransfer/Send(T592-10). Pair must be factory-listed before skim is useful; do not invent pair FoT math (H-01 / T592-1).initial_exempt: Vec<String>on tokenInstantiateMsg+ launcherCreateTokenMsg, only ifexemption_directoryis infeatures. Cap length (recommend ≤ 20).addr_validateeach. Reject protocol addresses (self token, factory, router, AutoLP) — those arePROTOCOL_EXEMPTand cannot be removed (T592-9). Manager cannot remove protocol entries later.trading_enabled(do not silently default true). Recommend UI defaulttrading_enabled: false(anti-snipe).max_walletoptional human amount → raw via decimals.cooldown_blocks≥ 0 integer. T592-11:trading_enabled=falseblocks both buy and sell; sell to a listed pair still bypassesmax_wallet.instantiateTaxCapslocked path).?payee=.initial_exempt(and AutoLP bind). Same ops as the identity issue: do not migrate every 11611 token; rotate launchertoken_code_idafter #589 GO.Relevant files
CreateTokenPage.tsxManageTokenPage.tsxcommunityTaxSku.tsparseTaxBpswithparseTaxPercentcommunityTaxInvoice.tscommunityTaxToken.tscommunity-tax-token/src/msg.rsInstantiateMsg,Sink,LaunchGuardsConfig,MAX_SINKScommunity-tax-token/src/contract.rscommunity-tax-token/src/invoice.rsvalidate_sinks(sum 10000)community-token-launcher/src/msg.rsCreateTokenMsgcommunity-token-launcher/src/contract.rsreply)community-tax-autolp/src/msg.rsdocs/frontend.md·docs/contracts-terraclassic.mdAGENTS_FRONTEND_CREATE_TOKEN.md,AGENTS_COMMUNITY_TAX_CW20.mdRecommended direction
parseTaxPercent(raw)→{ ok, bps }or error. Accept0,0.00,2.5,2.50,25,25.00. Reject2.501,25.01(if over cap),abc,10%trailing junk (or strip a single trailing%if you want — pick one and test it). Empty → 0.buildCreateTokenHook/ free-create:transfer_bps,sinks,launch_guards,initial_exempt,autolp_threshold,autolp_lp_recipient, explicitmax_*_bps.UpdateConfigas already designed.Acceptance criteria
transfer_bps. Unchecked → omitted.sinkswith bps sum 10000. Unchecked → omitted.MANAGER_EXEMPT. Protocol addrs rejected.launch_guards. Default-on trading without a control is a fail.make verify-issue-593green + newmake verify-issue-<iid>.Test plan (all paths)
0/0.00/ empty2.5/2.5025.00buy, 0 sell, 0 transfer25.01fail2.501,10.1.0,abc,1e2transfer_taxon, transfer 1.00%transfer_bps: 100, feature presenttransfer_taxoff, leftover draft 1%bps7000+3000; instantiate OKMAX_SINKS)autolp_code_idsetGetConfig.autolpset if (a)get_exemptions.managercontains itmax_buy_bps1000,buy_bps500buy_bps: 1001.00not100features, no SKU fields; launcherCreateTokenexecuteN × 50UST1Attack / abuse test plan
2.50→ 250 bps; snapshot hooktransfer_bpswithouttransfer_taxSKUSkimToLpfrom token transferRegisterListedPairmax_buy_bps: 2500withbuy_bps: 0instantiateTaxCaps(max = current), not a hidden 25% headroommax_walletin human vs raw mismatch (6 vs 18 dp)CombinedTaxCap(C593-13)?payee=/?sink=query999999999.99u16wrap0.1 + 0.2percent sumVerification criteria
docs/frontend.md+ skills: percent UX, SKU init table, AutoLP create rule.marked as related to #592
marked as related to #593
marked as related to #595
marked as related to #601
marked as related to #604
mentioned in issue #604
Depends on identity/wallet defaults in #604 for shared create-form validators (decimals, name/symbol, connected-wallet treasury/manager helpers). Percent tax fields should reuse the same page; do not fork a second wizard.
mentioned in merge request !1121
mentioned in issue #606
marked as related to #606
mentioned in issue #608
marked as related to #608
mentioned in issue #609
marked as related to #609
marked as related to #610
mentioned in issue #610
Audit INTERNAL_KIMIK3_1787468843 notes (approved 2026-08-23)
Do not open a second AutoLP / VariableRates ticket. Fold these into this issue.
H-1 — AutoV2Lp: documented “bind later” has no bind API
Same-tx AutoLP instantiate is out of v1 (
AGENTS_COMMUNITY_TAX_CW20.md,docs/contracts-terraclassic.md, REGISTRY). The audit’s new fact: there is no later execute that setscfg.autolp.apply_autolp_settingserrorsAutoLP contract not bound; enable AutoLp via launcherforever.Launcher
create_tokenstill buildsAutolpInitthenlet _ = (code_id, autolp_init). Mainnet launcher hasautolp_code_id=11613, so the SKU is charged for vapor.This issue must either refuse
auto_v2_lpat create until a bind path exists, or add instantiate+bind (same tx or a later manager/launcher bind) before charging 50 UST1. PoC:poc_autov2lp_paid_but_never_bound(invert when closed).AutoLP hardening (factory-listed pair + token as one side + skim floor) is a sibling issue, gated on this bind.
M-1 — VariableRates: implement only if needed, else remove
require_variable_or_free_profileis a no-op. Free-profile tokens can raise buy/sell to instantiatemax_*via a 50 UST1 settings batch without the SKU. Frontend copy “Adjust buy/sell after launch (still capped)” is true without paying.instantiateTaxCapsonly widens caps when the checkbox is on — the user could have typed thosemax_*anyway.Direction: implement a real gate only if product still wants a paid “change rates later” SKU (e.g. require the SKU to raise above instantiate rates, or to widen caps after create). Otherwise remove the SKU from the dApp catalog and stop charging 50 UST1 for theater. Do not leave the no-op.
PoC:
poc_variable_rates_sku_is_theater.L-3 (missing Manage Token launch-guard / sink / AutoLP editors) was already in this issue’s body.
mentioned in commit
fe47dd8c60mentioned in merge request !1122
Implemented in !1122 (depends on #604 identity/wallet helpers on the same wizard).
Acceptance
transfer_bps. Unchecked → omittedautolp_code_idis set; unset refuses the SKU (no 50 UST1 no-op)launch_guards. Silent default-on is a fail (contract requires explicit config)make verify-issue-593green +make verify-issue-605Verification
Not in this ticket
mentioned in commit
75a0536d58Follow-up on the 2026-08-23 audit note, now in !1122 (
75a0536d):autolp_code_idunset). No 50 UST1 for a discarded sister.max_*must equal current rates withoutvariable_rates. Settingsbuy_bps/sell_bpsrequire the SKU.require_variable_or_free_profileno-op removed. Manage buy/sell locked until unlock. Invariant C605-4.Sibling findings stay on their tickets: #606 (C-1/H-2/L-1), #608 (H-3/H-4), #609 (M-5), #610 (M-2/M-3).
mentioned in commit
715d9555bdmentioned in commit
33e4153f87mentioned in commit
784ac9e1cdmentioned in commit
709a2694d5mentioned in commit
fe2a71a5d6mentioned in issue #611
marked as related to #611
Merge !1122 — in-repo #605 / H-1 / M-1 passed (
make verify-issue-605green): percent taxes, SKU init payloads, AutoLP instantiate+bind or refuse, VariableRates gate.Merge integration (fixed on !1123/!1124, now on main):
audit_pocfixtures still used max_* headroom and expected AutoLP never-bound; those PoCs were inverted to match this MR. LaunchGuards tests that assumed instantiatetrading_enabled=truenow callenable_launch_guards.Ops leftover: LocalTerra store + Manage settings-batch LCD round-trip, and new wasm rotate — #611. AutoLP pair/skim stays #610. EnableFeature/SKU dedupe stays #606.
mentioned in issue #616
mentioned in commit
0e70c6b7famentioned in issue #620
mentioned in issue #603
mentioned in issue #669
marked as related to #669