vike
ReferenceBinaries

Venue setup tools

Two one-off operator binaries that arrange something at a venue before trading — cTrader's OAuth catcher and Hyperliquid's builder-fee grant.

Two binaries in this workspace are neither daemons nor front ends: they are one-off setup steps a human runs once against a venue, and then never again. Both are deliberately separate from the mount path — nothing in the live execution path invokes either.

ctrader_authorize — the OAuth catcher

cTrader's Open API is OAuth2, which normally means copying a ?code= out of a browser address bar and pasting it into a shell. crates/bridges/ctrader/src/bin/ctrader_authorize.rs removes that round trip. It starts a plain HTTP server on http://localhost:5033/, prints the authorize URL, blocks for the browser's redirect, exchanges the code for a vike_ctrader::oauth::Token in the same process, prints the token redacted, and writes it to <project>/settings/state/ctrader_token.json in the venue's own camelCase wire shape.

Its inputs come from the environment and never from argv: CTRADER_CLIENT_ID and CTRADER_CLIENT_SECRET are required; CTRADER_REDIRECT_URI defaults to the localhost address above and CTRADER_SCOPE to trading. Output is raw println! rather than tracing — the workspace convention for a tool whose stdout is a result.

The file it writes holds a live access and refresh token, and the module header records what changed after that was noticed. It used to be written as token.json in the process working directory with no resolver at all, so a live credential landed wherever the binary happened to be started from — frequently a world-readable directory on a server. Now the path resolves $CTRADER_TOKEN_FILE → <project>/settings/state/ctrader_token.json → ./token.json, and it is written owner-only (0600) on unix on every rung, including the working-directory fallback. The token's value is never printed or logged, only a redacted head and tail, and the tool never reads, moves or deletes a pre-existing token.json: a box that has one keeps it, untouched and unread.

The JSON file is read by nothing — copy the pair into the credential store

Nothing in the tree reads that file. The grant lives in <project>/settings/secrets.env on CTRADER_{TIER}_ACCESS_TOKEN and _REFRESH_TOKEN, and nowhere else — it is a credential, so it lives where credentials live, and there is deliberately no second source of truth to rank against it. settings/state/ctrader_token.json is this binary's own output record and stays that. After an authorize run you copy the pair into secrets.env yourself, and that hand-copy is now the only manual step in the loop.

Everything after that copy is automatic. A refresh is persisted back through the byte-preserving upsert that replaces exactly those two keys and leaves every comment, blank line and unrelated key verbatim — and both keys move together, because cTrader rotates the refresh token on every refresh. An expired grant self-heals at startup by spending the refresh token once and retrying the handshake; a healthy daemon refreshes ahead of the lapse on its heartbeat tick. See cTrader.

hyperliquid_builder_fee_approve — the builder-fee grant

Hyperliquid lets an order carry a builder's code, and separately lets that builder charge a fee. The fee needs a standing on-chain grant first, and crates/bridges/hyperliquid/src/bin/hyperliquid_builder_fee_approve.rs is the one-time tool that makes it. It is gated behind the builder-fee-approve feature: never built by default, never invoked from the live exec or mount path.

Its arguments are a builder address and a maximum fee rate, plus an optional --mainnet. <max_fee_rate> is Hyperliquid's percentage-string shape, e.g. "0.01%". The private key comes from HYPERLIQUID_{DEMO,LIVE}_PRIVATE_KEY in the credential store — never argv, never logs. --mainnet selects the LIVE tier and real funds; its absence selects DEMO and testnet.

crates/bridges/hyperliquid/src/builder_fee.rs states the two things worth carrying before you run it. It is a standing grant, not a per-order action: run it once per (account, builder, rate) tuple, not on every submit. And attribution-only mounts never need it at all — a builder fee of zero, which is this workspace's default and is resolved at mount time, requires no prior approval, because Hyperliquid only gates a nonzero fee.

Master wallet only, and the grant is not live-verified

Unlike other user-signed actions, Hyperliquid requires the grant to come from the master account's own key: an agent wallet is approved for builder-coded orders, it cannot approve a builder's fee on the account's behalf. Passing an agent key signs a well-formed but venue-rejected request — or worse, silently approves nothing, since the recovered signer address will not match the account. The binary therefore refuses to run when HYPERLIQUID_{tier}_ACCOUNT_ADDRESS is set, because that shape means the loaded key is an agent or API wallet.

The module also declares itself unverified live: the signing path is faithful to the venue's own SDK, but it has no golden vector and has not been round-tripped against the venue. Its tests prove the wire shape and field order, and that the produced signature recovers the signer's own address. They do not prove the venue accepts it, and a real testnet round trip is owed before trusting it with a live grant.

See Hyperliquid for the attribution row itself, and environment variables for where the credential keys are read.

On this page