Skip to content

[simplex]: post bids to the HyperFX orderbook, and to it alone without BRIDGE; the SDK reads bids from both - #1426

Merged
Wizdave97 merged 4 commits into
mainfrom
claude/simplex-orderbook-bids-6e423f
Oct 22, 2026
Merged

Wizdave97 merged 4 commits into
mainfrom
claude/simplex-orderbook-bids-6e423f

Conversation

@Wizdave97

@Wizdave97 Wizdave97 commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

What

The HyperFX orderbook (main) now takes bids on swappers' orders with submitBid(userOp) and serves them under the order's commitment with bids(commitment, leg, solver). This PR makes simplex post its bids there and the SDK read them from there.

Simplex

  • The Hyperbridge key is optional. Without simplex.substratePrivateKey the solver still delegates its SolverAccount and funds the EntryPoint, and bids on the orderbook alone. simplex init and the UI wizard let it be skipped.

  • Every bid goes to the orderbook: the same SCALE-encoded fill op Hyperbridge takes. New OrderbookClient.submitBid; REJECTION_CODES gains NO_LIMIT_ORDER and TOO_MANY_BIDS.

  • Hyperbridge only while the account holds BRIDGE. BridgeBalanceGate (src/core/bid-venues.ts) reads the free balance before a bid and lets it through while it covers one bid's cost: the pallet's storage deposit (on-chain value, else the runtime constant), the existential deposit and the paymentInfo fee. The reading stands for 30 s, is lowered after each placement, and is zeroed when Hyperbridge answers InsufficientBalance. Without BRIDGE a bid goes to the orderbook alone, logged once until the balance is back. A balance read that fails lets the bid through.

  • FillerStrategy.executeOrder(order, bids?: BidPlacer) replaces the raw IntentsCoprocessor parameter. FillResult.success/txHash/pending/error stay Hyperbridge's answer; FillResult.orderbook is the orderbook's.

  • Bid store: StoredBid.onOrderbook (SQLite on_orderbook, added in place). Retraction and the deposit sweep keep to rows with a Hyperbridge deposit, since an orderbook bid has none and cannot be withdrawn. Fill attribution counts an orderbook-only row as a live candidate inside the same window a retracted bid gets. The dashboard shows Orderbook for a bid Hyperbridge did not take.

  • orderExecuted.success and the activity bid row now mean "placed on either venue". Order intake no longer refuses a solver-selection order for want of a Hyperbridge connection while an orderbook is configured.

SDK

  • HyperFxOrderbook.bids(commitment, { leg?, solver? }) returns OrderbookBid[] with the SCALE-encoded userOp.
  • OrderExecutor.fetchBids reads the coprocessor (when configured) and the gateway's orderbook together, merged by (sender, bidId); the Hyperbridge copy wins a tie. One source failing leaves the other's bids; both failing throws. FillerBid.venue is "orderbook" for a bid read there. IntentGateway.executeOrder no longer requires a coprocessor; withOrderbook also redirects where bids are read from.
  • Docs page gains a "Bids on an order" section.

Note: sdk/packages/simplex/docs/ai/changelog/2026-10-21-bids-on-the-orderbook.md.

Validation

  • Schema fixture refreshed from polytope-labs/hyperfx-orderbook main; schema.test.ts holds every document against it.
  • Both new documents were sent verbatim to https://orderbook.hyperfx.finance/testnet/graphql: bids answered, and submitBid reached op verification (BidRejected: MALFORMED_USER_OP for a junk op).
  • Simplex: tsc clean on touched files; vitest src/tests/core src/tests/data src/tests/orderbook src/tests/services → 817 passed, 4 skipped. New tests: core/bid-venues.test.ts, core/orderbook-bids.test.ts.
  • SDK: typecheck clean; bidSelection, orderbookSchema, orderbookMarket, intentsCoprocessorHttpFallback, phantomBidDeclaration suites pass, including new merge tests.
  • End to end: the testnet swaps run gains orderbook-only-bid (solver 1 restarted with no Hyperbridge key; passes only when the fill comes from its orderbook bid, which Hyperbridge never held) and orderbook-only-swapper (the SDK given no coprocessor, reading bids from the orderbook alone).

🤖 Generated with Claude Code

…t BRIDGE; the SDK reads bids from both

The orderbook now takes bids on swappers' orders (submitBid) and serves them under
the order's commitment (bids). Simplex posts every bid there and to Hyperbridge only
while the account holds BRIDGE for the deposit, read by a balance gate before each
bid. Orderbook acceptance is recorded on the bid row (onOrderbook) so fills on
orderbook-only bids settle against the limit order that priced them, while the
retraction sweep keeps to rows with a Hyperbridge deposit.

The SDK's OrderExecutor reads bids from the coprocessor and the orderbook together,
merged by solver and bid id, and no longer requires a coprocessor to execute an
order. The schema fixture is refreshed from hyperfx-orderbook main.
`orderbook-only-bid` restarts solver 1 on an unfunded Hyperbridge account before its
book is posted, so its bid can only reach the orderbook, and passes when the order is
filled by solver 1 from a bid the orderbook served and Hyperbridge never held. The swap
worker points the SDK at the orderbook under test and records which solvers each venue
serves whenever bids arrive.
pnpm 11.28.7 applies the workspace's `trustPolicy: no-downgrade` to the version pinned in
`packageManager` before switching to it. pnpm@11.0.0 was token-published after 10.33.x had
been published through trusted publishing, so every CI install on a `version: 11` runner
now fails in the install step with a trust downgrade. 11.28.7 is trusted-publisher again
and a frozen install under it leaves the lockfile unchanged.
@Wizdave97
Wizdave97 requested a review from seunlanlege October 22, 2026 08:46

@seunlanlege seunlanlege left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the full diff. The design holds up, and the orderbook-only-bid e2e shows it working on testnet: solver 1, with no BRIDGE, won from a bid only the orderbook held.

Inline comments cover:

  • Should fix: the warning fires on every bid; the balance check holds up the orderbook post when the HTTP endpoint is dead; the 1010 match; dashboard stats count orderbook-only bids as Failed.
  • Nits and one design point on retraction.
  • Two requests: optional substratePrivateKey in simplex, and an explicitly optional coprocessor in the SDK.

Also:

  • The description's "Not covered: no end-to-end test places a real bid on a running orderbook" is out of date: d228489 adds that scenario.
  • The failing live job is getRequestBscAmoy.test.ts timing out while the indexer was erroring. This PR doesn't touch that path.

Comment thread sdk/packages/simplex/src/core/filler.ts
Comment thread sdk/packages/simplex/src/core/bid-venues.ts
Comment thread sdk/packages/simplex/src/core/bid-venues.ts Outdated
Comment thread sdk/packages/simplex/src/core/bid-venues.ts Outdated
Comment thread sdk/packages/simplex/src/core/bid-venues.ts Outdated
Comment thread sdk/packages/simplex/src/strategies/fx.ts
Comment thread sdk/packages/sdk/src/protocols/intents/OrderExecutor.ts Outdated
Comment thread sdk/packages/simplex/src/orderbook/client.ts
Comment thread sdk/packages/simplex/src/core/filler.ts
Comment thread sdk/packages/sdk/src/protocols/intents/IntentGateway.ts Outdated
- The BRIDGE balance gate owns the "orderbook alone" warning, so it fires once per change
  of answer rather than per bid; a failed balance read stands for the TTL; the orderbook
  post no longer waits on the balance read; Substrate's generic 1010 no longer counts as
  an empty balance; the pallet's InsufficientBalance pays its fee, as the docs now say.
- Bid stats and `failed()` count a bid the orderbook alone holds as placed.
- A bid Hyperbridge refused but the orderbook holds logs at warn.
- The SDK merges bids by userOpHash, skips an orderbook bid whose op does not decode,
  and documents the coprocessor as optional; the docs examples create the gateway
  without one; the retry result carries the last attempt's error.
- `simplex.substratePrivateKey` is optional: without it the solver still delegates and
  bids on the orderbook alone; `simplex init` and the UI wizard allow skipping it.
- e2e: solver 1 runs with no key at all in `orderbook-only-bid`, and
  `orderbook-only-swapper` runs the SDK without a coprocessor.
- The changelog states what retraction guarantees now that an orderbook bid cannot
  be withdrawn.

@seunlanlege seunlanlege left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All 11 points from the earlier review are addressed in 37d2dcf, including the optional substratePrivateKey and the optional coprocessor. Thanks.

Non-blocking nits, fine as a follow-up:

  • src/tests/core/undelegated-chains.test.ts:77: the comment still says setupSolverSelection bails without a Hyperbridge connection.
  • bid-venues.ts:49-50 and the changelog say a failed read "lets the bid through"; that only holds with no prior reading, since otherwise the last reading is kept.
  • filler.ts:300: a config with hyperbridgeWsUrl but no key never connects, without saying so. An info log ("no substratePrivateKey; bids go to the orderbook alone") would make that visible.
  • The live job's getRequestBscAmoy.test.ts has failed on both runs here (self-delivery got "Missing or invalid parameters", then it timed out waiting for a relayer) but passed on main on Oct 21. This PR doesn't touch that path, but it's worth a re-run before merging.

@Wizdave97
Wizdave97 merged commit f4ba323 into main Oct 22, 2026
3 of 4 checks passed
@Wizdave97
Wizdave97 deleted the claude/simplex-orderbook-bids-6e423f branch October 22, 2026 12:35
@seunlanlege seunlanlege mentioned this pull request Oct 22, 2026
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