Fix: Indexer factory pair provenance on discover_new_pair (GitLab #285 followup) #311
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#311
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?
Current codebase
Indexer pair discovery:
pair_discovery::sync_all_pairsqueries configuredFACTORY_ADDRESSpaginatedpairslist.discover_new_pairqueries any address responding to{"pair": {}}LCD query — used when parser sees swap/fill events for unknown addresses (parser.rs).discover_new_pairdoes not verify:PairInfoState.factorymatchesFACTORY_ADDRESScode_idmatches factory'spair_code_idWasm event scoping (#285 shipped): Parser trusts only runtime
_contract_address, not forgeablecontract_addressattribute — prevents attributing events to victim pairs.Remaining gap (factory provenance follow-up): Malicious or clone pair contracts mimicking the pair query API can still be indexed if they emit plausible wasm events, polluting charts, route graph, and volume.
Pair on-chain state stores
factory: AddrinPairInfoState(smartcontracts/contracts/pair/src/state.rs) but publicPairquery returns TerraSwap-compatible struct without factory field.Follow-up: GitLab #285 (factory provenance).
Why this is needed
Indexers and dApps assume indexed pairs are canonical CL8Y factory deployments. Indexing unverified contracts enables phishing pairs, fake volume, and route solver edges to malicious pools.
Constraints / guardrails
discover_new_pairshould fail closed or markunverifiedwhen provenance fails.Pairreverse lookup.FACTORY_ADDRESSrequired in prod (config.rsalready errors if empty in prod).Relevant files
indexer/src/indexer/pair_discovery.rsindexer/src/indexer/parser.rsindexer/src/config.rsindexer/src/db/queries/pairs.rssmartcontracts/contracts/pair/src/state.rs,contract.rssmartcontracts/contracts/factory/src/contract.rsindexer/src/indexer/parser.rsforged-emitter testsRecommended direction
Option A (indexer-only): After
pairquery, second query factory{"pair": { asset_infos }}and requirecontract_addrmatch.Option B (contract): Extend pair
QueryMsg::ConfigorPairresponse withfactoryaddr; indexer checks equality.Option C (schema):
pairs.verifiedboolean + migration to quarantine existing rows.Implement A quickly; B for long-term integrator trust.
Acceptance criteria
discover_new_pairrejects/non-indexes pairs not in configured factory.sync_all_pairspath unchanged for legitimate pairs.Test plan (all paths)
Attack / abuse / hack vectors
_contract_addressscoping + provenanceVerification criteria
/api/v1/pairs/{addr}/trades.marked as related to #285
mentioned in commit
ce9040cb93mentioned in merge request !790
Implementation complete in !790.
Summary:
discover_new_pairnow calls factoryPair { asset_infos }and requires the returnedcontract_addrto match the emitter before indexing. EmptyFACTORY_ADDRESSskips provenance with a warning (dev only). Documented as invariant P1.Verification:
cd indexer && cargo test --lib pair_discovery::tests(4/4 PASS); full lib suite 111/111 PASS.Issue remains open until MR merge.
mentioned in commit
104e28d603Verification complete — GitLab #311
Issue: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/311
Implementation: merged in !790 (
ce9040conmain).Acceptance criteria
discover_new_pairrejects/non-indexes pairs not in configured factorycd indexer && cargo test --lib pair_discovery::tests→ 4/4 PASS (verify_factory_provenance_rejects_unlisted_pair,_fails_when_factory_has_no_pair,_accepts_factory_listed_pair,_skipped_when_factory_empty)sync_all_pairspath unchanged for legitimate pairsgit diff ce9040c^..ce9040c -- indexer/src/indexer/pair_discovery.rs— no changes tosync_all_pairs; factory paginated sync unchangedcargo test --lib forged_contract_address→ 3/3 PASS; parser skips discovery failures with warn (parser.rsreturnsOk(())ondiscover_new_pairerr)docs/indexer-invariants.md(P1),docs/integrators.md§ Indexer pair list,indexer/.env.exampleFACTORY_ADDRESS commentpair_discovery.rs(attacker responds topairquery; factory lists canonical addr only → reject)Test plan (issue body)
verify_factory_provenance_accepts_factory_listed_pairverify_factory_provenance_rejects_unlisted_pairsync_all_pairsunchanged; no regression in lib suiteFACTORY_ADDRESSdevverify_factory_provenance_skipped_when_factory_emptyconfig.rsRunMode::Prod→ProdEmpty("FACTORY_ADDRESS")when trimmed emptyVerification criteria (supplementary)
pair_discovery.rs/api/v1/pairs/{addr}/tradesfrontend-dapp/.env.local,indexer/.envabsent). Logic path covered by unit tests above; recommend on-chain manual check when LocalTerra is available.Commands run
No repository changes required from this verification pass.
mentioned in merge request !818
mentioned in issue #345
mentioned in issue #337
mentioned in commit
edcda1fc91mentioned in commit
69a81432e9mentioned in issue #548
mentioned in issue #556
mentioned in issue #562
mentioned in issue #568
mentioned in issue #692