feat(soft-launch): CW20 faucet contract + dapp mint page (100 tokens / 5m cooldown) #473

Closed
opened 2026-07-12 05:26:00 +00:00 by PlasticDigits · 11 comments
PlasticDigits commented 2026-07-12 05:26:00 +00:00 (Migrated from gitlab.com)

Summary

Ship a bundled soft-launch faucet so users on the mainnet frontend (https://dex.cl8y.com) can select any mintable non-economic gemstone token and mint a fixed 100 units, with a 5-minute per-wallet cooldown. Scope includes:

  1. New CosmWasm faucet / drip contract (authorized minter of soft-launch CW20-mintable tokens)
  2. Mainnet frontend Mint / Faucet page + wallet execute path
  3. Deploy script + operator runbook (store/instantiate, env wiring, Coolify)
  4. Minter grant steps: cl8ydeploy (current primary minter) runs AddMinter for the faucet on each mintable CW20 — no governance/multisig minter handoff (noneconomic tokens; deployer may remain primary minter)

Related soft-launch record: deployments/mainnet-soft-launch/deploy-trace.md, runbook docs/runbooks/mainnet-soft-launch.md.


Current codebase

Soft-launch tokens (columbus-5)

Symbol Kind Address Mintable?
EMBER cw20-mintable (code 10184) terra1dmuruhht32x8f47nvm73pwp6q7uf2jtfhdt3nxcql4mmqkyfsraqn2dt94 Yes
CORAL mintable terra1k6cqupylk0wp4pj273pntwhv9py0q5guyqye8ssvukn9xq7mes7sdlmena Yes
JADE mintable terra1ejq3mjjgnklpa3pg4jterlfwsny055gpmcjf3fz0ev3ueajnzeysz6xxgr Yes
ONYX mintable terra178fgrfzv7njtmdp9vghyf2dx77sah8u8jluzs7ym562chaxnmj2s6mn6m9 Yes
RUBY mintable terra1fga508hzx8dd7x8q4uhm6mdhkqv6fxrtsea3r27smdqmv5k2jgxq5zk9fc Yes
TOPAZ mintable terra12k67cvfs7y7g8lca3qr4g4py6s6j69fu24gze5pjfamfpckv8mps7cymme Yes
QUARTZ cw20-base (code 6036) terra17dpnjlpgsnm8muu4msfjra4f2hrptnjp2jdpkka4p0e3px42ayxq0pmc2z No (fixed supply)
PEARL cw20-base terra18fzufz8cs7ez49xjwgs248x85za5v50yug55fj7lyxp9hapxyr7qnh3czs No (fixed supply)

All soft-launch trading tokens use 6 decimals (invariant SL3). Mint amount 100 human units ⇒ 100_000_000 base units.

Minter reality

Soft-launch instantiate set primary minter to the deploy key (cl8ydeploy / terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv):

# Verified on-chain (EMBER Minter{} query):
# minter = terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv, cap = null

Product decision: leave cl8ydeploy as primary minter for these noneconomic tokens. Do not require UpdateMinter → governance multisig. Faucet authorization is AddMinter { minter: <faucet> } signed by cl8ydeploy on each of the six mintables.

PlasticDigits cw20-mintable supports Mint, AddMinter, RemoveMinter (primary minter + additional minters map). Only the current primary minter (cl8ydeploy) can AddMinter / RemoveMinter.

DEX wasm admin / config.governance remaining on the multisig is unchanged and out of scope for this faucet work.

Frontend today

  • Mainnet dapp routes in frontend-dapp/src/App.tsx: Swap, Pool, Create, Tiers, Charts, Portfolio, Limits, Trade, Protocol — no faucet/mint page.
  • Nav: frontend-dapp/src/components/common/navItems.ts (primary + More menu).
  • Soft-launch Coolify env example does not expose mintable token addresses or a faucet address (deployments/mainnet-soft-launch/frontend.env.example pattern from deploy script).
  • Wallet broadcast patterns live under frontend-dapp/src/services/terraclassic/ (execute + fee estimation); reuse existing Keplr / WalletConnect paths used by Swap/Pool.

Contracts today

  • DEX stack under smartcontracts/contracts/{factory,pair,router,fee-discount,hooks} — no faucet/drip contract.
  • Soft-launch does not store a new CW20 code; it reuses mainnet mintable 10184.
  • LocalTerra seeds mintable tokens with test1 as minter (scripts/deploy-dex-local.sh) — useful for LocalTerra faucet QA after adding a local deploy path.

Ops / docs today

  • Soft-launch operator path: docs/runbooks/mainnet-soft-launch.md, skills/AGENTS_MAINNET_SOFT_LAUNCH.md, make deploy-mainnet-soft-launch.
  • Addresses: deployments/mainnet-soft-launch/addresses.env (+ deploy-trace).
  • No runbook step for faucet AddMinter grants.

Why this is needed

Soft-launch pools are live with non-economic gemstones, but new users cannot obtain tokens unless someone manually transfers from the deployer inventory. A public faucet:

  • Unblocks swap / pool / limits UX demos on dex.cl8y.com without custodian airdrops
  • Keeps supply growth rate-limited (fixed 100 + 5m cooldown) appropriate for noneconomic tokens
  • Moves day-to-day user minting behind an auditable drip contract (allowlist + cooldown) instead of ad-hoc deployer Mint txs
  • Completes soft-launch product surface: “trade the gems” requires “get the gems”

QUARTZ/PEARL remain non-mintable by design; faucet must not claim to mint them (users obtain them via swaps from mintable legs).


Constraints / guardrails

ID Guardrail
F1 Faucet may mint only allowlisted soft-launch mintable token addresses (default: EMBER, CORAL, JADE, ONYX, RUBY, TOPAZ). Reject unknown token args.
F2 Fixed drip size: 100 tokens (6 decimals → 100000000). No user-chosen amount.
F3 5-minute cooldown keyed by wallet address (recommend: global per wallet across all tokens — one drip every 300s regardless of which token was chosen). Document if product prefers per-token cooldowns.
F4 No mint of QUARTZ/PEARL (cw20-base). UI must list mintables only.
F5 Faucet contract must be an authorized minter on each allowlisted CW20 via cl8ydeploy AddMinter. Without this, Mint fails on-chain.
F6 cl8ydeploy remains primary CW20 minter for noneconomic soft-launch tokens. No multisig minter handoff required for this issue.
F7 Soft-launch invariants SL1–SL2 unchanged: do not whitelist economic CW20 code IDs. Faucet is not added to factory CW20 whitelist (it is not a trading token).
F8 Tokens remain non-economic / demo; UI copy must not imply financial claim, redemption, or real-asset backing.
F9 Pause / disable path: faucet admin (cl8ydeploy / designated faucet admin) can pause; cl8ydeploy can RemoveMinter on CW20s in emergency.
F10 No indexer dependency for the happy path (LCD query cooldown + execute). Optional indexer indexing of mint events is out of scope unless trivial.
F11 Production frontend only exposes faucet when VITE_FAUCET_ADDRESS (or equivalent) is set; hide/disable on networks without deploy.
F12 Gas paid by the user calling the faucet (not a sponsored meta-tx). Document LUNC gas requirement.

Relevant files

Area Paths
Soft-launch deploy / defaults scripts/deploy-dex-mainnet-soft-launch.sh, scripts/lib/mainnet-soft-launch-defaults.sh, Makefile (deploy-mainnet-soft-launch)
Soft-launch docs / record docs/runbooks/mainnet-soft-launch.md, skills/AGENTS_MAINNET_SOFT_LAUNCH.md, deployments/mainnet-soft-launch/deploy-trace.md, deployments/mainnet-soft-launch/addresses.env
Deploy key / terrad host scripts/lib/terrad-host.sh, soft-launch deploy key cl8ydeploy
New contract (to add) smartcontracts/contracts/faucet/ (or soft-launch-faucet/), workspace Cargo.toml, smartcontracts/artifacts/, optimizer build
CW20 mintable API (external) PlasticDigits cw20-mintable — Mint, AddMinter, RemoveMinter, Minter / Minters queries
Frontend shell frontend-dapp/src/App.tsx, frontend-dapp/src/components/common/navItems.ts, frontend-dapp/src/components/common/Layout.tsx
Frontend services frontend-dapp/src/services/terraclassic/ (execute, queries, fees), frontend-dapp/src/utils/constants.ts, frontend-dapp/.env.example
Coolify / Docker docker/frontend/Dockerfile, soft-launch frontend.env.example generation
LocalTerra parity scripts/deploy-dex-local.sh, LocalTerra env writers

1) Smart contract — soft-launch faucet

New CosmWasm contract, instantiated with:

  • admin = cl8ydeploy (operator pause/config for noneconomic faucet)
  • allowed_tokens: Vec<Addr> (the six mintables)
  • drip_amount: Uint128 = 100000000
  • cooldown_seconds: u64 = 300
  • State: last_claim: Map<&Addr, Timestamp> (or block time)

Execute

  • Drip { token: String } — sender receives drip_amount of token via WasmMsg::Execute Mint { recipient: info.sender, amount } on the CW20; enforce allowlist + cooldown; emit attributes.
  • Admin: Pause / Unpause, UpdateAllowedTokens, UpdateConfig (cooldown/amount within sane bounds).

Query

  • Config {}, Cooldown { address } → seconds_remaining, last_claim_at, can_claim.

Keep contract minimal (no deposits, no native funds, no arbitrary CW20 sends). Build via existing optimizer (make build-optimized target include).

2) Minter grant sequence (runbook-critical)

All signed by cl8ydeploy (no multisig):

  1. Deploy/instantiate faucet; record address.
  2. For each mintable token: AddMinter { minter: <faucet_addr> }.
  3. Verify: CW20 Minters shows faucet; sample Drip smoke.
  4. Record txs in deployments/mainnet-soft-launch/ (extend deploy-trace or new faucet-trace.md).
  5. Emergency: RemoveMinter { minter: faucet } + faucet Pause.

Script may broadcast AddMinter with the deploy key when explicitly opted in (same keyring pattern as soft-launch deploy).

3) Deploy script

Add e.g. scripts/deploy-soft-launch-faucet.sh + make deploy-soft-launch-faucet:

  • Store faucet wasm (or reuse code id if upgraded)
  • Instantiate with allowlist from addresses.env / defaults; admin = cl8ydeploy
  • Optionally run AddMinter for all six mintables with cl8ydeploy
  • Write FAUCET_ADDRESS into deployments/mainnet-soft-launch/addresses.env + VITE_FAUCET_ADDRESS / token list into frontend.env.example
  • Optional LocalTerra mirror in deploy-dex-local.sh for E2E

4) Frontend

  • New route e.g. /mint or /faucet (label Mint under More nav — soft-launch only when env set).
  • Page: wallet connect gate → token select (6 mintables with symbol/icon) → show drip amount 100 → cooldown countdown from chain query → Mint button → tx result + balance refresh.
  • Copy: noneconomic / demo disclaimer.
  • Unit tests for msg builders + cooldown formatting; Playwright path when LocalTerra faucet is deployed.

5) Docs

  • New runbook section or docs/runbooks/soft-launch-faucet.md linked from mainnet soft-launch runbook.
  • Update skills/AGENTS_MAINNET_SOFT_LAUNCH.md with faucet deploy + cl8ydeploy AddMinter checklist.

Acceptance criteria

  • Faucet contract implemented, unit-tested, and built as optimized wasm artifact in-repo.
  • Contract enforces allowlist, fixed drip 100000000, 300s cooldown, pause, and admin-only config updates.
  • Deploy script instantiates faucet on columbus-5 (and LocalTerra path for CI/dev) and emits env updates.
  • Runbook documents: store/instantiate, cl8ydeploy AddMinter payloads, verification queries, pause/RemoveMinter emergency — no governance minter handoff.
  • cl8ydeploy has signed AddMinter for faucet on all six mintables; verified on-chain.
  • Frontend page lists only mintable soft-launch tokens; mints 100; shows cooldown; refuses when paused / not connected / on cooldown.
  • Coolify/frontend.env.example includes faucet + token addresses needed by the UI.
  • QUARTZ/PEARL are not mintable via UI or contract allowlist.
  • Soft-launch deploy-trace (or faucet-trace) updated with code id, address, and minter-grant txs.
  • No regression to SL1–SL7 factory whitelist / fee-tier invariants.

Test plan (functional paths)

Contract (unit / cw-multi-test)

  • Happy path: allowlisted token, first drip succeeds; balance +100000000.
  • Second drip before 300s fails with clear cooldown error; after warp/time advance succeeds.
  • Non-allowlisted token rejected.
  • Pause blocks drip; unpause restores.
  • Unauthorized admin msgs rejected.
  • Drip when faucet is not a CW20 minter surfaces actionable error (or preflight query).
  • Config query + cooldown query accuracy.

Deploy / ops

  • DRY_RUN=1 deploy script prints instantiate + expected AddMinter msgs without broadcast.
  • Live/local instantiate + cl8ydeploy AddMinter writes addresses consistently with soft-launch env conventions.
  • Post-grant: LCD Minters shows faucet; sample Drip from funded wallet succeeds.

Frontend

  • Env unset → route hidden or clear “unavailable” state.
  • Connected wallet: select each of 6 tokens; mint; UI shows success + updated balance.
  • Cooldown UI blocks button and shows remaining time; refresh after LCD query.
  • Disconnected / wrong network messaging.
  • Mobile + desktop nav discoverability (More menu).
  • Disclaimer visible.

LocalTerra / E2E

  • After local faucet deploy + AddMinter, Playwright: open /mint, drip once, assert balance, retry within cooldown asserts failure messaging.
  • Swap path still works using faucet-funded wallet (optional smoke).

Test plan (attack / abuse / hack vectors)

Vector Expectation
Spam drip / sybil many wallets Cooldown is per address only — sybil is inherent; document residual risk for noneconomic tokens. Optional future: tighter drip or CAP. Do not require KYC.
Cooldown bypass via alternate sender Contract keys on info.sender only; CW20 recipient must be sender (no drip-to-other).
Drip-to-victim / grief mint Reject any recipient param; always mint to sender.
Unauthorized token / spoof address Allowlist exact Addr; no symbol-based trust from client.
Re-entrancy / callback on Mint Prefer straight WasmMsg::Execute Mint without relying on receiver hooks; CW20 mint should not invoke sender. Add test if mintable ever adds hooks.
Deploy key / faucet admin compromise Pause + RemoveMinter runbook; rotate deploy key per key-custody practices. Acceptable residual for noneconomic demo tokens.
Frontend phishing amount UI hardcodes 100; contract ignores client amount.
Economic token added to allowlist Admin-only update; runbook forbids adding mainnet economic CW20s; code review checklist.
Factory whitelist confusion Tests/docs assert faucet code id is not required on factory CW20 whitelist.
Pause race / stuck cooldown Pause does not need to clear cooldown map; unpause preserves timers (document).
Query spoof / stale UI cooldown UI must re-query before enabling button; handle LCD lag.
Gas grief (user pays) User-funded gas only; no contract balance to drain.
Cap / unbounded mint Soft-launch mintables have cap: null today — faucet rate limit is the sole public throttle; deployer primary minter retained by design for noneconomic tokens.

Verification criteria

  1. On-chain config: Faucet Config matches allowlist (6 addresses), drip_amount=100000000, cooldown_seconds=300, not paused.
  2. Minter grants: For each mintable token, faucet address appears as authorized minter (Minters query); primary minter remains cl8ydeploy.
  3. Functional smoke: From a fresh wallet with gas only — Drip EMBER succeeds once; immediate second Drip fails; after ≥300s succeeds (or time-warp on LocalTerra).
  4. Frontend prod: https://dex.cl8y.com/mint (or chosen path) with production env — select token, mint 100, cooldown UI correct; QUARTZ/PEARL absent.
  5. Docs: Runbook steps executed end-to-end by an operator with cl8ydeploy; deploy-trace/faucet-trace filled.
  6. CI: Contract tests green; frontend unit tests for faucet helpers green; soft-launch defaults tests still pass (make test-mainnet-soft-launch-defaults).
  7. Negative: Attempt drip of QUARTZ address (if forced via LCD) fails; paused faucet rejects drip.

Dependencies

  • Blocked by: access to cl8ydeploy keyring for instantiate + AddMinter (same soft-launch operator path).
  • Soft-launch DEX already deployed (addresses in deployments/mainnet-soft-launch/).
  • Blocks: frictionless public soft-launch trading demos for users without pre-funded gem balances.

Priority

P1 (soft-launch UX unblocker; noneconomic but user-facing)

Owner type

contracts + frontend + infra/docs (single bundled issue)

## Summary Ship a **bundled soft-launch faucet** so users on the mainnet frontend (`https://dex.cl8y.com`) can select any **mintable** non-economic gemstone token and mint a fixed **100** units, with a **5-minute per-wallet cooldown**. Scope includes: 1. New CosmWasm **faucet / drip** contract (authorized minter of soft-launch CW20-mintable tokens) 2. Mainnet frontend **Mint / Faucet** page + wallet execute path 3. Deploy script + operator **runbook** (store/instantiate, env wiring, Coolify) 4. **Minter grant** steps: `cl8ydeploy` (current primary minter) runs `AddMinter` for the faucet on each mintable CW20 — **no governance/multisig minter handoff** (noneconomic tokens; deployer may remain primary minter) Related soft-launch record: [`deployments/mainnet-soft-launch/deploy-trace.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/deployments/mainnet-soft-launch/deploy-trace.md), runbook [`docs/runbooks/mainnet-soft-launch.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/runbooks/mainnet-soft-launch.md). --- ## Current codebase ### Soft-launch tokens (columbus-5) | Symbol | Kind | Address | Mintable? | |--------|------|---------|-----------| | EMBER | cw20-mintable (code **10184**) | `terra1dmuruhht32x8f47nvm73pwp6q7uf2jtfhdt3nxcql4mmqkyfsraqn2dt94` | Yes | | CORAL | mintable | `terra1k6cqupylk0wp4pj273pntwhv9py0q5guyqye8ssvukn9xq7mes7sdlmena` | Yes | | JADE | mintable | `terra1ejq3mjjgnklpa3pg4jterlfwsny055gpmcjf3fz0ev3ueajnzeysz6xxgr` | Yes | | ONYX | mintable | `terra178fgrfzv7njtmdp9vghyf2dx77sah8u8jluzs7ym562chaxnmj2s6mn6m9` | Yes | | RUBY | mintable | `terra1fga508hzx8dd7x8q4uhm6mdhkqv6fxrtsea3r27smdqmv5k2jgxq5zk9fc` | Yes | | TOPAZ | mintable | `terra12k67cvfs7y7g8lca3qr4g4py6s6j69fu24gze5pjfamfpckv8mps7cymme` | Yes | | QUARTZ | cw20-base (code **6036**) | `terra17dpnjlpgsnm8muu4msfjra4f2hrptnjp2jdpkka4p0e3px42ayxq0pmc2z` | **No** (fixed supply) | | PEARL | cw20-base | `terra18fzufz8cs7ez49xjwgs248x85za5v50yug55fj7lyxp9hapxyr7qnh3czs` | **No** (fixed supply) | All soft-launch trading tokens use **6 decimals** (invariant **SL3**). Mint amount **100** human units ⇒ `100_000_000` base units. ### Minter reality Soft-launch instantiate set primary minter to the **deploy key** (`cl8ydeploy` / `terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv`): ```text # Verified on-chain (EMBER Minter{} query): # minter = terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv, cap = null ``` **Product decision:** leave `cl8ydeploy` as primary minter for these **noneconomic** tokens. Do **not** require `UpdateMinter` → governance multisig. Faucet authorization is `AddMinter { minter: <faucet> }` signed by `cl8ydeploy` on each of the six mintables. PlasticDigits [cw20-mintable](https://github.com/PlasticDigits/cw20-mintable) supports `Mint`, `AddMinter`, `RemoveMinter` (primary minter + additional minters map). Only the **current primary minter** (`cl8ydeploy`) can `AddMinter` / `RemoveMinter`. DEX wasm admin / `config.governance` remaining on the multisig is unchanged and **out of scope** for this faucet work. ### Frontend today - Mainnet dapp routes in `frontend-dapp/src/App.tsx`: Swap, Pool, Create, Tiers, Charts, Portfolio, Limits, Trade, Protocol — **no faucet/mint page**. - Nav: `frontend-dapp/src/components/common/navItems.ts` (primary + More menu). - Soft-launch Coolify env example does **not** expose mintable token addresses or a faucet address (`deployments/mainnet-soft-launch/frontend.env.example` pattern from deploy script). - Wallet broadcast patterns live under `frontend-dapp/src/services/terraclassic/` (execute + fee estimation); reuse existing Keplr / WalletConnect paths used by Swap/Pool. ### Contracts today - DEX stack under `smartcontracts/contracts/{factory,pair,router,fee-discount,hooks}` — **no faucet/drip contract**. - Soft-launch does not store a new CW20 code; it reuses mainnet mintable **10184**. - LocalTerra seeds mintable tokens with test1 as minter (`scripts/deploy-dex-local.sh`) — useful for LocalTerra faucet QA after adding a local deploy path. ### Ops / docs today - Soft-launch operator path: `docs/runbooks/mainnet-soft-launch.md`, `skills/AGENTS_MAINNET_SOFT_LAUNCH.md`, `make deploy-mainnet-soft-launch`. - Addresses: `deployments/mainnet-soft-launch/addresses.env` (+ deploy-trace). - No runbook step for faucet `AddMinter` grants. --- ## Why this is needed Soft-launch pools are live with non-economic gemstones, but **new users cannot obtain tokens** unless someone manually transfers from the deployer inventory. A public faucet: - Unblocks swap / pool / limits **UX demos** on `dex.cl8y.com` without custodian airdrops - Keeps supply growth **rate-limited** (fixed 100 + 5m cooldown) appropriate for noneconomic tokens - Moves day-to-day user minting behind an auditable drip contract (allowlist + cooldown) instead of ad-hoc deployer `Mint` txs - Completes soft-launch product surface: “trade the gems” requires “get the gems” QUARTZ/PEARL remain **non-mintable** by design; faucet must not claim to mint them (users obtain them via swaps from mintable legs). --- ## Constraints / guardrails | ID | Guardrail | |----|-----------| | **F1** | Faucet may mint **only** allowlisted soft-launch **mintable** token addresses (default: EMBER, CORAL, JADE, ONYX, RUBY, TOPAZ). Reject unknown `token` args. | | **F2** | Fixed drip size: **100** tokens (6 decimals → `100000000`). No user-chosen amount. | | **F3** | **5-minute** cooldown keyed by **wallet address** (recommend: global per wallet across all tokens — one drip every 300s regardless of which token was chosen). Document if product prefers per-token cooldowns. | | **F4** | No mint of QUARTZ/PEARL (cw20-base). UI must list mintables only. | | **F5** | Faucet contract **must** be an authorized minter on each allowlisted CW20 via `cl8ydeploy` `AddMinter`. Without this, `Mint` fails on-chain. | | **F6** | **`cl8ydeploy` remains primary CW20 minter** for noneconomic soft-launch tokens. No multisig minter handoff required for this issue. | | **F7** | Soft-launch invariants **SL1–SL2** unchanged: do not whitelist economic CW20 code IDs. Faucet is **not** added to factory CW20 whitelist (it is not a trading token). | | **F8** | Tokens remain **non-economic / demo**; UI copy must not imply financial claim, redemption, or real-asset backing. | | **F9** | Pause / disable path: faucet admin (`cl8ydeploy` / designated faucet admin) can pause; `cl8ydeploy` can `RemoveMinter` on CW20s in emergency. | | **F10** | No indexer dependency for the happy path (LCD query cooldown + execute). Optional indexer indexing of mint events is out of scope unless trivial. | | **F11** | Production frontend only exposes faucet when `VITE_FAUCET_ADDRESS` (or equivalent) is set; hide/disable on networks without deploy. | | **F12** | Gas paid by the **user** calling the faucet (not a sponsored meta-tx). Document LUNC gas requirement. | --- ## Relevant files | Area | Paths | |------|--------| | Soft-launch deploy / defaults | `scripts/deploy-dex-mainnet-soft-launch.sh`, `scripts/lib/mainnet-soft-launch-defaults.sh`, `Makefile` (`deploy-mainnet-soft-launch`) | | Soft-launch docs / record | `docs/runbooks/mainnet-soft-launch.md`, `skills/AGENTS_MAINNET_SOFT_LAUNCH.md`, `deployments/mainnet-soft-launch/deploy-trace.md`, `deployments/mainnet-soft-launch/addresses.env` | | Deploy key / terrad host | `scripts/lib/terrad-host.sh`, soft-launch deploy key `cl8ydeploy` | | New contract (to add) | `smartcontracts/contracts/faucet/` (or `soft-launch-faucet/`), workspace `Cargo.toml`, `smartcontracts/artifacts/`, optimizer build | | CW20 mintable API (external) | PlasticDigits `cw20-mintable` — `Mint`, `AddMinter`, `RemoveMinter`, `Minter` / `Minters` queries | | Frontend shell | `frontend-dapp/src/App.tsx`, `frontend-dapp/src/components/common/navItems.ts`, `frontend-dapp/src/components/common/Layout.tsx` | | Frontend services | `frontend-dapp/src/services/terraclassic/` (execute, queries, fees), `frontend-dapp/src/utils/constants.ts`, `frontend-dapp/.env.example` | | Coolify / Docker | `docker/frontend/Dockerfile`, soft-launch `frontend.env.example` generation | | LocalTerra parity | `scripts/deploy-dex-local.sh`, LocalTerra env writers | --- ## Recommended direction ### 1) Smart contract — soft-launch faucet New CosmWasm contract, instantiated with: - `admin` = `cl8ydeploy` (operator pause/config for noneconomic faucet) - `allowed_tokens: Vec<Addr>` (the six mintables) - `drip_amount: Uint128` = `100000000` - `cooldown_seconds: u64` = `300` - State: `last_claim: Map<&Addr, Timestamp>` (or block time) **Execute** - `Drip { token: String }` — sender receives `drip_amount` of `token` via WasmMsg::Execute `Mint { recipient: info.sender, amount }` on the CW20; enforce allowlist + cooldown; emit attributes. - Admin: `Pause` / `Unpause`, `UpdateAllowedTokens`, `UpdateConfig` (cooldown/amount within sane bounds). **Query** - `Config {}`, `Cooldown { address }` → `seconds_remaining`, `last_claim_at`, `can_claim`. Keep contract minimal (no deposits, no native funds, no arbitrary CW20 sends). Build via existing optimizer (`make build-optimized` target include). ### 2) Minter grant sequence (runbook-critical) All signed by **`cl8ydeploy`** (no multisig): 1. Deploy/instantiate faucet; record address. 2. For each mintable token: `AddMinter { minter: <faucet_addr> }`. 3. Verify: CW20 `Minters` shows faucet; sample `Drip` smoke. 4. Record txs in `deployments/mainnet-soft-launch/` (extend deploy-trace or new `faucet-trace.md`). 5. Emergency: `RemoveMinter { minter: faucet }` + faucet `Pause`. Script may broadcast `AddMinter` with the deploy key when explicitly opted in (same keyring pattern as soft-launch deploy). ### 3) Deploy script Add e.g. `scripts/deploy-soft-launch-faucet.sh` + `make deploy-soft-launch-faucet`: - Store faucet wasm (or reuse code id if upgraded) - Instantiate with allowlist from `addresses.env` / defaults; admin = `cl8ydeploy` - Optionally run `AddMinter` for all six mintables with `cl8ydeploy` - Write `FAUCET_ADDRESS` into `deployments/mainnet-soft-launch/addresses.env` + `VITE_FAUCET_ADDRESS` / token list into `frontend.env.example` - Optional LocalTerra mirror in `deploy-dex-local.sh` for E2E ### 4) Frontend - New route e.g. `/mint` or `/faucet` (label **Mint** under More nav — soft-launch only when env set). - Page: wallet connect gate → token select (6 mintables with symbol/icon) → show drip amount **100** → cooldown countdown from chain query → **Mint** button → tx result + balance refresh. - Copy: noneconomic / demo disclaimer. - Unit tests for msg builders + cooldown formatting; Playwright path when LocalTerra faucet is deployed. ### 5) Docs - New runbook section or `docs/runbooks/soft-launch-faucet.md` linked from mainnet soft-launch runbook. - Update `skills/AGENTS_MAINNET_SOFT_LAUNCH.md` with faucet deploy + `cl8ydeploy` `AddMinter` checklist. --- ## Acceptance criteria - [ ] Faucet contract implemented, unit-tested, and built as optimized wasm artifact in-repo. - [ ] Contract enforces allowlist, fixed drip `100000000`, 300s cooldown, pause, and admin-only config updates. - [ ] Deploy script instantiates faucet on columbus-5 (and LocalTerra path for CI/dev) and emits env updates. - [ ] Runbook documents: store/instantiate, `cl8ydeploy` `AddMinter` payloads, verification queries, pause/`RemoveMinter` emergency — **no** governance minter handoff. - [ ] `cl8ydeploy` has signed `AddMinter` for faucet on all six mintables; verified on-chain. - [ ] Frontend page lists only mintable soft-launch tokens; mints 100; shows cooldown; refuses when paused / not connected / on cooldown. - [ ] Coolify/`frontend.env.example` includes faucet + token addresses needed by the UI. - [ ] QUARTZ/PEARL are not mintable via UI or contract allowlist. - [ ] Soft-launch deploy-trace (or faucet-trace) updated with code id, address, and minter-grant txs. - [ ] No regression to SL1–SL7 factory whitelist / fee-tier invariants. --- ## Test plan (functional paths) ### Contract (unit / cw-multi-test) - [ ] Happy path: allowlisted token, first drip succeeds; balance +`100000000`. - [ ] Second drip before 300s fails with clear cooldown error; after warp/time advance succeeds. - [ ] Non-allowlisted token rejected. - [ ] Pause blocks drip; unpause restores. - [ ] Unauthorized admin msgs rejected. - [ ] Drip when faucet is **not** a CW20 minter surfaces actionable error (or preflight query). - [ ] Config query + cooldown query accuracy. ### Deploy / ops - [ ] `DRY_RUN=1` deploy script prints instantiate + expected `AddMinter` msgs without broadcast. - [ ] Live/local instantiate + `cl8ydeploy` `AddMinter` writes addresses consistently with soft-launch env conventions. - [ ] Post-grant: LCD `Minters` shows faucet; sample `Drip` from funded wallet succeeds. ### Frontend - [ ] Env unset → route hidden or clear “unavailable” state. - [ ] Connected wallet: select each of 6 tokens; mint; UI shows success + updated balance. - [ ] Cooldown UI blocks button and shows remaining time; refresh after LCD query. - [ ] Disconnected / wrong network messaging. - [ ] Mobile + desktop nav discoverability (More menu). - [ ] Disclaimer visible. ### LocalTerra / E2E - [ ] After local faucet deploy + `AddMinter`, Playwright: open `/mint`, drip once, assert balance, retry within cooldown asserts failure messaging. - [ ] Swap path still works using faucet-funded wallet (optional smoke). --- ## Test plan (attack / abuse / hack vectors) | Vector | Expectation | |--------|-------------| | Spam drip / sybil many wallets | Cooldown is **per address** only — sybil is inherent; document residual risk for noneconomic tokens. Optional future: tighter drip or CAP. Do **not** require KYC. | | Cooldown bypass via alternate sender | Contract keys on `info.sender` only; CW20 recipient must be sender (no drip-to-other). | | Drip-to-victim / grief mint | Reject any recipient param; always mint to sender. | | Unauthorized token / spoof address | Allowlist exact `Addr`; no symbol-based trust from client. | | Re-entrancy / callback on Mint | Prefer straight `WasmMsg::Execute` Mint without relying on receiver hooks; CW20 mint should not invoke sender. Add test if mintable ever adds hooks. | | Deploy key / faucet admin compromise | Pause + `RemoveMinter` runbook; rotate deploy key per key-custody practices. Acceptable residual for noneconomic demo tokens. | | Frontend phishing amount | UI hardcodes 100; contract ignores client amount. | | Economic token added to allowlist | Admin-only update; runbook forbids adding mainnet economic CW20s; code review checklist. | | Factory whitelist confusion | Tests/docs assert faucet code id is **not** required on factory CW20 whitelist. | | Pause race / stuck cooldown | Pause does not need to clear cooldown map; unpause preserves timers (document). | | Query spoof / stale UI cooldown | UI must re-query before enabling button; handle LCD lag. | | Gas grief (user pays) | User-funded gas only; no contract balance to drain. | | Cap / unbounded mint | Soft-launch mintables have `cap: null` today — faucet rate limit is the sole public throttle; deployer primary minter retained by design for noneconomic tokens. | --- ## Verification criteria 1. **On-chain config:** Faucet `Config` matches allowlist (6 addresses), `drip_amount=100000000`, `cooldown_seconds=300`, not paused. 2. **Minter grants:** For each mintable token, faucet address appears as authorized minter (`Minters` query); primary minter remains `cl8ydeploy`. 3. **Functional smoke:** From a fresh wallet with gas only — `Drip` EMBER succeeds once; immediate second `Drip` fails; after ≥300s succeeds (or time-warp on LocalTerra). 4. **Frontend prod:** `https://dex.cl8y.com/mint` (or chosen path) with production env — select token, mint 100, cooldown UI correct; QUARTZ/PEARL absent. 5. **Docs:** Runbook steps executed end-to-end by an operator with `cl8ydeploy`; deploy-trace/faucet-trace filled. 6. **CI:** Contract tests green; frontend unit tests for faucet helpers green; soft-launch defaults tests still pass (`make test-mainnet-soft-launch-defaults`). 7. **Negative:** Attempt drip of QUARTZ address (if forced via LCD) fails; paused faucet rejects drip. --- ## Dependencies - Blocked by: access to **`cl8ydeploy`** keyring for instantiate + `AddMinter` (same soft-launch operator path). - Soft-launch DEX already deployed (addresses in `deployments/mainnet-soft-launch/`). - Blocks: frictionless public soft-launch trading demos for users without pre-funded gem balances. ## Priority **P1** (soft-launch UX unblocker; noneconomic but user-facing) ## Owner type contracts + frontend + infra/docs (single bundled issue)
PlasticDigits commented 2026-07-12 05:29:04 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-07-12 05:46:04 +00:00 (Migrated from gitlab.com)

mentioned in commit 8ace6562f5

mentioned in commit 8ace6562f5292553e4c4ba417dc572ba93e386a9
PlasticDigits commented 2026-07-12 05:46:07 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1012

mentioned in merge request !1012
PlasticDigits commented 2026-07-12 06:02:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 37de409b1c

mentioned in commit 37de409b1c5b89af8a5011ce6be4128e6c70489b
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-12 06:02:33 +00:00
PlasticDigits commented 2026-07-12 06:54:12 +00:00 (Migrated from gitlab.com)

mentioned in commit c350a9ce68

mentioned in commit c350a9ce68dca8294461ea2eeb4649d5a187be63
PlasticDigits commented 2026-07-12 07:09:45 +00:00 (Migrated from gitlab.com)

mentioned in issue #474

mentioned in issue #474
PlasticDigits commented 2026-07-12 07:09:45 +00:00 (Migrated from gitlab.com)

marked as related to #474

marked as related to #474
PlasticDigits commented 2026-07-12 07:09:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #475

mentioned in issue #475
leonardocolucci commented 2026-07-16 11:49:12 +00:00 (Migrated from gitlab.com)

mentioned in issue #499

mentioned in issue #499
PlasticDigits commented 2026-08-18 12:08:56 +00:00 (Migrated from gitlab.com)

mentioned in issue #562

mentioned in issue #562
PlasticDigits commented 2026-08-18 12:08:56 +00:00 (Migrated from gitlab.com)

marked as related to #562

marked as related to #562
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#473
No description provided.