design(indexer): fee-ledger home is #1209/#1210/#1211 with marketing trail #1213

Closed
opened 2026-09-06 14:00:19 +00:00 by PlasticDigits · 3 comments

Summary

Home for fee-ledger ingest/API work is this repo’s indexer, not the marketing repository. This issue is the tracker epic + remaining trail. It does not implement new FeeSource parsers.

Three implement tickets already exist and already hold the migrated engineering bodies:

Slice Implement on this repo Closed marketing tracker
Pair-creation treasury uluna on GET /api/v1/protocol/fees (no instantiate-gas double-count) #1209 cl8y-marketing#1
Community SKU unlock + settings-batch invoices on the same API #1210 cl8y-marketing#4
Actor-joined priced fees with fee-discount-registry cohort split (retail / MM / unjoined) #1211 cl8y-marketing#5

Marketing #1 / #4 / #5 are already closed as tracker dupes with comments that name the replacements above. Do not reopen them for implement work. Do not relabel #1209 / #1210 / #1211 in this ticket.

This ticket’s remaining job: make strategy/docs and cross-issue links use the dex issue numbers, so agents and humans cannot treat marketing as a second fee authority.

Related, not this ticket:

  • #1204 — indexer OpenAPI/curl docs pack (already open; no ingest).
  • #1202 — source-to-fee client events (privacy hold; not fee truth).
  • #586 / #614 — existing seven-source census / UST1 window pattern.
  • #594 — community-token catalog (not protocol fees).
  • #597 — MM subscription invoices (not SKU/settings).

Bundle (do not split into a fourth ingest MR):

  1. Authority map — indexer protocol_fee_events is the governed ledger; marketing stores pointers and labeled snapshots only.
  2. Pointer retarget — marketing strategy/research files that still cite marketing #1 / #4 / #5 (or “open a ticket on marketing”) must cite #1209 / #1210 / #1211.
  3. Cross-link hygiene — #1210 / #1211 still name marketing #1 / #4 as the pair-creation / SKU siblings; those related links should also name #1209 / #1210.

Current codebase

Indexer is seven FeeSources; pair creation / invoices / cohort are missing

indexer/src/indexer/protocol_fees.rs FeeSource::ALL is length 7: swap_amm, book_take, limit_place, wrap, unwrap, ust1_mint, ust1_redeem. Wrap/UST1 require pinned contracts and explicit positive fee attrs (fail closed). Rows land in protocol_fee_events with UNIQUE (tx_hash, source, ordinal) and ON CONFLICT DO NOTHING. fee_usd is stamped at ingest.

indexer/src/indexer/parser.rs ingest_protocol_fee never receives a wallet. There is no create_pair / creation_fee_uluna parser, no community-invoice fee parser, and no by_cohort API.

GET stays O(1) rollup / 60s cache — no live SUM:

Frontend ProtocolFeeSourceKey and ProtocolFeeStats.tsx SOURCE_LABEL / SOURCE_ORDER match those seven keys only.

CHECK constraints in indexer/migrations/20260821120000_protocol_fees.sql (later widened for UST1 window) still have no pair_creation / sku_unlock / settings_fee.

Audit docs/audits/factory-treasury-bank-send.md item 11 still states the indexer has no pair-creation fee parser (pairs are discovered via instantiate / registry, which is not treasury census).

On-chain fees already exist (ingest is the gap)

Pair creation — factory execute_create_pair: config.pair_creation_fee_uluna (default 100_000_000 uluna) BankMsg::Send to config.treasury; wasm action=create_pair + creation_fee_uluna. Instantiate gas is a Cosmos tx fee, not treasury revenue. reply_instantiate_pair is registration, not a fee. Overpay refunds to sender.

SKU / settings invoices — community-tax token + launcher (INVOICE_UST1 = 50_000_000). Catalog ingest already exists in indexer/src/indexer/community_tokens.rs (sku_unlock / settings_fee / create kinds into community_token_events). That table answers “which token unlocked which SKU,” not “treasury USD on /protocol/fees.” Create-time N × 50 UST1 lives on launcher create_token, not on create_token_ready.

Cohort split — protocol_fee_events has no actor column. traders tier_id SMALLINT NOT NULL DEFAULT 0 plus fee_discount_registered. Unregistered retail is not Tier 0 MM. Live traders is current state; a naive join would mis-label retail as MM and rewrite history on deregister. traders.total_fees_paid is mixed-unit and must not drive /protocol headlines.

Marketing repo is research/governance, not a fee service

PlasticDigits/cl8y-marketing README: evidence-led marketing; durable net realized protocol fees as the objective. Structure is research/, strategy/, content/. Issue bodies for the closed trackers name:

Path Role
strategy/fee-growth-model.md Fee inventory; pair creation called out as missing from the seven indexed sources
strategy/90-day-plan.md Phase 0: reconcile seven sources; add pair creation without double-counting gas
strategy/technical-architecture.md Indexer is economic authority; marketing is research/governance
strategy/operating-system.md Operating architecture / measurement
research/snapshots/2026-09-03-protocol-fees.json Snapshot excluding pair creation
research/source-register.md Source quality register

Those files are the pointer surface. They must not grow a parallel fee indexer, notebook-as-truth, or implement-queue for wasm parsers.

Trail status (already done vs leftover)

Done

  • #1209 / #1210 / #1211 opened on this repo with full ingest/API bodies.
  • Marketing #1 / #4 / #5 closed with replacement URLs (do not silent-reopen).

Leftover (this issue)

  • Strategy/research markdown that still says “see marketing #1 / #4 / #5” or implies implement-home is marketing.
  • Related-issue links inside #1210 / #1211 that still point at marketing #1 / #4 instead of #1209 / #1210.
  • Risk that a later agent re-opens the marketing trackers or files a fourth copy of the ingest work.

Why the work is needed

Phase 0 ledgers include pair creation, project-team invoices, and (later) a privacy-safe retail/MM split. The public API cannot report those yet. That ingest work belongs on #1209 / #1210 / #1211.

Without a single home map, two failure modes stay open:

  1. Second fee authority — a marketing-side counter or LCD notebook treated as equal to protocol_fee_events. Campaign decisions then diverge from /protocol.
  2. Wrong-repo implement — agents follow closed marketing issues (titles still look like feats; labels may still say implement) and try to parse wasm in the marketing tree.

Pointer retarget is cheap and prevents both. It is not optional “docs later”: it is the trail the three ingest tickets assumed when they were copied here.


Constraints and guardrails

  1. Do not implement ingest in this issue. No new FeeSource, migration CHECK, API field, or UI label here. That is #1209 then #1210 then #1211 (stack order: pair_creation → invoices → cohort). #1211 also depends on #1202 remaining on hold — do not expand #1202.
  2. Do not reopen marketing #1 / #4 / #5 for implement, “ready,” or code. If a comment is required on those issues, it is a one-line pointer at the dex replacement only.
  3. Do not churn labels on #1209 / #1210 / #1211 (no extra ready/implement/close from this ticket).
  4. Indexer wins after ship. Any Phase 0 LCD reconciliation of factory→treasury uluna (or CMM UST1 invoices) must stay labeled provisional until the matching ingest lands, then be marked retired in marketing snapshots.
  5. Do not mix sources. Pair-creation uluna, SKU/settings UST1, swap/wrap/window, and client analytics are four different truths. Catalog community_token_events ≠ protocol fees.
  6. Do not double-count instantiate gas, refunds, reply_instantiate_pair, buy/sell tax, AutoLP, migrate-adopt, or pay-with-any-token swap legs as community invoices.
  7. Cohort privacy. No wallet lists, no person-to-wallet map, no campaign_id on fee rows. Split is aggregate (retail / MM / unjoined) as-of height. Do not treat traders.tier_id = 0 as MM unless fee_discount_registered (or equivalent as-of-height membership) is true.
  8. Pin emitters on the implement tickets (factory, wrap mapper, UST1 window, community launcher, catalogued tokens). Forged contract_address without underscore is ignored (#285).
  9. GET stays O(1) rollup / 60s cache. Additive JSON. Unconfigured pin → omit source (not fake $0). Idle configured → "0". Unpriced → null.
  10. No social / X / paid-media work in this ticket or in #1209–#1211.
  11. Do not expand #1204. When new sources ship, OpenAPI follows those ingest MRs (or a later docs follow-up), not this epic.
  12. Do not invent a second public /protocol/fees on any other repo.

Relevant files

This repo (implement ingest only via child issues)

Path Why
indexer/src/indexer/protocol_fees.rs FeeSource enum / wrap-window pattern
indexer/src/indexer/parser.rs ingest_protocol_fee wiring; no actor today
indexer/src/indexer/community_tokens.rs Catalog only; do not treat as fee truth
indexer/src/db/queries/protocol_fees.rs Insert / rollup
indexer/migrations/20260821120000_protocol_fees.sql CHECK / uniqueness pattern
indexer/migrations/20260824120000_ust1_window_protocol_fees.sql Prior source-widening pattern
indexer/src/api/protocol_fees.rs, protocol_fee_series.rs, api/defillama.rs Public ledger
indexer/src/indexer/trader_tracker.rs Registry sync; as-of-height trap for #1211
frontend-dapp/src/types/index.ts ProtocolFeeSourceKey
frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx Labels / hide-idle
smartcontracts/contracts/factory/src/contract.rs creation_fee_uluna (read-only for ingest)
smartcontracts/contracts/community-tax-token/src/invoice.rs 50 UST1 invoices (read-only)
docs/audits/factory-treasury-bank-send.md Item 11 until #1209 ships
docs/indexer-invariants.md Protocol-fees invariants
skills/AGENTS_INDEXER_UST1_WINDOW_FEES.md, AGENTS_INDEXER_WRAP_FEE_INGEST.md Pattern to copy on children

Marketing repo (pointers / snapshots only)

Path Why
strategy/fee-growth-model.md Cite #1209 / #1210 / #1211 as implement home
strategy/90-day-plan.md Phase 0 ingest bullets → dex issue numbers
strategy/technical-architecture.md Authority sentence; no second indexer
strategy/operating-system.md Measurement points at public API
strategy/phase-0-status.md Blockers should name dex issues if they name marketing feats
research/snapshots/ Keep snapshots; label provisional vs indexer
research/source-register.md Source quality; indexer API as authority
Closed issues #1 / #4 / #5 Remain closed; trail already names replacements

  1. Treat this issue as the epic. Implementers pick #1209, then #1210, then #1211. Do not open additional feat tickets that copy those titles.
  2. Pointer PR on marketing (docs-only): grep cl8y-marketing#1, #4, #5, and prose like “open on marketing” / “implement here” in strategy/ and research/. Replace with the table in the Summary. Keep historical snapshot JSON bytes stable unless a comment/header records “pair creation not in this extract; tracked on dex #1209.”
  3. Related-link edit on #1210 / #1211 (issue body “Related” lines only): marketing #1 → #1209, marketing #4 → #1210. Do not rewrite the ingest ACs.
  4. After each child ships: marketing fee-growth / snapshot notes the new stream as live; provisional LCD stopgap marked retired. That update is already an AC on the child — do not duplicate the parser tests here.
  5. If Forgejo issue bodies cannot be edited in place, a one-line comment on #1210 / #1211 of the form Related ingest siblings: #1209 #1210 #1211 is enough. No chat logs.

Acceptance criteria

  • AC1. This issue is the only design/home ticket for the three slices; ingest remains #1209 / #1210 / #1211 (no fourth copy of those titles).
  • AC2. Marketing strategy/ + research/ markdown that referenced marketing #1 / #4 / #5 for implement now references the dex issue numbers in the Summary table. Historical “closed tracker” mentions may remain if they also name the dex replacement.
  • AC3. Marketing #1 / #4 / #5 stay closed. No new feat on marketing that re-states pair_creation / SKU invoices / cohort ingest.
  • AC4. #1210 / #1211 related links name #1209 / #1210 (not only marketing #1 / #4).
  • AC5. No marketing service, script, or table writes fee truth. Architecture docs still say indexer is the ledger.
  • AC6. No social/X spend, no #1204 scope creep, no #1202 expansion, no wallet lists.
  • AC7. Child implement tickets keep their existing ACs (gas exclusion, pin factory/launcher, one row per invoice, as-of-height cohort, fail-closed amounts). This epic does not weaken them.

Test plan (functional paths)

# Path Expect
T1 Grep marketing strategy/ research/ for cl8y-marketing/issues/1 (and #1 in fee-ledger context) Either gone or paired with dex #1209
T2 Same for marketing #4 Paired with #1210
T3 Same for marketing #5 Paired with #1211
T4 fj issue view marketing 1 / 4 / 5 State closed; comments still name dex replacements
T5 Open issues search on marketing for pair_creation / protocol/fees ingest No new open feat duplicating #1209–#1211
T6 Open issues search on this repo for those three titles Exactly #1209 / #1210 / #1211 plus this epic (no extra copies)
T7 #1210 / #1211 related section Dex sibling links present
T8 strategy/technical-architecture.md (or equivalent authority doc) Indexer = economic authority; marketing ≠ fee service
T9 Child tickets still describe fail-closed pins / uniqueness / no gas Unchanged ingest ACs
T10 #1204 / #1202 Untouched by the pointer PR

Docs-only change: no indexer/frontend test suite required on this epic. Child ingest tickets keep make verify-issue-586 / make verify-issue-614 plus their own verify-issue-* bundles.


Test plan (attack, hack, and abuse)

# Vector Expect
A1 Agent implements FeeSource parsers inside PlasticDigits/cl8y-marketing Forbidden; this epic + children say home is this indexer
A2 Re-open marketing #1 / #4 / #5 as implement-ready Forbidden; stay closed trackers
A3 File a fourth dex feat that copies #1209 / #1210 / #1211 titles Duplicate; close pointing here / at the existing child
A4 Treat LCD notebook or snapshot JSON as equal to /protocol/fees after ingest ships Indexer wins; stopgap labeled provisional then retired
A5 Count instantiate gas / refunds / reply_instantiate_pair as pair_creation Forbidden (#1209)
A6 Mix SKU invoices into pair_creation or swap_amm Forbidden (#1210)
A7 Double-count launcher + token enable_feature One fee row (#1210)
A8 Naive traders.tier_id = 0 ⇒ MM Forbidden; unregistered default 0 is not Tier 0 MM (#1211)
A9 Live join that rewrites historical fees after deregister Forbidden; as-of-height (#1211)
A10 Publish wallet lists / person-to-wallet maps in marketing or /protocol Forbidden
A11 Spoof wasm create_pair / invoice from unpinned contracts Ignored on children (#285)
A12 Infer fees from config × count or 50e6 × SKU flags without a paid tx Forbidden
A13 Put exact invoice amounts or wallets into client analytics (#1202) Out of scope; not fee truth
A14 Expand this epic into #1204 OpenAPI or social/X spend Out of scope
A15 Relabel #1209–#1211 ready/implement from this ticket Forbidden
A16 Symbol spoof / $1 UST1 / vFDUSD as USD Price via catalog identity on children
A17 Unconfigured factory/launcher pin reporting fake $0 Omit source
A18 Replay/reorg double insert (tx_hash, source, ordinal) uniqueness on children

Verification criteria

  • Summary table in this issue matches live Forgejo: three open (or later-closed-by-ship) children on code/cl8y-dex-terraclassic, three closed marketing trackers with replacement URLs.
  • Marketing pointer PR: git grep -n 'cl8y-marketing#1\|issues/1' strategy research (and #4 / #5) is empty or every hit also names the dex replacement in the same paragraph.
  • No new marketing feat titled like the three ingest slices.
  • make verify-issue-586 and make verify-issue-614 still green (no accidental ingest change in the pointer PR). This epic’s PR should be docs-only on marketing (plus optional issue-body related-link edits).
  • Manual: a new agent given “pair creation fees on the protocol ledger” lands on #1209, not on a marketing implement queue.

Out of scope

  • Implementing pair_creation / SKU / settings / cohort ingest (children).
  • #1204 OpenAPI pack.
  • #1202 client events / UTM.
  • Social, X, paid media, or spend.
  • Changing on-chain pair_creation_fee_uluna or INVOICE_UST1.
  • MM subscription invoices (#597).
  • Indexer exact-out /route/solve.
  • Building any fee service outside this indexer.
## Summary **Home for fee-ledger ingest/API work is this repo’s indexer**, not the marketing repository. This issue is the **tracker epic + remaining trail**. It does **not** implement new `FeeSource` parsers. Three implement tickets already exist and already hold the migrated engineering bodies: | Slice | Implement on this repo | Closed marketing tracker | |-------|------------------------|--------------------------| | Pair-creation treasury uluna on `GET /api/v1/protocol/fees` (no instantiate-gas double-count) | [#1209](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1209) | [cl8y-marketing#1](https://git.cl8y.com/PlasticDigits/cl8y-marketing/issues/1) | | Community SKU unlock + settings-batch invoices on the same API | [#1210](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1210) | [cl8y-marketing#4](https://git.cl8y.com/PlasticDigits/cl8y-marketing/issues/4) | | Actor-joined priced fees with fee-discount-registry cohort split (retail / MM / unjoined) | [#1211](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1211) | [cl8y-marketing#5](https://git.cl8y.com/PlasticDigits/cl8y-marketing/issues/5) | Marketing #1 / #4 / #5 are **already closed** as tracker dupes with comments that name the replacements above. Do **not** reopen them for implement work. Do **not** relabel #1209 / #1210 / #1211 in this ticket. **This ticket’s remaining job:** make strategy/docs and cross-issue links use the **dex issue numbers**, so agents and humans cannot treat marketing as a second fee authority. Related, **not this ticket:** - [#1204](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1204) — indexer OpenAPI/curl docs pack (already open; no ingest). - [#1202](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1202) — source-to-fee client events (privacy hold; not fee truth). - [#586](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/586) / [#614](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/614) — existing seven-source census / UST1 window pattern. - [#594](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/594) — community-token **catalog** (not protocol fees). - [#597](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/597) — MM subscription invoices (not SKU/settings). Bundle (do not split into a fourth ingest MR): 1. **Authority map** — indexer `protocol_fee_events` is the governed ledger; marketing stores pointers and labeled snapshots only. 2. **Pointer retarget** — marketing strategy/research files that still cite marketing #1 / #4 / #5 (or “open a ticket on marketing”) must cite #1209 / #1210 / #1211. 3. **Cross-link hygiene** — #1210 / #1211 still name marketing #1 / #4 as the pair-creation / SKU siblings; those related links should also name #1209 / #1210. --- ## Current codebase ### Indexer is seven `FeeSource`s; pair creation / invoices / cohort are missing [`indexer/src/indexer/protocol_fees.rs`](indexer/src/indexer/protocol_fees.rs) `FeeSource::ALL` is length **7**: `swap_amm`, `book_take`, `limit_place`, `wrap`, `unwrap`, `ust1_mint`, `ust1_redeem`. Wrap/UST1 require pinned contracts and explicit positive fee attrs (fail closed). Rows land in `protocol_fee_events` with `UNIQUE (tx_hash, source, ordinal)` and `ON CONFLICT DO NOTHING`. `fee_usd` is stamped at ingest. [`indexer/src/indexer/parser.rs`](indexer/src/indexer/parser.rs) `ingest_protocol_fee` never receives a wallet. There is **no** `create_pair` / `creation_fee_uluna` parser, **no** community-invoice fee parser, and **no** `by_cohort` API. GET stays O(1) rollup / 60s cache — no live `SUM`: - `GET /api/v1/protocol/fees?window=24h|7d|30d` — [`indexer/src/api/protocol_fees.rs`](indexer/src/api/protocol_fees.rs) - Daily series + DeFiLlama breakdown mirror the same seven keys Frontend [`ProtocolFeeSourceKey`](frontend-dapp/src/types/index.ts) and [`ProtocolFeeStats.tsx`](frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx) `SOURCE_LABEL` / `SOURCE_ORDER` match those seven keys only. CHECK constraints in [`indexer/migrations/20260821120000_protocol_fees.sql`](indexer/migrations/20260821120000_protocol_fees.sql) (later widened for UST1 window) still have **no** `pair_creation` / `sku_unlock` / `settings_fee`. Audit [`docs/audits/factory-treasury-bank-send.md`](docs/audits/factory-treasury-bank-send.md) **item 11** still states the indexer has no pair-creation **fee** parser (pairs are discovered via instantiate / registry, which is not treasury census). ### On-chain fees already exist (ingest is the gap) **Pair creation** — factory [`execute_create_pair`](smartcontracts/contracts/factory/src/contract.rs): `config.pair_creation_fee_uluna` (default `100_000_000` uluna) `BankMsg::Send` to `config.treasury`; wasm `action=create_pair` + `creation_fee_uluna`. Instantiate gas is a Cosmos tx fee, not treasury revenue. `reply_instantiate_pair` is registration, not a fee. Overpay refunds to sender. **SKU / settings invoices** — community-tax token + launcher (`INVOICE_UST1 = 50_000_000`). Catalog ingest already exists in [`indexer/src/indexer/community_tokens.rs`](indexer/src/indexer/community_tokens.rs) (`sku_unlock` / `settings_fee` / `create` kinds into `community_token_events`). That table answers “which token unlocked which SKU,” **not** “treasury USD on `/protocol/fees`.” Create-time `N × 50 UST1` lives on launcher `create_token`, not on `create_token_ready`. **Cohort split** — `protocol_fee_events` has no actor column. [`traders`](indexer/migrations/20260310000001_initial_schema.sql) `tier_id SMALLINT NOT NULL DEFAULT 0` plus `fee_discount_registered`. Unregistered retail is **not** Tier 0 MM. Live `traders` is current state; a naive join would mis-label retail as MM and rewrite history on deregister. `traders.total_fees_paid` is mixed-unit and must not drive `/protocol` headlines. ### Marketing repo is research/governance, not a fee service [`PlasticDigits/cl8y-marketing`](https://git.cl8y.com/PlasticDigits/cl8y-marketing) README: evidence-led marketing; durable net realized protocol fees as the objective. Structure is `research/`, `strategy/`, `content/`. Issue bodies for the closed trackers name: | Path | Role | |------|------| | `strategy/fee-growth-model.md` | Fee inventory; pair creation called out as missing from the seven indexed sources | | `strategy/90-day-plan.md` | Phase 0: reconcile seven sources; add pair creation without double-counting gas | | `strategy/technical-architecture.md` | Indexer is economic authority; marketing is research/governance | | `strategy/operating-system.md` | Operating architecture / measurement | | `research/snapshots/2026-09-03-protocol-fees.json` | Snapshot excluding pair creation | | `research/source-register.md` | Source quality register | Those files are the pointer surface. They must not grow a parallel fee indexer, notebook-as-truth, or implement-queue for wasm parsers. ### Trail status (already done vs leftover) **Done** - #1209 / #1210 / #1211 opened on this repo with full ingest/API bodies. - Marketing #1 / #4 / #5 closed with replacement URLs (do not silent-reopen). **Leftover (this issue)** - Strategy/research markdown that still says “see marketing #1 / #4 / #5” or implies implement-home is marketing. - Related-issue links inside #1210 / #1211 that still point at marketing #1 / #4 instead of #1209 / #1210. - Risk that a later agent re-opens the marketing trackers or files a fourth copy of the ingest work. --- ## Why the work is needed Phase 0 ledgers include pair creation, project-team invoices, and (later) a privacy-safe retail/MM split. The public API cannot report those yet. That **ingest** work belongs on #1209 / #1210 / #1211. Without a **single home map**, two failure modes stay open: 1. **Second fee authority** — a marketing-side counter or LCD notebook treated as equal to `protocol_fee_events`. Campaign decisions then diverge from `/protocol`. 2. **Wrong-repo implement** — agents follow closed marketing issues (titles still look like feats; labels may still say implement) and try to parse wasm in the marketing tree. Pointer retarget is cheap and prevents both. It is not optional “docs later”: it is the trail the three ingest tickets assumed when they were copied here. --- ## Constraints and guardrails 1. **Do not implement ingest in this issue.** No new `FeeSource`, migration CHECK, API field, or UI label here. That is #1209 then #1210 then #1211 (stack order: pair_creation → invoices → cohort). #1211 also depends on #1202 remaining on hold — do not expand #1202. 2. **Do not reopen marketing #1 / #4 / #5** for implement, “ready,” or code. If a comment is required on those issues, it is a one-line pointer at the dex replacement only. 3. **Do not churn labels** on #1209 / #1210 / #1211 (no extra ready/implement/close from this ticket). 4. **Indexer wins after ship.** Any Phase 0 LCD reconciliation of factory→treasury uluna (or CMM UST1 invoices) must stay labeled **provisional** until the matching ingest lands, then be marked retired in marketing snapshots. 5. **Do not mix sources.** Pair-creation uluna, SKU/settings UST1, swap/wrap/window, and client analytics are four different truths. Catalog `community_token_events` ≠ protocol fees. 6. **Do not double-count instantiate gas**, refunds, `reply_instantiate_pair`, buy/sell tax, AutoLP, migrate-adopt, or pay-with-any-token swap legs as community invoices. 7. **Cohort privacy.** No wallet lists, no person-to-wallet map, no `campaign_id` on fee rows. Split is aggregate (retail / MM / unjoined) as-of height. Do not treat `traders.tier_id = 0` as MM unless `fee_discount_registered` (or equivalent as-of-height membership) is true. 8. **Pin emitters** on the implement tickets (factory, wrap mapper, UST1 window, community launcher, catalogued tokens). Forged `contract_address` without underscore is ignored ([#285](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/285)). 9. **GET stays O(1) rollup / 60s cache.** Additive JSON. Unconfigured pin → omit source (not fake `$0`). Idle configured → `"0"`. Unpriced → `null`. 10. **No social / X / paid-media work** in this ticket or in #1209–#1211. 11. **Do not expand [#1204](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1204).** When new sources ship, OpenAPI follows those ingest MRs (or a later docs follow-up), not this epic. 12. **Do not invent a second public `/protocol/fees` on any other repo.** --- ## Relevant files ### This repo (implement ingest only via child issues) | Path | Why | |------|-----| | `indexer/src/indexer/protocol_fees.rs` | `FeeSource` enum / wrap-window pattern | | `indexer/src/indexer/parser.rs` | `ingest_protocol_fee` wiring; no actor today | | `indexer/src/indexer/community_tokens.rs` | Catalog only; do not treat as fee truth | | `indexer/src/db/queries/protocol_fees.rs` | Insert / rollup | | `indexer/migrations/20260821120000_protocol_fees.sql` | CHECK / uniqueness pattern | | `indexer/migrations/20260824120000_ust1_window_protocol_fees.sql` | Prior source-widening pattern | | `indexer/src/api/protocol_fees.rs`, `protocol_fee_series.rs`, `api/defillama.rs` | Public ledger | | `indexer/src/indexer/trader_tracker.rs` | Registry sync; as-of-height trap for #1211 | | `frontend-dapp/src/types/index.ts` | `ProtocolFeeSourceKey` | | `frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx` | Labels / hide-idle | | `smartcontracts/contracts/factory/src/contract.rs` | `creation_fee_uluna` (read-only for ingest) | | `smartcontracts/contracts/community-tax-token/src/invoice.rs` | 50 UST1 invoices (read-only) | | `docs/audits/factory-treasury-bank-send.md` | Item 11 until #1209 ships | | `docs/indexer-invariants.md` | Protocol-fees invariants | | `skills/AGENTS_INDEXER_UST1_WINDOW_FEES.md`, `AGENTS_INDEXER_WRAP_FEE_INGEST.md` | Pattern to copy on children | ### Marketing repo (pointers / snapshots only) | Path | Why | |------|-----| | `strategy/fee-growth-model.md` | Cite #1209 / #1210 / #1211 as implement home | | `strategy/90-day-plan.md` | Phase 0 ingest bullets → dex issue numbers | | `strategy/technical-architecture.md` | Authority sentence; no second indexer | | `strategy/operating-system.md` | Measurement points at public API | | `strategy/phase-0-status.md` | Blockers should name dex issues if they name marketing feats | | `research/snapshots/` | Keep snapshots; label provisional vs indexer | | `research/source-register.md` | Source quality; indexer API as authority | | Closed issues #1 / #4 / #5 | Remain closed; trail already names replacements | --- ## Recommended direction 1. **Treat this issue as the epic.** Implementers pick #1209, then #1210, then #1211. Do not open additional feat tickets that copy those titles. 2. **Pointer PR on marketing** (docs-only): grep `cl8y-marketing#1`, `#4`, `#5`, and prose like “open on marketing” / “implement here” in `strategy/` and `research/`. Replace with the table in the Summary. Keep historical snapshot JSON bytes stable unless a comment/header records “pair creation not in this extract; tracked on dex #1209.” 3. **Related-link edit** on #1210 / #1211 (issue body “Related” lines only): marketing #1 → #1209, marketing #4 → #1210. Do not rewrite the ingest ACs. 4. **After each child ships:** marketing fee-growth / snapshot notes the new stream as live; provisional LCD stopgap marked retired. That update is already an AC on the child — do not duplicate the parser tests here. 5. If Forgejo issue bodies cannot be edited in place, a one-line comment on #1210 / #1211 of the form `Related ingest siblings: #1209 #1210 #1211` is enough. No chat logs. --- ## Acceptance criteria - [ ] **AC1.** This issue is the only **design/home** ticket for the three slices; ingest remains #1209 / #1210 / #1211 (no fourth copy of those titles). - [ ] **AC2.** Marketing `strategy/` + `research/` markdown that referenced marketing #1 / #4 / #5 for **implement** now references the dex issue numbers in the Summary table. Historical “closed tracker” mentions may remain if they also name the dex replacement. - [ ] **AC3.** Marketing #1 / #4 / #5 stay **closed**. No new feat on marketing that re-states pair_creation / SKU invoices / cohort ingest. - [ ] **AC4.** #1210 / #1211 related links name #1209 / #1210 (not only marketing #1 / #4). - [ ] **AC5.** No marketing service, script, or table writes fee truth. Architecture docs still say indexer is the ledger. - [ ] **AC6.** No social/X spend, no #1204 scope creep, no #1202 expansion, no wallet lists. - [ ] **AC7.** Child implement tickets keep their existing ACs (gas exclusion, pin factory/launcher, one row per invoice, as-of-height cohort, fail-closed amounts). This epic does not weaken them. --- ## Test plan (functional paths) | # | Path | Expect | |---|------|--------| | T1 | Grep marketing `strategy/` `research/` for `cl8y-marketing/issues/1` (and `#1` in fee-ledger context) | Either gone or paired with dex #1209 | | T2 | Same for marketing #4 | Paired with #1210 | | T3 | Same for marketing #5 | Paired with #1211 | | T4 | `fj issue view` marketing 1 / 4 / 5 | State closed; comments still name dex replacements | | T5 | Open issues search on marketing for `pair_creation` / `protocol/fees` ingest | No new open feat duplicating #1209–#1211 | | T6 | Open issues search on this repo for those three titles | Exactly #1209 / #1210 / #1211 plus this epic (no extra copies) | | T7 | #1210 / #1211 related section | Dex sibling links present | | T8 | `strategy/technical-architecture.md` (or equivalent authority doc) | Indexer = economic authority; marketing ≠ fee service | | T9 | Child tickets still describe fail-closed pins / uniqueness / no gas | Unchanged ingest ACs | | T10 | #1204 / #1202 | Untouched by the pointer PR | Docs-only change: no indexer/frontend test suite required on **this** epic. Child ingest tickets keep `make verify-issue-586` / `make verify-issue-614` plus their own `verify-issue-*` bundles. --- ## Test plan (attack, hack, and abuse) | # | Vector | Expect | |---|--------|--------| | A1 | Agent implements `FeeSource` parsers inside `PlasticDigits/cl8y-marketing` | Forbidden; this epic + children say home is this indexer | | A2 | Re-open marketing #1 / #4 / #5 as implement-ready | Forbidden; stay closed trackers | | A3 | File a fourth dex feat that copies #1209 / #1210 / #1211 titles | Duplicate; close pointing here / at the existing child | | A4 | Treat LCD notebook or snapshot JSON as equal to `/protocol/fees` after ingest ships | Indexer wins; stopgap labeled provisional then retired | | A5 | Count instantiate gas / refunds / `reply_instantiate_pair` as pair_creation | Forbidden (#1209) | | A6 | Mix SKU invoices into `pair_creation` or `swap_amm` | Forbidden (#1210) | | A7 | Double-count launcher + token `enable_feature` | One fee row (#1210) | | A8 | Naive `traders.tier_id = 0` ⇒ MM | Forbidden; unregistered default 0 is not Tier 0 MM (#1211) | | A9 | Live join that rewrites historical fees after deregister | Forbidden; as-of-height (#1211) | | A10 | Publish wallet lists / person-to-wallet maps in marketing or `/protocol` | Forbidden | | A11 | Spoof wasm `create_pair` / `invoice` from unpinned contracts | Ignored on children (#285) | | A12 | Infer fees from `config × count` or `50e6 × SKU flags` without a paid tx | Forbidden | | A13 | Put exact invoice amounts or wallets into client analytics (#1202) | Out of scope; not fee truth | | A14 | Expand this epic into #1204 OpenAPI or social/X spend | Out of scope | | A15 | Relabel #1209–#1211 ready/implement from this ticket | Forbidden | | A16 | Symbol spoof / `$1` UST1 / vFDUSD as USD | Price via catalog identity on children | | A17 | Unconfigured factory/launcher pin reporting fake `$0` | Omit source | | A18 | Replay/reorg double insert | `(tx_hash, source, ordinal)` uniqueness on children | --- ## Verification criteria - Summary table in this issue matches live Forgejo: three open (or later-closed-by-ship) children on `code/cl8y-dex-terraclassic`, three closed marketing trackers with replacement URLs. - Marketing pointer PR: `git grep -n 'cl8y-marketing#1\|issues/1' strategy research` (and #4 / #5) is empty **or** every hit also names the dex replacement in the same paragraph. - No new marketing feat titled like the three ingest slices. - `make verify-issue-586` and `make verify-issue-614` still green (no accidental ingest change in the pointer PR). This epic’s PR should be **docs-only on marketing** (plus optional issue-body related-link edits). - Manual: a new agent given “pair creation fees on the protocol ledger” lands on #1209, not on a marketing implement queue. ## Out of scope - Implementing pair_creation / SKU / settings / cohort ingest (children). - [#1204](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1204) OpenAPI pack. - [#1202](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/1202) client events / UTM. - Social, X, paid media, or spend. - Changing on-chain `pair_creation_fee_uluna` or `INVOICE_UST1`. - MM subscription invoices ([#597](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/597)). - Indexer exact-out `/route/solve`. - Building any fee service outside this indexer.
Author
Owner

cl8y-agent-control: queued implement job 0232cde9-375d-44f6-aeab-b503c12179fe (not executed; no Hetzner VM).

cl8y-agent-control: queued `implement` job `0232cde9-375d-44f6-aeab-b503c12179fe` (not executed; no Hetzner VM).
Author
Owner

Trail PRs (do not merge protected main from the agent):

Related ingest siblings: #1209 #1210 #1211. Verify: make verify-issue-1213.

Trail PRs (do not merge protected main from the agent): - Dex home map: https://git.cl8y.com/code/cl8y-dex-terraclassic/pulls/1214 - Marketing pointers: https://git.cl8y.com/PlasticDigits/cl8y-marketing/pulls/7 Related ingest siblings: #1209 #1210 #1211. Verify: `make verify-issue-1213`.
Author
Owner

Verified on docs/1213-fee-ledger-home (updates existing PR, no new ingest):

  • make verify-issue-1213 — 4/4 PASS (before and after the pointer-map follow-up).
  • No FeeSource / CHECK / pair_creation / sku_unlock / settings_fee on this epic.
  • AC4: #1210 / #1211 issue-body Related lines now name #1209 / #1210 / #1211 (closed marketing #1 / #4 remain as trackers).
  • Skill now points at marketing strategy/fee-ledger-home.md (companion PlasticDigits/cl8y-marketing#7).

Do not merge protected main from this agent (Woodpecker + autoland).

Verified on `docs/1213-fee-ledger-home` (updates existing PR, no new ingest): - `make verify-issue-1213` — 4/4 PASS (before and after the pointer-map follow-up). - No `FeeSource` / CHECK / `pair_creation` / `sku_unlock` / `settings_fee` on this epic. - AC4: #1210 / #1211 issue-body Related lines now name #1209 / #1210 / #1211 (closed marketing #1 / #4 remain as trackers). - Skill now points at marketing `strategy/fee-ledger-home.md` (companion https://git.cl8y.com/PlasticDigits/cl8y-marketing/pulls/7). Do not merge protected `main` from this agent (Woodpecker + autoland).
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#1213
No description provided.