@hyperbridge/simplex 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,62 +1,53 @@
1
1
  # @hyperbridge/simplex
2
2
 
3
- Automated intent solver for the Hyperbridge IntentGateway. Install the desktop app, run the
4
- standalone binary, or embed the engine in your own Node application.
3
+ [![npm](https://img.shields.io/npm/v/@hyperbridge/simplex.svg)](https://www.npmjs.com/package/@hyperbridge/simplex)
4
+ [![node](https://img.shields.io/node/v/@hyperbridge/simplex.svg)](https://nodejs.org)
5
+ [![license](https://img.shields.io/npm/l/@hyperbridge/simplex.svg)](https://github.com/polytope-labs/hyperbridge/blob/main/sdk/packages/simplex/LICENSE)
5
6
 
6
- Full documentation:
7
- [docs.hyperbridge.network/developers/sdk/simplex](https://docs.hyperbridge.network/developers/sdk/simplex/)
7
+ An automated solver for [Hyperbridge](https://hyperbridge.network) intents.
8
8
 
9
- ## Desktop app (Recommended)
9
+ Simplex watches the IntentGateway on the chains you configure. It prices each swap against the
10
+ limit orders you post to the HyperFX orderbook, then bids for and fills the swaps you have priced.
10
11
 
11
- [Download Simplex Desktop](https://github.com/polytope-labs/hyperbridge/releases?q=simplex-desktop-v&expanded=true)
12
- for macOS, Windows, or Linux. Choose the newest stable `simplex-desktop-v…` release and its installer
13
- for your platform. The app bundles this package and the matching Node runtime, opens the setup wizard
14
- on first launch, and keeps the solver running from the system tray. macOS and Windows install
15
- authenticated updates; Linux updates remain manual until release metadata is independently signed.
12
+ Embed it in your own Node service, or run it as a ready-made app:
16
13
 
17
- The desktop app and `@hyperbridge/simplex` always use the same version. Its bundle identifier is
18
- `network.hyperbridge.simplex` and its installed product name is **Simplex**.
14
+ - **Library**: call `Simplex.start()` in your process, with your own signer and storage.
15
+ - **CLI**: `simplex` sets itself up in the browser and serves a local dashboard.
16
+ - **Desktop app**: installers for macOS, Windows and Linux.
17
+ - **Docker**: the [`polytopelabs/simplex`](https://hub.docker.com/r/polytopelabs/simplex) image.
19
18
 
20
- A fresh desktop config is stored at:
21
-
22
- - macOS: `~/Library/Application Support/Simplex/filler-config.toml`
23
- - Windows: `%APPDATA%\Simplex\filler-config.toml`
24
- - Linux: `$XDG_CONFIG_HOME/Simplex/filler-config.toml`, or `~/.config/Simplex/filler-config.toml`
25
-
26
- `filler-config.toml` contains private keys and credentials in plaintext. New files are mode `0600`
27
- on Unix, but software running as the operator can still read them. Keep the file out of source
28
- control and broadly shared backups. `simplex.substratePrivateKey` is required in every signer mode,
29
- so Turnkey and MPC Vault operators still have a raw Substrate key on disk.
30
-
31
- The browser-installable PWA remains the remote/mobile dashboard for an existing solver. It is a UI
32
- shell, not a packaged solver, and is not the preferred local installation.
33
-
34
- See the [installation guide](https://docs.hyperbridge.network/developers/evm/simplex/installation/)
35
- for installer names, lifecycle details, and the advanced Docker and npm paths.
36
-
37
- ## Advanced: embed as a library
19
+ ## Install
38
20
 
39
21
  ```bash
40
22
  npm install @hyperbridge/simplex
41
23
  ```
42
24
 
25
+ Requires Node.js 22.16 or later.
26
+
27
+ ## Quick start
28
+
43
29
  ```ts
44
- import { Simplex, privateKeySigner } from "@hyperbridge/simplex"
30
+ import { Simplex, privateKeySigner, type SimplexConfig } from "@hyperbridge/simplex"
45
31
  import { SqliteDataStore } from "@hyperbridge/simplex/sqlite"
46
32
 
33
+ const config: SimplexConfig = {
34
+ simplex: {
35
+ maxConcurrentOrders: 5,
36
+ substratePrivateKey: process.env.SUBSTRATE_KEY!,
37
+ hyperbridgeWsUrl: "wss://nexus.rpc.polytope.technology",
38
+ },
39
+ chains: [{ rpcUrls: ["https://base.example"] }, { rpcUrls: ["https://ethereum.example"] }],
40
+ orderbook: { url: "https://orderbook.hyperfx.finance/mainnet/graphql" },
41
+ }
42
+
47
43
  const simplex = await Simplex.start({
48
44
  config,
49
45
  signer: privateKeySigner(process.env.SOLVER_KEY as `0x${string}`),
50
46
  data: new SqliteDataStore("./simplex-data"),
47
+ logger: process.stdout,
51
48
  })
52
49
 
53
- simplex.on("order:filled", ({ orderId, profitUsd }) => {
54
- console.log(`filled ${orderId} for $${profitUsd}`)
55
- })
56
-
57
- // Every runtime control the dashboard offers is a method — nothing needs a restart.
58
- // Prices come from limit orders posted to the HyperFX orderbook: 10,000 USDC in for
59
- // 13,900,000 CNGN out, filled on Base, for swaps from Ethereum or Base.
50
+ // Pay out 13,900,000 cNGN on Base for 10,000 USDC, to swaps from Ethereum or Base.
60
51
  await simplex.limitOrders.create({
61
52
  fillChain: "EVM-8453",
62
53
  tokenIn: "USDC",
@@ -65,148 +56,91 @@ await simplex.limitOrders.create({
65
56
  amountOut: "13900000",
66
57
  acceptedSources: ["EVM-1", "EVM-8453"],
67
58
  })
68
- await simplex.chains.setRpcUrls(8453, ["https://base-new.example"])
69
59
 
60
+ simplex.on("order:filled", ({ orderId, profitUsd }) => {
61
+ console.log(`filled ${orderId} for $${profitUsd}`)
62
+ })
63
+
64
+ // When you are done:
70
65
  await simplex.stop()
71
66
  ```
72
67
 
73
- `Simplex.start` takes a plain config object — no TOML file required — and returns once the solver is
74
- running. The config must name an `orderbook`; it carries no prices, and the solver fills only against
75
- the limit orders you create while it runs. It logs nothing until you point `logger` at a sink, so importing the package never writes to
76
- your stdout.
68
+ `Simplex.start` resolves once the solver is running. The config holds no prices. Simplex fills only
69
+ against the limit orders you create, so a fresh solver quotes nothing until you post one.
77
70
 
78
- Signing is an interface, not a setting. `Signer` is an identity and three operations — sign this
79
- typed data, this EIP-7702 authorization, this transaction — with no viem types on it, so satisfying
80
- it never means matching this package's viem version. `privateKeySigner`, `secretPhraseSigner`,
81
- `turnkeySigner` and `mpcVaultSigner` ship with the package, `viemSigner` adapts any viem account (a
82
- `toAccount` wrapper around an HSM or a remote signing service included), and your own implementation
83
- is a first-class citizen. Persistence is pluggable the same way: the default
84
- store is in-memory, `SqliteDataStore` is durable, and `SimplexDataStore` is a small async interface
85
- you can implement over Postgres, Redis or anything else. A solver that submits bids should use a
86
- durable store, since bid records are how locked deposits are found again for retraction.
71
+ ## Features
87
72
 
88
- See [Running as a library](https://docs.hyperbridge.network/developers/sdk/simplex).
73
+ - **Priced by your limit orders.** No price feeds. Each order says what you take in, what you pay
74
+ out, and on which chain.
75
+ - **Bring your own signer.** `Signer` is a small interface with no viem types. Simplex ships
76
+ `privateKeySigner`, `secretPhraseSigner`, `turnkeySigner` and `mpcVaultSigner`, and `viemSigner`
77
+ wraps any viem account.
78
+ - **Bring your own storage.** The default store is in memory. `SqliteDataStore` is durable, and
79
+ `SimplexDataStore` is a small interface you can implement over any database. Use a durable store
80
+ when bidding, because bid records are how locked deposits are found again.
81
+ - **Live control.** Limit orders, chains, vaults, assets and rebalancing all change at runtime
82
+ through `simplex.limitOrders`, `simplex.chains` and the other controllers. Nothing needs a restart.
83
+ - **Typed events.** Subscribe to `order:detected`, `order:filled`, `limit-order:filled` and more.
84
+ - **Quiet by default.** Simplex logs nothing until you pass `logger`, so it never writes to your
85
+ stdout uninvited.
89
86
 
90
- ## Advanced: npm binary and Docker
87
+ ## Command line
91
88
 
92
89
  ```bash
93
90
  npm install -g @hyperbridge/simplex
94
91
  simplex
95
92
  ```
96
93
 
97
- The scope matters: the bare `simplex` name on npm is an unrelated package. The installed command is
98
- still `simplex`. Prefer a container? The same binary ships as
99
- [`polytopelabs/simplex`](https://hub.docker.com/r/polytopelabs/simplex) — quickstart on the Docker
100
- Hub page.
94
+ Install the scoped package. The bare `simplex` package on npm is unrelated.
101
95
 
102
- With no config present, `simplex` opens a local browser wizard that walks through the minimum setup
103
- (chains, RPCs, bundlers, signer, Hyperbridge account), validates every endpoint live,
104
- writes a commented `filler-config.toml` (mode 600) and starts the solver in the same process.
105
- `simplex init` is the equivalent terminal wizard.
96
+ With no config, `simplex` opens a setup wizard in your browser. The wizard writes
97
+ `filler-config.toml` and starts the solver. With a config, `simplex` starts the solver and serves its
98
+ dashboard at `http://127.0.0.1:8686`.
106
99
 
107
- With a config present (`./filler-config.toml`, `$SIMPLEX_HOME/config.toml`, or `-c <path>`),
108
- `simplex` runs the solver directly.
100
+ ```bash
101
+ simplex run -c filler-config.toml # run with an existing config
102
+ simplex run -c filler-config.toml --no-ui # run without the dashboard
103
+ simplex init # set up in the terminal instead
104
+ ```
109
105
 
110
- ### Web UI
106
+ The same binary runs in Docker as
107
+ [`polytopelabs/simplex`](https://hub.docker.com/r/polytopelabs/simplex).
111
108
 
112
- The solver serves a local web UI at `127.0.0.1:8686` by default:
109
+ ## Desktop app
113
110
 
114
- - setup wizard (when no config exists) — private key, secret phrase, MPCVault or Turnkey signer, chains and endpoints
115
- - status, pause/resume (persists across restarts), graceful stop, balances per chain
116
- - live activity feed (orders detected/filled/skipped, bids, rebalances) streamed over SSE
117
- - limit orders: post, inspect with the fills that drew them down, and cancel
118
- - operations: manual vault sweep/redeem, runtime allowlist editing, log level switch, rebalancing trigger view, masked config view
111
+ Simplex Desktop bundles this package with its own Node runtime. It runs the setup wizard on first
112
+ launch and keeps the solver running from the system tray.
113
+ [Download it for macOS, Windows or Linux](https://docs.hyperbridge.network/developers/evm/simplex/installation/).
119
114
 
120
- Flags:
115
+ ## Security
121
116
 
122
- ```bash
123
- simplex run -c filler-config.toml # UI on 127.0.0.1:8686
124
- simplex run -c filler-config.toml --ui 9000 # custom port
125
- simplex run -c filler-config.toml --no-ui # headless
126
- simplex run --no-open # start the wizard, don't launch a browser
127
- simplex run --log-format json # NDJSON on stdout instead of colourised lines
128
- ```
117
+ - `filler-config.toml` holds private keys in plain text. It is written with mode `0600`, but keep it
118
+ out of source control and shared backups.
119
+ - The dashboard has no login. It listens only on `127.0.0.1` by default. Do not expose it on a
120
+ network you do not trust. To reach it from a phone, use
121
+ [remote access](https://docs.hyperbridge.network/developers/evm/simplex/api/remote-access/).
129
122
 
130
- `--no-open` and `--log-format json` are for running the solver under a supervisor. The wizard still
131
- starts and still reports its URL under `--no-open`; only the browser launch is skipped. `json` makes
132
- every line simplex writes to stdout one JSON object, with no ANSI escapes, which is what a captured log
133
- file needs. (One caveat: `@polkadot/api` prints a plain-text line to stdout if the Hyperbridge runtime
134
- upgrades while the solver is running, so parse defensively.)
123
+ ## Documentation
135
124
 
136
- The limit-order API:
137
-
138
- ```bash
139
- curl http://127.0.0.1:8686/api/orderbook/books # books, dust floors, tokens per chain
140
- curl http://127.0.0.1:8686/api/limit-orders?status=open # also ?chain= and ?book=
141
- curl -X POST http://127.0.0.1:8686/api/limit-orders \
142
- -H "Content-Type: application/json" -H "X-Simplex-UI: 1" \
143
- -d '{"fillChain": "EVM-8453", "tokenIn": "USDC", "amountIn": "10000",
144
- "tokenOut": "CNGN", "amountOut": "13900000", "acceptedSources": ["EVM-1", "EVM-8453"]}'
145
- curl http://127.0.0.1:8686/api/limit-orders/<id> # { order, fills, bids }
146
- curl -X DELETE http://127.0.0.1:8686/api/limit-orders/<id> -H "X-Simplex-UI: 1"
147
- ```
148
-
149
- Amounts are whole tokens as decimal strings. `acceptedSources` must name at least one source chain,
150
- and `ttlSecs` is optional (default `[orderbook] defaultTtlSecs`, or 365 days). Orders live in
151
- `bids.db`, not the config file: a fill draws an order down and reposts the rest, and it lapses when
152
- its TTL runs out. See the
153
- [limit orders guide](https://docs.hyperbridge.network/developers/evm/simplex/limit-orders/).
154
-
155
- The server is unauthenticated — mutating requests need the `X-Simplex-UI: 1` header (CSRF
156
- hygiene), and both the wizard and the operator UI bind loopback unless told otherwise. Only bind
157
- another interface (e.g. `--ui 0.0.0.0:8686`, which the docker image does inside its own network
158
- namespace) on a trusted network.
159
-
160
- Loopback is machine-local, not user-local. On a shared machine, another OS user may be able to reach
161
- the unauthenticated TCP UI and invoke operator actions. Prefer `--ui-socket` in an owner-only
162
- directory or the authenticated, opt-in tunnel when other local users are not trusted. The generated
163
- `filler-config.toml` stores signing keys in plaintext; it is written atomically with mode `0600` on
164
- Unix, but must still be kept out of source control and broadly shared backups.
165
-
166
- ## Remote access from a phone
167
-
168
- The UI is loopback-only, and most operator machines sit behind NAT. Remote access keeps an
169
- outbound SSH tunnel from simplex to a relay ([polytope-labs/simplex-tunnel](https://github.com/polytope-labs/simplex-tunnel),
170
- hosted at `simplex.tunnel.polytope.technology`) that leases this simplex a stable public port.
171
- A phone's SSH client connects to that port with a local port forward, and the browser opens
172
- `http://localhost:8686`.
173
-
174
- The phone's SSH session terminates in an SSH server embedded in simplex, not in sshd and not in
175
- the relay, so the relay only ever carries ciphertext. That server accepts public-key auth against
176
- the devices paired in the UI and `direct-tcpip` channels to the UI bind, and nothing else: no
177
- shell, exec, PTY or other destinations.
178
-
179
- It is off by default. Turn it on and pair devices under **Operations > Remote access** in the UI;
180
- the choice is written to `[simplex.tunnel]` in the config. To pair, create a key in the phone's SSH
181
- app and paste its public key into the panel, so the private key never leaves the phone; for apps
182
- that cannot make their own, simplex can generate a pair instead and shows the private key exactly
183
- once, as text and as a QR code. Either way the panel shows the host, port, username, host-key
184
- fingerprint and local forward to enter in the SSH app (Blink and Termius on iOS, ConnectBot and
185
- JuiceSSH on Android). A paired key opens the whole dashboard, including the
186
- Send and treasury tools, so keep it on the device and revoke it from the same panel if the
187
- device is lost. Keys live under `<data-dir>/tunnel/` in plain OpenSSH formats.
188
-
189
- The hosted relay's host key is pinned in the binary, so first contact is verified. A self-hosted
190
- relay is pinned on first contact unless `relayHostKey` in `[simplex.tunnel]` names its fingerprint.
191
-
192
- The tunnel is best-effort: it retries with backoff and never affects filling. It only runs in
193
- operator mode, never while the setup wizard holds secrets.
125
+ - [Library guide](https://docs.hyperbridge.network/developers/sdk/simplex/)
126
+ - [API reference](https://docs.hyperbridge.network/developers/sdk/api/simplex/)
127
+ - [Configuration](https://docs.hyperbridge.network/developers/evm/simplex/configuration/)
128
+ - [Limit orders](https://docs.hyperbridge.network/developers/evm/simplex/limit-orders/)
129
+ - [Dashboard](https://docs.hyperbridge.network/developers/evm/simplex/dashboard/) and
130
+ [HTTP API](https://docs.hyperbridge.network/developers/evm/simplex/api/overview/)
131
+ - [Troubleshooting](https://docs.hyperbridge.network/developers/evm/simplex/troubleshooting/)
194
132
 
195
133
  ## Development
196
134
 
135
+ This package lives in the [Hyperbridge monorepo](https://github.com/polytope-labs/hyperbridge) at
136
+ `sdk/packages/simplex`.
137
+
197
138
  ```bash
198
139
  pnpm install
199
- pnpm build # library + CLI bundles, then the vite web UI into dist/ui
140
+ pnpm build # library, CLI and dashboard
200
141
  pnpm test
201
- pnpm cli run -c filler-config.toml
202
- pnpm ui:dev # web UI dev server with /api proxied to a running solver
203
142
  ```
204
143
 
205
- The build emits two shapes from one source tree: the library entry points
206
- (`dist/index.js`, `dist/sqlite.js`) leave dependencies external so a consumer resolves one copy of
207
- `viem` and `decimal.js`, while the CLI (`dist/bin/simplex.js`) bundles everything into a single file
208
- so a global install or the docker image runs without a dependency tree.
209
-
210
144
  ## License
211
145
 
212
- Apache-2.0
146
+ [Apache-2.0](https://github.com/polytope-labs/hyperbridge/blob/main/sdk/packages/simplex/LICENSE)