feat(voting): operator-voting package — limited DB balances-at-height + signatures, proposals, blacklist #510
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#510
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
Create a new standalone package
operator-voting(sibling toindexer/ underpackages/as appropriate) that provides the offchain voting control plane with least-privilege Postgres access:Frontend and indexer remain separate; this package must not receive the indexer’s broad DB credentials.
CL8Y:
terra16wtml2q66g82fdkx66tap0qjkahqwp4lwq3ngtygacg5q0kzycgqvhpax3(fee-discount / hpax3). LocalTerra TCL8Y via shared env.Linked:
Current codebase
indexer/src/api/— almost entirely read DEX analytics; only notable POST isroute/solve(quote, not user auth). No signature verify, no vote routesDATABASE_URLwith full migrate/write — unsuitable to expose directly to a voting write APIindexer/Cargo.toml; frontend has Keplr tx sign (terraWalletSignTxRaw.ts) but nosignArbitrarytyping/helperspackages/localnet-trading-swarm(TS); Rust indexer is standalone cratecl8y-dex-indexer(not a workspace member with shared voting crate yet)indexer.dex.cl8y.com); pattern for a second service/env exists via deploy docsWhy this is needed
Voting must accept user-submitted signatures and persist them. Putting that write path on the full indexer DB role expands blast radius (analytics tables, ingestion state). A dedicated
operator-votingbinary/package with a restricted DB role (SELECT on balance views + CRUD on signature/proposal/vote tables only) isolates abuse and matches the product constraint: limited database access only for balances-at-height reads and signature read/write.Also centralizes ADR-36 verify, proposal rules (≥1000 CL8Y to create), snapshot freeze, tally, and
VOTING_BLACKLISTenforcement in one audit surface.Constraints / guardrails
operator-votingDB user must not INSERT/UPDATE indexer ledger tables,indexer_state, swap tables, etc. Prefer dedicated schema (e.g.voting) +GRANT SELECTon balance view/function from indexer migrations.signArbitrary) → recover/deriveterra1…and require it matches claimed voter/proposer/registrar.Husing Postgres balance-at-height only (no archive LCD).VOTING_BLACKLIST_ADDRESSESorOPERATOR_VOTING_BLACKLIST) — blacklisted wallets cannot vote (and document whether they can still register/create proposals; default: cannot vote; creating proposals as blacklisted should also be denied unless product says otherwise — deny both vote and propose).(proposal_id, wallet); proposal create is not replayable with same id.operator-votingas requested; shipable as its own Coolify service with its ownDATABASE_URL(restricted).Relevant files
New
operator-voting/orpackages/operator-voting/— crate/package root (Cargo.tomlor Node — prefer Rust to share sqlx/postgres ops with indexer, unless team standardizes TS; recommend Rust Axum sibling binary)operator-votingor additive indexer migrations that create views +votingschema with grantsReuse / integrate
indexer/src/api/mod.rspatterns (utoipa, CORS, governor rate limits) as reference — do not merge routes into indexerVITE_OPERATOR_VOTING_URL(frontend issue)Reference only
frontend-dapp/src/services/terraclassic/terraWalletSignTxRaw.ts,wallet.tsdocs/security-model.md, Coolify deploy runbooksRecommended direction
Responsibilities
POST /v1/registerGET /v1/registration/:addrPOST /v1/proposalsGET /v1/proposals,GET /v1/proposals/:idPOST /v1/proposals/:id/votesGET /v1/proposals/:id/votes/:addrGET /v1/balances/:addr?height=Env
DATABASE_URL(restricted role)CL8Y_TOKEN_ADDRESSVOTING_BLACKLIST_ADDRESSES— comma-separatedterra1…(trim whitespace; invalid entries fail startup)CORS_ORIGINS,API_BIND, chain-id / signing domain constantsMIN_PROPOSAL_CL8Ydefault1000(human units) →1000 * 10^18rawDB
signatures,proposals,proposal_snapshots(wallet → weight),votesvoting_cl8y_balance_at(address, height)from indexer migrationsCrypto
signArbitraryoncolumbus-5/ LocalTerra chain-idAcceptance criteria
operator-votingpackage builds and runs as its own service.VOTING_BLACKLIST_ADDRESSES(or final agreed name) parsed from env; blacklisted addresses cannot vote (and cannot create proposals per guardrail above).Test plan (all paths)
1000 * 10^18).swap_events/ ledger tables fails.Test plan — attack, hack & abuse vectors
voterfield ≠ recovered address — reject.Verification criteria
operator-voting.Labels
backendindexerenhancementarchitecturesecuritydeployPriority
P1
mentioned in issue #509
Bundle links
operator-voting— signatures, proposals, votes,VOTING_BLACKLIST_ADDRESSESDepends on #509 balance views/grants. Blocks #511 for full-stack E2E.
mentioned in issue #511
marked as related to #509
marked as related to #511
mentioned in issue #588
marked as related to #588
Scope add: EVM signatures + BSC snapshot weight (core)
A majority of CL8Y holders are on BSC, not Terra Classic.
operator-votingmust verify EIP-191personal_signfrom EVM wallets (in addition to Terra ADR-36), persist signatures for0xaddresses, and freeze vote power from the BSC BEP-20 ledger as well as the Terra CW20 ledger.Proposal create should record both a Terra Classic height and a BSC block number.
VOTING_BLACKLIST_ADDRESSESmust accept normalized EVM addresses.Terra-only auth/weights would exclude most tokenholders — not an acceptable MVP.
Tracking issue (BSC integration): https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/588
Voting work left this repo on 2026-08-25.
Canonical project: https://gitlab.com/PlasticDigits/voting
Also opened there: Legal clickwrap (#5), wallet reuse (#6). Do not implement voting in this DEX repo.
mentioned in issue #637