Context
PR #126 added satoshi-exact supply/value conservation invariants to snapshot import on master (SHARES: Σ account.vesting_shares == dgp.total_vesting_shares; TOKEN: Σ pools == dgp.current_supply). Merging master into the pm (Prediction Markets) branch brings these checks in — but PM introduces new TOKEN pools (bets, LP, lazy-pool, commit escrow, dispute fees, oracle insurance, leverage), so the base TOKEN sum no longer equals current_supply on a PM snapshot.
To avoid bricking PM snapshot import, the TOKEN check on the pm branch is currently LOG-ONLY (plugins/snapshot/plugin.cpp, TODO(pm)): it sums a best-effort PM pool set and logs the delta per-component, but does not fail import. The SHARES check and the #125 count/referential/singleton checks remain fatal (PM holds no VESTS).
Task
Reconcile the PM TOKEN accounting to delta == 0 satoshi-exact on real PM snapshots, then re-arm the TOKEN check as a fatal FC_ASSERT (as on master).
Candidate non-overlapping PM TOKEN holdings (best-effort, from static read of pm_evaluator.cpp)
Σ pm_bet.amount — market/outcome bets_sum and CPMM reserve_a/reserve_b are aggregates of these → excluded.
Σ pm_liquidity.amount WHERE provider != "" — empty-provider LP is the lazy pool, already in allocated_balance → excluded.
pm_lazy_pool.free_balance + allocated_balance — pm_lazy_deposit.principal is a per-depositor claim on this → excluded.
Σ pm_commit.escrow_amount
Σ pm_dispute.dispute_fee
Σ pm_market.forfeit_pool
Σ pm_oracle.insurance
Σ (pm_leverage_position.collateral + loan) — loan is debited from free_balance at open → held in the position, not the pool; leverage_fund_used is a marker → excluded.
Open questions to resolve (the UNVERIFIED status filters in code)
- Bet held-states: which
pm_bet.status values still hold TOKEN (currently summing 0/5/6 = active/queued/revealed-pending)? Are resolved (3) / cancelled (1) / refunded (2) bets deleted or retained with a stale amount?
- Commit escrow vs forfeit_pool: on forfeit (
status 2), escrow moves to market.forfeit_pool. Confirm escrow_amount is zeroed then (else double-count with forfeit_pool). On reveal (status 1), is escrow returned or converted into a pm_bet (already summed)?
- Dispute fee: returned/slashed on close — confirm only
status 0 holds it.
- Leverage: confirm
free_balance is debited by loan at open (so loan isn't double-counted), and which status values still hold collateral + loan.
- forfeit_pool: confirm it is zeroed post-settlement (so summing all markets is safe).
Acceptance criteria
Follow-up to #125 / #126.
Context
PR #126 added satoshi-exact supply/value conservation invariants to snapshot import on
master(SHARES:Σ account.vesting_shares == dgp.total_vesting_shares; TOKEN:Σ pools == dgp.current_supply). Mergingmasterinto thepm(Prediction Markets) branch brings these checks in — but PM introduces new TOKEN pools (bets, LP, lazy-pool, commit escrow, dispute fees, oracle insurance, leverage), so the base TOKEN sum no longer equalscurrent_supplyon a PM snapshot.To avoid bricking PM snapshot import, the TOKEN check on the
pmbranch is currently LOG-ONLY (plugins/snapshot/plugin.cpp,TODO(pm)): it sums a best-effort PM pool set and logs the delta per-component, but does not fail import. The SHARES check and the #125 count/referential/singleton checks remain fatal (PM holds no VESTS).Task
Reconcile the PM TOKEN accounting to delta == 0 satoshi-exact on real PM snapshots, then re-arm the TOKEN check as a fatal
FC_ASSERT(as on master).Candidate non-overlapping PM TOKEN holdings (best-effort, from static read of
pm_evaluator.cpp)Σ pm_bet.amount— market/outcomebets_sumand CPMMreserve_a/reserve_bare aggregates of these → excluded.Σ pm_liquidity.amount WHERE provider != ""— empty-provider LP is the lazy pool, already inallocated_balance→ excluded.pm_lazy_pool.free_balance + allocated_balance—pm_lazy_deposit.principalis a per-depositor claim on this → excluded.Σ pm_commit.escrow_amountΣ pm_dispute.dispute_feeΣ pm_market.forfeit_poolΣ pm_oracle.insuranceΣ (pm_leverage_position.collateral + loan)—loanis debited fromfree_balanceat open → held in the position, not the pool;leverage_fund_usedis a marker → excluded.Open questions to resolve (the UNVERIFIED status filters in code)
pm_bet.statusvalues still hold TOKEN (currently summing 0/5/6 = active/queued/revealed-pending)? Are resolved (3) / cancelled (1) / refunded (2) bets deleted or retained with a staleamount?status 2), escrow moves tomarket.forfeit_pool. Confirmescrow_amountis zeroed then (else double-count withforfeit_pool). On reveal (status 1), is escrow returned or converted into apm_bet(already summed)?status 0holds it.free_balanceis debited byloanat open (soloanisn't double-counted), and whichstatusvalues still holdcollateral + loan.Acceptance criteria
pm_tokenaccounting reconcilesdelta == 0on ≥6 real PM snapshots covering all lifecycle states (active markets, open commits, disputes, active leverage, post-settlement).pm_evaluator.cppmoney-flow (no double-count, no missed holding).FC_ASSERT(remove the LOG-ONLY path), matching master.database::validate_invariants()source of truth once defined.Follow-up to #125 / #126.