Settlement<COLLATERAL> object and trades on behalf of all depositors via a pooled BalanceManager + TradeCap held by the vault.
Vault lifecycle

State: OPEN. Depositor to vault (DepositReceipt), vault pull_for_mint into Binary Settlement, mint_pair lands YES + NO in the vault's V3 BalanceManager, TradeCap places limit orders on V3 pools, record_mint keeps aggregate_cost in sync. State: SETTLED. mark_resolved fires, keeper sweeps (cancel + withdraw + redeem), receive_settlement flips state, depositors redeem receipts for pro-rata DUSDC.
On-chain story
- Users deposit collateral into a shared
DarkPoolVault<T>. Each gets aDepositReceiptfor their pro-rata share. The deposit tx is visible (you to vault), but it doesn’t reveal which side or which strike they’d bet on. - The vault stores the ids of a DeepBook V3
BalanceManagerand aTradeCap(off-vault, held by the keeper as Sui objects). It also stores the binary-marketSettlementid this vault trades against. - The vault itself doesn’t dispatch the V3 calls. The keeper’s PTB does, threading both the vault and the BalanceManager into a single atomic block.
- The keeper batches deposits, mints YES+NO pairs from the Settlement, and (optionally) sells one leg on the V3 pool. Each mint is mirrored by
record_mintso the vault’saggregate_coststays in sync. - At resolution the keeper calls
settlement::redeem_{yes,no}on the winning side, hands the resulting DUSDC to the vault viareceive_settlement, and users callredeemto claim their pro-rata share.
Tradeoffs vs trading directly on V3
- Privacy. V3 explorer sees
<vault BalanceManager> placed YES limit @ 62¢, not the user. The user-to-vault link is visible at deposit time, but the deposit-to-specific-V3-order link is not. - Latency. Deposits sit idle until the keeper’s next mint batch (
scripts/keeper-tick.ts, runnable as a cron). - Liquidity. Pre-resolution exit requires the vault to either
burn_pairor sell the held legs on V3, bounded by V3 pool depth.
Invariants
Fromdark_pool_tests.move:
sum(receipt.shares)over all live receipts equalsvault.total_shares.coin::value(balance)at any point equalssum(deposits) - sum(payouts).- Post-settlement,
sum(redeem outputs) == final_payout_micro(modulo BigInt truncation, bounded by N wei or less). record_mintnever emits when state is notSTATE_OPEN.
Out of scope for v0.3
- Mid-life NAV re-computation (multi-market vaults).
- Pre-resolution withdrawal at NAV minus haircut.
- Multi-Settlement vaults.
Live testnet vault
For thewc26_euro_champion World Cup market:
Verified flow: 2 DUSDC deposit, keeper minted 2 YES + 2 NO pairs into the vault’s BalanceManager (tx
5y5xkwbu…eg5i), then the BalanceManager rested 1.9 YES + 1.9 NO asks at $0.55 on real V3 books via TradeCap (tx 4wFHsCEU…).
See Vault Deposit Walkthrough for the full UX.
