feat(indexer): index pair_creation fees on /api/v1/protocol/fees (no instantiate-gas double-count) #1209
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#1209
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Index factory pair-creation treasury uluna on
GET /api/v1/protocol/feesasFeeSource::PairCreation/pair_creation. The on-chain fee already exists. The indexer has seven sources and nocreate_pairparser.Do not count CosmWasm instantiate gas (validator fee, not treasury revenue). Do not mix SKU/settings invoices (#1210) or cohort split (#1211). Design/home: #1213.
Closed marketing tracker: cl8y-marketing#1. Do not reopen it. Do not implement fee truth in marketing.
Given / When / Then
Given a successful factory
CreatePairon the pinnedFACTORY_ADDRESSwithcreation_fee_uluna> 0When the indexer ingests that tx
Then it inserts one
protocol_fee_eventsrow (source=pair_creation, amount = the wasm attr)And instantiate gas, overpay refunds, and
reply_instantiate_pairare not fee rowsAnd
GET /api/v1/protocol/feesexposespair_creationwith the same idle/unpriced/windowsemantics as wrap/windowNot a duplicate / already implemented
FeeSource.pair_creationonce this source exists.pair_creation_fee_uluna(already shipped).Not implemented:
FeeSource::ALLis length 7.indexer/src/indexer/has nocreate_pair/creation_fee_ulunaparser. Pair discovery is not treasury census.Current codebase
On-chain (already correct)
Factory
execute_create_pair:config.pair_creation_fee_uluna(default100_000_000uluna).BankMsg::Sendfee →config.treasury.SubMsg::reply_on_success). Instantiate failure reverts the fee.action=create_pair,pair=…,creation_fee_uluna=<fee>.action=reply_instantiate_pair(registration only — not a fee).Gas for instantiate is a separate Cosmos tx fee.
Indexer ingest (seven sources)
FeeSourceisswap_amm,book_take,limit_place,wrap,unwrap,ust1_mint,ust1_redeem. Wrap/UST1 require pinned addresses and explicit positive fee attrs (fail closed).ingest_protocol_feedropsamount_raw <= 0. Rows land inprotocol_fee_eventswithUNIQUE (tx_hash, source, ordinal)andON CONFLICT DO NOTHING.fee_usdstamped at ingest. GET is O(1) rollup / 60s cache — no liveSUM.FACTORY_ADDRESSis required in everyRUN_MODE(#451). There is no wrap-style “factory unset” omit path; pin is the existing factory env.pair_discovery.rsfinds pairs via instantiate / factory registry. Audit item 11 still states there is no pair-creation fee parser.CHECK constraints (
20260824120000_ust1_window_protocol_fees.sql) and DeFiLlama daily fields match the seven keys.Frontend
ProtocolFeeSourceKeyandProtocolFeeStats.tsxSOURCE_LABEL/SOURCE_ORDERhave nopair_creation.Why the new implementation is needed
/protocoland DeFiLlama cannot report project-team pair-creation revenue. Offline LCD reconciliation of factory→treasury uluna is acceptable only as a labeled provisional stopgap. A second fee service in marketing would fork economic truth.The UST1 window (#614) is the pattern: new
FeeSource, pinned contract, explicit amount attr, rollups, Defillama, UI label, verify target.Constraints / guardrails
creation_fee_uluna. Optional same-tx cross-check vs factory→treasury ulunaBankMsg. Ignore instantiate gas, fee-payer burn, sender refunds, andreply_instantiate_pair.amount_raw > 0required. Zero-fee creates: no fee row. Do not inferconfig.pair_creation_fee_uluna × create count(fee can change mid-window)._contract_addressequals pinnedFACTORY_ADDRESS. Ignore spoofcreate_pairand unreservedcontract_address(no underscore).ulunacatalog identity (PFee / H-series), not free-text symbol. Unpriced: store event,fee_usdNULL; activity + all unpriced → APInull.window=remains24h|7d|30d. Additive JSON.Relevant files
indexer/src/indexer/protocol_fees.rsFeeSourceenum / wrap-window parse patternindexer/src/indexer/parser.rsingest_protocol_feewiringindexer/src/db/queries/protocol_fees.rsindexer/migrations/20260824120000_ust1_window_protocol_fees.sqlindexer/src/api/protocol_fees.rs,protocol_fee_series.rs,api/defillama.rsindexer/tests/indexer_protocol_fees.rs,indexer_protocol_fees_series.rs,indexer_defillama.rsfrontend-dapp/src/types/index.tsProtocolFeeSourceKeyfrontend-dapp/src/components/protocol/ProtocolFeeStats.tsxsmartcontracts/contracts/factory/src/contract.rscreation_fee_uluna(read-only)docs/indexer-invariants.md,docs/audits/factory-treasury-bank-send.mdskills/AGENTS_INDEXER_UST1_WINDOW_FEES.md,AGENTS_INDEXER_WRAP_FEE_INGEST.md,AGENTS_INDEXER_FEE_LEDGER_HOME.mdRecommended direction
FeeSource::PairCreation/pair_creation. Copy wrap/window: per-action scan, reserved_contract_address, fail-closed positive amount.action=create_pair+ positivecreation_fee_uluna. Asset = nativeuluna. Stampfee_usdfrom LUNC catalog.FeeSource::ALL, rollups, Defillama additive field, frontend key + label Pair creation.make verify-issue-1209(or equivalent) bundled like #614. Playbook skill optional.(tx_hash, source, ordinal); must not count gas.Reject: counting gas; inferring fee from config × count; mixing invoices into this source.
Acceptance criteria
FeeSourceincludespair_creation; CHECK constraints, rollups, Defillama, and UI labels updated.creation_fee_ulunaon pinned factorycreate_pairinserts exactly oneprotocol_fee_eventsrow;tx_hashis the create tx.reply_instantiate_pairare not ingested as fees.GET /api/v1/protocol/feesand/dailyexposepair_creationwith idle"0"/ unpricednull/windowallowlist unchanged (invalid window still 400).event_count > 0. Unknown source strings are not interpolated into JS.docs/indexer-invariants.mdand factory-treasury audit item 11 updated (parser now exists).Test plan (functional paths)
creation_fee_uluna; USD stamped or NULL per LUNC catalogpair_creationrow_contract_addressonlywindow=24h|7d|30d; bad window 400by_sourceincludespair_creation; additive JSON"0"/nullrules as wrap/UST1make verify-issue-586/make verify-issue-614still greenTest plan (attack, hack, and abuse)
action=create_pairfrom non-factory contract_contract_address= pinned factorycontract_address(no underscore)reply_instantiate_pair(tx_hash, source, ordinal)uniquenessulunacatalog identitycreation_fee_ulunaVerification criteria
by_sourcecontainspair_creationwith correctevent_count/amount_usdsemantics.create_pairtxhash matchesprotocol_fee_events(source=pair_creation) and does not include gas asamount.make verify-issue-1209(or the issue verify target named in the PR) plusmake verify-issue-586/make verify-issue-614.feat: index pair_creation fees on /api/v1/protocol/fees (no instantiate-gas double-count)to feat(indexer): index pair_creation fees on /api/v1/protocol/fees (no instantiate-gas double-count)Repair: DEX-native DoR. Not implemented (
FeeSourcestill 7; no create_pair fee parser). Left unbundled from #1210/#1211 per #1213 stack. Marketing #1 stays closed tracker./agent implement
/agent implement
/agent implement
Verification on refreshed main (
54c4868e): keep #1209 open.FeeSourcestill has seven values; there is noPairCreationparser ormake verify-issue-1209target.Remaining:
creation_fee_ulunafrom pinned factorycreate_pair; ignore spoof/unreserved emitters, gas, refunds, reply attrs, and duplicate bank-send counting.pair_id IS NULLwith #1269's non-pair partial unique key; wire rollups, API/daily, DeFiLlama, and the fixed UI label while preserving idle/unpriced/window semantics.make verify-issue-1209; update audit item 11 after ingest ships.Related: #1213 is the closed home map; #1269 is the closed uniqueness prerequisite; #1210/#1211 are separate later sources; #285 governs reserved emitter identity. None replaces #1209.
Checks:
make verify-issue-1213passed 4/4. #1269 docs/source checks, 34 unit tests, and parser test passed; its integration run passed 25/26 with one Postgres pool timeout, and the isolated case passed on rerun.Reopening (Market sensor). This was auto-closed when docs-only PR #1348 merged, but the acceptance criterion is not met: live
GET /api/v1/protocol/fees?window=24hon 2026-09-25 still returns only 7by_sourcevalues (book_take, limit_place, swap_amm, unwrap, ust1_mint, ust1_redeem, wrap), with no pair_creation source. Close only when the indexer ingests it and it appears on the live endpoint. Labels ready+agent:implement stay.