deploy-local: attach factory pair_creation_fee_uluna on every create_pair #318

Closed
opened 2026-06-05 04:12:09 +00:00 by PlasticDigits · 14 comments
PlasticDigits commented 2026-06-05 04:12:09 +00:00 (Migrated from gitlab.com)

Summary

make deploy-local / scripts/deploy-dex-local.sh fails at Phase 4 when creating the first factory pair: the factory rejects create_pair because no uluna is attached for the governance-set pair creation fee introduced in GitLab #276. Local QA, E2E, indexer bootstrap, and agent verification flows that depend on a full deploy are blocked unless operators manually add --amount 100000000uluna per pair.

Current codebase

On-chain (GitLab #276)

  • Default fee: 100_000_000 uluna (100 LUNC) — DEFAULT_PAIR_CREATION_FEE_ULUNA in smartcontracts/packages/dex-common/src/factory.rs.
  • Factory create_pair (smartcontracts/contracts/factory/src/contract.rs):
    • Loads config.pair_creation_fee_uluna (instantiate default or governance SetPairCreationFee).
    • Requires info.funds to include at least that amount of native uluna only (UnexpectedPairCreationFunds if other denoms are attached).
    • Forwards exact fee to config.treasury; refunds overpay to sender.
    • Enforces one CreatePair per block (OnePairCreationPerBlock).
  • Errors: InsufficientPairCreationFee, UnexpectedPairCreationFunds, OnePairCreationPerBlock in smartcontracts/contracts/factory/src/error.rs.
  • Tests: create_pair_charges_fee_to_treasury_and_gov_can_set_it in smartcontracts/tests/src/lib.rs (no fee → reject; exact fee → treasury credited; gov can update fee).

Local deploy script (broken)

  • scripts/deploy-dex-local.sh instantiates the factory without overriding pair_creation_fee_uluna → on-chain fee is 100M uluna (serde default).
  • terrad_tx helper (lines ~100–111) does not pass --amount on wasm executes.
  • Three create_pair loops call the factory without attached uluna:
    1. Phase 4 — ${#PAIR_CONFIGS[@]} main pairs (~20)
    2. Phase 4b — 3 unpaired-token pairs
    3. Phase 4c — 2 wrapped-native pairs (LUNC-C / USTC-C)
  • Observed failure (QA #272 verification, 2026-06): Phase 4.1 EMBER/CORAL — Pair creation requires 100000000 uluna attached.
  • scripts/e2e-seed-wrap-pairs.sh — create_pair via terrad_tx wasm execute with no --amount (will fail once factory fee is non-zero on the target chain).

What still works

  • Contract unit/integration tests use pair_creation_fee_uluna: zero or attach coins in multitest.
  • Manual pair creation with --amount 100000000uluna succeeds on LocalTerra.

Why this is needed

  • make deploy-local is the documented path for LocalTerra + frontend-dapp/.env.local + indexer/.env (docs/local-development.md, docs/qa-onboarding.md, AGENTS.md, CI e2e job).
  • make start-qa chains make deploy-local → make qa-verify-deploy; deploy abort means QA stack never completes.
  • E2E / charts / agent playbooks assume a full pair grid from the deploy script, not a partial deploy stopped at pair 1.
  • Fee behavior is intentional on-chain (#276); deploy tooling must align, not disable the fee silently without an explicit local-only decision.

Constraints and guardrails

  • Do not remove or bypass the on-chain pair creation fee for production paths.
  • Prefer reading pair_creation_fee_uluna from factory QueryMsg::Config at deploy time so script stays correct if governance changes the fee on a long-lived local chain.
  • Only uluna may be attached for the fee; do not attach CW20 or other denoms.
  • Respect OnePairCreationPerBlock — existing sleep between txs may be sufficient; if batching is added, keep one create per block.
  • Local test wallet (test1 / terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v) must have enough uluna for ~25 pairs × fee (+ gas); document or assert balance early with a clear error.
  • Optional local-only: explicit pair_creation_fee_uluna: "0" in factory instantiate JSON is acceptable only if documented and isolated to local deploy; default recommendation is attach the real fee so local behavior matches mainnet economics.
  • Keep make check-fee-discount-tier-docs and deploy script drift rules unchanged unless this issue explicitly extends them.

Relevant files

Area Path
Deploy script scripts/deploy-dex-local.sh (terrad_tx, Phase 4 / 4b / 4c create_pair)
E2E seed scripts/e2e-seed-wrap-pairs.sh
Terrad helpers scripts/lib/e2e-terrad-tx.sh (if shared wrapper is introduced)
Factory fee constant smartcontracts/packages/dex-common/src/factory.rs
Factory execute smartcontracts/contracts/factory/src/contract.rs (execute_create_pair)
Factory tests smartcontracts/tests/src/lib.rs (create_pair_charges_fee_to_treasury_and_gov_can_set_it)
QA scripts/qa/start-qa.sh, scripts/qa/verify-deploy.sh, Makefile (deploy-local, qa-verify-deploy)
Docs docs/local-development.md, docs/qa-onboarding.md, AGENTS.md
  1. Helper in deploy-dex-local.sh (or scripts/lib/) e.g. factory_create_pair():
    • Query factory config once after instantiate → PAIR_CREATION_FEE_ULUNA variable.
    • terrad_tx wasm execute "$FACTORY" "$CREATE_MSG" --amount "${PAIR_CREATION_FEE_ULUNA}uluna".
  2. Replace all three create_pair call sites to use the helper.
  3. Pre-flight: after factory instantiate, query test1 uluna balance; fail fast if < (num_pairs_to_create × fee) + gas_buffer.
  4. Update e2e-seed-wrap-pairs.sh the same way (query fee or source from env written by deploy).
  5. Docs: one line in docs/local-development.md / QA onboarding that pair creation consumes uluna per pair (treasury on local = test address).
  6. Regression guard: shell test or CI smoke that greps deploy script for create_pair + --amount (or runs scripts/qa/test-deploy-local-pair-fee.sh against a running localterra) — see test plan.

Acceptance criteria

  • make deploy-local (or bash scripts/deploy-dex-local.sh) completes Phase 4–4c without InsufficientPairCreationFee on a fresh LocalTerra volume.
  • Every factory create_pair in deploy-dex-local.sh attaches ≥ on-chain pair_creation_fee_uluna (prefer exact amount).
  • e2e-seed-wrap-pairs.sh succeeds on a chain deployed with non-zero pair creation fee.
  • Treasury (config.treasury, same as test address on local) balance increases by fee × pairs_created (modulo any pre-existing balance).
  • If factory fee is queried at runtime, changing fee via SetPairCreationFee on a dev chain does not require script edits (re-deploy or re-query).
  • Clear error when test1 uluna balance is insufficient before Phase 4.

Test plan — functional paths

Case Expected
Fresh LocalTerra + make deploy-local All pairs created; .env.local / indexer/.env written; make qa-verify-deploy passes
Re-run deploy on existing chain Documented behavior unchanged (may hit PairAlreadyExists — out of scope unless idempotency is required)
Factory pair_creation_fee_uluna == 0 (if local instantiate override added) create_pair with no --amount still works
Factory fee = 100000000 (default) Each create attaches 100M uluna; treasury credited
Overpay (e.g. attach 200M) Pair still created; excess refunded to sender (on-chain; optional script test)
e2e-seed-wrap-pairs.sh after deploy Creates wrap pairs without fee error

Test plan — attack / abuse / edge vectors

Vector Expected
Attach non-uluna denom with create_pair UnexpectedPairCreationFunds; deploy must never send CW20/native other than uluna for fee
Underpay (script regression: omit --amount) InsufficientPairCreationFee; caught by deploy failure or automated grep test
Two create_pair in same block Second fails OnePairCreationPerBlock; deploy spacing must remain safe
Drain test1 uluna via inflated pair count × fee Pre-flight balance check fails with actionable message
Wrong treasury on mainnet Out of scope for script; local deploy uses test treasury address

Verification criteria

  • make start && make wait-healthy && make build-optimized && make deploy-local exit 0 on clean VM.
  • make qa-verify-deploy pass after deploy.
  • Query factory config → pair_creation_fee_uluna; count pairs in registry; treasury uluna delta ≈ fee × count.
  • scripts/e2e-seed-wrap-pairs.sh (with .env.local from deploy) exit 0.
  • No regression in cargo test -p cl8y-dex-tests create_pair_charges_fee_to_treasury_and_gov_can_set_it.
  • GitLab #276 — on-chain pair creation fee
  • GitLab #272 QA — deploy failure observed during verification (workaround: manual --amount 100000000uluna)
## Summary `make deploy-local` / `scripts/deploy-dex-local.sh` fails at **Phase 4** when creating the first factory pair: the factory rejects `create_pair` because no `uluna` is attached for the governance-set **pair creation fee** introduced in GitLab **#276**. Local QA, E2E, indexer bootstrap, and agent verification flows that depend on a full deploy are blocked unless operators manually add `--amount 100000000uluna` per pair. ## Current codebase ### On-chain (GitLab #276) - **Default fee:** `100_000_000` uluna (100 LUNC) — `DEFAULT_PAIR_CREATION_FEE_ULUNA` in `smartcontracts/packages/dex-common/src/factory.rs`. - **Factory `create_pair`** (`smartcontracts/contracts/factory/src/contract.rs`): - Loads `config.pair_creation_fee_uluna` (instantiate default or governance `SetPairCreationFee`). - Requires `info.funds` to include **at least** that amount of **native `uluna` only** (`UnexpectedPairCreationFunds` if other denoms are attached). - Forwards exact fee to `config.treasury`; **refunds overpay** to sender. - Enforces **one `CreatePair` per block** (`OnePairCreationPerBlock`). - **Errors:** `InsufficientPairCreationFee`, `UnexpectedPairCreationFunds`, `OnePairCreationPerBlock` in `smartcontracts/contracts/factory/src/error.rs`. - **Tests:** `create_pair_charges_fee_to_treasury_and_gov_can_set_it` in `smartcontracts/tests/src/lib.rs` (no fee → reject; exact fee → treasury credited; gov can update fee). ### Local deploy script (broken) - `scripts/deploy-dex-local.sh` instantiates the factory **without** overriding `pair_creation_fee_uluna` → on-chain fee is **100M uluna** (serde default). - **`terrad_tx`** helper (lines ~100–111) does not pass `--amount` on wasm executes. - **Three** `create_pair` loops call the factory **without** attached uluna: 1. Phase 4 — `${#PAIR_CONFIGS[@]}` main pairs (~20) 2. Phase 4b — 3 unpaired-token pairs 3. Phase 4c — 2 wrapped-native pairs (LUNC-C / USTC-C) - Observed failure (QA #272 verification, 2026-06): Phase 4.1 EMBER/CORAL — `Pair creation requires 100000000 uluna attached`. ### Related scripts (same gap) - `scripts/e2e-seed-wrap-pairs.sh` — `create_pair` via `terrad_tx wasm execute` with **no** `--amount` (will fail once factory fee is non-zero on the target chain). ### What still works - Contract unit/integration tests use `pair_creation_fee_uluna: zero` or attach coins in multitest. - Manual pair creation with `--amount 100000000uluna` succeeds on LocalTerra. ## Why this is needed - **`make deploy-local`** is the documented path for LocalTerra + `frontend-dapp/.env.local` + `indexer/.env` (`docs/local-development.md`, `docs/qa-onboarding.md`, `AGENTS.md`, CI `e2e` job). - **`make start-qa`** chains `make deploy-local` → `make qa-verify-deploy`; deploy abort means QA stack never completes. - **E2E / charts / agent playbooks** assume a full pair grid from the deploy script, not a partial deploy stopped at pair 1. - Fee behavior is **intentional** on-chain (#276); deploy tooling must align, not disable the fee silently without an explicit local-only decision. ## Constraints and guardrails - **Do not** remove or bypass the on-chain pair creation fee for production paths. - **Prefer** reading `pair_creation_fee_uluna` from factory `QueryMsg::Config` at deploy time so script stays correct if governance changes the fee on a long-lived local chain. - **Only `uluna`** may be attached for the fee; do not attach CW20 or other denoms. - Respect **`OnePairCreationPerBlock`** — existing `sleep` between txs may be sufficient; if batching is added, keep one create per block. - **Local test wallet** (`test1` / `terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v`) must have enough uluna for ~25 pairs × fee (+ gas); document or assert balance early with a clear error. - **Optional local-only:** explicit `pair_creation_fee_uluna: "0"` in factory instantiate JSON is acceptable **only** if documented and isolated to local deploy; default recommendation is attach the real fee so local behavior matches mainnet economics. - Keep **`make check-fee-discount-tier-docs`** and deploy script drift rules unchanged unless this issue explicitly extends them. ## Relevant files | Area | Path | |------|------| | Deploy script | `scripts/deploy-dex-local.sh` (`terrad_tx`, Phase 4 / 4b / 4c `create_pair`) | | E2E seed | `scripts/e2e-seed-wrap-pairs.sh` | | Terrad helpers | `scripts/lib/e2e-terrad-tx.sh` (if shared wrapper is introduced) | | Factory fee constant | `smartcontracts/packages/dex-common/src/factory.rs` | | Factory execute | `smartcontracts/contracts/factory/src/contract.rs` (`execute_create_pair`) | | Factory tests | `smartcontracts/tests/src/lib.rs` (`create_pair_charges_fee_to_treasury_and_gov_can_set_it`) | | QA | `scripts/qa/start-qa.sh`, `scripts/qa/verify-deploy.sh`, `Makefile` (`deploy-local`, `qa-verify-deploy`) | | Docs | `docs/local-development.md`, `docs/qa-onboarding.md`, `AGENTS.md` | ## Recommended direction 1. **Helper** in `deploy-dex-local.sh` (or `scripts/lib/`) e.g. `factory_create_pair()`: - Query factory `config` once after instantiate → `PAIR_CREATION_FEE_ULUNA` variable. - `terrad_tx wasm execute "$FACTORY" "$CREATE_MSG" --amount "${PAIR_CREATION_FEE_ULUNA}uluna"`. 2. Replace all three `create_pair` call sites to use the helper. 3. **Pre-flight:** after factory instantiate, query `test1` uluna balance; fail fast if `< (num_pairs_to_create × fee) + gas_buffer`. 4. Update **`e2e-seed-wrap-pairs.sh`** the same way (query fee or source from env written by deploy). 5. **Docs:** one line in `docs/local-development.md` / QA onboarding that pair creation consumes uluna per pair (treasury on local = test address). 6. **Regression guard:** shell test or CI smoke that greps deploy script for `create_pair` + `--amount` (or runs `scripts/qa/test-deploy-local-pair-fee.sh` against a running localterra) — see test plan. ## Acceptance criteria - [ ] `make deploy-local` (or `bash scripts/deploy-dex-local.sh`) completes Phase 4–4c without `InsufficientPairCreationFee` on a fresh LocalTerra volume. - [ ] Every factory `create_pair` in `deploy-dex-local.sh` attaches **≥** on-chain `pair_creation_fee_uluna` (prefer exact amount). - [ ] `e2e-seed-wrap-pairs.sh` succeeds on a chain deployed with non-zero pair creation fee. - [ ] Treasury (`config.treasury`, same as test address on local) balance increases by `fee × pairs_created` (modulo any pre-existing balance). - [ ] If factory fee is queried at runtime, changing fee via `SetPairCreationFee` on a dev chain does not require script edits (re-deploy or re-query). - [ ] Clear error when `test1` uluna balance is insufficient before Phase 4. ## Test plan — functional paths | Case | Expected | |------|----------| | Fresh LocalTerra + `make deploy-local` | All pairs created; `.env.local` / `indexer/.env` written; `make qa-verify-deploy` passes | | Re-run deploy on existing chain | Documented behavior unchanged (may hit `PairAlreadyExists` — out of scope unless idempotency is required) | | Factory `pair_creation_fee_uluna == 0` (if local instantiate override added) | `create_pair` with no `--amount` still works | | Factory fee = `100000000` (default) | Each create attaches 100M uluna; treasury credited | | Overpay (e.g. attach 200M) | Pair still created; excess refunded to sender (on-chain; optional script test) | | `e2e-seed-wrap-pairs.sh` after deploy | Creates wrap pairs without fee error | ## Test plan — attack / abuse / edge vectors | Vector | Expected | |--------|----------| | Attach non-uluna denom with `create_pair` | `UnexpectedPairCreationFunds`; deploy must never send CW20/native other than uluna for fee | | Underpay (script regression: omit `--amount`) | `InsufficientPairCreationFee`; caught by deploy failure or automated grep test | | Two `create_pair` in same block | Second fails `OnePairCreationPerBlock`; deploy spacing must remain safe | | Drain test1 uluna via inflated pair count × fee | Pre-flight balance check fails with actionable message | | Wrong treasury on mainnet | Out of scope for script; local deploy uses test treasury address | ## Verification criteria - [ ] `make start && make wait-healthy && make build-optimized && make deploy-local` exit 0 on clean VM. - [ ] `make qa-verify-deploy` pass after deploy. - [ ] Query factory `config` → `pair_creation_fee_uluna`; count pairs in registry; treasury uluna delta ≈ `fee × count`. - [ ] `scripts/e2e-seed-wrap-pairs.sh` (with `.env.local` from deploy) exit 0. - [ ] No regression in `cargo test -p cl8y-dex-tests create_pair_charges_fee_to_treasury_and_gov_can_set_it`. ## Related - GitLab **#276** — on-chain pair creation fee - GitLab **#272** QA — deploy failure observed during verification (workaround: manual `--amount 100000000uluna`)
PlasticDigits commented 2026-06-05 04:12:10 +00:00 (Migrated from gitlab.com)

marked as related to #276

marked as related to #276
Brouie commented 2026-06-05 06:10:49 +00:00 (Migrated from gitlab.com)

mentioned in merge request !772

mentioned in merge request !772
Brouie commented 2026-06-05 06:11:08 +00:00 (Migrated from gitlab.com)

Took this one. The local deploy was dodging the #276 fee by instantiating the factory with pair_creation_fee_uluna=0 — that was my earlier convenience, but it hides the fee path from local/E2E, which is exactly what you flagged here.

Reworked deploy-dex-local.sh to match mainnet economics instead:

  • Instantiate the factory with the real default fee (override via LOCAL_PAIR_CREATION_FEE_ULUNA).
  • Read the fee back from factory Config and attach exactly that on every create_pair via a factory_create_pair helper — covers Phase 4 / 4b / 4c, and stays correct if governance changes the fee on a long-lived chain.
  • Pre-flight: check test1 can cover fee × pairs before Phase 4, fail fast with an actionable message instead of dying mid-deploy.

e2e-seed-wrap-pairs.sh already had the query+attach pattern, so it lines up. verify-issue-276.sh now guards that the deploy actually attaches the fee, and the docs that claimed "local uses fee 0" are corrected.

Proven on a fresh post-#276 factory:

  • Config query returns pair_creation_fee_uluna = 100000000 via the exact path the script reads.
  • create_pair with no fee → rejected: "Pair creation requires 100000000 uluna attached."
  • create_pair with --amount 100000000uluna → ok, pair created; treasury credited the fee minus the ~0.5% Terra Classic transfer tax on the BankMsg send.

One thing worth knowing: the currently deployed contracts predate #276 (built before the fee field landed), so the live factory doesn't have the field at all — needs a redeploy to pick up #276. make deploy-local rebuilds optimized artifacts first, so the documented path is fine.

Branch qa/318-315-deploy-fee-gas, commit f5747ed, MR !772 (bundled with #315). Still want a full fresh-volume make deploy-local run through Phase 4-4c to sign it off end to end — folding that into the next chain refresh. @PlasticDigits

Took this one. The local deploy was dodging the #276 fee by instantiating the factory with pair_creation_fee_uluna=0 — that was my earlier convenience, but it hides the fee path from local/E2E, which is exactly what you flagged here. Reworked deploy-dex-local.sh to match mainnet economics instead: - Instantiate the factory with the real default fee (override via LOCAL_PAIR_CREATION_FEE_ULUNA). - Read the fee back from factory Config and attach exactly that on every create_pair via a factory_create_pair helper — covers Phase 4 / 4b / 4c, and stays correct if governance changes the fee on a long-lived chain. - Pre-flight: check test1 can cover fee × pairs before Phase 4, fail fast with an actionable message instead of dying mid-deploy. e2e-seed-wrap-pairs.sh already had the query+attach pattern, so it lines up. verify-issue-276.sh now guards that the deploy actually attaches the fee, and the docs that claimed "local uses fee 0" are corrected. Proven on a fresh post-#276 factory: - Config query returns pair_creation_fee_uluna = 100000000 via the exact path the script reads. - create_pair with no fee → rejected: "Pair creation requires 100000000 uluna attached." - create_pair with --amount 100000000uluna → ok, pair created; treasury credited the fee minus the ~0.5% Terra Classic transfer tax on the BankMsg send. One thing worth knowing: the currently deployed contracts predate #276 (built before the fee field landed), so the live factory doesn't have the field at all — needs a redeploy to pick up #276. make deploy-local rebuilds optimized artifacts first, so the documented path is fine. Branch qa/318-315-deploy-fee-gas, commit f5747ed, MR !772 (bundled with #315). Still want a full fresh-volume make deploy-local run through Phase 4-4c to sign it off end to end — folding that into the next chain refresh. @PlasticDigits
Brouie commented 2026-06-05 06:11:11 +00:00 (Migrated from gitlab.com)

mentioned in issue #315

mentioned in issue #315
PlasticDigits commented 2026-06-05 07:59:29 +00:00 (Migrated from gitlab.com)

mentioned in commit 019ded61e2

mentioned in commit 019ded61e24c4de8f99d570f8c43aa5ffea2953d
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-05 07:59:30 +00:00
totdking commented 2026-06-05 09:48:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #325

mentioned in issue #325
PlasticDigits commented 2026-06-05 09:55:27 +00:00 (Migrated from gitlab.com)

mentioned in merge request !783

mentioned in merge request !783
ghost1 commented 2026-06-05 09:58:42 +00:00 (Migrated from gitlab.com)

mentioned in commit 9ec5c0db10

mentioned in commit 9ec5c0db10b6a9844353aaea71ff75582e21a61f
PlasticDigits commented 2026-06-05 09:59:00 +00:00 (Migrated from gitlab.com)

mentioned in merge request !769

mentioned in merge request !769
PlasticDigits commented 2026-06-05 10:28:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #320

mentioned in issue #320
PlasticDigits commented 2026-06-05 13:44:12 +00:00 (Migrated from gitlab.com)

mentioned in issue #329

mentioned in issue #329
ghost1 commented 2026-06-05 13:56:15 +00:00 (Migrated from gitlab.com)

mentioned in commit e924ac1e0f

mentioned in commit e924ac1e0f4757116c4ea30d5d10c3e848e55b76
PlasticDigits commented 2026-06-05 13:56:44 +00:00 (Migrated from gitlab.com)

mentioned in merge request !813

mentioned in merge request !813
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 71016dae1b

mentioned in commit 71016dae1b9271f3f897f21d70a046836e75a5fd
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#318
No description provided.