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.
import_pm_oracles() previously skipped the oracle-metrics fields added by the P1-P5 commits (markets_in_dispute_window, disputes_awaiting_ response/decision, resolved_late_count, resolution_time_hist), so a snapshot taken after the upgrade lost them on import (gauges were re-derived by pm_seed_oracle_gauges only when dgpo.pm_oracle_gauges_ seeded was absent, and the forward-accumulating histogram/late counter were never recoverable). Forward-compatible import: fields are read only when present, so old snapshots (pre-upgrade) still import cleanly and keep the existing seed-on-first-block behavior; new snapshots preserve the gauges and the resolution-latency histogram. Display-only; no consensus impact. Matches the fc::array<share_type,8> serialization used by FC_REFLECT (base64 vector<char> via from_variant).
avg_resolution_time (uint32) * (n-1) + rt can reach the uint64 boundary once n approaches the uint32 max (product of two uint32 values is within a hair of 2^64, and adding rt can tip it over). Accumulate the running mean in fc::uint128_t to keep the counter exact. Mathematically equivalent to the previous integer formula; verified with a quick script across normal and boundary cases (matches on all).
Add an on-time resolution ratio as a 4th reputation factor in the display-only reliability_score. Late-but-delivered resolves increment markets_resolved and previously earned full accuracy credit, so a chronically-late oracle scored identical to a punctual one; the existing resolved_late_count (P5) now feeds the score. timely = (markets_resolved - resolved_late_count) / markets_resolved, optimistic 10000 until anything is resolved, clamped late<=resolved. Rebalanced blend: accuracy 40% . verdicts 30% . responsiveness 15% . timeliness 15% (max -1500bp for an always-late oracle). Non-consensus, bp 0..10000, clients unaffected. avg_resolution_time stays out (latency from betting close, not deadline overrun).
… v2.1) Bring the API-plugin reference and the spec in line with the shipped oracle-metrics work on this branch: - prediction-market-api.md: add list_markets_in_dispute_window and list_oracle_disputes; rewrite the pm_oracle DTO to document the reliability_score v2.1 four-factor blend, the stored workload gauges, and the computed-on-read awaiting/oldest-age and p50/p95 latency reads. - specification.md section 14: replace the superseded 0-100 composite (volume/experience tiers, freshness, trust_score) with the actually implemented v2.1 bp score (accuracy 40 / verdicts 30 / responsive 15 / timely 15, decayed penalty stamps, ban docks, confidence shrink); add a Workload Gauges & Latency Telemetry subsection; expand the raw-metrics table to the real reflected field names and the new gauges/counters; add on_time_rate; note the pm_dispute_opened vop (P1). Docs only.
…-import fix(snapshot): import pm_oracle oracle-metrics fields (P1-P5)
…t128 fix(pm): compute avg_resolution_time running mean in uint128
…bury a good oracle at 0 penalty_stamps is a lifetime cumulative counter (one per zero-volume resolution, pm_evaluator §4.10). On a busy/seeded oracle it reaches tens of thousands (testnet polymarket = 65183), and reliability_score charged the RAW count x300bp -> ~19.5M bp deduction -> score floored to 0 even though accuracy, verdicts, responsiveness and timeliness were all ~perfect. Cap the effective stamps at 4, exactly as the lazy-allocation consumer already does (pm_evaluator ~line 740), so both readers of penalty_stamps agree and the fault-stamp ding is bounded to 1200 bp. Display-only / non-consensus (API plugin), no HF impact. Single-TU -fsyntax-only clean. After this, testnet polymarket reliability ~8793 bp instead of 0.
… grief disputers pm_resolve_market shifted result_expiration EARLIER only (if now < result_expiration). That let a griefing oracle stall until ~result_expiration + pm_dispute_grace_sec and report only then: the dispute deadline (result_expiration + grace) was already spent, so disputers got a near-zero or zero window. Owner flagged the hole. Fix: set result_expiration = now unconditionally on resolve (early OR late), exactly as pm_no_contest already does. The dispute/settle/LP-lock grace now ALWAYS starts from the announcement, so disputers always get the full pm_dispute_grace_sec regardless of report timing. The settle wait extends by however late the report was — the necessary price of a fair, always-full dispute window. late/rt telemetry is captured pre-shift, so resolved_late_count and latency stats stay honest. Spec + comments updated. Single-TU clean.
…first User-facing activity feeds surfaced oldest positions first (id asc), so a user's latest bets sat below months-old ones. Add an optional order arg (default "newest", id desc via reverse equal-range traversal; "oldest" keeps the legacy order) to get_account_positions, get_account_leverage_positions, get_market_bets, list_markets_by_creator and list_markets_by_oracle. Oracle work-queue methods (awaiting_resolution, in_dispute_window, by_oracle_status) intentionally stay oldest-first — a queue is worked longest-waiting first.
… sort for by_oracle/by_creator A) list_markets_by_category gains an optional status arg (default -1 = any) so an "active only" browse pages accurately server-side instead of the client over-fetching and dropping rows locally. B) list_markets_by_oracle / list_markets_by_creator accept order=volume (bets_sum desc) and order=expiration (soonest-closing first, open-ended last) in addition to newest/oldest, so oracle/creator profile pages can offer the same sort chips as category browse. Shared page_markets_sorted helper materializes the account's market set and sorts it, mirroring the volume/expiration path list_markets_by_category already uses.
The oracle profile's Active/Resolved market tabs are served by this method and defaulted to oldest-first — the same stale-first problem just fixed elsewhere. Add an optional order (newest default, plus oldest/volume/ expiration via page_markets_sorted) so profile tabs lead with the latest markets and can offer volume/ending sort chips. Work-queue methods (awaiting_resolution / in_dispute_window) are separate and unchanged.
…cessing cap process_pm_markets() section 6 (batch epoch settle) walked every active allow_batch market in by_status (status, id) order and consumed the per-block pm_processing_cap_per_block budget (done++ and current_epoch++) for EVERY market, even ones with zero queued bets. With more active allow_batch markets than the cap (e.g. 50k+ polymarket mirror markets on testnet vs cap=200), the loop stopped after the ~cap oldest markets and never reached newly-created markets: their revealed commit-reveal bets stayed queued (status=5) forever and current_epoch never advanced. Fix: only advance current_epoch and consume the cap for markets that actually had queued (status=5) bets this epoch. Idle markets are skipped without touching done, so the scan can reach newly-created markets and their bets settle on the next epoch boundary. Existing behavior for markets with queued bets is unchanged (slippage refunds still count as work, so had_queued covers both settled and refunded paths).
…sign spec (F1/steemit#300) Foundation for the deferred outcome-contingent early-exit claim mechanism: early exits (bet cancel / leverage close) will no longer extract curve value from LPs; their outcome-contingent profit is paid at settlement from a bounded slice (default 33%) of the losing pool, FIFO by exit time. New median-voted validator param bounds that slice. Struct + validate + FC_REFLECT (append-only) + calc_median wired; single-TU -fsyntax-only clean. Mechanism (object, evaluator rewiring, settlement distribution) follows. Spec: docs/prediction-markets/early-exit-deferred-claim.md
New consensus object for outcome-contingent early-exit claims: object_type enum
(append-only) + fwd decl + id_type, struct with {market, account, kind, outcome_index,
claim_amount, exit_time} and by_id / (market,id) FIFO indices, FC_REFLECT, add_core_index,
and snapshot export/import (forward-only, no seed → must be serialized). Also reflects the
previously-unlisted pm_lazy_withdraw_request_object_type in FC_REFLECT_ENUM (clears -Wswitch).
Additive/inert — no evaluator wires it yet. Single-TU -fsyntax-only clean (database, pm_evaluator,
snapshot). Next: cancel_bet/leverage-close record claims + settlement FIFO distribution.
…nert) settle_market pays outcome-contingent deferred claims BEFORE the parimutuel split, from a bounded slice (pm_early_exit_reward_cap_percent x losers_sum) of the losing pool, FIFO by exit order (by_claim_market), winning outcome only; unfunded = haircut; unused slice flows to winners; every market claim consumed. paid_claims folded into forfeit_pool so winners_pool drops by exactly the paid amount (>= (1-cap)*losers - fees >= 0: no uncovered mint, no LP hit). Conservation validated by standalone model (6 scenarios, IN==OUT + winners_pool>=0). Inert until the exit paths record claims. single-TU clean. Next: exit side (cancel_bet + liquidate_position + pm_leverage_close) records claims; void handling; dedicated claim-paid vop + read API.
…money logic closed
- cancel_bet (binary): refund=min(curve_refund,stake); profit tail -> pm_deferred_claim
{kind=0,outcome=side}; residual>=0 -> forfeit (never negative).
- liquidate_position: pool takes obligation; residual (cv-pool_received) -> claim
{kind=1,outcome} instead of immediate pay; forfeit += total_bet-pool_received.
reason 4 = terminal void/no-contest -> refund immediately (old path), forfeit += total_bet-cv.
- force_close_positions(reason=2 default); settle_market passes 4 on win<0, return_liquidity
passes 4; both void paths purge_deferred_claims (no winning outcome -> claims worthless).
- pm_leverage_close (voluntary): residual -> claim, forfeit += total_bet-obligation.
Conservation validated by standalone model (6 scenarios, IN==OUT, winners_pool>=0, no mint,
LP untouched). single-TU -fsyntax-only clean. TODO: claim-paid vop + read API; libs; UI; article.
…emit#300) The settlement distribution loop credited early-exit deferred claims with a bare adjust_balance, leaving no account-history trace and no way for indexers/clients to reconcile the settlement's token flow. Add a dedicated virtual op and a read API: - pm_early_exit_claim_paid_operation {account, market_id, kind, outcome_index, claimed, paid}: appended at the END of the operation variant (existing op-ids stay stable), FC_REFLECT'd, and emitted next to the adjust_balance in settle_market. claimed vs paid exposes any bucket-exhaustion haircut. Routed to the early-exiter's account history via the account_history impacted-accounts visitor. - get_deferred_claims(market, [from=0], [limit=100]): a market's pending outcome-contingent claims in FIFO exit order (by_claim_market); empty once the market settles (claims consumed). Plugin-only, like get_lazy_withdraw_requests — clients call via rawApi/JSON-RPC, no wallet wiring. All three touched TUs pass single-TU -fsyntax-only. Spec checklist updated.
…#139) Section 6 of process_pm_markets() after #139 no longer let idle markets eat the processing cap, but two gaps remained: - The scan still paid the LMSR q-vector snapshot per idle market before detecting idleness. Probe the bet index first: an idle market now costs one lower_bound (bets at a market's current epoch are queued-only, so an empty probe means idle). - The scan always restarted at the lowest id, so >= cap always-busy low-id markets could permanently starve newer ones (cheap griefing: dust batch bets on the oldest cap markets every epoch). Persist a round-robin cursor in dynamic_global_property_object (pm_batch_settle_cursor) and resume the scan there, wrapping once per boundary. The market by_status index becomes ordered_unique (status, id) so the cursor can seek mid-range and in-status iteration order is deterministic by id; all existing users do prefix lookups (scalar lower_bound / equal_range) and are unaffected. Index + dgpo field changes require a chain reset — the pm branch testnet is being reset for #139 anyway. Regression tests (consensus_sim, BUILD_CONSENSUS_TESTS): - batch_settle_idle_markets_do_not_starve: cap=1, three allow_batch markets, bet only on the newest — guards the #139 fix (fails on pre-#139 code). - batch_settle_round_robin_prevents_busy_starvation: cap=1, market 0 fed a fresh queued bet every epoch — guards the cursor (fails without it).
fix(pm): round-robin batch-epoch settle scan + idle fast-path (follow-up to #139)
…arantee Long-lived leverage positions accrue funding_paid unbounded in accrue_leverage_funding, so obligation (liquidation_threshold + funding_paid) can exceed total_bet. pot_retained = total_bet - obligation then goes negative, pushing forfeit_pool below zero and manufacturing an `uncovered` shortfall (LP principal hit / mint) at settlement — defeating the F1/steemit#300 no-uncovered-by-construction guarantee. Clamp pot_retained at 0 in both pm_leverage_close and liquidate_position. The pool still recovers its obligation from cv (reserves); the market pot simply never goes negative, so winners_pool >= (1-cap)*losers - fees >= 0 holds unconditionally.
fix(pm): clamp leverage pot_retained at 0 to preserve no-uncovered guarantee
…m loop (steemit#349) Adversarial follow-ups to the F1/steemit#300 early-exit review (owner-approved bundle), riding the same pm chain-reset as F1/#139/#140/#141. steemit#348 (defense-in-depth, closes the remainder of goal steemit#290): F1 guarantees `uncovered == 0` by construction, but #141 showed a regression can break it and it was charged to LP principal SILENTLY (the only diagnostic was in the no-LP subcase). Add an always-on elog in settle_liquidity whenever uncovered > 0, regardless of LP presence, so any future regression is loud in node logs / acceptance instead of eroding LP principal unseen. Log-only: deterministic, no consensus effect, no halt (a hard assert would take the chain down on an unforeseen edge — worse than charging LP and logging). steemit#349 (DoS bound): settle_market's early-exit claim-distribution loop iterated every deferred claim on a market with no cap — a griefer could spam cancels/leverage-closes to force unbounded per-block work when the market settles (same class as #139/#140). Add MAX_PM_DEFERRED_CLAIMS_PER_MARKET (10000) and a monotonic `deferred_claim_count` on pm_market_object; past the cap an early-exit skips recording its contingent claim. Conservation-safe: the skipped tail simply stays in the curve and pays 0 at settlement, exactly like bucket-exhaustion — NOT routed to forfeit_pool (that would double-count the tail, which is still in the curve → a mint). The exit itself always succeeds; only the contingent upside is forgone past the cap. Field: FC_REFLECT appended (order stable), snapshot export via reflection, import contains-guarded so it survives reimport. All touched TUs pass single-TU -fsyntax-only.
…Theorem 2) The early-exit reward cap (pm_early_exit_reward_cap_percent, default 33%) bounds paid_claims to cap*losers_sum, but that alone does NOT guarantee solvency: per-market fees are capped only by oracle+creator+liquidity <= 100% at creation (no chain param), so a valid market can push fees near 100% of losers_sum. Combined with the default cap this makes fees+claims exceed the losing pool; compute_settlement then floors winners_pool at 0 and charges the shortfall to LP principal (uncovered, F1) - reachable with VALID default params, not just extreme governance medians. Clamp the bucket to the settlement headroom (avail - fixed_paid + forfeit_pool == winners_pool before claims), mirroring parimutuel.cpp fee math exactly. paid_claims can no longer drive winners_pool negative, so the no-uncovered / no-mint / LP-safe guarantee holds unconditionally (not only under a fees+cap<=100% governance invariant). The clamp only ever reduces the bucket, so it is strictly more conservative. Found by adversarial self-review while formalizing Theorem 2 for the Onix paper.
…U PDFs - add Section 6.8 (Early Exit via Deferred Outcome-Contingent Claims), Theorem 2 (Bounded Early Exit) and Corollary 3 (no-mint / LP-safe / loser-never-profits) to both EN and RU whitepapers - update abstract, contributions and the leverage subsection (6.6) to reconcile with the deferred-claim mechanism - regenerate onix-protocol-paper.pdf (34 pp) and -ru.pdf (42 pp) from the updated markdown (pandoc + XeLaTeX)
- onix-protocol-paper-ledger.pdf (EN, 27 pp) and -ru-ledger.pdf (RU, 31 pp), built with the Ledger journal class (pdflatex) - LaTeX sources onix-protocol-paper.tex / -ru.tex and ledger.cls (patched for TeX Live 2026: caption compatibility, theorem env, babel main=english+russian, cleveref/amsmath order, pretitle, keywords \item scoped to its env) - both carry the F1 early-exit section, Theorem 2 and Corollary 3, matching the markdown/PDF pandoc builds
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).