Skip to content

fix: multi-sig admin (#733), on-chain governance (#735), event indexer exactly-once (#753), accounting proptest invariants (#801) - #1088

Merged
joelpeace48-cell merged 2 commits into
FinesseStudioLab:mainfrom
kulayddon:feat/fix-issues-733-735-753-801
Jul 29, 2026
Merged

fix: multi-sig admin (#733), on-chain governance (#735), event indexer exactly-once (#753), accounting proptest invariants (#801)#1088
joelpeace48-cell merged 2 commits into
FinesseStudioLab:mainfrom
kulayddon:feat/fix-issues-733-735-753-801

Conversation

@kulayddon

Copy link
Copy Markdown
Contributor

Summary

  • Backend/Indexer: Backpressure + exactly-once event processing with a durable cursor #753eventIndexer.js poll() had no cursor persistence, no per-event dedupe, and no backpressure. Added pollWithCursor() with: a durable cursor stored in indexer_cursors (loaded on startup, written after each batch succeeds); exactly-once processing via a processed_events table keyed on (contract_id, ledger, event_index) so replaying any ledger range produces zero duplicate rows; and a bounded-concurrency Semaphore that pauses ingestion when all in-flight slots are occupied. Migration 013 adds both tables. Five new tests cover cursor resume, cursor save, dedupe short-circuit, batch processing, and return value.

  • Testing: Property/invariant tests for contract accounting (proptest) #801 — Existing proptest suite in fuzz_test.rs covered single-user balance consistency but not the global accounting invariants from the issue. Added three new proptest suites: fuzz_global_balance_accounting_invariant verifies sum(all_user_balances) == total_credited - total_claimed across multi-user random sequences and also cross-checks the contract's total_claimed() counter; fuzz_no_negative_balances verifies over-claims are rejected with an error and leave the balance unchanged; fuzz_batch_credit_accounting verifies per-recipient balance deltas and batch totals match exactly after batch_credit.

  • Contracts: Multi-sig / threshold admin (both contracts use a single Address) #733 — Admin authority in both contracts is a single Address. Added M-of-N multi-sig gate to the rewards contract: init_multisig (admin only) configures a MultiSigConfig with a signers set and threshold; propose_privileged_op opens a proposal (proposer auto-approves); approve_privileged_op accumulates approvals (prevents double-vote and signer-not-in-set); execute_privileged_op runs once approvals.len() >= threshold. Signer rotation flows through the same proposal, so no single key can change the set unilaterally. Full lifecycle events: privprop / privappr / privexec.

  • Contracts: On-chain governance for parameter changes (proposal + voting/delay) #735 — Economic parameters were admin-set instantly. Added governance flow: propose_param_change opens a ParamProposal with a quorum requirement and a time-lock delay; vote_param_change accumulates votes (idempotent per voter); execute_param_change (admin) applies the change only after delay elapsed and quorum met, returning the (param_key, new_value) pair so the caller can write to the target storage slot; cancel_param_change (admin) vetoes at any time. Events at every lifecycle step: govprp / govvote / govexec / govcanc.

Test plan

  • Run node --test backend/src/jobs/eventIndexer.test.js — all existing tests pass plus 5 new cursor/dedupe/backpressure tests
  • Run migration 013 on a fresh DB and confirm indexer_cursors and processed_events tables are created
  • Replay the same ledger range twice with pollWithCursor — row counts in application tables must be identical both times
  • Kill process mid-batch and restart — confirm it resumes from the persisted cursor with no missed or duplicated events
  • cargo test -p trivela-rewards-contract — existing tests plus three new proptest suites pass
  • Verify fuzz_global_balance_accounting_invariant catches a hypothetical double-credit bug by mutating the contract and confirming a test failure
  • Call init_multisig + propose_privileged_op + approve_privileged_op (threshold - 1 times) → execute_privileged_op returns InsufficientApprovals; add the final approval → executes
  • propose_param_changeexecute_param_change before time-lock elapses → TimeLockActive; advance ledger past delay → succeeds

Closes #733
Closes #735
Closes #753
Closes #801

kulayddon and others added 2 commits July 29, 2026 19:55
…-once, accounting invariant tests

- FinesseStudioLab#733: Add M-of-N multi-sig admin gate to rewards contract. `init_multisig`
  configures a threshold signer set; `propose_privileged_op` /
  `approve_privileged_op` / `execute_privileged_op` require threshold
  approvals before any privileged op executes. Signer rotation flows through
  the same proposal gate. New `MultiSigConfig` and `PrivilegedProposal`
  contract types with full lifecycle events.

- FinesseStudioLab#735: Add on-chain governance for parameter changes. `propose_param_change`
  opens a time-locked proposal; `vote_param_change` accumulates quorum;
  `execute_param_change` applies the change after delay + quorum; admin can
  `cancel_param_change` at any time. `ParamProposal` type stores the full
  lifecycle with events at each step.

- FinesseStudioLab#753: Add `pollWithCursor` to the event indexer with durable cursor
  persistence, per-event exactly-once dedupe, and bounded concurrency
  backpressure. Cursor is loaded from `indexer_cursors` on startup and
  written only after the full batch succeeds. `processed_events` table
  (contract_id + ledger + event_index PK) makes re-playing any ledger range
  idempotent. A `Semaphore` caps in-flight handlers so bursts do not grow
  unbounded. Migration 013 adds both tables. Tests cover cursor resume,
  cursor persistence, dedupe short-circuit, and multi-event batches.

- FinesseStudioLab#801: Add three new proptest suites to fuzz_test.rs:
  `fuzz_global_balance_accounting_invariant` asserts sum(user_balances) ==
  total_credited - total_claimed across multi-user random sequences;
  `fuzz_no_negative_balances` asserts over-claims are rejected and leave
  balances unchanged; `fuzz_batch_credit_accounting` asserts per-recipient
  deltas and batch totals match exactly.

Closes FinesseStudioLab#733
Closes FinesseStudioLab#735
Closes FinesseStudioLab#753
Closes FinesseStudioLab#801
@joelpeace48-cell
joelpeace48-cell merged commit 44a2452 into FinesseStudioLab:main Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants