test(pm): margin/leverage safety — bad-debt transfer, profit close, Sybil settlement throttle (PR #124) - #151
Merged
Merged
Conversation
… close, Sybil throttle (PR #124) Three CI-wired consensus_sim cases in test_pm_lifecycle.cpp, driven through the REAL evaluators + database + settlement cron, targeting the leverage/margin subsystem: - leverage_bad_debt_is_transfer_not_mint: forces genuine pool bad debt (pool_received < loan) via the cancel-bet cascade and asserts the loss is a zero-sum TRANSFER, not a mint — current_supply moves by block inflation alone, pool free_balance stays >= 0. LPs bear leverage counterparty risk; the chain never emits tokens to cover it. - leverage_profit_close_never_mints: open -> same-side whale -> profitable voluntary close -> resolve -> settle. Asserts the #141 pot_retained clamp keeps forfeit_pool >= 0 and current_supply moves by block inflation alone (no mint on the profit path either). - leverage_sybil_settlement_is_cap_throttled: documents an abuse probe. There is NO per-market/per-account leverage-position count cap and NO minimum loan (validate only requires loan>0, collateral>0), so a Sybil can open many cheap positions on one market (test opens 12). BUT the forced settlement is throttled: process_pm_markets §2d force-closes open positions once betting is over, sharing the single per-block `done < cap` budget, so <= cap positions close per block (test: max 5 == cap) BEFORE settle_market's uncapped force_close_positions backstop is reached. Not a single-block DoS. Regression guard: if the §2d throttle is removed, closures exceed cap and this fails. Built the full chain locally and ran all three green: "*** No errors detected".
On1x
added a commit
that referenced
this pull request
Aug 12, 2026
…teemit#536) Require loan >= pm_min_liquidity in the pm_leverage_open evaluator. validate() only checks loan>0, so without a floor a Sybil could open unbounded near-zero loan positions on one market, each consuming a slice of the capped leverage fund and a settlement force-close slot -> a liquidation backlog that throttles PM cron throughput for ~N/cap blocks (see the leverage_sybil_settlement_is_cap _throttled coverage added in PR #151). A minimum loan bounds the global open position count to fund_total / pm_min_liquidity, so the backlog is bounded by construction. Reuses the existing median-voted pm_min_liquidity (no new chain property or serialization change); governance can still raise the floor. Adds the leverage_min_loan_floor_enforced consensus_sim case: a sub-floor loan is rejected, a loan exactly at the floor is accepted (so PR #151's Sybil case, which borrows exactly pm_min_liquidity, still opens).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Margin/leverage safety coverage for the HF14 prediction markets, following the review of PR #124. Adds three CI-wired
consensus_simcases totests/consensus_sim/scenarios/test_pm_lifecycle.cpp, all driven through the real evaluators + database + settlement cron (not the standalone replay math). Purely additive (+365 lines, no existing code touched); auto-registered by Boost, run underctest/CI like the other cases.leverage_bad_debt_is_transfer_not_mintForces genuine pool bad debt (
pool_received < loan) via the cancel-bet cascade and asserts the loss is a zero-sum transfer, not a mint:current_supplymoves by block inflation alone and poolfree_balancestays ≥ 0. The pool is not always made whole — a fast adverse move sticks LPs with the loss — but the chain never emits tokens to cover a leveraged bettor.leverage_profit_close_never_mintsOpen → same-side whale → profitable voluntary close → resolve → settle. Asserts the
#141pot_retainedclamp keepsforfeit_pool ≥ 0andcurrent_supplymoves by block inflation alone (no mint on the profit path either).leverage_sybil_settlement_is_cap_throttledDocuments a margin-abuse probe and its (working) defense. There is no per-market / per-account leverage-position count cap and no minimum loan (
validateonly requiresloan>0, collateral>0), so a Sybil can open many cheap positions on one market — the test opens 12. The hoped-for exploit was that resolving such a market would liquidate all positions in one block via the uncappedsettle_market → force_close_positionsbackstop (block-time DoS). It does not:process_pm_markets §2dforce-closes open positions once betting is over, and that sweep shares the single per-blockdone < capbudget, so ≤ cap positions close per block (test observed max 5 == cap) before the uncapped backstop is ever reached. Not a single-block DoS. This is a regression guard — if the §2d throttle is removed, closures would exceed cap and the test fails.Verification
Built the full chain +
consensus_sim_teststarget locally and ran all three:Note (defense-in-depth suggestion, not blocking)
The Sybil surface is throttled for safety (no single-block DoS, no mint), but a large position flood still creates a liquidation backlog: N positions take ~N/cap blocks to drain, during which their collateral/loans sit in limbo. A per-account position cap or a minimum loan size would bound that backlog as defense-in-depth. Filed as a review comment on #124.