Skip to main content
The full dark-pool vault loop is live on testnet for the wc26_euro_champion World Cup binary market. Deposit, keeper mint, V3 quoting, settlement, pro-rata redeem.

1. (Once) Bootstrap a new vault

--market is a slug from .binary-markets/registry.json. The Move target is ${DARKPOOL_PACKAGE_ID}::dark_pool::create_vault<DUSDC>. One PTB does: balance_manager::new to mint_trade_cap to dark_pool::create_vault. Shares the vault + BalanceManager; keeps TradeCap + VaultAdminCap with the keeper (sender). Prints VAULT_OBJECT_ID. Paste into .env.

2. Deposit

From the UI

  1. Go to /dark-pool.
  2. Pick the vault card.
  3. Click Deposit privately.
  4. Enter amount, confirm. PTB shape:
  5. Receipt object appears in your wallet. Block explorer sees <you> -> vault. Direction / strike is opaque.

From a script (smoke test / TVL seeder)

Uses the exact PTB shape the frontend signs.

3. Keeper tick

Deploys the pooled deposits. Idempotent. A second run with nothing idle is a no-op.
One PTB:
If yesPoolId / noPoolId exist in the registry, the tick also posts POST_ONLY asks on both pools via the vault’s TradeCap (generate_proof_as_trader). From V3’s perspective the trader is the vault’s BalanceManager, not any depositor.
Fee headroom. The keeper quotes roundLot(held × 100/105) because place_limit_order with pay_with_deep=false locks qty + the input-token fee at placement. Without the headroom, quoting 100% of holdings aborts EBalanceManagerBalanceTooLow. Discovered during the first live run.

4. Resolve + settle

Once the binary market’s expiry has passed and someone signs binary-market:resolve, the keeper flips to settlement mode:
Now does:
The idle-sweep step is mandatory. Receipt redemption pays from final_payout_micro only, so idle DUSDC left in vault.balance would be stranded forever. Encoded in the script.

5. User redeem

UI: /dark-pool to Withdraw button on the vault card. PTB:
Math:
Receipt is destroyed; sender gets pro-rata DUSDC.