perp-cli 0.12.17 → 0.14.1
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 +247 -27
- package/dist/_stderr-filter.js +0 -1
- package/dist/agent-wallet/lighter-keystore.d.ts +11 -0
- package/dist/agent-wallet/lighter-keystore.js +92 -10
- package/dist/agent-wallet/passphrase.d.ts +1 -1
- package/dist/agent-wallet/passphrase.js +16 -3
- package/dist/agent-wallet/store.d.ts +37 -4
- package/dist/agent-wallet/store.js +132 -0
- package/dist/agent-wallet/venue-keystore.d.ts +14 -0
- package/dist/agent-wallet/venue-keystore.js +121 -0
- package/dist/api/public/hyperliquid.js +4 -4
- package/dist/api/public/lighter.js +5 -5
- package/dist/api/public/pacifica.d.ts +0 -1
- package/dist/api/public/pacifica.js +4 -13
- package/dist/api/public/urls.d.ts +9 -1
- package/dist/api/public/urls.js +35 -13
- package/dist/arb/file-lock.d.ts +11 -0
- package/dist/arb/file-lock.js +74 -0
- package/dist/arb/index.d.ts +2 -2
- package/dist/arb/index.js +2 -2
- package/dist/arb/pending-entry.d.ts +32 -0
- package/dist/arb/pending-entry.js +77 -0
- package/dist/arb/sizing.d.ts +6 -13
- package/dist/arb/sizing.js +12 -51
- package/dist/arb/state.d.ts +45 -12
- package/dist/arb/state.js +214 -42
- package/dist/arb/utils.d.ts +20 -6
- package/dist/arb/utils.js +43 -39
- package/dist/bot/conditions.d.ts +4 -4
- package/dist/bot/conditions.js +11 -6
- package/dist/bot/config.d.ts +17 -1
- package/dist/bot/config.js +48 -12
- package/dist/bot/engine.d.ts +61 -2
- package/dist/bot/engine.js +610 -144
- package/dist/bot/fill-size.d.ts +7 -0
- package/dist/bot/fill-size.js +18 -0
- package/dist/bot/index.d.ts +1 -1
- package/dist/bot/index.js +1 -1
- package/dist/bot/perp-order.d.ts +99 -0
- package/dist/bot/perp-order.js +299 -0
- package/dist/bot/presets.d.ts +7 -0
- package/dist/bot/presets.js +17 -0
- package/dist/bot/quarantine.d.ts +75 -0
- package/dist/bot/quarantine.js +190 -0
- package/dist/bot/quote-rules.d.ts +23 -0
- package/dist/bot/quote-rules.js +69 -0
- package/dist/bot/strategies/avellaneda-mm.d.ts +32 -2
- package/dist/bot/strategies/avellaneda-mm.js +72 -70
- package/dist/bot/strategies/basis-arb.js +2 -0
- package/dist/bot/strategies/dca-strategy.d.ts +2 -0
- package/dist/bot/strategies/dca-strategy.js +5 -0
- package/dist/bot/strategies/funding-arb-strategy.d.ts +43 -3
- package/dist/bot/strategies/funding-arb-strategy.js +571 -380
- package/dist/bot/strategies/funding-arb-utils.d.ts +48 -23
- package/dist/bot/strategies/funding-arb-utils.js +159 -195
- package/dist/bot/strategies/funding-arb-v2.d.ts +32 -0
- package/dist/bot/strategies/funding-arb-v2.js +258 -47
- package/dist/bot/strategies/funding-auto.js +215 -194
- package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +14 -0
- package/dist/bot/strategies/spot-perp-arb-strategy.js +217 -50
- package/dist/bot/strategies/spot-perp-executor.d.ts +73 -19
- package/dist/bot/strategies/spot-perp-executor.js +319 -120
- package/dist/bot/strategies/spot-perp-state.d.ts +43 -0
- package/dist/bot/strategies/spot-perp-state.js +70 -0
- package/dist/bot/strategy-types.d.ts +6 -0
- package/dist/bot/tui/BotDashboard.d.ts +7 -2
- package/dist/bot/tui/BotDashboard.js +6 -3
- package/dist/bridge-engine.d.ts +120 -19
- package/dist/bridge-engine.js +710 -422
- package/dist/bridge-signers.d.ts +54 -0
- package/dist/bridge-signers.js +161 -0
- package/dist/cache.d.ts +4 -1
- package/dist/cache.js +11 -0
- package/dist/cli-flags.d.ts +50 -0
- package/dist/cli-flags.js +104 -0
- package/dist/cli-program.d.ts +35 -0
- package/dist/cli-program.js +303 -0
- package/dist/cli-spec.js +1 -1
- package/dist/client-id-tracker.js +11 -2
- package/dist/commands/account.d.ts +7 -1
- package/dist/commands/account.js +70 -92
- package/dist/commands/agent-import.d.ts +114 -0
- package/dist/commands/agent-import.js +794 -0
- package/dist/commands/agent.d.ts +232 -2
- package/dist/commands/agent.js +1858 -955
- package/dist/commands/alerts.d.ts +1 -0
- package/dist/commands/alerts.js +31 -28
- package/dist/commands/arb/index.d.ts +60 -1
- package/dist/commands/arb/index.js +381 -384
- package/dist/commands/arb-auto.d.ts +132 -4
- package/dist/commands/arb-auto.js +1474 -967
- package/dist/commands/arb.d.ts +3 -1
- package/dist/commands/arb.js +62 -30
- package/dist/commands/bot.js +127 -47
- package/dist/commands/bridge.d.ts +2 -1
- package/dist/commands/bridge.js +339 -192
- package/dist/commands/builder.d.ts +55 -0
- package/dist/commands/builder.js +387 -0
- package/dist/commands/funds-onchain.d.ts +32 -0
- package/dist/commands/funds-onchain.js +248 -0
- package/dist/commands/funds.d.ts +25 -0
- package/dist/commands/funds.js +925 -245
- package/dist/commands/history.js +102 -54
- package/dist/commands/init.d.ts +107 -15
- package/dist/commands/init.js +1116 -249
- package/dist/commands/jobs.d.ts +2 -1
- package/dist/commands/jobs.js +77 -15
- package/dist/commands/manage.js +136 -91
- package/dist/commands/market.d.ts +4 -1
- package/dist/commands/market.js +35 -32
- package/dist/commands/outcome.d.ts +10 -0
- package/dist/commands/outcome.js +396 -0
- package/dist/commands/plan.js +52 -12
- package/dist/commands/portfolio.d.ts +1 -0
- package/dist/commands/portfolio.js +60 -72
- package/dist/commands/rebalance.d.ts +2 -1
- package/dist/commands/rebalance.js +33 -43
- package/dist/commands/risk.js +46 -19
- package/dist/commands/settings.d.ts +1 -0
- package/dist/commands/settings.js +246 -51
- package/dist/commands/trade.d.ts +50 -0
- package/dist/commands/trade.js +1943 -695
- package/dist/commands/wallet.d.ts +30 -1
- package/dist/commands/wallet.js +357 -459
- package/dist/config.d.ts +60 -9
- package/dist/config.js +252 -82
- package/dist/constants.d.ts +29 -4
- package/dist/constants.js +62 -20
- package/dist/dashboard/server.d.ts +2 -0
- package/dist/dashboard/server.js +9 -6
- package/dist/dashboard/ui.js +6 -4
- package/dist/dashboard/ws-feeds.js +20 -8
- package/dist/dex-asset-map.js +5 -3
- package/dist/errors.d.ts +122 -0
- package/dist/errors.js +194 -0
- package/dist/event-stream.js +75 -19
- package/dist/evm-master-tx.d.ts +59 -0
- package/dist/evm-master-tx.js +154 -0
- package/dist/exchanges/adapter-network.d.ts +10 -0
- package/dist/exchanges/adapter-network.js +10 -0
- package/dist/exchanges/arcus/adapter.d.ts +196 -0
- package/dist/exchanges/arcus/adapter.js +1092 -0
- package/dist/exchanges/arcus/agent.d.ts +55 -0
- package/dist/exchanges/arcus/agent.js +188 -0
- package/dist/exchanges/arcus/client.d.ts +63 -0
- package/dist/exchanges/arcus/client.js +285 -0
- package/dist/exchanges/arcus/public.d.ts +65 -0
- package/dist/exchanges/arcus/public.js +138 -0
- package/dist/exchanges/arcus/signing.d.ts +176 -0
- package/dist/exchanges/arcus/signing.js +288 -0
- package/dist/exchanges/arcus/spot-chain.d.ts +60 -0
- package/dist/exchanges/arcus/spot-chain.js +241 -0
- package/dist/exchanges/arcus/spot-router.d.ts +177 -0
- package/dist/exchanges/arcus/spot-router.js +183 -0
- package/dist/exchanges/arcus/spot.d.ts +109 -0
- package/dist/exchanges/arcus/spot.js +645 -0
- package/dist/exchanges/aster-funds.d.ts +127 -0
- package/dist/exchanges/aster-funds.js +252 -0
- package/dist/exchanges/aster-nonce.d.ts +2 -0
- package/dist/exchanges/aster-nonce.js +107 -0
- package/dist/exchanges/aster-spot.d.ts +117 -0
- package/dist/exchanges/aster-spot.js +686 -0
- package/dist/exchanges/aster-typed-data.d.ts +133 -7
- package/dist/exchanges/aster-typed-data.js +121 -7
- package/dist/exchanges/aster.d.ts +240 -6
- package/dist/exchanges/aster.js +1139 -195
- package/dist/exchanges/builder-fee.d.ts +254 -0
- package/dist/exchanges/builder-fee.js +421 -0
- package/dist/exchanges/canonical-symbols.d.ts +32 -0
- package/dist/exchanges/canonical-symbols.js +96 -0
- package/dist/exchanges/capabilities.d.ts +7 -1
- package/dist/exchanges/capabilities.js +7 -0
- package/dist/exchanges/hl-signing.d.ts +165 -0
- package/dist/exchanges/hl-signing.js +158 -0
- package/dist/exchanges/hyperliquid-outcome.d.ts +211 -0
- package/dist/exchanges/hyperliquid-outcome.js +646 -0
- package/dist/exchanges/hyperliquid-spot.d.ts +44 -5
- package/dist/exchanges/hyperliquid-spot.js +308 -117
- package/dist/exchanges/hyperliquid.d.ts +462 -57
- package/dist/exchanges/hyperliquid.js +1575 -449
- package/dist/exchanges/index.d.ts +6 -0
- package/dist/exchanges/index.js +4 -0
- package/dist/exchanges/interface.d.ts +63 -10
- package/dist/exchanges/interface.js +18 -3
- package/dist/exchanges/ioc-outcome.d.ts +44 -0
- package/dist/exchanges/ioc-outcome.js +57 -0
- package/dist/exchanges/legacy-trading-v2.d.ts +39 -0
- package/dist/exchanges/legacy-trading-v2.js +940 -0
- package/dist/exchanges/lighter-public.d.ts +43 -0
- package/dist/exchanges/lighter-public.js +276 -0
- package/dist/exchanges/lighter-rh-deposit.d.ts +62 -0
- package/dist/exchanges/lighter-rh-deposit.js +185 -0
- package/dist/exchanges/lighter-signer.d.ts +123 -0
- package/dist/exchanges/lighter-signer.js +215 -0
- package/dist/exchanges/lighter-spot.d.ts +91 -13
- package/dist/exchanges/lighter-spot.js +595 -233
- package/dist/exchanges/lighter.d.ts +611 -39
- package/dist/exchanges/lighter.js +1890 -649
- package/dist/exchanges/ondo/adapter.d.ts +152 -0
- package/dist/exchanges/ondo/adapter.js +811 -0
- package/dist/exchanges/ondo/agent.d.ts +31 -0
- package/dist/exchanges/ondo/agent.js +101 -0
- package/dist/exchanges/ondo/client.d.ts +60 -0
- package/dist/exchanges/ondo/client.js +297 -0
- package/dist/exchanges/ondo/funds.d.ts +95 -0
- package/dist/exchanges/ondo/funds.js +198 -0
- package/dist/exchanges/ondo/public.d.ts +95 -0
- package/dist/exchanges/ondo/public.js +214 -0
- package/dist/exchanges/ondo/spot.d.ts +127 -0
- package/dist/exchanges/ondo/spot.js +392 -0
- package/dist/exchanges/outcome-interface.d.ts +140 -0
- package/dist/exchanges/outcome-interface.js +16 -0
- package/dist/exchanges/pacifica-spot.d.ts +83 -0
- package/dist/exchanges/pacifica-spot.js +324 -0
- package/dist/exchanges/pacifica-typed-data.d.ts +30 -13
- package/dist/exchanges/pacifica-typed-data.js +57 -9
- package/dist/exchanges/pacifica.d.ts +293 -4
- package/dist/exchanges/pacifica.js +1044 -90
- package/dist/exchanges/precision.d.ts +47 -0
- package/dist/exchanges/precision.js +209 -0
- package/dist/exchanges/qfex/adapter.d.ts +341 -0
- package/dist/exchanges/qfex/adapter.js +1386 -0
- package/dist/exchanges/qfex/agent.d.ts +58 -0
- package/dist/exchanges/qfex/agent.js +188 -0
- package/dist/exchanges/qfex/client.d.ts +54 -0
- package/dist/exchanges/qfex/client.js +138 -0
- package/dist/exchanges/qfex/errors.d.ts +70 -0
- package/dist/exchanges/qfex/errors.js +236 -0
- package/dist/exchanges/qfex/public.d.ts +122 -0
- package/dist/exchanges/qfex/public.js +268 -0
- package/dist/exchanges/qfex/signing.d.ts +160 -0
- package/dist/exchanges/qfex/signing.js +283 -0
- package/dist/exchanges/qfex/ws-transport.d.ts +294 -0
- package/dist/exchanges/qfex/ws-transport.js +798 -0
- package/dist/exchanges/rate-limiter.d.ts +12 -0
- package/dist/exchanges/rate-limiter.js +64 -0
- package/dist/exchanges/registry.d.ts +14 -2
- package/dist/exchanges/registry.js +20 -32
- package/dist/exchanges/slippage.d.ts +37 -0
- package/dist/exchanges/slippage.js +70 -0
- package/dist/exchanges/spot-factory.d.ts +166 -0
- package/dist/exchanges/spot-factory.js +431 -0
- package/dist/exchanges/spot-interface.d.ts +98 -4
- package/dist/exchanges/spot-interface.js +27 -1
- package/dist/exchanges/spot-result.d.ts +79 -0
- package/dist/exchanges/spot-result.js +273 -0
- package/dist/exchanges/trading-v2.d.ts +117 -0
- package/dist/exchanges/trading-v2.js +301 -0
- package/dist/exchanges/venue-types.d.ts +231 -0
- package/dist/exchanges/venue-types.js +87 -0
- package/dist/exchanges/venue.d.ts +211 -0
- package/dist/exchanges/venue.js +132 -0
- package/dist/exchanges/venues/arcus.d.ts +8 -0
- package/dist/exchanges/venues/arcus.js +109 -0
- package/dist/exchanges/venues/aster.d.ts +49 -0
- package/dist/exchanges/venues/aster.js +176 -0
- package/dist/exchanges/venues/create-helpers.d.ts +18 -0
- package/dist/exchanges/venues/create-helpers.js +199 -0
- package/dist/exchanges/venues/hyperliquid.d.ts +23 -0
- package/dist/exchanges/venues/hyperliquid.js +126 -0
- package/dist/exchanges/venues/index.d.ts +16 -0
- package/dist/exchanges/venues/index.js +26 -0
- package/dist/exchanges/venues/lighter-family.d.ts +92 -0
- package/dist/exchanges/venues/lighter-family.js +166 -0
- package/dist/exchanges/venues/lighter-rh.d.ts +7 -0
- package/dist/exchanges/venues/lighter-rh.js +58 -0
- package/dist/exchanges/venues/lighter.d.ts +6 -0
- package/dist/exchanges/venues/lighter.js +55 -0
- package/dist/exchanges/venues/ondo.d.ts +29 -0
- package/dist/exchanges/venues/ondo.js +136 -0
- package/dist/exchanges/venues/pacifica.d.ts +8 -0
- package/dist/exchanges/venues/pacifica.js +95 -0
- package/dist/exchanges/venues/qfex.d.ts +39 -0
- package/dist/exchanges/venues/qfex.js +140 -0
- package/dist/execution-log.js +10 -2
- package/dist/funding/legacy-public.d.ts +31 -0
- package/dist/funding/legacy-public.js +369 -0
- package/dist/funding/normalize.d.ts +28 -16
- package/dist/funding/normalize.js +61 -29
- package/dist/funding/rates.d.ts +46 -11
- package/dist/funding/rates.js +228 -277
- package/dist/guardrail/perp-guardrail.js +0 -0
- package/dist/index.js +156 -684
- package/dist/jobs.d.ts +84 -6
- package/dist/jobs.js +239 -41
- package/dist/landing.d.ts +7 -2
- package/dist/landing.js +19 -3
- package/dist/mcp-server.d.ts +14 -4
- package/dist/mcp-server.js +821 -403
- package/dist/mcp-trade-guard.d.ts +16 -0
- package/dist/mcp-trade-guard.js +59 -0
- package/dist/onchain-balances.d.ts +40 -0
- package/dist/onchain-balances.js +173 -0
- package/dist/pacifica/client.d.ts +41 -10
- package/dist/pacifica/client.js +167 -63
- package/dist/pacifica/constants.d.ts +0 -1
- package/dist/pacifica/constants.js +0 -5
- package/dist/pacifica/deposit.d.ts +30 -3
- package/dist/pacifica/deposit.js +119 -2
- package/dist/pacifica/faucet.d.ts +29 -0
- package/dist/pacifica/faucet.js +100 -0
- package/dist/pacifica/sign-tx.d.ts +15 -0
- package/dist/pacifica/sign-tx.js +41 -0
- package/dist/pacifica/types/account.d.ts +28 -4
- package/dist/pacifica/types/lake.d.ts +20 -5
- package/dist/pacifica/types/lake.js +4 -0
- package/dist/pacifica/types/market.d.ts +5 -0
- package/dist/pacifica/types/order.d.ts +4 -1
- package/dist/pacifica/types/position.d.ts +9 -1
- package/dist/plan-executor.d.ts +10 -5
- package/dist/plan-executor.js +165 -54
- package/dist/position-history.js +13 -0
- package/dist/rebalance.d.ts +26 -2
- package/dist/rebalance.js +86 -7
- package/dist/relay-swap.d.ts +232 -0
- package/dist/relay-swap.js +630 -0
- package/dist/risk.js +5 -1
- package/dist/secret-env.d.ts +15 -0
- package/dist/secret-env.js +36 -0
- package/dist/settings.d.ts +169 -6
- package/dist/settings.js +219 -38
- package/dist/signer/ows-evm.d.ts +13 -0
- package/dist/signer/ows-evm.js +22 -0
- package/dist/smart-order.d.ts +9 -0
- package/dist/smart-order.js +53 -8
- package/dist/strategies/dca.d.ts +6 -2
- package/dist/strategies/dca.js +66 -26
- package/dist/strategies/funding-arb.d.ts +11 -1
- package/dist/strategies/funding-arb.js +202 -89
- package/dist/strategies/grid.d.ts +31 -0
- package/dist/strategies/grid.js +89 -11
- package/dist/strategies/pending-stop.d.ts +8 -0
- package/dist/strategies/pending-stop.js +12 -0
- package/dist/strategies/split-order.d.ts +45 -17
- package/dist/strategies/split-order.js +157 -91
- package/dist/strategies/trailing-stop.d.ts +2 -1
- package/dist/strategies/trailing-stop.js +52 -6
- package/dist/strategies/twap.d.ts +6 -1
- package/dist/strategies/twap.js +39 -11
- package/dist/trade-validator.d.ts +22 -0
- package/dist/trade-validator.js +119 -15
- package/dist/utils/numeric.d.ts +46 -0
- package/dist/utils/numeric.js +79 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +96 -19
- package/dist/withdraw-gate.d.ts +49 -0
- package/dist/withdraw-gate.js +131 -0
- package/package.json +15 -6
- package/skills/perp-cli/SKILL.md +159 -55
- package/skills/perp-cli/references/agent-operations.md +112 -58
- package/skills/perp-cli/references/commands.md +269 -73
- package/skills/perp-cli/references/strategies.md +34 -31
- package/skills/perp-cli/scripts/arb-monitor.sh +10 -5
- package/skills/perp-cli/scripts/funding-analysis.sh +14 -9
- package/skills/perp-cli/scripts/preflight.sh +21 -14
- package/skills/perp-cli/scripts/spot-perp-scan.sh +12 -7
- package/skills/perp-cli/scripts/validate-arb.sh +31 -15
- package/vendor/lighter-signer/SHA256SUMS +2 -0
- package/vendor/lighter-signer/VERSION +8 -0
- package/vendor/lighter-signer/lighter-signer.wasm +0 -0
- package/vendor/lighter-signer/wasm_exec.js +575 -0
- package/dist/bot/strategies/funding-arb-v2-strategy.d.ts +0 -42
- package/dist/bot/strategies/funding-arb-v2-strategy.js +0 -864
package/dist/config.d.ts
CHANGED
|
@@ -1,19 +1,70 @@
|
|
|
1
1
|
import { Keypair } from "@solana/web3.js";
|
|
2
|
-
|
|
2
|
+
import type { Network, VenueId } from "./exchanges/venue-types.js";
|
|
3
|
+
import type { VenueCredentials } from "./exchanges/venue.js";
|
|
4
|
+
/** @deprecated alias — every venue id is an exchange id (design §10.3). */
|
|
5
|
+
export type Exchange = VenueId;
|
|
6
|
+
/** CLI (and MCP) inputs that select credentials. Absent flag = null. */
|
|
7
|
+
export interface CliCredentialOpts {
|
|
8
|
+
privateKey: string | null;
|
|
9
|
+
/** --wallet <name>: OWS wallet, else local wallets.json entry */
|
|
10
|
+
wallet: string | null;
|
|
11
|
+
/** --ows <name> */
|
|
12
|
+
ows: string | null;
|
|
13
|
+
/** --ows-key <token> (or OWS_API_KEY env) */
|
|
14
|
+
owsKey: string | null;
|
|
15
|
+
/** --passphrase <pp> */
|
|
16
|
+
passphrase: string | null;
|
|
17
|
+
}
|
|
18
|
+
export declare const NO_CLI_CREDENTIAL_OPTS: CliCredentialOpts;
|
|
19
|
+
/** True when the OWS vault holds a wallet with this name (no catch: a broken OWS install throws). */
|
|
20
|
+
export declare function owsWalletExists(walletName: string): boolean;
|
|
3
21
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
export declare function tryLoadPrivateKey(exchange: Exchange, pkOverride?: string, walletName?: string): Promise<string | null>;
|
|
8
|
-
/**
|
|
9
|
-
* Resolve an OWS wallet name to a signer-ready marker.
|
|
10
|
-
* Returns the OWS wallet name prefixed with "ows:" so callers can detect OWS mode.
|
|
22
|
+
* Resolve an OWS wallet name to a signer-ready marker ("ows:<name>"), or null
|
|
23
|
+
* when the vault has no such wallet.
|
|
11
24
|
*/
|
|
12
25
|
export declare function resolveOwsWallet(walletName: string): string | null;
|
|
13
26
|
/** Check if a key string represents an OWS wallet reference. */
|
|
14
27
|
export declare function isOwsKey(key: string): boolean;
|
|
15
28
|
/** Extract OWS wallet name from an ows: prefixed key string. */
|
|
16
29
|
export declare function getOwsWalletName(key: string): string;
|
|
17
|
-
|
|
30
|
+
/** CLI/MCP-shared credential resolution (design §10.2). */
|
|
31
|
+
export declare function resolveCredentials(venue: VenueId, opts: CliCredentialOpts, network: Network): Promise<VenueCredentials>;
|
|
32
|
+
/**
|
|
33
|
+
* Whether any credential source is configured for the venue (explicit checks,
|
|
34
|
+
* no catch). true does not mean the source is valid — creating the adapter
|
|
35
|
+
* surfaces that error.
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasCredentials(venue: VenueId, opts: CliCredentialOpts): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Account-role venues (registry order) with a configured credential source —
|
|
40
|
+
* the default set for "all exchanges" aggregate views. Market-data-only venues
|
|
41
|
+
* never qualify.
|
|
42
|
+
*/
|
|
43
|
+
export declare function listConfiguredAccountVenues(opts?: CliCredentialOpts): Promise<VenueId[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Master key for a venue as a string: "ows:<name>" for OWS wallets, else the raw key.
|
|
46
|
+
* Throws NO_ENV_TIER for venues without an env/PK tier when nothing else is configured,
|
|
47
|
+
* and a setup hint when no source exists.
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadPrivateKey(exchange: VenueId, pkOverride?: string, walletName?: string): Promise<string>;
|
|
50
|
+
/** Root-program option values → credential selectors (shared by the CLI adapter factory and master-only commands). */
|
|
51
|
+
export declare function cliCredentialOptsFrom(rootOpts: Record<string, unknown>): CliCredentialOpts;
|
|
52
|
+
/**
|
|
53
|
+
* Commands that only the account owner can sign (deposit, withdraw, transfer, bridge, referral
|
|
54
|
+
* set, agent approve/revoke): refuse up front with NO_SIGNER_AVAILABLE when no master wallet is
|
|
55
|
+
* configured on this machine — e.g. only an agent / API key imported from the exchange website.
|
|
56
|
+
* Never falls back to the agent key (it cannot sign these). A configured-but-missing master
|
|
57
|
+
* (active wallet not in the vault) throws KEY_NOT_FOUND from resolveMasterKey.
|
|
58
|
+
*/
|
|
59
|
+
export declare function requireMasterWallet(venue: VenueId, opts: CliCredentialOpts, action: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* The OWS master wallet selected by the CLI flags / active wallet, with the passphrase that opens
|
|
62
|
+
* it — for on-chain transactions the master signs itself (deposits, bridges). null when the
|
|
63
|
+
* master source is not an OWS wallet (none configured, or a raw private key).
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveOwsMaster(venue: VenueId, opts: CliCredentialOpts): Promise<{
|
|
66
|
+
wallet: string;
|
|
67
|
+
passphrase: string;
|
|
68
|
+
} | null>;
|
|
18
69
|
export declare function parseSolanaKeypair(input: string): Keypair;
|
|
19
70
|
export declare function isEvmPrivateKey(input: string): boolean;
|
package/dist/config.js
CHANGED
|
@@ -4,32 +4,34 @@ import chalk from "chalk";
|
|
|
4
4
|
import { resolve } from "path";
|
|
5
5
|
import { existsSync, readFileSync } from "fs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
|
+
import { PerpError } from "./errors.js";
|
|
8
|
+
import { isLegacyVenueId } from "./exchanges/venue-types.js";
|
|
7
9
|
const _require = createRequire(import.meta.url);
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
+
* Legacy env private-key variables (design §10.3). New venues have no env tier:
|
|
12
|
+
* loadPrivateKey()/resolveCredentials() never read env keys for them.
|
|
13
|
+
* v0.12.10 restored ASTER_PRIVATE_KEY so Aster Tier 3 env-PK loading works.
|
|
11
14
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const envMap = {
|
|
16
|
+
pacifica: ["PACIFICA_PRIVATE_KEY", "pk"],
|
|
17
|
+
hyperliquid: ["HYPERLIQUID_PRIVATE_KEY", "HL_PRIVATE_KEY"],
|
|
18
|
+
lighter: ["LIGHTER_PRIVATE_KEY"],
|
|
19
|
+
aster: ["ASTER_PRIVATE_KEY"],
|
|
20
|
+
};
|
|
21
|
+
export const NO_CLI_CREDENTIAL_OPTS = {
|
|
22
|
+
privateKey: null, wallet: null, ows: null, owsKey: null, passphrase: null,
|
|
23
|
+
};
|
|
24
|
+
/** True when the OWS vault holds a wallet with this name (no catch: a broken OWS install throws). */
|
|
25
|
+
export function owsWalletExists(walletName) {
|
|
26
|
+
const { listWallets } = _require("@open-wallet-standard/core");
|
|
27
|
+
return listWallets().some((w) => w.name === walletName);
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
21
|
-
* Resolve an OWS wallet name to a signer-ready marker
|
|
22
|
-
*
|
|
30
|
+
* Resolve an OWS wallet name to a signer-ready marker ("ows:<name>"), or null
|
|
31
|
+
* when the vault has no such wallet.
|
|
23
32
|
*/
|
|
24
33
|
export function resolveOwsWallet(walletName) {
|
|
25
|
-
|
|
26
|
-
const { getWallet } = _require("@open-wallet-standard/core");
|
|
27
|
-
getWallet(walletName); // throws if not found
|
|
28
|
-
return `ows:${walletName}`;
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
34
|
+
return owsWalletExists(walletName) ? `ows:${walletName}` : null;
|
|
33
35
|
}
|
|
34
36
|
/** Check if a key string represents an OWS wallet reference. */
|
|
35
37
|
export function isOwsKey(key) {
|
|
@@ -39,80 +41,248 @@ export function isOwsKey(key) {
|
|
|
39
41
|
export function getOwsWalletName(key) {
|
|
40
42
|
return key.slice(4);
|
|
41
43
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
function legacyKeyFile(venue) {
|
|
45
|
+
return resolve(process.env.HOME || "~", ".perp", `${venue}.key`);
|
|
46
|
+
}
|
|
47
|
+
function envKeyOf(venue) {
|
|
48
|
+
for (const envVar of envMap[venue] ?? []) {
|
|
49
|
+
const v = process.env[envVar];
|
|
50
|
+
if (v)
|
|
51
|
+
return v;
|
|
46
52
|
}
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
// config.ts generic PRIVATE_KEY — recorded as out of scope in §10.11, legacy venues only.
|
|
54
|
+
const generic = process.env.PRIVATE_KEY;
|
|
55
|
+
return generic ? generic : null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The master key source for a venue, in precedence order:
|
|
59
|
+
* --ows → --wallet (OWS, else local wallets.json) → --private-key →
|
|
60
|
+
* settings.owsActiveWallet → [legacy venues only] env → wallets.json active → ~/.perp/<venue>.key
|
|
61
|
+
* Returns null only when no source is configured. A configured source that
|
|
62
|
+
* cannot be resolved throws (SSOT Rule #2).
|
|
63
|
+
*/
|
|
64
|
+
async function resolveMasterKey(venue, opts) {
|
|
65
|
+
if (opts.ows !== null)
|
|
66
|
+
return { kind: "ows", wallet: opts.ows };
|
|
67
|
+
if (opts.wallet !== null) {
|
|
68
|
+
if (owsWalletExists(opts.wallet))
|
|
69
|
+
return { kind: "ows", wallet: opts.wallet };
|
|
54
70
|
const { getWalletKeyByName } = await import("./commands/wallet.js");
|
|
55
|
-
const key = getWalletKeyByName(
|
|
71
|
+
const key = getWalletKeyByName(opts.wallet);
|
|
56
72
|
if (!key)
|
|
57
|
-
throw new
|
|
58
|
-
return key;
|
|
73
|
+
throw new PerpError("KEY_NOT_FOUND", `Wallet "${opts.wallet}" not found`, { remediation: "Run: perp wallet list" });
|
|
74
|
+
return { kind: "pk", key };
|
|
59
75
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (owsKey)
|
|
70
|
-
return owsKey;
|
|
76
|
+
if (opts.privateKey !== null)
|
|
77
|
+
return { kind: "pk", key: opts.privateKey };
|
|
78
|
+
const { loadSettings } = await import("./settings.js");
|
|
79
|
+
const active = loadSettings().owsActiveWallet;
|
|
80
|
+
if (active) {
|
|
81
|
+
if (!owsWalletExists(active)) {
|
|
82
|
+
throw new PerpError("KEY_NOT_FOUND", `Active OWS wallet "${active}" is not in the OWS vault`, {
|
|
83
|
+
remediation: "Run: perp wallet list, then select an existing wallet (perp wallet use <name>)",
|
|
84
|
+
});
|
|
71
85
|
}
|
|
86
|
+
return { kind: "ows", wallet: active };
|
|
72
87
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return walletKey;
|
|
88
|
+
if (!isLegacyVenueId(venue))
|
|
89
|
+
return null;
|
|
90
|
+
const envKey = envKeyOf(venue);
|
|
91
|
+
if (envKey !== null)
|
|
92
|
+
return { kind: "pk", key: envKey };
|
|
93
|
+
const { getActiveWalletKey } = await import("./commands/wallet.js");
|
|
94
|
+
const walletKey = getActiveWalletKey(venue);
|
|
95
|
+
if (walletKey)
|
|
96
|
+
return { kind: "pk", key: walletKey };
|
|
97
|
+
const keyFile = legacyKeyFile(venue);
|
|
98
|
+
if (existsSync(keyFile))
|
|
99
|
+
return { kind: "pk", key: readFileSync(keyFile, "utf-8").trim() };
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
/** Registered agent meta for a venue (any network), or null — presence check only. */
|
|
103
|
+
async function agentOf(venue) {
|
|
104
|
+
const store = await import("./agent-wallet/store.js");
|
|
105
|
+
switch (venue) {
|
|
106
|
+
case "ondo": return store.getVenueAgent("ondo");
|
|
107
|
+
case "arcus": return store.getVenueAgent("arcus");
|
|
108
|
+
case "qfex": return store.getVenueAgent("qfex");
|
|
109
|
+
case "pacifica":
|
|
110
|
+
case "hyperliquid":
|
|
111
|
+
case "lighter":
|
|
112
|
+
case "lighter-rh":
|
|
113
|
+
case "aster":
|
|
114
|
+
return store.getAgent(venue);
|
|
101
115
|
}
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Agent meta to sign with on `network`. Legacy-shaped agents are selected by
|
|
119
|
+
* their recorded network (a mainnet agent is never handed to a testnet adapter).
|
|
120
|
+
* Ondo / Arcus metas are selected by their `network` field the same way.
|
|
121
|
+
*/
|
|
122
|
+
async function agentForNetwork(venue, network) {
|
|
123
|
+
const store = await import("./agent-wallet/store.js");
|
|
124
|
+
switch (venue) {
|
|
125
|
+
case "ondo": return store.getVenueAgentForNetwork("ondo", network);
|
|
126
|
+
case "arcus": return store.getVenueAgentForNetwork("arcus", network);
|
|
127
|
+
case "qfex": return store.getVenueAgentForNetwork("qfex", network);
|
|
128
|
+
case "pacifica":
|
|
129
|
+
case "hyperliquid":
|
|
130
|
+
case "lighter":
|
|
131
|
+
case "lighter-rh":
|
|
132
|
+
case "aster":
|
|
133
|
+
return store.getAgentForNetwork(venue, network);
|
|
104
134
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Passphrase that opens an OWS master wallet. Precedence between explicit
|
|
138
|
+
* user inputs: --ows-key token (routes through the OWS policy engine) →
|
|
139
|
+
* --passphrase → OWS_PASSPHRASE env. None given → "" (the OWS empty
|
|
140
|
+
* passphrase; this is what the pre-venue OWS path always used).
|
|
141
|
+
*/
|
|
142
|
+
function owsPassphraseOf(opts) {
|
|
143
|
+
if (opts.owsKey !== null)
|
|
144
|
+
return opts.owsKey;
|
|
145
|
+
if (opts.passphrase !== null)
|
|
146
|
+
return opts.passphrase;
|
|
147
|
+
if ("OWS_PASSPHRASE" in process.env)
|
|
148
|
+
return process.env.OWS_PASSPHRASE ?? "";
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
function owsKeyTokenOf(opts) {
|
|
152
|
+
if (opts.owsKey !== null)
|
|
153
|
+
return opts.owsKey;
|
|
154
|
+
// OWS_API_KEY env: recorded as out of scope in §10.11 (kept as before).
|
|
155
|
+
const env = process.env.OWS_API_KEY;
|
|
156
|
+
return env ? env : null;
|
|
157
|
+
}
|
|
158
|
+
/** CLI/MCP-shared credential resolution (design §10.2). */
|
|
159
|
+
export async function resolveCredentials(venue, opts, network) {
|
|
160
|
+
const withToken = { ...opts, owsKey: owsKeyTokenOf(opts) };
|
|
161
|
+
// Custodial venues (masterKeyKind "none": qfex) have no master key to resolve.
|
|
162
|
+
const { ensureVenuesRegistered } = await import("./exchanges/venues/index.js");
|
|
163
|
+
const { getVenue } = await import("./exchanges/venue.js");
|
|
164
|
+
ensureVenuesRegistered();
|
|
165
|
+
const master = getVenue(venue).masterKeyKind === "none" ? null : await resolveMasterKey(venue, withToken);
|
|
166
|
+
return {
|
|
167
|
+
pk: master?.kind === "pk" ? master.key : null,
|
|
168
|
+
owsWallet: master?.kind === "ows" ? master.wallet : null,
|
|
169
|
+
owsPassphrase: master?.kind === "ows" ? owsPassphraseOf(withToken) : null,
|
|
170
|
+
owsKeyToken: withToken.owsKey,
|
|
171
|
+
agent: await agentForNetwork(venue, network),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Whether any credential source is configured for the venue (explicit checks,
|
|
176
|
+
* no catch). true does not mean the source is valid — creating the adapter
|
|
177
|
+
* surfaces that error.
|
|
178
|
+
*/
|
|
179
|
+
export async function hasCredentials(venue, opts) {
|
|
180
|
+
// A venue without any owner-wallet signing path (qfex: custodial, API key only) is configured
|
|
181
|
+
// only by an imported key — a master wallet / private key is not a credential for it.
|
|
182
|
+
const { ensureVenuesRegistered } = await import("./exchanges/venues/index.js");
|
|
183
|
+
const { getVenue } = await import("./exchanges/venue.js");
|
|
184
|
+
ensureVenuesRegistered();
|
|
185
|
+
if (getVenue(venue).masterKeyKind === "none")
|
|
186
|
+
return (await agentOf(venue)) !== null;
|
|
187
|
+
if (opts.ows !== null || opts.wallet !== null || opts.privateKey !== null)
|
|
188
|
+
return true;
|
|
189
|
+
if ((await agentOf(venue)) !== null)
|
|
190
|
+
return true;
|
|
191
|
+
const { loadSettings } = await import("./settings.js");
|
|
192
|
+
if (loadSettings().owsActiveWallet)
|
|
193
|
+
return true;
|
|
194
|
+
if (!isLegacyVenueId(venue))
|
|
195
|
+
return false;
|
|
196
|
+
if (envKeyOf(venue) !== null)
|
|
197
|
+
return true;
|
|
198
|
+
const { getActiveWalletKey } = await import("./commands/wallet.js");
|
|
199
|
+
if (getActiveWalletKey(venue))
|
|
200
|
+
return true;
|
|
201
|
+
return existsSync(legacyKeyFile(venue));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Account-role venues (registry order) with a configured credential source —
|
|
205
|
+
* the default set for "all exchanges" aggregate views. Market-data-only venues
|
|
206
|
+
* never qualify.
|
|
207
|
+
*/
|
|
208
|
+
export async function listConfiguredAccountVenues(opts = NO_CLI_CREDENTIAL_OPTS) {
|
|
209
|
+
const { ensureVenuesRegistered } = await import("./exchanges/venues/index.js");
|
|
210
|
+
const { listVenuesWithRole } = await import("./exchanges/venue.js");
|
|
211
|
+
ensureVenuesRegistered();
|
|
212
|
+
const venues = listVenuesWithRole("account").map(v => v.id);
|
|
213
|
+
const configured = await Promise.all(venues.map(v => hasCredentials(v, opts)));
|
|
214
|
+
return venues.filter((_, i) => configured[i]);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Master key for a venue as a string: "ows:<name>" for OWS wallets, else the raw key.
|
|
218
|
+
* Throws NO_ENV_TIER for venues without an env/PK tier when nothing else is configured,
|
|
219
|
+
* and a setup hint when no source exists.
|
|
220
|
+
*/
|
|
221
|
+
export async function loadPrivateKey(exchange, pkOverride, walletName) {
|
|
222
|
+
const opts = {
|
|
223
|
+
...NO_CLI_CREDENTIAL_OPTS,
|
|
224
|
+
privateKey: pkOverride ?? null,
|
|
225
|
+
ows: walletName?.startsWith("ows:") ? walletName.slice(4) : null,
|
|
226
|
+
wallet: walletName && !walletName.startsWith("ows:") ? walletName : null,
|
|
227
|
+
};
|
|
228
|
+
const master = await resolveMasterKey(exchange, opts);
|
|
229
|
+
if (master?.kind === "ows")
|
|
230
|
+
return `ows:${master.wallet}`;
|
|
231
|
+
if (master?.kind === "pk")
|
|
232
|
+
return master.key;
|
|
233
|
+
if (!isLegacyVenueId(exchange)) {
|
|
234
|
+
throw new PerpError("NO_ENV_TIER", `${exchange} has no env/private-key tier`, {
|
|
235
|
+
remediation: `Use an OWS wallet (perp wallet generate, then --ows <name>) or register an agent: perp wallet agent approve ${exchange}`,
|
|
236
|
+
});
|
|
109
237
|
}
|
|
110
|
-
throw new
|
|
238
|
+
throw new PerpError("NO_SIGNER_AVAILABLE", `No wallet configured for ${exchange}.\n\n` +
|
|
111
239
|
` Quick start: ${chalk.cyan("perp wallet generate")}\n\n` +
|
|
112
240
|
` Or manually:\n` +
|
|
113
|
-
` perp wallet import
|
|
114
|
-
` perp wallet set ${exchange}
|
|
115
|
-
|
|
241
|
+
` perp wallet import Import key to OWS vault (hidden prompt / stdin)\n` +
|
|
242
|
+
` perp wallet set ${exchange} Import key (hidden prompt / stdin) to OWS vault`, { exchange, remediation: masterMissingRemediation(exchange) });
|
|
243
|
+
}
|
|
244
|
+
/** Root-program option values → credential selectors (shared by the CLI adapter factory and master-only commands). */
|
|
245
|
+
export function cliCredentialOptsFrom(rootOpts) {
|
|
246
|
+
const str = (v) => (typeof v === "string" ? v : null);
|
|
247
|
+
return {
|
|
248
|
+
privateKey: str(rootOpts.privateKey),
|
|
249
|
+
wallet: str(rootOpts.wallet),
|
|
250
|
+
ows: str(rootOpts.ows),
|
|
251
|
+
owsKey: str(rootOpts.owsKey),
|
|
252
|
+
passphrase: str(rootOpts.passphrase),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function masterMissingRemediation(venue) {
|
|
256
|
+
const chain = venue === "pacifica" ? "solana" : "evm";
|
|
257
|
+
return `Do this on the exchange website, or add the master wallet to this computer: perp wallet import --name <name> --chain ${chain} (hidden prompt / stdin), then perp wallet use <name> (or pass --ows <name>). An imported agent / API key can trade but cannot move funds.`;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Commands that only the account owner can sign (deposit, withdraw, transfer, bridge, referral
|
|
261
|
+
* set, agent approve/revoke): refuse up front with NO_SIGNER_AVAILABLE when no master wallet is
|
|
262
|
+
* configured on this machine — e.g. only an agent / API key imported from the exchange website.
|
|
263
|
+
* Never falls back to the agent key (it cannot sign these). A configured-but-missing master
|
|
264
|
+
* (active wallet not in the vault) throws KEY_NOT_FOUND from resolveMasterKey.
|
|
265
|
+
*/
|
|
266
|
+
export async function requireMasterWallet(venue, opts, action) {
|
|
267
|
+
const master = await resolveMasterKey(venue, { ...opts, owsKey: owsKeyTokenOf(opts) });
|
|
268
|
+
if (master !== null)
|
|
269
|
+
return;
|
|
270
|
+
throw new PerpError("NO_SIGNER_AVAILABLE", `${action} needs the ${venue} master wallet, which is not on this computer`, {
|
|
271
|
+
exchange: venue,
|
|
272
|
+
remediation: masterMissingRemediation(venue),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* The OWS master wallet selected by the CLI flags / active wallet, with the passphrase that opens
|
|
277
|
+
* it — for on-chain transactions the master signs itself (deposits, bridges). null when the
|
|
278
|
+
* master source is not an OWS wallet (none configured, or a raw private key).
|
|
279
|
+
*/
|
|
280
|
+
export async function resolveOwsMaster(venue, opts) {
|
|
281
|
+
const withToken = { ...opts, owsKey: owsKeyTokenOf(opts) };
|
|
282
|
+
const master = await resolveMasterKey(venue, withToken);
|
|
283
|
+
if (master === null || master.kind !== "ows")
|
|
284
|
+
return null;
|
|
285
|
+
return { wallet: master.wallet, passphrase: owsPassphraseOf(withToken) };
|
|
116
286
|
}
|
|
117
287
|
export function parseSolanaKeypair(input) {
|
|
118
288
|
// Try base58 first
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared constants for perp-cli.
|
|
3
3
|
*/
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Published taker fee per venue (fraction, e.g. 0.00035 = 0.035%) — configuration, not a
|
|
6
|
+
* fallback (SSOT Rule #2 shipped defaults): used when settings.fees has no entry for the venue.
|
|
7
|
+
*/
|
|
5
8
|
export declare const TAKER_FEES: Record<string, number>;
|
|
6
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Published maker fee per venue (fraction; negative = rebate). Only venues whose base-tier
|
|
11
|
+
* maker rate is published and verified are listed; others resolve to 0 in getMakerFee().
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAKER_FEES: Record<string, number>;
|
|
14
|
+
/**
|
|
15
|
+
* Taker fee for a venue: settings.fees[venue].taker → TAKER_FEES[venue] → DEFAULT_TAKER_FEE
|
|
16
|
+
* (estimate for venues without a published entry). loadSettings() errors (malformed
|
|
17
|
+
* settings.json) propagate — never replaced by the built-in fees.
|
|
18
|
+
*/
|
|
7
19
|
export declare function getTakerFee(exchange: string): number;
|
|
8
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Maker fee for a venue: settings.fees[venue].maker → MAKER_FEES[venue] → 0 (no maker fee
|
|
22
|
+
* published/configured). loadSettings() errors propagate.
|
|
23
|
+
*/
|
|
9
24
|
export declare function getMakerFee(exchange: string): number;
|
|
10
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Taker-fee estimate for an id with no TAKER_FEES entry. Every venue id in VENUE_IDS has
|
|
27
|
+
* a published entry above, so this applies only to genuinely unknown ids — e.g. arb-auto's
|
|
28
|
+
* getTakerFee("default") and trade-validator's venue-agnostic notional fee estimate.
|
|
29
|
+
*/
|
|
11
30
|
export declare const DEFAULT_TAKER_FEE = 0.00035;
|
|
31
|
+
/**
|
|
32
|
+
* Hyperliquid's minimum order value, venue-wide (native perps and HIP-3 dexes): the venue refuses
|
|
33
|
+
* smaller orders with "Order must have minimum value of $10". It is a documented constant, not a
|
|
34
|
+
* field of `meta` / `metaAndAssetCtxs`, so it is the one order minimum that lives in code.
|
|
35
|
+
*/
|
|
36
|
+
export declare const HL_MIN_ORDER_VALUE_USD = "10";
|
package/dist/constants.js
CHANGED
|
@@ -2,36 +2,78 @@
|
|
|
2
2
|
* Shared constants for perp-cli.
|
|
3
3
|
*/
|
|
4
4
|
import { loadSettings } from "./settings.js";
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Published taker fee per venue (fraction, e.g. 0.00035 = 0.035%) — configuration, not a
|
|
7
|
+
* fallback (SSOT Rule #2 shipped defaults): used when settings.fees has no entry for the venue.
|
|
8
|
+
*/
|
|
6
9
|
export const TAKER_FEES = {
|
|
7
10
|
hyperliquid: 0.00035,
|
|
8
11
|
pacifica: 0.00035,
|
|
9
12
|
lighter: 0,
|
|
10
13
|
aster: 0.0004, // 0.04% taker fee
|
|
14
|
+
// Ondo Perps base rate (docs.ondoperps.xyz/fees, 2026-10-02): taker 5 bps. A limited-time
|
|
15
|
+
// 50% promotion (2.5 bps) is NOT assumed — it can end without notice; set
|
|
16
|
+
// settings.fees.ondo to use the promotional or a volume-tier rate.
|
|
17
|
+
ondo: 0.0005,
|
|
18
|
+
// Arcus mainnet tier 0 "Base" (GET https://api.arcus.xyz/v1/feetiers, read 2026-10-02):
|
|
19
|
+
// taker_fee_ppm 225. The docs publish no rates ("read fees from the API"); higher-volume
|
|
20
|
+
// tiers are cheaper (Bronze 190 … Max 95 ppm). Testnet Base differs (450 ppm).
|
|
21
|
+
arcus: 0.000225,
|
|
22
|
+
// Lighter RH "Standard" (default) account tier: 0% / 0% (apidocs.lighter.xyz lighter-rh).
|
|
23
|
+
// "Plus" is 0.005%/0.005%; "Premium" is 0.0120%/0.0350% (maker/taker) down to
|
|
24
|
+
// 0.0084%/0.0245% by 14-day volume — Premium accounts must set settings.fees["lighter-rh"].
|
|
25
|
+
"lighter-rh": 0,
|
|
26
|
+
// QFEX entry tier ("Tier 5", < $2m 30-day effective volume; docs.qfex.com/qfex/fees, read
|
|
27
|
+
// 2026-10-04): taker 0.10% on single stocks — the HIGHEST class rate, so index / commodity
|
|
28
|
+
// orders (0.05%) are never under-estimated. Lower tiers / the lifetime-tier promotion: set
|
|
29
|
+
// settings.fees.qfex.
|
|
30
|
+
qfex: 0.001,
|
|
11
31
|
};
|
|
12
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Published maker fee per venue (fraction; negative = rebate). Only venues whose base-tier
|
|
34
|
+
* maker rate is published and verified are listed; others resolve to 0 in getMakerFee().
|
|
35
|
+
*/
|
|
36
|
+
export const MAKER_FEES = {
|
|
37
|
+
ondo: 0.0002, // base 2 bps; promotional 1 bp not assumed (see TAKER_FEES.ondo)
|
|
38
|
+
arcus: 0, // mainnet Base tier maker_fee_ppm 0
|
|
39
|
+
// Aster perpetuals, Crypto — General (docs.asterdex.com trading/perpetuals/fees-and-specs/fees,
|
|
40
|
+
// read 2026-10-02): maker 0%, taker 0.04% (TAKER_FEES.aster). RWA markets: maker 0 bps.
|
|
41
|
+
aster: 0,
|
|
42
|
+
"lighter-rh": 0, // Standard tier (Premium: 0.012% under $1M 14-day volume)
|
|
43
|
+
qfex: 0.0005, // Tier 5 single stocks 0.05% (indices / commodities 0.02%); see TAKER_FEES.qfex
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Taker fee for a venue: settings.fees[venue].taker → TAKER_FEES[venue] → DEFAULT_TAKER_FEE
|
|
47
|
+
* (estimate for venues without a published entry). loadSettings() errors (malformed
|
|
48
|
+
* settings.json) propagate — never replaced by the built-in fees.
|
|
49
|
+
*/
|
|
13
50
|
export function getTakerFee(exchange) {
|
|
14
51
|
const key = exchange.toLowerCase();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
catch { /* fallback to hardcoded */ }
|
|
22
|
-
return TAKER_FEES[key] ?? 0.00035;
|
|
52
|
+
const configured = loadSettings().fees[key]?.taker;
|
|
53
|
+
if (configured !== undefined)
|
|
54
|
+
return configured;
|
|
55
|
+
return TAKER_FEES[key] ?? DEFAULT_TAKER_FEE;
|
|
23
56
|
}
|
|
24
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Maker fee for a venue: settings.fees[venue].maker → MAKER_FEES[venue] → 0 (no maker fee
|
|
59
|
+
* published/configured). loadSettings() errors propagate.
|
|
60
|
+
*/
|
|
25
61
|
export function getMakerFee(exchange) {
|
|
26
62
|
const key = exchange.toLowerCase();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch { /* fallback */ }
|
|
34
|
-
return 0;
|
|
63
|
+
const configured = loadSettings().fees[key]?.maker;
|
|
64
|
+
if (configured !== undefined)
|
|
65
|
+
return configured;
|
|
66
|
+
return MAKER_FEES[key] ?? 0;
|
|
35
67
|
}
|
|
36
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Taker-fee estimate for an id with no TAKER_FEES entry. Every venue id in VENUE_IDS has
|
|
70
|
+
* a published entry above, so this applies only to genuinely unknown ids — e.g. arb-auto's
|
|
71
|
+
* getTakerFee("default") and trade-validator's venue-agnostic notional fee estimate.
|
|
72
|
+
*/
|
|
37
73
|
export const DEFAULT_TAKER_FEE = 0.00035;
|
|
74
|
+
/**
|
|
75
|
+
* Hyperliquid's minimum order value, venue-wide (native perps and HIP-3 dexes): the venue refuses
|
|
76
|
+
* smaller orders with "Order must have minimum value of $10". It is a documented constant, not a
|
|
77
|
+
* field of `meta` / `metaAndAssetCtxs`, so it is the one order minimum that lives in code.
|
|
78
|
+
*/
|
|
79
|
+
export const HL_MIN_ORDER_VALUE_USD = "10";
|
|
@@ -63,6 +63,8 @@ export interface DashboardSnapshot {
|
|
|
63
63
|
dexAssets: DexAssetRow[];
|
|
64
64
|
dexNames: string[];
|
|
65
65
|
exchangeStatus: Record<string, string>;
|
|
66
|
+
/** Error message per venue (or "funding" when the whole fetch failed). */
|
|
67
|
+
exchangeErrors: Record<string, string>;
|
|
66
68
|
};
|
|
67
69
|
}
|
|
68
70
|
export interface DashboardOpts {
|
package/dist/dashboard/server.js
CHANGED
|
@@ -9,7 +9,7 @@ import { WebSocketServer, WebSocket } from "ws";
|
|
|
9
9
|
import { getUI } from "./ui.js";
|
|
10
10
|
import { WsFeedManager } from "./ws-feeds.js";
|
|
11
11
|
// Cached arb data (polled less frequently)
|
|
12
|
-
let cachedArb = { opportunities: [], dexArb: [], dexAssets: [], dexNames: [], exchangeStatus: {} };
|
|
12
|
+
let cachedArb = { opportunities: [], dexArb: [], dexAssets: [], dexNames: [], exchangeStatus: {}, exchangeErrors: {} };
|
|
13
13
|
// Cached market data (polled with arb cycle — market metadata rarely changes)
|
|
14
14
|
const cachedMarkets = new Map();
|
|
15
15
|
/**
|
|
@@ -40,10 +40,12 @@ async function pollArbData() {
|
|
|
40
40
|
const opportunities = [];
|
|
41
41
|
const dexArb = [];
|
|
42
42
|
let exchangeStatus = {};
|
|
43
|
+
let exchangeErrors = {};
|
|
43
44
|
try {
|
|
44
45
|
const { fetchAllFundingRates } = await import("../funding/rates.js");
|
|
45
46
|
const snapshot = await fetchAllFundingRates({ minSpread: 5 });
|
|
46
47
|
exchangeStatus = snapshot.exchangeStatus;
|
|
48
|
+
exchangeErrors = snapshot.exchangeErrors;
|
|
47
49
|
for (const sym of snapshot.symbols.slice(0, 20)) {
|
|
48
50
|
opportunities.push({
|
|
49
51
|
symbol: sym.symbol,
|
|
@@ -60,8 +62,9 @@ async function pollArbData() {
|
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
|
-
catch {
|
|
64
|
-
|
|
65
|
+
catch (e) {
|
|
66
|
+
exchangeStatus = { funding: "error" };
|
|
67
|
+
exchangeErrors = { funding: e instanceof Error ? e.message : String(e) };
|
|
65
68
|
}
|
|
66
69
|
const dexAssets = [];
|
|
67
70
|
const dexNamesSet = new Set();
|
|
@@ -95,8 +98,8 @@ async function pollArbData() {
|
|
|
95
98
|
const row = {
|
|
96
99
|
base,
|
|
97
100
|
dexes: assets.map((a) => {
|
|
98
|
-
//
|
|
99
|
-
const ann = annualizeRate(a.fundingRate, "hyperliquid");
|
|
101
|
+
// Venue ref: "hyperliquid" for native, "hl:<dex>" for HIP-3 (same basis, §10.1)
|
|
102
|
+
const ann = annualizeRate(a.fundingRate, a.dex === "hl" ? "hyperliquid" : `hl:${a.dex}`);
|
|
100
103
|
return { dex: a.dex, rate: a.fundingRate, annualizedPct: ann, markPrice: a.markPrice, oi: a.openInterest };
|
|
101
104
|
}),
|
|
102
105
|
};
|
|
@@ -113,7 +116,7 @@ async function pollArbData() {
|
|
|
113
116
|
// dex arb unavailable
|
|
114
117
|
}
|
|
115
118
|
const dexNames = [...dexNamesSet].sort();
|
|
116
|
-
return { opportunities, dexArb, dexAssets: dexAssets.slice(0, 30), dexNames, exchangeStatus };
|
|
119
|
+
return { opportunities, dexArb, dexAssets: dexAssets.slice(0, 30), dexNames, exchangeStatus, exchangeErrors };
|
|
117
120
|
}
|
|
118
121
|
/**
|
|
119
122
|
* Poll all exchanges and return a unified snapshot.
|