Skip to content

feat(sdk): LMSR pool admin adjust/close with review fixes#55

Merged
tvolk131 merged 2 commits intomasterfrom
feat/lmsr-admin-adjust
Mar 21, 2026
Merged

feat(sdk): LMSR pool admin adjust/close with review fixes#55
tvolk131 merged 2 commits intomasterfrom
feat/lmsr-admin-adjust

Conversation

@tvolk131
Copy link
Copy Markdown
Contributor

Summary

Implements AdminAdjust and Close transitions for LMSR pools, fixing 20 issues from the initial LMSR pool implementation review. Includes the full Simplicity witness pipeline (signature computation, witness satisfaction, C evaluator verification) tested end-to-end on regtest.

Key changes

  • Admin adjust/close SDK methods with locator-based params, reserve-value consistency validation, per-asset wallet change with correct PSET-indexed blinding, and fee absorption from explicit collateral surplus
  • Genesis hash fix — admin signature uses the actual chain genesis hash (fetched via set_chain_genesis_hash) instead of LWK's hardcoded constant, which doesn't match on regtest
  • attach_lmsr_pool_witnesses genesis hash parameter — was hardcoded to all_zeros, breaking any path that hashes genesis_block_hash() explicitly
  • Store fixes — parameterized LIMIT binding (was format string interpolation), #[derive(Debug)] on PriceTransitionInput
  • Tauri fixesscan_lmsr_pool initial outpoints from creation_txid:0/1/2, ScanLmsrPoolResponse type, adjust/close stub commands
  • C evaluator checkc_eval.rs provides a corrected FFI binding for simplicity-sys's evalTCOExpression (upstream has a missing minCost parameter, reported in rust-simplicity#355)
  • Dependency pinsimplicity-lang/simplicity-sys pinned to upstream master post-PR #348 (value bit corruption fix)

Test plan

  • 256 SDK unit tests pass (including 4 new: swap BitMachine primary + secondary, admin C evaluator, PSET structure, close math)
  • 13 store unit tests pass (including 8 new: list/filter/price history)
  • 6 regtest integration tests pass (including 2 new: admin adjust increase + decrease)
  • Existing swap/create/scan tests unaffected
  • 0 clippy errors, 0 new TS errors

Docs

  • docs/lmsr-admin-adjust-testing.md — testing design decisions and the four bugs found during implementation
  • docs/simplicity-test-methodology.md — when to use BitMachine unit tests vs C evaluator vs regtest integration tests

🤖 Generated with Claude Code

Store limit order creation metadata (txid, market_id, direction_label,
offered_amount) in SQLite so the wallet can label order-creation
transactions instead of showing them as generic sends.

- Add migration for 4 new nullable columns on maker_orders
- Extend MakerOrderInfo, schema, models, and conversions
- Add record_order_creation() store method
- Persist order to store after on-chain creation in create_limit_order
- Add list_own_orders Tauri command returning OwnOrderSummary
- Frontend: fetch own orders on unlock/create/cancel, build txid->label
  map, render amber badges on limit order transactions in wallet activity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 21, 2026 14:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end LMSR pool admin transitions (adjust/close) to the Rust SDK + Tauri layer, and wires new UI capabilities around limit orders, pool listing/scanning, and price-history-driven charting.

Changes:

  • Implement LMSR pool admin adjust/close in the SDK with full Simplicity witness + evaluator validation and regtest coverage.
  • Add limit order create/cancel + order fetching, and persist “own order” metadata for wallet/tx labeling.
  • Introduce pool store queries + price history plumbing, and update UI to show orderbook, user orders/pools, and chart from history.

Reviewed changes

Copilot reviewed 47 out of 49 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/utils/market.ts Remove synthetic depth; add full orderbook helper
src/types.ts Add limit-order + LMSR pool + price history types
src/state.ts Add UI state for orders/pools/history + market-maker mode
src/services/pools.ts Add Tauri invocations for LMSR pool operations + history
src/services/markets.ts Add order fetch/create/cancel + preserve per-market cached data
src/main.ts Background load of orders/pools/history during navigation/boot
src/lifecycle/subscriptions.ts Refresh orders on discovery events with in-flight coalescing
src/handlers/click.ts Wire UI actions for limit orders + market-maker toggles
src/components/wallet/unlocked.ts Show user limit orders + pools; add tx labeling map
src/components/wallet/activity.ts Render tx rows with limit-order badge/links
src/components/shell.ts Gate “My Markets” behind market-maker mode; add toggle UI
src/components/market-chart.ts Prefer chart series from stored price history
src/components/home.ts Gate “Create New Market” behind market-maker mode
src/components/detail.ts Add market/limit order selector; show full orderbook + pools panel
src/components/chart-series.ts Build chart series from price history entries
src/actions.ts Add pool-create action IDs
src-tauri/tauri.conf.json Update Tauri app identifier
src-tauri/src/lib.rs Register new Tauri commands (orders + pools)
src-tauri/src/discovery.rs Export DiscoveredOrder from SDK into Tauri layer
src-tauri/src/commands.rs Implement fetch/create/cancel/list orders; pool list/scan/history; stubs for adjust/close
src-tauri/src/chain_adapter.rs Improve irreversible confirmation lookup + header-hash derivation
src-tauri/crates/deadcat-sdk/tests/maker_order.rs Fix test outpoints; add combined-UTXO coverage
src-tauri/crates/deadcat-sdk/tests/lmsr_pool.rs Add regtest admin adjust tests + genesis override setup
src-tauri/crates/deadcat-sdk/src/sdk.rs Implement pool admin adjust/close + genesis override; combined-UTXO order creation
src-tauri/crates/deadcat-sdk/src/node.rs Add scan_for_adjust + adjust/close wrappers; expose genesis/admin pubkey helpers
src-tauri/crates/deadcat-sdk/src/network.rs Add “simplicity byte-order” genesis helper
src-tauri/crates/deadcat-sdk/src/maker_order/pset/create_order.rs Support combined funding+fee UTXO path + tests
src-tauri/crates/deadcat-sdk/src/lmsr_pool/table.rs Add LMSR table generation utility + tests
src-tauri/crates/deadcat-sdk/src/lmsr_pool/mod.rs Gate C evaluator module behind testing feature
src-tauri/crates/deadcat-sdk/src/lmsr_pool/c_eval.rs Add corrected C evaluator FFI pipeline
src-tauri/crates/deadcat-sdk/src/lmsr_pool/assembly.rs Add genesis param; BitMachine + C evaluator checks during witness attach
src-tauri/crates/deadcat-sdk/src/lmsr_pool/api.rs Add Adjust/Close request/response API types
src-tauri/crates/deadcat-sdk/src/lib.rs Re-export new LMSR APIs + table generator
src-tauri/crates/deadcat-sdk/src/chain.rs Add chain backend genesis hash API
src-tauri/crates/deadcat-sdk/docs/simplicity-test-methodology.md Document Simplicity evaluation tiers/testing guidance
src-tauri/crates/deadcat-sdk/docs/lmsr-admin-adjust-testing.md Document admin-adjust bugs/fixes + methodology
src-tauri/crates/deadcat-sdk/deadcat-store/src/store.rs Add pool + price history storage/query + order creation metadata
src-tauri/crates/deadcat-sdk/deadcat-store/src/schema.rs Extend maker_orders schema with creation metadata fields
src-tauri/crates/deadcat-sdk/deadcat-store/src/models/maker_order.rs Add new maker order fields to models
src-tauri/crates/deadcat-sdk/deadcat-store/src/lib.rs Re-export new store types (pools/history)
src-tauri/crates/deadcat-sdk/deadcat-store/src/conversions.rs Populate new maker order fields in conversions
src-tauri/crates/deadcat-sdk/deadcat-store/migrations/2026-03-20-000001_create_price_history/up.sql Add price history table/indexes
src-tauri/crates/deadcat-sdk/deadcat-store/migrations/2026-03-20-000001_create_price_history/down.sql Drop price history table
src-tauri/crates/deadcat-sdk/deadcat-store/migrations/2026-03-19-000001_add_order_creation_fields/up.sql Add maker order creation metadata columns
src-tauri/crates/deadcat-sdk/deadcat-store/migrations/2026-03-19-000001_add_order_creation_fields/down.sql Document SQLite drop-column no-op
src-tauri/crates/deadcat-sdk/Cargo.toml Enable testing feature for simplicity-sys test-utils
src-tauri/Cargo.toml Patch simplicity-lang/simplicity-sys to specific upstream rev
.gitignore Keep SDK docs while ignoring root docs drafts

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +44 to +52
if (isLimitOrder) {
const badgeContent = escapeHtml(orderInfo.label);
if (orderInfo.marketId) {
label =
'<button data-open-market="' +
escapeAttr(orderInfo.marketId) +
'" class="rounded bg-amber-500/20 px-1.5 py-0.5 text-[10px] font-medium text-amber-300 hover:bg-amber-500/30 transition cursor-pointer">' +
badgeContent +
"</button>";
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limit-order transaction label uses data-open-market with orderInfo.marketId, but data-open-market is expected to be the UI/internal market id (see existing creationTxToMarket mapping). OwnOrderSummary.market_id appears to be the canonical 32-byte market_id hex, so clicking the badge likely won’t open the market. Consider storing/using the internal market id here (e.g., resolve market_id -> Market.id before building orderTxLabel).

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +163
// Convert history entries to timestamped probability values
const historyPoints = history
.map((entry) => ({
time: new Date(entry.recorded_at).getTime(),
probability: Math.max(0.02, Math.min(0.98, entry.implied_yes_price_bps / 10000)),
}))
.filter((p) => p.time >= startTime.getTime() && p.time <= endTime.getTime())
.sort((a, b) => a.time - b.time);
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new Date(entry.recorded_at) is parsing a SQLite datetime('now') string (typically YYYY-MM-DD HH:MM:SS), which is not reliably parseable across browsers/environments and can be interpreted in local time. Consider returning RFC3339/ISO-8601 timestamps from the backend (or normalizing to YYYY-MM-DDTHH:MM:SSZ before parsing) to avoid chart time skew/NaN dates.

Copilot uses AI. Check for mistakes.
Comment thread src/main.ts
Comment on lines +181 to +186
// Fetch limit orders for the selected market in the background
fetchOrders(market.marketId).then((orders) => {
mergeOrdersIntoMarket(market.marketId, orders);
render();
});

Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These background fetchOrders(...) calls don’t have a .catch(...) handler. If the invoke fails (e.g., Tauri not ready / relay unreachable), this can produce unhandled promise rejections. Consider adding .catch(...) (or using void + try/catch in an async IIFE) to keep the app resilient.

Copilot uses AI. Check for mistakes.
Comment thread src-tauri/src/commands.rs
Comment on lines +1673 to +1684
let params: deadcat_sdk::PredictionMarketParams =
serde_json::from_str(&request.contract_params_json)
.map_err(|e| format!("invalid contract params: {e}"))?;
let side = parse_trade_side(&request.side)?;
let direction = parse_trade_direction(&request.direction)?;

let base_asset_id = match side {
deadcat_sdk::TradeSide::Yes => params.yes_token_asset,
deadcat_sdk::TradeSide::No => params.no_token_asset,
};
let quote_asset_id = params.collateral_asset_id;

Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_limit_order trusts request.market_id for labeling/persistence, but it’s not validated against the canonical market_id derived from contract_params_json (i.e., PredictionMarketParams::market_id()). A mismatched market_id would silently mislabel the order in the local store/UI. Consider validating equality and returning an error on mismatch.

Copilot uses AI. Check for mistakes.
@tvolk131 tvolk131 force-pushed the feat/lmsr-admin-adjust branch 2 times, most recently from 7ad97f0 to f35ab2f Compare March 21, 2026 14:48
Implement AdminAdjust and Close transitions for LMSR pools, fixing 20
issues from the initial LMSR pool implementation review.

SDK:
- adjust_lmsr_pool / close_lmsr_pool with locator-based params (no
  redundant pool_params field)
- Reserve-value consistency validation (UTXO values must match declared
  reserves)
- Per-asset wallet-input change with correct PSET-indexed blinding
- Fee absorption from explicit collateral surplus for decrease path
- Admin signature with chain genesis hash (not hardcoded LWK constant)
- set_chain_genesis_hash / chain_genesis_hash for regtest support
- attach_lmsr_pool_witnesses takes genesis_hash parameter (was all-zeros)
- scan_for_adjust / pool_admin_pubkey on DeadcatNode
- generate_lmsr_table: q_step_lots > 0 validation, depth-20 comment
- Import ordering, dead code removal

Store:
- #[derive(Debug)] on PriceTransitionInput
- Parameterized LIMIT binding (was format! string interpolation)
- 8 new tests for list_lmsr_pools and price history

Tauri:
- scan_lmsr_pool initial outpoints from creation_txid:0/1/2 (was
  current reserve outpoints)
- adjust_lmsr_pool / close_lmsr_pool stub commands
- ScanLmsrPoolResponse TS type fix

Frontend:
- Price history chart integration (buildChartFromHistory)
- Pool UI scaffolding, poolsLoading removal

Tests (256 SDK unit + 13 store + 6 integration):
- BitMachine execution for swap primary and both secondary inputs
- C evaluator (corrected FFI) for admin adjust
- PSET structure verification for decrease path
- Close reclaimed amounts
- Regtest: admin adjust increase (blinding) and decrease (fee absorption)

Dependencies:
- Pin simplicity-lang/sys to upstream post-PR-#348 (value bit corruption)
- simplicity-sys optional dep with test-utils for C evaluator

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tvolk131 tvolk131 force-pushed the feat/lmsr-admin-adjust branch from f35ab2f to 43572e9 Compare March 21, 2026 15:24
@tvolk131 tvolk131 merged commit f1b0ca9 into master Mar 21, 2026
1 check passed
@dmnyc dmnyc deleted the feat/lmsr-admin-adjust branch April 15, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants