Margin Rescue built on dreamDEX

Using Margin Rescue

There are two ways in. The app runs in your browser, read-only, for any public dreamDEX account. The command line does the same reads and can also prepare and verify a guarded reduction on an account you own. Neither ever asks for a key.

  • App: read-only, in the browser
  • CLI: Node 20.12 or later
  • Testnet only

Before you start

  • You need the public address of a dreamDEX perps account on the Somnia Hideki testnet (chain 50383). The account must hold positions for there to be anything to rescue.
  • The app needs nothing installed and never signs anything. On the public site your browser reads the public chain data itself; run locally, the project's server makes the same reads.
  • For the command line you need Node 20.12 or later and npm. Foundry is needed only for the contract tests and the fork rehearsals.

Read an account

  1. Open the app and paste the account address.
  2. Set how far BTC and ETH move, in percent, or pick a preset. Negative is down. The default is BTC −8% and ETH −12%.
  3. Set the target buffer in USDso: how much equity you want left above maintenance margin after the move. 0 means “not below maintenance”.
  4. Choose Analyze. The account is read at one block across all 21 pools, which usually takes 15 to 25 seconds.

The first thing to check is the reconciliation verdict. EXACT means the independent rebuild matched dreamDEX's MarginBank to the raw unit, so the analysis can be trusted. Anything else blocks a recommendation, and the reason is shown.

The figures
NameMeaning
E_riskHealth equity: unlocked collateral plus unrealized PnL minus funding owed. This is what the bank compares with its requirements.
E_totalE_risk plus collateral locked behind resting orders.
MMMaintenance margin across every held market.
bufferE_risk − MM. Below zero, the account is under maintenance.

The meter beside the verdict draws health equity against the dashed maintenance line, now and at the scenario. The scenario row shows each held market's reference mark and its fixed scenario price. Markets other than BTC and ETH stay at their reference marks and are still counted.

Compare reductions

The second screen lists no action first, then each evaluated reduction:

  • Order: the guarded order the reduction would send, with its protective limit.
  • Cut now: how much notional exposure the reduction removes at today's prices.
  • Cost now: slippage against the mark plus fees, from the book as it was read. Negative means the book paid more than the mark.
  • Buffer at scenario: what the buffer would be at the scenario prices after the reduction, drawn as a bar around zero.
  • Goal: whether that buffer meets the target. Meets or Fails.

If doing nothing already meets the target, nothing is recommended. Otherwise the preferred candidate is the one that meets the target with the smallest notional cut, then the lowest cost. Some reductions make the scenario worse; reducing a short that hedges a long is the usual case. Those are flagged as harmful. A candidate can also be unavailable, for example when it rounds to zero on the lot grid or would leave a remainder below the minimum order. The reason is listed.

Read a recorded result

The third screen shows what happened when a reduction was actually executed. You can choose one of three recorded runs:

  • Fork, real 6-market account: the full loop at block 33,472,615. ETH −50% was selected, 0.8165 ETH filled inside the limit, and the buffer recomputed from the fills matched the forecast.
  • Fork, rehearsal of the live plan: the exact live executor run on a fork, from deploying the guard to the verified cleanup.
  • Live run 1: the same plan on the live network. It has run: goal met, cleanup verified.

For a run, compare three numbers: the forecast made before sending, the actual buffer recomputed from what really filled at the same scenario prices, and the account's current health at today's marks. The list of ledger checks shows that the account changed only in the ways the transaction explains.

Run it locally

Your terminal
git clone https://github.com/a252937166/proving-ground-dreamdex.git
cd proving-ground-dreamdex
npm ci
npm run serve            # this site at http://127.0.0.1:8787

# Rebuild an account's health and compare it with the bank (exit 0 only if EXACT)
npm run mr -- reconcile --account 0xACCOUNT --out /tmp/mr

# The fixed scenario and the candidates
npm run mr -- analyze --account 0xACCOUNT \
  --shock BTC=-8 --shock ETH=-12 --target 0 --out /tmp/mr
#   --price ETH=2000     an absolute price instead of a shock
#   --slippage-bps 50    the protective limit beyond the touch
#   --include-cancel     also evaluate cancelling resting orders
#   --block N            analyse a past block

analyze writes snapshot.json, reconciliation.json, scenario.json, candidates.json and a readable analysis.txt into the output directory. Every integer is a decimal string, so the files stay exact.

Reduce on your own account

This part signs transactions on your account. The site never does it. You run it yourself, testnet only, with your own wallet.

  1. Deploy your own ReduceOnlyGuard(owner, MarginBank, [pools]) from contracts/. It is bound to your address and to the pools you list.
  2. Grant it placeOrderFor on the pool you will reduce: setOperatorApprovalForPool(pool, guard, [0x80054449], true) on dreamDEX's OperatorPermissionsRegistry. This is the same grant dreamDEX's “Link a bot” writes.
  3. Plan the action from your analysis. This runs the preflight and refresh, computes the action id, journals it as NOT_SENT and prints the unsigned transaction to the guard:
    Plan
    npm run mr -- plan --analysis /tmp/mr --guard 0xGUARD
  4. Right before signing, refresh. An account that changed invalidates the confirmation, and it must not be sent:
    Refresh
    npm run mr -- refresh --analysis /tmp/mr --action 0xACTION
  5. Sign and send the printed transaction with your own wallet, then bind and recompute:
    Recompute
    npm run mr -- recompute --analysis /tmp/mr --action 0xACTION --tx 0xHASH
  6. If a send is ever ambiguous, settle it from chain data. This never re-sends:
    Resolve
    npm run mr -- actions --resolve
  7. When you are done, revoke the grant with the same call and false.

What the numbers do not say

  • The scenario is a static what-if at stated prices. It does not predict prices, the path to them, liquidation, or fills of resting orders and stops along the way.
  • An expected fill comes from the book as it was read. It is not a guaranteed fill.
  • The preferred candidate is the best of a small evaluated set, not a global optimum.
  • Everything runs on the Somnia Hideki testnet. None of it is financial advice or a promise about real funds.

When something looks wrong

The result says BLOCKED.
The reason is listed. Common causes are a stale mark, an inexact reconciliation, a stop list the indexer has not caught up on, or a linked child account, which this version analyses but does not act on. If the reason is a stale mark, analysing again a little later may succeed.
NO_ACTION_NEEDED.
Doing nothing already meets your target under that scenario. Try a larger move or a higher target to see the candidates compete.
NO_FEASIBLE_CANDIDATE.
No single evaluated reduction reaches the target. The table still shows how close each one gets.
Why does the analysis take 20 seconds?
It reads every pool, every order and the stop list at one pinned block, then confirms that the block is still canonical. Speed is traded for a snapshot that cannot mix two blocks.