Conversation
…ront-running protection - Introduce two optional execution modes per bet: batch (mode 1) and commit-reveal (mode 2) - Preserve instant per-bet execution (mode 0) as default for best UX - Define global and per-market parameters for configuration and governance control - Implement batch epochs with unified uniform-price settlement to prevent intra-batch front-running - Add commit-reveal operations: bet commitment, reveal, penalty for no-reveal with transfer into winners' pool - Design batch settlement math preserving liquidity provider invariant and fairness via canonical CPMM aggregation - Add database schema changes for bets, commitments, and market flags supporting new modes and states - Extend market logs to track batch-related actions: commit, reveal, batch settlement, and forfeits - Specify layered defenses against front-running including epoch snapshot pricing and min_tokens enforcement - Define phased rollout plan: batch mode first, then commit-reveal, followed by tiering and client policies - Document open questions and future improvements like encrypted sealed bids (mode 3) and cancellation policy
…off strategy - Add new chain_properties versions 4 (hf13) and 5 (hf14 PM) for governance params - Introduce 40+ Prediction Market consensus parameters including fees, disputes, batch settings, cron budget, lazy pool, and leverage - Define market fee structure and governance cap rules focusing on oracle fee cap - Document versioning, median calculation, and validator publishing rules for new params - Implement leverage fund as sub-allocation of lazy pool free balance with detailed accounting and protocol state transitions - Present full mathematical leverage model: CPMM/LMSR calculations, cancel values, liquidation thresholds, safety margin, and leverage constraints - Describe atomic liquidation mechanism ensuring pool protection before opposing bets execute, including cascade logic and cascade loop handling - Analyze risk types and mitigation: price-movement risk elimination via atomic liquidation, safety margins, and dynamic caps; outcome risk remains inherent - Provide detailed architecture overview, fund allocation parameters, frontend UI terminology (Boost vs Leverage), and risk analysis - Outline protocol operations, API endpoints, database schema, pre-calculation and slider logic for leverage positions - Address MEV considerations for liquidation rebalancing and sandwich attacks with mitigation plans for VIZ DLT implementation
…ion by role - Add comprehensive README outlining canonical scenarios for normal and disputed resolves - Document master ledger calculations for payout distributions and zero-sum properties - Include role-specific subfolders with interaction diagrams and signed/virtual operations - Provide detailed token flow tables for normal and disputed market outcomes - Outline leverage mechanics including open, close, liquidation, and settlement steps - Describe dispute scenarios: disputer wins, loses, and forced auto-close with penalties - Verify all operations and virtual operations present in code with references - Add instructions on how to observe states and events via API plugin methods - Cover edge cases like time penalties, liquidations, and refund mechanics - Provide an index of workflow document folders by participant role for easy navigation
- Updated fc submodule pointer from 99b5d133 to 5a9d84a1 - Ensured thirdparty dependencies are current and consistent
- Added mermaid package version 11.4.1 - Added vitepress-plugin-mermaid version 2.0.17 for Mermaid integration - Added multiple new dependencies related to mermaid and diagram rendering - Included types packages for d3 and related libraries for better type support - Updated package-lock.json to reflect new dependencies and their versions - Removed several optional and deprecated dependencies to clean up lock file
- Increase total number of hardforks from 13 to 14 - Introduce hardfork 14 with features for prediction markets (binary CPMM, multi LMSR) - Add oracles, dispute mechanisms, batch/commit-reveal, and lazy liquidity pools - Define placeholder activation times for mainnet and testnet - Use version 4.0.0 for hardfork 14 release candidate
- Add chain_properties_pm median evaluator and integrate into median calculation - Implement lazy-pool logic for DAO-committee voting weight in committee_processing - Register PM evaluators for all PM operations in database initialization - Add core indexes for PM-related objects for consensus and chain state tracking - Implement PM liquidity settlement, market resolution, leverage liquidation, and recall mechanics - Add HF14 hardfork initialization including lazy-liquidity pool singleton creation - Update CMakeLists.txt to include PM source and header files with proper compiler flags - Enhance database.cpp with PM processing hooks and vote weight adjustments for lazy pool stake - Provide detailed internal helpers for PM operation including settle market, refund bets, and liquidity allocation
…ive APIs - Implement prediction_market_api plugin with full lifecycle management - Provide APIs to query markets, outcomes, bets, positions, and liquidity - Support account leverage positions and creator ban status retrieval - Offer oracle info and list oracles with reliability scoring - Include dispute info and vote tallying with projected verdict calculation - Record and prune metadata and kline time-series data on block application - Add support for lazy pool and deposit queries along with chain properties - Implement metadata parsing and filtered market listing by category and jurisdiction - Integrate with chain plugin database and handle post-operation kline recording - Configure plugin with pmm-ttl-days option for metadata retention days - Setup CMake build configuration for prediction_market_api plugin library
- Introduce functions to import pm_oracle, pm_market, pm_outcome, and pm_dispute objects with shared_string member handling - Add export and import logic for all HF14 PM related indices in snapshot processing - Clear existing PM objects before importing new ones during database initialization - Enhance snapshot deserialization to handle absent PM objects in pre-HF14 snapshots - Log import counts for each PM object type during snapshot loading to aid diagnostics
- Include prediction_market_api plugin in wallet build dependencies - Add remote_prediction_market_api binding with optional connection handling - Implement pm_api() accessor for prediction_market_api proxy with assertion - Introduce prediction market helper methods for oracle registration, update, market creation, bet placement, commitment hashing, bet commit/reveal/cancel, liquidity management, market resolution, dispute creation/voting/resolution, position transfer, lazy deposit/withdraw, and leverage operations - Add read API passthrough methods for markets, oracles, bets, positions, liquidity, disputes, lazy pool, chain properties, market metadata, and market kline data - Extend fc::api remote_node_api.hpp with prediction market API message signature class and FC_API definition - Update wallet.hpp and wallet.cpp with full prediction market API support and method declarations - Ensure wallet starts normally even if prediction_market_api plugin is unavailable on connected node
- Include prediction_market_api in CMakeLists.txt for vizd program - Add prediction_market_api header inclusion in main.cpp - Register prediction_market_api plugin in appbase application initialization code
…ests - Add tests covering oracle registration after HF14 activation - Implement full binary market lifecycle: creation, betting, resolution, payout - Test committee dispute scenario with outcome overturning via voting - Verify lazy-pool stake contributes to dispute voting weight and quorum - Ensure external oracle rejection refunds seed liquidity exactly once - Add bet cancellation scenario reversing CPMM reserves and bets sum - Adjust consensus_sim harness to support new pm tests and sanitizer flags conditionally - Expose direct database access in simulated_node for test assertions - Fix simulated_node block witness field to validator for accuracy in tests
…operties support - Introduce HF13 distribution epoch length and HF14 prediction markets features in governance docs - Add detailed median-voted HF14 prediction-market parameters and kill-switch flags explanation - Add new `prediction_market_api` plugin with extensive JSON-RPC read-only methods for markets, bets, oracles, disputes, lazy pool, and governance data access - Include computed DTOs and charting support for prediction markets with offset-from-newest pagination - Document prediction market concepts analysis comparing Onix protocol to theoretical models - Update advanced hardfork and chain properties docs to cover new prediction market functionality
- Introduce readonly JSON-RPC plugin for HF14 prediction markets state access - Document market-related API methods including markets, outcomes, bets, liquidity, and metadata - Describe position, leverage, oracle, dispute, lazy pool, and governance methods - Provide details on kline/time series for market weight history and pagination approach - Explain computed DTOs representing bets, oracles, votes, and payout structures - Include example usage and code snippets for API calls and data processing - Link to relevant protocol operations and chain property documentation docs(governance): update chain properties with HF13 and PM parameters - Add chain_properties_hf13 with distribution_epoch_length parameter - Introduce chain_properties_pm (v5) for ~30 prediction market parameters and kill-switch flags - Detail all median-voted parameters for oracle, market, batch, dispute, time penalty, lazy pool, leverage, and fairness - Clarify live kill-switch flags to disable commit-reveal, lazy pool, or leverage without hardfork docs(advanced): extend hardfork management with HF13 and prediction markets - Add entries for HF13 epoch length and HF14 prediction markets including CPMM/LMSR, oracles, disputes, commit-reveal, lazy-pool, and chain properties v5 docs(prediction-markets): add comprehensive analysis of conceptual mapping of Onix PM protocol - Provide detailed table comparing 90 theoretical prediction market concepts against VIZ Onix on-chain implementation - Categorize concepts as solved, inherent, not needed, partial/roadmap, client layer, or open risks - Discuss information theory, mechanism design, liquidity and trading aspects in depth - Highlight Onix innovations: risk-free LP, CPMM binary, LMSR multi, commit-reveal batch bets, optional leverage subsystem, lazy pool governance voting weight - Explain architectural decisions omitting orderbooks, combinatorial markets, and peer prediction
- Updated chainbase submodule commit from 39ab2c2 to d429230 - Ensures third-party library is aligned with latest upstream changes
…cycle, coverage floors and thin-client APIs Consensus (HF14 follow-up ops, appended so operation indices stay stable): - pm_dispute_oracle_respond (op 22): the market oracle posts a public rebuttal onto an open dispute; stored on the dispute object (public-hearing model), allowed only while open and within oracle_response_deadline, re-post overwrites. - pm_unban (op 23): the resolver that imposed an account-mode ban (banned_by) may lift it early; sets banned_until to epoch and clears banned_by. - pm_ban_expired (virtual): the per-block cron sweeps temporary oracle/creator bans at banned_until, clears them and emits the lift for history/indexers. On-chain state: - pm_market gains decision_url/decision_reason — the oracle's resolution statement stored on-chain (set by pm_resolve_market / pm_no_contest reason), readable via get_market with no history scan. - pm_resolve_market_operation gains decision_reason (reflected on the wire). - pm_dispute gains oracle_response/oracle_response_time. - pm_oracle and pm_creator_ban gain banned_by; pm_creator_ban gains a by_ban_expiry index so the cron sweeps expired bans oldest-first (cleared bans sort into the 0-bucket, permanent bans past now, both skipped). Chain properties (witness-median tunables): - pm_listing_min_coverage_percent (2.5x): hide under-insured markets from the default catalog (enforced by the API plugin, revealed via show_risky). - pm_betting_min_coverage_percent (1.5x, advisory): client risk-confirm threshold; validated betting <= listing. Thin-client read APIs (non-consensus, for the viz-js client): - get_leverage_quote / get_leverage_close_preview / get_leverage_convert_preview reuse the frozen pm::leverage math to mirror the open/close/convert evaluators. - get_market_categories (taxonomy + live counts), get_market_full (one-call enriched, account-scoped), get_lazy_allocations / get_market_lazy_allocation. - Wallet remote_node_api bindings for all of the above. Docs & tests: - EN + ru + zh-CN docs updated (chain-properties, prediction-market-api, specification, operations overview/prediction-markets/validators, virtual-operations); library-integration spec + thin-client plan added. - test_pm_lifecycle: cases #58-#63 cover oracle rebuttal + decision_reason, no-contest rationale, manual unban and its guards, and ban auto-expiry vop.
…throughs The cli_wallet build failed because remote_prediction_market_api and the wallet_api pm_get_*/pm_list_* methods returned the node's typed objects. Those chainbase state objects (pm_market_object, pm_bet_object, ...) and the API DTOs embedding them are not default-constructible (deleted default ctor / shared_string members require a segment manager), so fc::api's client deserializer (T tmp; var.as<T>()) could not instantiate them. Return fc::variant instead: the node already emits fully-formed JSON and cli_wallet prints the variant unchanged, so the read surface is identical.
…te_node_api cli_wallet failed to compile because remote_node_api.hpp pulled in <graphene/plugins/prediction_market_api/prediction_market_api.hpp> transitively, but programs/cli_wallet has no include path to that plugin. After the read pass-throughs switched to fc::variant, the header (and the pmapi alias) are no longer referenced anywhere in the wallet, so remove them. graphene_wallet still builds; the public wallet header no longer leaks a plugin-only dependency.
…LP fee Add two HF14 median-voted consensus parameters and their enforcement: - pm_oracle_accept_window_sec (default 1h): a pending market the named oracle never accepts nor rejects is voided by the per-block cron once now >= created_time + window. The creators seed liquidity is refunded (return_liquidity); the non-refundable creation fee stays with the DAO fund. Tracked via a new pm_market_object.accept_deadline field and a by_accept_deadline index; emits the new pm_market_expired virtual op (op-id 101, appended last in the operation variant to keep tags stable). - pm_lazy_min_liquidity_fee_percent (default 2%): the lazy pool skips markets whose liquidity_fee_percent is below this reward floor, so it never subsidizes depth it is not paid enough to provide. Wired into calc_median and chain_properties_pm::validate().
… fee Cover the new pm_oracle_accept_window_sec / pm_market_expired lifecycle and the pm_lazy_min_liquidity_fee_percent reward-floor gate across: - EN docs (chain-properties, specification, operations, virtual-operations) - RU and zh-CN localizations (@l10n) at full parity with the EN source - library integration spec (delta section + property/vop tables, op-id 101) and thin-client plan - Onix paper EN + RU (state machine, acceptance flow, lazy-pool gate); PDFs rebuilt via pandoc + xelatex (EN 30pp, RU 32pp, 0 missing glyphs).
- Added warning that the live protocol uses basis points (bp), not permille (‰) - Explained the conversion from original PHP prototype’s permille to bp in on-chain code - Specified that all fee fields (oracle_fee_percent, creator_fee_percent, liquidity_fee_percent, etc.) use bp (10000 = 100%) - Highlighted the use of `fromBP` parser for fee fields and rejection of markets exceeding fee sum 10000 - Warned that using deprecated `fromPermille` leads to incorrect fee values, off by a factor of 10
…line The ?: between time_point_sec() and (now + fc::seconds(...)) has no common type — the latter yields fc::time_point, and each type converts to the other, which GCC rejects as ambiguous. Wrap the second branch in an explicit time_point_sec(), matching the copy-init conversion already used for the reveal/dispute deadlines in this file.
…erations The generic impacted-account visitor only collected signing authorities, so prediction-market events were missing from the histories of accounts that did not sign them: - signed ops lost their counterparties (pm_create_market -> oracle, pm_transfer_position -> recipient, pm_unban -> target, oracle auto-accept whitelist); - virtual ops carry no authority at all, so payouts, forfeits, liquidations, oracle penalties, market accept/expire and ban expiry were invisible to the affected users. Add explicit get_impacted_account_visitor overloads for the PM user and virtual operations, inserting every account field they carry. Market-only virtual ops that reference a market by id but carry no account name (pm_batch_settle / pm_dispute_finalize / pm_dispute_auto_close / pm_lazy_recall) are intentionally left to the generic handler.
|
Addressed the account-history review blocker in 3eebfd6: added explicit |
…, per-node) The free-form `metadata` JSON was stored in the consensus `pm_market_object` (shared_string) permanently — never pruned — even though consensus never reads it (it is written once and only parsed off-chain by the prediction_market_api plugin). That let a market permanently bloat every node's chainbase/shared memory with unbounded, unvalidated data. Move it out of consensus entirely: - pm_market_object: drop the `metadata` field (member, ctor, FC_REFLECT). The operation `pm_create_market_operation.metadata` is unchanged — clients still send it and it lives in the block log, exactly like custom_operation.json. - pm_create_market_evaluator: stop persisting metadata into state. - prediction_market_api: ingest metadata off-chain from the create operation (post_apply_operation) into the existing prunable pm_market_meta_object, instead of reading it back from the consensus object in on_block. - snapshot: drop the metadata import/export for pm_market (auto-excluded from the reflected dump; import of legacy snapshots ignores the field). Because it is now non-consensus, each node prunes it on its own schedule via --pmm-ttl-days (default lowered 7 -> 5; 0 keeps it forever for archival nodes). No consensus length/UTF-8 cap is needed — the blob no longer touches state.
|
Addressed the unbounded on-chain |
…xed retention A resolved+settled market (status 3, payout_status 3) is immutable — no betting, dispute, resolve or payout can touch it again; it only lingered in chainbase "for history", growing shared-memory state without bound. process_pm_markets() now GCs such markets and their whole object cluster (outcomes, bets, liquidity, commits, dispute votes, leverage positions, the dispute and lazy-allocation rows) once they have been closed for a FIXED protocol constant PM_CLOSED_MARKET_RETENTION_SEC = 5 days (measured from result_expiration + dispute grace). The retention is hardcoded and identical on every node, so pruning is fully deterministic: every node deletes exactly the same markets at the same block, keeping shared-memory state and snapshots in lock-step network-wide (a node syncing from a snapshot ends up with the same market set as everyone else). Work is bounded by the existing per-block cap. Only status-3/payout-3 markets are collected; disputed (payout_status 2) and never-settled markets are left untouched. Nothing holds an id-reference to a settled market, so there are no dangling references after removal.
|
Follow-up (31e8aab): resolved markets are now garbage-collected from consensus state. A settled market (status 3 / payout_status 3) is immutable, so |
…ones Extend the market garbage collector to reclaim ANY dead market a fixed 5 days after it becomes terminal — not only resolved+paid ones. A market is dead once nothing can act on it: resolved and paid out, void/no-contest, oracle-rejected, or the oracle never accepted and the accept window expired. To anchor the retention on the actual moment of death (rather than the declared result_expiration), add a `finalized_time` field to pm_market_object, set to the head-block time at every terminal transition: - oracle rejects the market (status -1) - accept window expires, market voided (pm_market_expired) - oracle misses resolution, refund (pm_oracle_missed_penalty) - dispute auto-close refund - settlement / auto-payout (covers resolved, no-contest, post-dispute) A new by_finalized index (finalized_time, id) lets process_pm_markets() sweep terminal markets in time order, skipping the finalized_time==0 live bucket, and delete each cluster PM_CLOSED_MARKET_RETENTION_SEC (5 days) later. Retention is a fixed protocol constant identical on every node, so pruning stays deterministic and snapshots identical network-wide. Snapshot import reads finalized_time when present. Work stays bounded by the per-block cap.
…ional) The first backfill mapped create ops to markets positionally by block timestamp, assuming market.created_time == the DLT block's own timestamp. created_time is set from head_block_time() which lags by a block, so the timestamp bucket was off and titles landed on the wrong markets (observed shift on testnet). Replace with a strong identity key (creator + url + betting/result expiration + outcome count) — all consensus fields the evaluator copies verbatim from the op. A key mismatch now simply leaves a market's meta empty; it can never mis-assign a title to the wrong market. Duplicate keys resolve in id order via a small list. Recovery: replay-from-snapshot starts with an empty meta index, so rebuilding the node on this image re-ingests all meta correctly (the previous wrong meta is gone).
…ves) A market created with betting_expiration == 0 keeps betting open until the oracle resolves it; result_expiration (<= now + pm_max_market_duration, i.e. <= 1 year) becomes a pure emergency backstop. If the oracle never resolves by then, the existing missed-resolution path in process_pm_markets refunds every bet and slashes the oracle insurance — so the "oracle abandoned the market" case has a trustless recourse without a dispute. - create: betting_expiration==0 branch requires allow_early_resolution and a result_expiration within (now, now + pm_max_market_duration]. Non-open-ended markets keep the existing checks. - betting / liquidity gates (place, commit, reveal, add, withdraw): treat 0 as "open while the market is active". - leverage: available on open-ended markets too (the extra volatility is the bettor's own risk). The expiration-buffer check only applies when there is a real betting deadline; guarding it also avoids the epoch-0 underflow of (betting_expiration - buffer). - prediction_market_api: mirror the leverage buffer guard; report auto_close_time = 0 (no force-close point) for open-ended markets. Resolve evaluator and the missed-resolution backstop are reused unchanged. Gated by HF14, no separate feature flag.
Adds a time-based funding cost to leverage positions so a long-held loan (now possible on open-ended markets) pays the lazy pool for the capital it ties up. - New median-voted chain property pm_leverage_funding_rate_ppm_per_day (uint32, ppm of the loan per 24h; default 50 = 0.005%/day; 0 disables). Validated <= 100%/day. - pm_leverage_position_object gains funding_paid (cumulative) and funding_due_time (next 24h boundary), plus a by_lev_funding_due index (status, funding_due_time, id). - accrue_leverage_funding() charges whole 24h periods (one-shot catch-up) from the bettor's equity into funding_paid, which raises the effective obligation (liquidation_threshold + funding_paid) and thus pulls up the liquidation point. Funding flows to LP yield through the existing pool_profit path. - process_pm_markets() gets a funding sweep: for each due active position, accrue, reprice at current reserves, and liquidate (reason 3) if now underwater. - open sets funding_due_time = created_time + 24h; close/convert/liquidate accrue first and settle funding to the pool. cascade trigger includes funding_paid. - prediction_market_api leverage quote exposes funding_rate_ppm_per_day; get_pm_chain_properties returns the new property automatically. Snapshot uses generic FC_REFLECT import/export so the new fields are covered.
Sibling markets of one real-world event (a match/game) carry the same opaque metadata.event key. Index it off-chain in the prediction_market_api plugin (non-consensus, prunable — same mechanism as category/description), mirroring by_meta_category with a by_meta_event index, and expose: list_markets_by_event(event, from, limit) -> full market cards, oldest-first market_card and get_market_meta now surface the event field; wallet CLI gets pm_list_markets_by_event. Parsers already emit meta.event (Polymarket event_id, Kalshi event_ticker). Enables client event pages / parent-child nesting. Plugin TU compiles clean; meta_parse_test covers the new field.
…0->64, MAX_PM_OUTCOMES_PER_MARKET 16->128)
…pletes multi-outcome limit bump)
…event pages/cards)
Fresh chains built from this branch enable leverage out of the box. On an already-running testnet the median value persists in state, so validators must still vote pm_leverage_enabled on to activate it there.
…d A/B) make_weight_sums hardcoded binary outcome labels as A/B, so clients could not show the actual outcome names (team names, Yes/No, Over/Under) even though pm_create_market stores real labels on-chain in pm_outcome_object for binary markets too. Read those labels for binary as well (fallback to A/B only when a label is blank). Feeds get_market_weight_sums/get_market_full so Forecaster can render named outcome bars.
Tag source casing is inconsistent ("Dota 2" vs "counter strike 2") and
clients lowercase tags, so a case-sensitive match made a 'dota 2' query
return nothing. Add meta_csv_contains_ci (both sides ASCII-lowercased) and
use it for the tag filter; comma-boundary semantics unchanged. Category /
jurisdiction / subcategory matching left as-is.
… tag counts get_market_categories only exposes GLOBAL top-20 hot tags, so a browse UI had to count tags from whatever page it loaded — the number jumped (e.g. Dota 2 shows 1 in the newest-page view, 540 once the tag is opened). New method returns authoritative per-tag counts within one category (all tags, scanning only that category's index slice), so the UI can show a stable count that doesn't depend on the loaded page. Tags returned in hot_tags (categories empty).
…sorted rows The category listing already loads each market to sort by volume/expiration, but returned only the meta_object (no financials), so clients had to fire a per-market get_market_weight_sums just to show a volume badge and could not rank markets globally across categories (Forecaster Popular fell back to round-robin). Return each row as a variant and, when the market was loaded, attach volume (= bets_sum, raw shares). Wire-compatible: existing meta fields unchanged, newest/oldest rows omit the field (client fills lazily). Return type vector<pm_market_meta_object> -> vector<fc::variant>.
…ult (hide_children arg, meta.child field)
…nd pay from free_balance as capital returns; support partial withdraw; add pending_withdrawals + get_lazy_withdraw_requests
… + free_balance≥0 invariant (Transitions 9/11/12)
…ending_withdrawals), not free_balance alone — fixes over-issuance when capital is deployed; docs updated
The block-generation loop wrapped each pending-tx apply in a try/catch whose wlog lines were commented out, so a transaction that passes pending push but fails _apply_transaction at block generation was dropped with no trace in the node log (valid-at-pending / never-included / sync-broadcast-hangs, and nothing logged). Re-enable the diagnostic wlog so such drops surface the fc::exception.
…kets_by_category rows
…no raw CSV in listings)
…dlog->elog (surface silent apply/assert drops)
…t unique index (bet field is always default 0)
…vent listings
Insurance backs an oracle's whole book, not each market. Rework below_risk_floor
into oracle_below_risk_floor (per-oracle, cached per head block):
(A) insurance < pm_min_oracle_insurance -> hide the ENTIRE book, incl. zero-bet
markets. Fixes broke/slashed oracles staying fully visible because every
fresh market had bets_sum==0 and so never tripped the old per-market check.
(B) insurance*100 < coverage% * sum(bets_sum over the oracle's OPEN markets).
Also apply the filter (show_risky opt-out) to list_markets_by_category and
list_markets_by_event, which Forecaster uses to browse and previously bypassed
the floor entirely. Non-consensus (API plugin) -> API-node rebuild, no replay.
…126) Brings the wedged-behind-network watchdog (#125) and the snapshot post-import completeness/supply invariants (#126) onto the PM branch. The #125 checks (count reconciliation, referential integrity, singletons) and the #126 SHARES conservation check are PM-agnostic and stay fatal. The #126 TOKEN supply invariant is extended for PM: PM is zero-sum, so a bet / liquidity / lazy-deposit / commit-escrow / dispute-fee / oracle- insurance / leverage-collateral moves TOKEN out of account.balance into a PM object field. Those pools are now summed (minimal non-overlapping set, duplicates such as bets_sum/reserves, empty-provider lazy LP, and deposit.principal excluded). Because this PM accounting is not yet satoshi-validated against real PM snapshots, the TOKEN check is LOG-ONLY on this branch (per-component delta logged, import NOT failed) until reconciled to delta==0 and re-armed as a fatal FC_ASSERT. Tracked in #127 with a TODO(pm) at the check. Conflicts: tests/consensus_sim/CMakeLists.txt (kept both test_pm_lifecycle and test_wedge_predicate scenarios).
…oken breakdown Logs per-status token sums for bet/leverage/commit/dispute/liquidity plus a bet_held-vs-Σmarket.bets_sum drift, right before the TOKEN invariant line, to localize the delta=-9079 undercount. Read-only; revert after localizing. Branch off origin/pm (5230165). -fsyntax-only clean.
…rve_a/b, lmsr_subsidy, liquidity_fee_earned, oracle_fixed_fee) to localize -9079 residual
At leverage open, collateral+loan (total_bet) leaves circulation and is tracked as the position (counted while active). At close/liquidate only cancel_value cv returns to pool+bettor; the remainder total_bet-cv (AMM spread + kdiv floor) was left frozen in the virtual reserves and, on never-settling markets, became an untracked token deficit (the static ~9079-raw snapshot residual, issue #127). Route that remainder to market.forfeit_pool at both exit sites so token supply reconciles exactly: it is counted by the snapshot invariant (pm_forfeit) and distributed to winners at settlement, matching the design intent that price-impact accrues to the rest of the market. pm_leverage_convert already conserves (position becomes a real bet, bets_sum += total_bet), so only liquidate_position and pm_leverage_close needed the fix.
…y residual Localization done + leverage-exit residual fixed (6b002c1), so re-arm the PM token supply invariant: it now ++invariant_failures (fails snapshot import) on ANY divergence. Removes the TEMP per-status / market-fields instrumentation probes. TEMP TESTNET ANCHOR: PM_SUPPLY_LEGACY_RESIDUAL = -9079. The current testnet snapshot carries a frozen PRE-FIX leverage-floor residual that code cannot retro-heal; anchoring the check to that known constant makes the invariant live again and catches any NEW drift, while tolerating the legacy value. Set the anchor to 0 for mainnet / after a clean state rebuild → strict ==0 enforcement. See q#199=B.
Add three display-only running aggregates to account_object so clients can read how much of an account's own funds is frozen in prediction markets in a single get_accounts call, instead of summing tens of thousands of markets: pm_liquidity_committed - own LP/creator liquidity in live markets pm_bets_staked - own stake in open/queued bets pm_leverage_collateral - own collateral in active leverage positions This commit lays the foundation only: - fields on account_object + account_api_object (get_accounts DTO) - database::pm_adjust_frozen(account, kind, delta) maintenance helper (clamped at zero; NEVER gates consensus - cosmetic telemetry only) - database::pm_seed_frozen_counters() one-time walk of existing pm_liquidity / pm_bet / pm_leverage_position objects - seed trigger + guard flag dgpo.pm_frozen_counters_seeded at the top of process_pm_markets(), so counters are seeded without a full replay (VIZ testnet is DLT-only, no genesis) Not yet wired: the ~25 incremental lock/unlock/move touchpoints in pm_evaluator.cpp. Until those land the counters seed once and then drift, so this branch is NOT deploy-ready. Single-TU -fsyntax-only clean.
Maintain the account_object frozen aggregates incrementally at every PM
lock/unlock/move point in pm_evaluator.cpp:
liquidity: create_market seed, add_liquidity (LOCK); withdraw_liquidity,
settle_liquidity, return_liquidity (UNLOCK principal only)
bets: place_bet binary+LMSR, reveal (LOCK); void refund, winner/loser
settle, refund_all_bets, cancel_bet, batch-settle slippage
(UNLOCK); transfer_position full/partial (MOVE)
leverage: leverage_open (LOCK); liquidate_position, leverage_close
(UNLOCK); leverage_convert (MOVE collateral->bets as total_bet)
Fees to recipients (oracle/creator/committee/void-compensation) and the
loan portion of leverage stay out - only the account's own principal
entering/leaving the locked set moves a counter.
Add database::pm_verify_frozen_counters(): re-derives the expected totals
from live objects and diffs the stored aggregates, logging any drift.
Called once right after seeding to log a baseline (clean/MISMATCH); safe to
invoke later to detect drift. Single-TU -fsyntax-only clean.
…tus API Adds a (oracle, status, id) composite index on pm_market plus a read-only list_markets_by_oracle_status(oracle, status, from, limit) API (plugin + wallet). Lets clients pull one oracle's markets filtered to a single status (active/resolved/...) in a bounded index walk instead of fetching by_oracle and filtering client-side. No hardfork, read-only.
Summary
Introduces Hardfork 14 (HF14): Prediction Markets — a full on-chain
prediction-market subsystem for the VIZ blockchain, plus the read-only APIs,
wallet bindings, snapshot support, tests and documentation around it.
The feature is hardfork-gated (
CHAIN_HARDFORK_14) and preserves the zero-sumtoken invariant: prediction markets never mint or burn tokens,
current_supplyis untouched, and settlement conserves value across bets, LP and forfeit pools.
What's included
Consensus / chain
bets, liquidity, resolution, disputes, leverage) gated behind HF14.
pm_dispute_oracle_respond), early ban lift(
pm_unban) and automatic ban expiry (pm_ban_expiredvirtual op via theper-block cron).
decision_url/decision_reason)and dispute oracle responses, readable without history scans.
coverage floors for listing (2.5x) and betting (1.5x, advisory).
Plugin / wallet / snapshot
prediction_market_apiplugin with extensive read APIs: market/oracle/dispute queries, category taxonomy + live counts, klines, one-call enriched
market view, and non-consensus leverage previews (quote/close/convert) that
reuse the in-node margin math.
remote_node_apibindings for the PM read APIs.Docs & tests
operations, virtual operations) and workflow/integration design docs.
test_pm_lifecycleconsensus-sim suite covering the fullmarket lifecycle, disputes, leverage, bans and settlement invariants.
Notes
master. Feature branch:pm(16 commits).