feat(voting): BSC BEP20 CL8Y ledger + EVM wallet voting (core electorate) #588

Closed
opened 2026-08-21 11:32:36 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-08-21 11:32:36 +00:00 (Migrated from gitlab.com)

Summary

BSC is core to the voting electorate, not an optional extra. A majority of CL8Y holders are on BNB Smart Chain (BEP-20), not Terra Classic CW20. Shipping #509 / #510 / #511 as Terra-only would exclude most tokenholders from registration, proposal weight, and ballots.

Extend the offchain snapshot-voting bundle so that:

  1. The indexer tracks BEP-20 CL8Y balances for registered EVM wallets (live balanceOf at registration + Transfer logs forward — same “no archive node” model as #509).
  2. operator-voting accepts EVM wallet signatures (EIP-191 personal_sign) for register / propose / vote, and freezes vote power from both the Terra CW20 ledger and the BSC BEP-20 ledger.
  3. The dApp lets holders connect an EVM wallet (MetaMask / WalletConnect EIP-155) and complete the same /vote flows.

No new Solidity or CosmWasm contracts. Frontend + Postgres + indexer + operator-voting only.

BEP-20 CL8Y (canonical BSC): 0x8F452a1fdd388A45e1080992eFF051b4dd9048d2 (CL8Y_v2, 18 decimals) — same asset brand as Terra CW20 terra16wtml…hpax3. Configurable via env (BSC_CL8Y_TOKEN_ADDRESS).

Terra CW20 (unchanged, #509): terra16wtml2q66g82fdkx66tap0qjkahqwp4lwq3ngtygacg5q0kzycgqvhpax3.

This issue is the cross-chain / EVM work item. It does not replace #509–#511; those issues must include BSC in their scope (see comments on each).

Bundle

Issue Role after this work
#509 Indexer/Postgres registration + Terra CW20 and BSC BEP-20 ledgers for registered wallets
#510 operator-voting — Cosmos ADR-36 and EVM EIP-191 sigs; snapshot = Terra height plus BSC block; blacklist includes 0x addresses
#511 dApp register / propose / vote for Keplr/Station and EVM wallets
This issue BSC integration contract: token pin, RPC/log indexing, snapshot pairing, EVM identity, double-count/bridge rules

Why this is needed

#509–#511 currently assume a Terra Classic wallet + CW20 Balance + wasm transfer events. That is correct for the DEX’s home chain and for fee-discount cl8y_token, but it is not the majority CL8Y holder set.

Without BSC:

  • Most CL8Y cannot register or vote.
  • Proposal threshold (≥1000 CL8Y in #511) is measured on the minority chain only.
  • Snapshot tallies systematically under-weight the token.

Venus eth_call on BSC_RPC_URLS (#571) already proves the indexer can talk to BSC JSON-RPC. That path is oracle-only and must not be overloaded. Voting needs a separate BEP-20 ledger + EVM auth plane.


Current codebase

Area Status
BSC JSON-RPC indexer/src/indexer/venus_vfdusd.rs + config.bsc_rpc_urls (BSC_RPC_URLS) — Venus vFDUSD eth_call only. No eth_getLogs, no ERC-20 balanceOf, no Transfer parser
Browser BSC Forbidden for oracle (#571 V571-5): no VITE_* BSC RPC, no BscScan from the dApp. Wallet provider connect for signing is a new surface
EVM wallets in dApp Cosmos-only: Keplr / Station / WC / Simulated Wallet (frontend-dapp/src/services/terraclassic/wallet.ts). WalletConnect is EIP-155 Cosmos pairing (#519 / #554 / #566), not BSC
Legal EVM sign Hosted portal https://terms.cl8y.com/sign/evm (#517 clickwrap) — external redirect, not in-app MetaMask; do not reuse as voting auth
Voting ledger Not implemented (#509). Designed for CW20 wasm events only
operator-voting Not implemented (#510). Designed for ADR-36 / Terra bech32
Frontend /vote Not implemented (#511). Designed for Terra signArbitrary

Constraints / guardrails

  1. Core, not phase-2. Do not ship Terra-only voting to production as “done.” BSC registration + BEP-20 weight must land with (or immediately after) the Terra path; a Terra-only electorate is an incomplete product.
  2. No new contracts on BSC or Terra. Do not deploy a voting token, snapshot contract, or governor.
  3. No BSC archive-node requirement. Registration balance = live balanceOf(wallet) at current eth_blockNumber. History afterward = Transfer logs for the registered set only (mirror #509).
  4. Pin the token. Only trust logs/balanceOf for configured BSC_CL8Y_TOKEN_ADDRESS (default 0x8F452a1fdd388A45e1080992eFF051b4dd9048d2). Ignore other BEP-20s and lookalike tickers.
  5. 18-decimal raw integer amounts as strings / NUMERIC — same as CW20; no float.
  6. Registered-set filter. Index Transfer logs only when from or to is a registered EVM address (plus the registered counterparty). Do not ingest the full CL8Y holder universe.
  7. Reuse BSC_RPC_URLS transport, not the Venus module. New indexer module (e.g. bsc_cl8y_ledger.rs). Empty BSC_RPC_URLS skips live BSC (CI/LocalTerra) the same way #571 does. Never log RPC URLs/keys. Soft-fail RPC must not invent balances.
  8. Browser must not grow Vite BSC RPC hosts for balance reads (keep V571-5). Indexer owns eth_call / eth_getLogs. Injected/WC provider is only for connect + personal_sign.
  9. Snapshot pairing. A proposal freezes both a Terra Classic height (existing #509) and a BSC block number taken at create time (wall-clock aligned). Vote weight for an address is the ledger balance on its chain at that chain’s frozen height/block. Document inclusive block ordering.
  10. Identity v1 = one address, one voter. A Terra terra1… registration and a 0x… registration are distinct voters unless product later adds explicit linking. Do not silently merge by heuristic.
  11. No double-count of the same units. Terra CW20 and BSC BEP-20 are separately circulating supplies today (not a lock-and-mint bridge in this repo). Each registered address votes its chain balance. If an official bridge later locks tokens on one side, document so locked/in-flight supply is not counted twice. Do not convert via USD or DEX pool prices.
  12. Blacklist (VOTING_BLACKLIST_ADDRESSES) must accept normalized 0x (EIP-55 checksum optional; compare case-insensitive) and Terra bech32.
  13. Propose threshold (≥1000 CL8Y) is evaluated against the registering address’s chain ledger (BEP-20 for EVM, CW20 for Terra). Do not sum unrelated addresses.
  14. Reorgs: BSC reorg unwind/replay for registered EVM wallets; do not share tables with Venus venus_vfdusd_rates.
  15. Do not use fee-discount tiers, trader_positions, or PancakeSwap LP as vote weight.
  16. Do not break Cosmos WalletConnect mobile pairing (#519 / #554 / #566) when adding EIP-155.

Relevant files

Indexer / BSC I/O

  • indexer/src/config.rs (bsc_rpc_urls)
  • indexer/src/indexer/venus_vfdusd.rs (RPC failover / eth_call pattern — do not overload)
  • indexer/src/startup.rs, indexer/src/lcd/mod.rs (Terra live balance analogue)
  • indexer/migrations/, docs/indexer-invariants.md
  • New: BEP-20 Transfer log parser + balanceOf registration ingest + BSC height/block cursor

operator-voting (#510)

  • New package: EIP-191 recover (ecrecover over keccak256("\x19Ethereum Signed Message:\n" + len + message)), chain-id / domain separation, EVM address normalize
  • Restricted SQL: voting_bsc_cl8y_balance_at(wallet, block) beside Terra voting_cl8y_balance_at

Frontend (#511)

  • frontend-dapp/src/services/terraclassic/wallet.ts, hooks/useWallet.ts, WalletConnect pairing stores (#554)
  • frontend-dapp/src/utils/legalClickwrap.ts (Legal EVM portal is not voting)
  • New: EVM connect + personal_sign helper; /vote copy that Terra or BSC holders can register
  • Skills: AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md, AGENTS_FRONTEND_COPY_COGNITIVE_LOAD.md, AGENTS_INDEXER_VENUS_VFDUSD.md (RPC hygiene)

Env / deploy

  • BSC_RPC_URLS (existing), BSC_CL8Y_TOKEN_ADDRESS, Coolify indexer + operator-voting + frontend examples
  • VITE_* must not include BSC RPC URLs

Indexer (extends #509)

  • Tables (illustrative): voting_registrations gains chain (terra | bsc) + address; cl8y_bep20_transfers (bsc_block, tx_hash, log_index, from, to, amount); cl8y_bsc_balances checkpoints for balance(wallet, bsc_block) when block >= registered_at_block.
  • On EVM register: eth_blockNumber + eth_call balanceOf(address) on pinned CL8Y; persist; no historical eth_getLogs backfill unless explicitly designed (default no backfill, same as #509).
  • Poll eth_getLogs for Transfer topic 0xddf252ad… on the pinned token; filter to registered set; handle mint/burn (from/to zero address).
  • Cursor + reorg: store last processed BSC block; unwind like Terra indexer_state.

operator-voting (extends #510)

  • Verify either ADR-36 (Terra) or EIP-191 (EVM) from payload chain / recovered address.
  • Proposal create records { terra_height, bsc_block, created_at }.
  • Tally: Terra voters use CW20 ledger; EVM voters use BEP-20 ledger; never mix units into USD.
  • Blacklist + rate limits apply to both address formats.

Frontend (extends #511)

  • Wallet modal: keep Terra connectors; add BSC (injected EIP-1193 + WalletConnect eip155:56).
  • Register / propose / vote: sign canonical bytes with the connected wallet’s scheme; show which chain’s CL8Y is counted.
  • Copy: registration is required on the chain you hold before a proposal you care about is created; do not imply on-chain DAO finality.
  • Simulated / test path: mocked EVM signer for vitest; do not require live MetaMask in CI.

Acceptance criteria

  • Configurable pinned BEP-20 CL8Y address; indexer fails closed when the BSC voting feature is enabled and the address/RPC config is invalid.
  • Registering an EVM wallet stores live balanceOf + current BSC block; no archive/debug_trace requirement.
  • Subsequent BEP-20 Transfers to/from that wallet update the BSC ledger; unregistered EVM traffic is not stored (except as counterparty on a registered leg).
  • balance(evm, B) for B >= registered_at_block is reconstructible from the ledger; property/integration tested with fixtures (wiremock / Anvil — not live mainnet).
  • operator-voting accepts EIP-191 register / propose / vote from the recovered 0x address; Terra ADR-36 path still works.
  • Proposal snapshot stores Terra height and BSC block; EVM vote weight uses the BSC ledger at that block (not tip).
  • Blacklist matches normalized EVM addresses; denylisted 0x cannot vote or propose.
  • dApp can connect an EVM wallet and complete register → (optional) propose if ≥1000 BEP-20 CL8Y → vote.
  • Cosmos WalletConnect mobile flows (#519 / #554 / #566) still pass.
  • No VITE_* BSC RPC; no Venus poller reuse; docs/invariants/Coolify env updated.
  • Linked #509 / #510 / #511 describe BSC in-scope (this issue + comments).

Test plan (all paths)

  1. Unit — log parser: Transfer fixtures for pinned token; ignore other contracts; mint/burn; registered vs unregistered from/to.
  2. Unit — balance math: sequential Transfers; self-transfer; 18-dec strings.
  3. Unit — EIP-191: recover matches signer; rejects wrong length / v / replayed Terra payload.
  4. Integration — registration: mock RPC balanceOf at block N; row matches.
  5. Integration — follow: register A; A→B (B unregistered): A decreases, B not a voter; later B register is a new live snapshot (no backfill).
  6. Integration — snapshot: transfers at B1,B2,B3; query at B2 returns post-B2; vote after sell still uses snapshot block.
  7. Cross-chain isolation: Terra transfers do not change EVM weight and vice versa.
  8. Frontend: EVM connect + sign happy path (mock provider); Terra path unchanged; disconnected / wrong-chain (not 56) errors.
  9. WC regression: existing Cosmos WC unit tests still pass.
  10. Config: empty BSC_RPC_URLS skips BSC ledger when feature optional in CI; production voting compose requires it.

Test plan — attack, hack & abuse vectors

  1. Lookalike token: Transfer logs from a fake CL8Y BEP-20 — must ignore.
  2. RPC spoof / SSRF: BSC_RPC_URLS remains env-only (existing I389-18 class); do not take RPC URL from client.
  3. Signature cross-scheme: Terra ADR-36 blob submitted as EVM vote (and reverse) — reject.
  4. Replay: same EVM sig on another proposal / chain id / domain — reject.
  5. Checksum / case tricks: 0xabc… vs 0xAbC… must be one wallet; blacklist bypass via case must fail.
  6. Unregistered log flood: spam Transfers among unregistered EVM wallets — no unbounded rows.
  7. Flash move before snapshot: large BEP-20 into a registered wallet — counted by design; document (same as #509).
  8. Bridge double-count: document current separately-circulating assumption; add a test note if a lock address is later excluded.
  9. Venus coupling: BSC CL8Y indexer outage must not break vFDUSD oracle and vice versa.
  10. Phishing copy: UI must not ask for EVM seed; only wallet popup sign. Do not send users to BscScan to “verify voting.”

Verification criteria

  • Indexer unit + integration tests for BEP-20 ledger (Postgres; mocked BSC).
  • operator-voting tests for EIP-191 + mixed Terra/EVM blacklist + dual snapshot fields.
  • Frontend vitest for EVM gates / client; Cosmos WC tests still green.
  • Docs: docs/indexer-invariants.md + Coolify env; skill notes that voting BSC I/O ≠ Venus.
  • Manual or staging: MetaMask on BSC register + vote; Keplr Terra path still works.
  • Confirm production voting is not marked complete while BSC holders cannot participate.

Labels

architecture backend frontend indexer enhancement security product UX

Priority

P1 — core electorate. Majority of CL8Y is BEP-20 on BSC.

## Summary **BSC is core to the voting electorate, not an optional extra.** A majority of CL8Y holders are on **BNB Smart Chain (BEP-20)**, not Terra Classic CW20. Shipping #509 / #510 / #511 as Terra-only would exclude most tokenholders from registration, proposal weight, and ballots. Extend the offchain snapshot-voting bundle so that: 1. The indexer tracks **BEP-20 CL8Y balances** for **registered EVM wallets** (live `balanceOf` at registration + Transfer logs forward — same “no archive node” model as #509). 2. `operator-voting` accepts **EVM wallet signatures** (EIP-191 `personal_sign`) for register / propose / vote, and freezes vote power from **both** the Terra CW20 ledger and the BSC BEP-20 ledger. 3. The dApp lets holders **connect an EVM wallet** (MetaMask / WalletConnect EIP-155) and complete the same `/vote` flows. **No new Solidity or CosmWasm contracts.** Frontend + Postgres + indexer + `operator-voting` only. **BEP-20 CL8Y (canonical BSC):** [`0x8F452a1fdd388A45e1080992eFF051b4dd9048d2`](https://bscscan.com/token/0x8F452a1fdd388A45e1080992eFF051b4dd9048d2) (`CL8Y_v2`, 18 decimals) — same asset brand as Terra CW20 `terra16wtml…hpax3`. Configurable via env (`BSC_CL8Y_TOKEN_ADDRESS`). **Terra CW20 (unchanged, #509):** `terra16wtml2q66g82fdkx66tap0qjkahqwp4lwq3ngtygacg5q0kzycgqvhpax3`. This issue is the **cross-chain / EVM work item**. It does **not** replace #509–#511; those issues must include BSC in their scope (see comments on each). ### Bundle | Issue | Role after this work | |-------|----------------------| | **#509** | Indexer/Postgres registration + **Terra CW20 and BSC BEP-20** ledgers for registered wallets | | **#510** | `operator-voting` — Cosmos ADR-36 **and** EVM EIP-191 sigs; snapshot = Terra height **plus** BSC block; blacklist includes `0x` addresses | | **#511** | dApp register / propose / vote for **Keplr/Station and EVM wallets** | | **This issue** | BSC integration contract: token pin, RPC/log indexing, snapshot pairing, EVM identity, double-count/bridge rules | --- ## Why this is needed #509–#511 currently assume a Terra Classic wallet + CW20 `Balance` + wasm transfer events. That is correct for the DEX’s home chain and for fee-discount `cl8y_token`, but it is **not** the majority CL8Y holder set. Without BSC: - Most CL8Y cannot register or vote. - Proposal threshold (≥1000 CL8Y in #511) is measured on the minority chain only. - Snapshot tallies systematically under-weight the token. Venus `eth_call` on `BSC_RPC_URLS` (#571) already proves the indexer can talk to BSC JSON-RPC. That path is **oracle-only** and must not be overloaded. Voting needs a **separate** BEP-20 ledger + EVM auth plane. --- ## Current codebase | Area | Status | |------|--------| | BSC JSON-RPC | `indexer/src/indexer/venus_vfdusd.rs` + `config.bsc_rpc_urls` (`BSC_RPC_URLS`) — **Venus vFDUSD `eth_call` only**. No `eth_getLogs`, no ERC-20 `balanceOf`, no Transfer parser | | Browser BSC | **Forbidden** for oracle (#571 **V571-5**): no `VITE_*` BSC RPC, no BscScan from the dApp. Wallet *provider* connect for signing is a new surface | | EVM wallets in dApp | Cosmos-only: Keplr / Station / WC / Simulated Wallet (`frontend-dapp/src/services/terraclassic/wallet.ts`). WalletConnect is **EIP-155 Cosmos pairing** (#519 / #554 / #566), not BSC | | Legal EVM sign | Hosted portal `https://terms.cl8y.com/sign/evm` (#517 clickwrap) — **external redirect**, not in-app MetaMask; do not reuse as voting auth | | Voting ledger | **Not implemented** (#509). Designed for CW20 wasm events only | | `operator-voting` | **Not implemented** (#510). Designed for ADR-36 / Terra bech32 | | Frontend `/vote` | **Not implemented** (#511). Designed for Terra `signArbitrary` | --- ## Constraints / guardrails 1. **Core, not phase-2.** Do not ship Terra-only voting to production as “done.” BSC registration + BEP-20 weight must land with (or immediately after) the Terra path; a Terra-only electorate is an incomplete product. 2. **No new contracts** on BSC or Terra. Do not deploy a voting token, snapshot contract, or governor. 3. **No BSC archive-node requirement.** Registration balance = live `balanceOf(wallet)` at current `eth_blockNumber`. History afterward = Transfer logs for the registered set only (mirror #509). 4. **Pin the token.** Only trust logs/`balanceOf` for configured `BSC_CL8Y_TOKEN_ADDRESS` (default `0x8F452a1fdd388A45e1080992eFF051b4dd9048d2`). Ignore other BEP-20s and lookalike tickers. 5. **18-decimal** raw integer amounts as strings / `NUMERIC` — same as CW20; no float. 6. **Registered-set filter.** Index Transfer logs only when `from` or `to` is a registered EVM address (plus the registered counterparty). Do not ingest the full CL8Y holder universe. 7. **Reuse `BSC_RPC_URLS` transport, not the Venus module.** New indexer module (e.g. `bsc_cl8y_ledger.rs`). Empty `BSC_RPC_URLS` skips live BSC (CI/LocalTerra) the same way #571 does. Never log RPC URLs/keys. Soft-fail RPC must not invent balances. 8. **Browser must not grow Vite BSC RPC hosts** for balance reads (keep **V571-5**). Indexer owns `eth_call` / `eth_getLogs`. Injected/WC provider is only for connect + `personal_sign`. 9. **Snapshot pairing.** A proposal freezes **both** a Terra Classic height (existing #509) **and** a BSC block number taken at create time (wall-clock aligned). Vote weight for an address is the ledger balance on **its** chain at that chain’s frozen height/block. Document inclusive block ordering. 10. **Identity v1 = one address, one voter.** A Terra `terra1…` registration and a `0x…` registration are distinct voters unless product later adds explicit linking. Do not silently merge by heuristic. 11. **No double-count of the same units.** Terra CW20 and BSC BEP-20 are separately circulating supplies today (not a lock-and-mint bridge in this repo). Each registered address votes its chain balance. If an official bridge later locks tokens on one side, document so locked/in-flight supply is not counted twice. Do **not** convert via USD or DEX pool prices. 12. **Blacklist** (`VOTING_BLACKLIST_ADDRESSES`) must accept normalized `0x` (EIP-55 checksum optional; compare case-insensitive) **and** Terra bech32. 13. **Propose threshold (≥1000 CL8Y)** is evaluated against the **registering address’s** chain ledger (BEP-20 for EVM, CW20 for Terra). Do not sum unrelated addresses. 14. **Reorgs:** BSC reorg unwind/replay for registered EVM wallets; do not share tables with Venus `venus_vfdusd_rates`. 15. **Do not** use fee-discount tiers, `trader_positions`, or PancakeSwap LP as vote weight. 16. **Do not** break Cosmos WalletConnect mobile pairing (#519 / #554 / #566) when adding EIP-155. --- ## Relevant files **Indexer / BSC I/O** - `indexer/src/config.rs` (`bsc_rpc_urls`) - `indexer/src/indexer/venus_vfdusd.rs` (RPC failover / `eth_call` pattern — **do not overload**) - `indexer/src/startup.rs`, `indexer/src/lcd/mod.rs` (Terra live balance analogue) - `indexer/migrations/`, `docs/indexer-invariants.md` - New: BEP-20 Transfer log parser + `balanceOf` registration ingest + BSC height/block cursor **operator-voting (#510)** - New package: EIP-191 recover (`ecrecover` over `keccak256("\x19Ethereum Signed Message:\n" + len + message)`), chain-id / domain separation, EVM address normalize - Restricted SQL: `voting_bsc_cl8y_balance_at(wallet, block)` beside Terra `voting_cl8y_balance_at` **Frontend (#511)** - `frontend-dapp/src/services/terraclassic/wallet.ts`, `hooks/useWallet.ts`, WalletConnect pairing stores (#554) - `frontend-dapp/src/utils/legalClickwrap.ts` (Legal EVM portal is **not** voting) - New: EVM connect + `personal_sign` helper; `/vote` copy that Terra **or** BSC holders can register - Skills: `AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md`, `AGENTS_FRONTEND_COPY_COGNITIVE_LOAD.md`, `AGENTS_INDEXER_VENUS_VFDUSD.md` (RPC hygiene) **Env / deploy** - `BSC_RPC_URLS` (existing), `BSC_CL8Y_TOKEN_ADDRESS`, Coolify indexer + `operator-voting` + frontend examples - `VITE_*` must not include BSC RPC URLs --- ## Recommended direction ### Indexer (extends #509) - Tables (illustrative): `voting_registrations` gains `chain` (`terra` \| `bsc`) + `address`; `cl8y_bep20_transfers` (bsc_block, tx_hash, log_index, from, to, amount); `cl8y_bsc_balances` checkpoints for `balance(wallet, bsc_block)` when `block >= registered_at_block`. - On EVM register: `eth_blockNumber` + `eth_call` `balanceOf(address)` on pinned CL8Y; persist; no historical `eth_getLogs` backfill unless explicitly designed (default **no backfill**, same as #509). - Poll `eth_getLogs` for Transfer topic `0xddf252ad…` on the pinned token; filter to registered set; handle mint/burn (`from`/`to` zero address). - Cursor + reorg: store last processed BSC block; unwind like Terra `indexer_state`. ### operator-voting (extends #510) - Verify **either** ADR-36 (Terra) **or** EIP-191 (EVM) from payload `chain` / recovered address. - Proposal create records `{ terra_height, bsc_block, created_at }`. - Tally: Terra voters use CW20 ledger; EVM voters use BEP-20 ledger; never mix units into USD. - Blacklist + rate limits apply to both address formats. ### Frontend (extends #511) - Wallet modal: keep Terra connectors; add **BSC** (injected EIP-1193 + WalletConnect `eip155:56`). - Register / propose / vote: sign canonical bytes with the connected wallet’s scheme; show which chain’s CL8Y is counted. - Copy: registration is required **on the chain you hold** before a proposal you care about is created; do not imply on-chain DAO finality. - Simulated / test path: mocked EVM signer for vitest; do not require live MetaMask in CI. --- ## Acceptance criteria - [ ] Configurable pinned BEP-20 CL8Y address; indexer fails closed when the BSC voting feature is enabled and the address/RPC config is invalid. - [ ] Registering an EVM wallet stores live `balanceOf` + current BSC block; no archive/`debug_trace` requirement. - [ ] Subsequent BEP-20 Transfers to/from that wallet update the BSC ledger; unregistered EVM traffic is not stored (except as counterparty on a registered leg). - [ ] `balance(evm, B)` for `B >= registered_at_block` is reconstructible from the ledger; property/integration tested with fixtures (wiremock / Anvil — not live mainnet). - [ ] `operator-voting` accepts EIP-191 register / propose / vote from the recovered `0x` address; Terra ADR-36 path still works. - [ ] Proposal snapshot stores Terra height **and** BSC block; EVM vote weight uses the BSC ledger at that block (not tip). - [ ] Blacklist matches normalized EVM addresses; denylisted `0x` cannot vote or propose. - [ ] dApp can connect an EVM wallet and complete register → (optional) propose if ≥1000 BEP-20 CL8Y → vote. - [ ] Cosmos WalletConnect mobile flows (#519 / #554 / #566) still pass. - [ ] No `VITE_*` BSC RPC; no Venus poller reuse; docs/invariants/Coolify env updated. - [ ] Linked #509 / #510 / #511 describe BSC in-scope (this issue + comments). --- ## Test plan (all paths) 1. **Unit — log parser:** Transfer fixtures for pinned token; ignore other contracts; mint/burn; registered vs unregistered `from`/`to`. 2. **Unit — balance math:** sequential Transfers; self-transfer; 18-dec strings. 3. **Unit — EIP-191:** recover matches signer; rejects wrong length / `v` / replayed Terra payload. 4. **Integration — registration:** mock RPC `balanceOf` at block N; row matches. 5. **Integration — follow:** register A; A→B (B unregistered): A decreases, B not a voter; later B register is a new live snapshot (**no backfill**). 6. **Integration — snapshot:** transfers at B1,B2,B3; query at B2 returns post-B2; vote after sell still uses snapshot block. 7. **Cross-chain isolation:** Terra transfers do not change EVM weight and vice versa. 8. **Frontend:** EVM connect + sign happy path (mock provider); Terra path unchanged; disconnected / wrong-chain (not 56) errors. 9. **WC regression:** existing Cosmos WC unit tests still pass. 10. **Config:** empty `BSC_RPC_URLS` skips BSC ledger when feature optional in CI; production voting compose requires it. --- ## Test plan — attack, hack & abuse vectors 1. **Lookalike token:** Transfer logs from a fake CL8Y BEP-20 — must ignore. 2. **RPC spoof / SSRF:** `BSC_RPC_URLS` remains env-only (existing I389-18 class); do not take RPC URL from client. 3. **Signature cross-scheme:** Terra ADR-36 blob submitted as EVM vote (and reverse) — reject. 4. **Replay:** same EVM sig on another proposal / chain id / domain — reject. 5. **Checksum / case tricks:** `0xabc…` vs `0xAbC…` must be one wallet; blacklist bypass via case must fail. 6. **Unregistered log flood:** spam Transfers among unregistered EVM wallets — no unbounded rows. 7. **Flash move before snapshot:** large BEP-20 into a registered wallet — counted by design; document (same as #509). 8. **Bridge double-count:** document current separately-circulating assumption; add a test note if a lock address is later excluded. 9. **Venus coupling:** BSC CL8Y indexer outage must not break vFDUSD oracle and vice versa. 10. **Phishing copy:** UI must not ask for EVM seed; only wallet popup sign. Do not send users to BscScan to “verify voting.” --- ## Verification criteria - [ ] Indexer unit + integration tests for BEP-20 ledger (Postgres; mocked BSC). - [ ] `operator-voting` tests for EIP-191 + mixed Terra/EVM blacklist + dual snapshot fields. - [ ] Frontend vitest for EVM gates / client; Cosmos WC tests still green. - [ ] Docs: `docs/indexer-invariants.md` + Coolify env; skill notes that voting BSC I/O ≠ Venus. - [ ] Manual or staging: MetaMask on BSC register + vote; Keplr Terra path still works. - [ ] Confirm production voting is not marked complete while BSC holders cannot participate. ## Labels `architecture` `backend` `frontend` `indexer` `enhancement` `security` `product` `UX` ## Priority P1 — **core electorate**. Majority of CL8Y is BEP-20 on BSC.
PlasticDigits commented 2026-08-21 11:32:37 +00:00 (Migrated from gitlab.com)

marked as related to #509

marked as related to #509
PlasticDigits commented 2026-08-21 11:32:38 +00:00 (Migrated from gitlab.com)

marked as related to #510

marked as related to #510
PlasticDigits commented 2026-08-21 11:32:38 +00:00 (Migrated from gitlab.com)

marked as related to #511

marked as related to #511
PlasticDigits commented 2026-08-21 11:32:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #509

mentioned in issue #509
PlasticDigits commented 2026-08-21 11:32:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #510

mentioned in issue #510
PlasticDigits commented 2026-08-21 11:32:52 +00:00 (Migrated from gitlab.com)

mentioned in issue #511

mentioned in issue #511
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-25 06:07:37 +00:00
PlasticDigits commented 2026-08-25 06:08:52 +00:00 (Migrated from gitlab.com)

Voting work left this repo on 2026-08-25.

Canonical project: https://gitlab.com/PlasticDigits/voting

Former IID here New
#509 https://gitlab.com/PlasticDigits/voting/-/issues/1
#510 https://gitlab.com/PlasticDigits/voting/-/issues/2
#511 https://gitlab.com/PlasticDigits/voting/-/issues/3
#588 https://gitlab.com/PlasticDigits/voting/-/issues/4

Also opened there: Legal clickwrap (#5), wallet reuse (#6). Do not implement voting in this DEX repo.

Voting work left this repo on 2026-08-25. Canonical project: https://gitlab.com/PlasticDigits/voting | Former IID here | New | |-----------------|-----| | #509 | https://gitlab.com/PlasticDigits/voting/-/issues/1 | | #510 | https://gitlab.com/PlasticDigits/voting/-/issues/2 | | #511 | https://gitlab.com/PlasticDigits/voting/-/issues/3 | | #588 | https://gitlab.com/PlasticDigits/voting/-/issues/4 | Also opened there: Legal clickwrap (#5), wallet reuse (#6). Do not implement voting in this DEX repo.
PlasticDigits commented 2026-08-25 06:08:58 +00:00 (Migrated from gitlab.com)

mentioned in issue #637

mentioned in issue #637
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#588
No description provided.