perp-cli 0.12.17 → 0.14.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 +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 +286 -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 +286 -0
- package/dist/commands/funds.d.ts +25 -0
- package/dist/commands/funds.js +939 -245
- package/dist/commands/history.js +72 -45
- 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 +316 -337
- 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 +219 -6
- package/dist/exchanges/aster.js +1023 -153
- 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 +166 -0
- package/dist/exchanges/ondo/adapter.js +835 -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 +122 -0
- package/dist/exchanges/ondo/funds.js +290 -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 +288 -4
- package/dist/exchanges/pacifica.js +1013 -76
- 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 +1383 -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 +34 -0
- package/dist/exchanges/venues/ondo.js +140 -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 +28 -0
- package/dist/exchanges/venues/qfex.js +132 -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 +820 -402
- package/dist/mcp-trade-guard.d.ts +16 -0
- package/dist/mcp-trade-guard.js +59 -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 +142 -55
- package/skills/perp-cli/references/agent-operations.md +110 -56
- package/skills/perp-cli/references/commands.md +266 -71
- 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
|
@@ -1,7 +1,76 @@
|
|
|
1
|
+
import { unsupported } from "../exchanges/trading-v2.js";
|
|
1
2
|
import chalk from "chalk";
|
|
2
3
|
import { printJson, jsonOk, withJsonErrors } from "../utils.js";
|
|
3
|
-
import { loadSettings, saveSettings } from "../settings.js";
|
|
4
|
+
import { loadSettings, saveSettings, SHIPPED_DEFAULT_SLIPPAGE_BPS } from "../settings.js";
|
|
4
5
|
import { ENV_FILE, loadEnvFile, setEnvVar, EXCHANGE_ENV_MAP, validateKey } from "./init.js";
|
|
6
|
+
import { getVenue, resolveVenueId } from "../exchanges/venue.js";
|
|
7
|
+
import "../exchanges/venues/index.js";
|
|
8
|
+
import { maxDefaultSlippageBps, parseSlippageSettingBps } from "../exchanges/slippage.js";
|
|
9
|
+
import { PerpError } from "../errors.js";
|
|
10
|
+
import { isSecretEnvName } from "../secret-env.js";
|
|
11
|
+
import { BUILDER_FEE_CAPABILITIES, parseBuilderEntry, requireBuilderCapability } from "../exchanges/builder-fee.js";
|
|
12
|
+
import { validateDebridgeAffiliate, validateWithdrawGate, WITHDRAW_GATE_VENUES } from "../settings.js";
|
|
13
|
+
import { confirmWithdrawGateChange } from "../withdraw-gate.js";
|
|
14
|
+
const invalidParam = (problem) => new PerpError("INVALID_PARAMS", problem, {
|
|
15
|
+
remediation: "perp settings set builder.<venue> <address|code>,<feeBps> (e.g. builder.hyperliquid 0xabc…,1)",
|
|
16
|
+
});
|
|
17
|
+
/** `builder.<venue>` value "<address|code>,<feeBps>" → validated settings entry. */
|
|
18
|
+
function builderEntryOf(key, value) {
|
|
19
|
+
const venue = getVenue(key.slice("builder.".length)).id;
|
|
20
|
+
const cap = requireBuilderCapability(venue);
|
|
21
|
+
if (cap.feeKind === "share") {
|
|
22
|
+
// Fee share (QFEX): the code only — there is no user-paid fee to configure.
|
|
23
|
+
const entry = { code: value.trim() };
|
|
24
|
+
parseBuilderEntry(venue, entry, problem => new PerpError("INVALID_PARAMS", problem, {
|
|
25
|
+
remediation: `perp settings set builder.${venue} <uuid> (the builder code only — ${venue} builder codes share the venue fee; no feeBps)`,
|
|
26
|
+
}));
|
|
27
|
+
return { venue, entry };
|
|
28
|
+
}
|
|
29
|
+
const parts = value.split(",");
|
|
30
|
+
if (parts.length !== 2)
|
|
31
|
+
throw invalidParam(`${key} value must be "<${cap.identity}>,<feeBps>" (got "${value}")`);
|
|
32
|
+
const fee = Number(parts[1].trim());
|
|
33
|
+
const entry = { [cap.identity]: parts[0].trim(), feeBps: parts[1].trim() === "" ? NaN : fee };
|
|
34
|
+
parseBuilderEntry(venue, entry, invalidParam); // strict: identity format, fee > 0, ≤ venue cap, venue increment
|
|
35
|
+
return { venue, entry };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* L5: a builder.<venue> value charges the USER on every perp order, so setting one needs an
|
|
39
|
+
* explicit y/N (or --yes) that shows the fee. Non-interactive / --json without --yes is refused.
|
|
40
|
+
*/
|
|
41
|
+
async function confirmBuilderSetting(venue, entry, yes, json) {
|
|
42
|
+
if (yes)
|
|
43
|
+
return;
|
|
44
|
+
const cap = requireBuilderCapability(getVenue(venue).id);
|
|
45
|
+
const fee = `${cap.feeKind === "max" ? "up to " : ""}${String(entry.feeBps)} bps`;
|
|
46
|
+
const share = cap.feeKind === "share";
|
|
47
|
+
const what = share
|
|
48
|
+
? `builder.${venue} = ${String(entry.code)}: your ${venue} fills are attributed to ${String(entry.code)}; you pay the normal fee (the venue shares part of it with the builder — no extra charge; attached to the trading connection from the next order)`
|
|
49
|
+
: `builder.${venue} = ${String(entry[cap.identity])} charges ${fee} on YOUR ${venue} perp orders (paid by you, to the builder${cap.approval === "none" ? "; no venue approval step — attached from the next order" : ""})`;
|
|
50
|
+
if (json || process.stdin.isTTY !== true) {
|
|
51
|
+
throw new PerpError("INVALID_PARAMS", `Setting a builder ${share ? "code" : "fee"} needs explicit confirmation: ${what}`, {
|
|
52
|
+
remediation: `Re-run with --yes to confirm: perp settings set builder.${venue} ${share ? "<uuid>" : `<${cap.identity}>,<feeBps>`} --yes`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const { createInterface } = await import("node:readline/promises");
|
|
56
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
57
|
+
try {
|
|
58
|
+
const a = (await rl.question(` ${what}. Save? [y/N]: `)).trim().toLowerCase();
|
|
59
|
+
if (a !== "y" && a !== "yes")
|
|
60
|
+
throw new PerpError("INVALID_PARAMS", `builder.${venue} not set — cancelled, nothing was saved`);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
rl.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Parse `slippageBps.<venue>` → venue id (aliases accepted). Throws UNKNOWN_VENUE. */
|
|
67
|
+
function slippageVenueOf(key) {
|
|
68
|
+
const venue = getVenue(key.slice("slippageBps.".length));
|
|
69
|
+
if (venue.capabilities === null) {
|
|
70
|
+
throw unsupported(venue.displayName, "trading", "no trading API, so slippageBps does not apply", "Set slippageBps only for trading venues");
|
|
71
|
+
}
|
|
72
|
+
return venue.id;
|
|
73
|
+
}
|
|
5
74
|
// Resolve exchange alias → env var key
|
|
6
75
|
function resolveEnvKey(nameOrKey) {
|
|
7
76
|
// Direct env var name
|
|
@@ -30,15 +99,36 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
30
99
|
.action(async () => {
|
|
31
100
|
await withJsonErrors(isJson(), async () => {
|
|
32
101
|
const s = loadSettings();
|
|
102
|
+
const defaultSlippageShipped = s.defaultSlippageBps === SHIPPED_DEFAULT_SLIPPAGE_BPS;
|
|
33
103
|
if (isJson())
|
|
34
|
-
return printJson(jsonOk(s));
|
|
104
|
+
return printJson(jsonOk({ ...s, defaultSlippageBpsSource: defaultSlippageShipped ? "shipped default" : "user" }));
|
|
35
105
|
console.log(chalk.cyan.bold("\n CLI Settings\n"));
|
|
36
106
|
console.log(` Default Exchange: ${s.defaultExchange ? chalk.cyan(s.defaultExchange) : chalk.gray("pacifica (built-in)")}`);
|
|
37
|
-
console.log(
|
|
38
|
-
console.log(chalk.white.bold("\n Referral Codes:"));
|
|
39
|
-
console.log(` Pacifica: ${s.referralCodes.pacifica || chalk.gray("(none)")}`);
|
|
107
|
+
console.log(chalk.white.bold("\n Referral Codes (bound only by an explicit `wallet manage referral set`):"));
|
|
40
108
|
console.log(` Hyperliquid: ${s.referralCodes.hyperliquid || chalk.gray("(none)")}`);
|
|
41
109
|
console.log(` Lighter: ${s.referralCodes.lighter || chalk.gray("(none)")}`);
|
|
110
|
+
console.log(chalk.white.bold("\n Builder fees (off unless set; attached only after venue approval):"));
|
|
111
|
+
const builderEntries = Object.entries(s.builder);
|
|
112
|
+
if (builderEntries.length === 0)
|
|
113
|
+
console.log(chalk.gray(" (none — no builder fee is attached on any venue)"));
|
|
114
|
+
for (const [v, e] of builderEntries) {
|
|
115
|
+
const id = "address" in e ? e.address : e.code;
|
|
116
|
+
const fee = "feeBps" in e ? `${e.feeBps} bps` : "fee share (you pay the normal fee)";
|
|
117
|
+
console.log(` ${v.padEnd(14)} ${id} ${fee}${BUILDER_FEE_CAPABILITIES[v]?.feeKind === "max" ? " (max)" : ""}`);
|
|
118
|
+
}
|
|
119
|
+
console.log(chalk.white.bold("\n Withdraw gate (qfex: API-key withdrawals; hyperliquid: withdraw / transfer to a non-owner address; off unless set):"));
|
|
120
|
+
const gates = Object.entries(s.withdraw);
|
|
121
|
+
if (gates.length === 0)
|
|
122
|
+
console.log(chalk.gray(` (none — gated withdrawals on ${WITHDRAW_GATE_VENUES.join(", ")} are refused; Hyperliquid to the owner's own address is always allowed)`));
|
|
123
|
+
for (const [v, g] of gates)
|
|
124
|
+
console.log(` ${v.padEnd(14)} max ${g.maxPerTx}/tx, ${g.maxPerDay}/day → ${g.allowlist.join(", ")}`);
|
|
125
|
+
const aff = s.bridge.debridgeAffiliate;
|
|
126
|
+
console.log(` deBridge affiliate: ${aff === null ? chalk.gray("(none)") : `referral ${aff.referralCode ?? "-"} · fee ${aff.feePercent === null ? "none" : `${aff.feePercent}% → ${aff.feeRecipient}`}`}`);
|
|
127
|
+
console.log(chalk.white.bold("\n Slippage bound (bps) — market / close / trigger orders:"));
|
|
128
|
+
console.log(` ${"default".padEnd(14)} ${s.defaultSlippageBps}${defaultSlippageShipped ? chalk.gray(" (shipped default)") : ""}`);
|
|
129
|
+
for (const [v, bps] of Object.entries(s.slippageBps))
|
|
130
|
+
console.log(` ${v.padEnd(14)} ${bps}`);
|
|
131
|
+
console.log(chalk.gray(" precedence: --slippage-bps → slippageBps.<venue> → default"));
|
|
42
132
|
console.log(chalk.white.bold("\n Fee Tiers:"));
|
|
43
133
|
for (const [ex, fee] of Object.entries(s.fees)) {
|
|
44
134
|
const tPct = (fee.taker * 100).toFixed(4);
|
|
@@ -48,10 +138,9 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
48
138
|
console.log(chalk.gray(`\n Config: ~/.perp/settings.json\n`));
|
|
49
139
|
});
|
|
50
140
|
});
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// perp settings set referralApplied.hyperliquid false (and same for lighter)
|
|
141
|
+
// HL / Lighter referral codes are applied only by the explicit
|
|
142
|
+
// `perp -e <hyperliquid|lighter> wallet manage referral set [code]` (never on
|
|
143
|
+
// adapter creation). referralCodes.<venue> is that command's default code.
|
|
55
144
|
// ── settings fees ──
|
|
56
145
|
// Bare `settings fees` shows current tiers (same as `settings fees show`).
|
|
57
146
|
const showFees = async () => {
|
|
@@ -79,16 +168,18 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
79
168
|
.action(showFees);
|
|
80
169
|
fees
|
|
81
170
|
.command("sync")
|
|
82
|
-
.description("Fetch fee tiers from exchange APIs and save")
|
|
83
|
-
.
|
|
84
|
-
.action(async (opts) => {
|
|
171
|
+
.description("Fetch fee tiers from exchange APIs and save (-e <exchange> to sync only one)")
|
|
172
|
+
.action(async () => {
|
|
85
173
|
await withJsonErrors(isJson(), async () => {
|
|
174
|
+
// -e/--exchange is the root option: read it there only when it was passed on the command
|
|
175
|
+
// line (never the root's default venue — no flag means "all").
|
|
176
|
+
const only = program.getOptionValueSource("exchange") === "cli" ? String(program.opts().exchange) : undefined;
|
|
86
177
|
if (!getAdapterForExchange) {
|
|
87
178
|
console.error(chalk.red(" Fee sync requires exchange adapters. Set up keys first with `perp setup`."));
|
|
88
179
|
return;
|
|
89
180
|
}
|
|
90
181
|
const s = loadSettings();
|
|
91
|
-
const exchanges =
|
|
182
|
+
const exchanges = only !== undefined ? [only.toLowerCase()] : ["hyperliquid", "pacifica", "lighter"];
|
|
92
183
|
const results = {};
|
|
93
184
|
for (const ex of exchanges) {
|
|
94
185
|
try {
|
|
@@ -186,16 +277,55 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
186
277
|
.description("Set a specific setting")
|
|
187
278
|
.argument("<key>", "Setting key (e.g. referralCodes.hyperliquid)")
|
|
188
279
|
.argument("<value>", "Setting value")
|
|
189
|
-
.
|
|
280
|
+
.option("--yes", "Confirm a builder.<venue> fee without the y/N prompt")
|
|
281
|
+
.action(async (key, value, opts) => {
|
|
190
282
|
await withJsonErrors(isJson(), async () => {
|
|
191
283
|
const s = loadSettings();
|
|
192
284
|
if (key === "default-exchange" || key === "defaultExchange") {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
285
|
+
s.defaultExchange = resolveVenueId(value);
|
|
286
|
+
}
|
|
287
|
+
else if (key === "defaultSlippageBps") {
|
|
288
|
+
s.defaultSlippageBps = parseSlippageSettingBps(key, value, maxDefaultSlippageBps());
|
|
289
|
+
}
|
|
290
|
+
else if (key.startsWith("slippageBps.")) {
|
|
291
|
+
const venue = slippageVenueOf(key);
|
|
292
|
+
s.slippageBps[venue] = parseSlippageSettingBps(key, value, getVenue(venue).maxSlippageBps);
|
|
293
|
+
}
|
|
294
|
+
else if (key.startsWith("builder.")) {
|
|
295
|
+
const { venue, entry } = builderEntryOf(key, value);
|
|
296
|
+
await confirmBuilderSetting(venue, entry, opts.yes === true, isJson());
|
|
297
|
+
s.builder[venue] = entry;
|
|
298
|
+
}
|
|
299
|
+
else if (key.startsWith("withdraw.")) {
|
|
300
|
+
// settings.withdraw.<venue> = "<address[+address…]>,<maxPerTx>,<maxPerDay>". Changing the
|
|
301
|
+
// allowlist / limits needs an interactive terminal confirmation — no --yes, never --json.
|
|
302
|
+
const venue = getVenue(key.slice("withdraw.".length)).id;
|
|
303
|
+
const parts = value.split(",");
|
|
304
|
+
if (parts.length !== 3) {
|
|
305
|
+
throw new PerpError("INVALID_PARAMS", `${key} value must be "<address[+address…]>,<maxPerTx>,<maxPerDay>" (got "${value}")`, {
|
|
306
|
+
remediation: `e.g. perp settings set withdraw.${venue} 0xYourWallet,100,500`,
|
|
307
|
+
});
|
|
197
308
|
}
|
|
198
|
-
|
|
309
|
+
const num = (raw) => (raw.trim() === "" ? NaN : Number(raw.trim()));
|
|
310
|
+
const gate = validateWithdrawGate(venue, {
|
|
311
|
+
allowlist: parts[0].split("+").map(a => a.trim()).filter(a => a !== ""), maxPerTx: num(parts[1]), maxPerDay: num(parts[2]),
|
|
312
|
+
}, problem => new PerpError("INVALID_PARAMS", problem));
|
|
313
|
+
await confirmWithdrawGateChange(venue, gate, isJson());
|
|
314
|
+
s.withdraw[venue] = gate;
|
|
315
|
+
}
|
|
316
|
+
else if (key === "bridge.debridgeAffiliate.referralCode" || key === "bridge.debridgeAffiliate.fee") {
|
|
317
|
+
const cur = s.bridge.debridgeAffiliate ?? { referralCode: null, feePercent: null, feeRecipient: null };
|
|
318
|
+
let next;
|
|
319
|
+
if (key.endsWith(".referralCode")) {
|
|
320
|
+
next = { ...cur, referralCode: value };
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
const parts = value.split(",");
|
|
324
|
+
if (parts.length !== 2)
|
|
325
|
+
throw invalidParam(`${key} value must be "<percent>,<recipient>" (got "${value}")`);
|
|
326
|
+
next = { ...cur, feePercent: parts[0].trim() === "" ? NaN : Number(parts[0].trim()), feeRecipient: parts[1].trim() };
|
|
327
|
+
}
|
|
328
|
+
s.bridge.debridgeAffiliate = validateDebridgeAffiliate(next, invalidParam);
|
|
199
329
|
}
|
|
200
330
|
else if (key.startsWith("referralCodes.")) {
|
|
201
331
|
const exchange = key.split(".")[1];
|
|
@@ -208,7 +338,7 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
208
338
|
}
|
|
209
339
|
}
|
|
210
340
|
else if (key.startsWith("referralApplied.")) {
|
|
211
|
-
//
|
|
341
|
+
// Bookkeeping only (set by `wallet manage referral set`).
|
|
212
342
|
const exchange = key.split(".")[1];
|
|
213
343
|
if (exchange in s.referralApplied) {
|
|
214
344
|
s.referralApplied[exchange] = value === "true" || value === "on";
|
|
@@ -220,13 +350,88 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
220
350
|
}
|
|
221
351
|
else {
|
|
222
352
|
console.error(chalk.red(` Unknown key: ${key}`));
|
|
223
|
-
console.log(chalk.gray(" Valid keys: default-exchange, referralCodes.{
|
|
353
|
+
console.log(chalk.gray(" Valid keys: default-exchange, referralCodes.{hyperliquid,lighter}, referralApplied.{hyperliquid,lighter}, defaultSlippageBps, slippageBps.<venue>, builder.<venue>, withdraw.<venue>, bridge.debridgeAffiliate.{referralCode,fee}\n"));
|
|
224
354
|
return;
|
|
225
355
|
}
|
|
226
356
|
saveSettings(s);
|
|
227
357
|
if (isJson())
|
|
228
358
|
return printJson(jsonOk({ key, value }));
|
|
229
359
|
console.log(chalk.green(`\n ${key} = ${value}\n`));
|
|
360
|
+
if (key.startsWith("builder.")) {
|
|
361
|
+
const venue = getVenue(key.slice("builder.".length)).id;
|
|
362
|
+
const cap = requireBuilderCapability(venue);
|
|
363
|
+
if (cap.feeKind === "share") {
|
|
364
|
+
console.log(chalk.yellow(` Your ${venue} fills are attributed to this builder code; you pay the normal fee (no extra charge).`));
|
|
365
|
+
console.log(chalk.gray(` Attribution cannot be confirmed from the trader side. Disable per command with --no-builder; remove with: perp settings unset builder.${venue}\n`));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
console.log(chalk.yellow(` This adds a builder fee to YOUR ${venue} perp orders (paid by you, to the builder).`));
|
|
369
|
+
console.log(chalk.gray(cap.approval === "master"
|
|
370
|
+
? ` Nothing is attached until the venue approval is confirmed: perp wallet builder approve ${venue}\n Disable per command with --no-builder; remove with: perp settings unset builder.${venue}\n`
|
|
371
|
+
: ` ${venue} needs no approval — the fee is attached from the next order.\n Disable per command with --no-builder; remove with: perp settings unset builder.${venue}\n`));
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
// ── settings unset ──
|
|
376
|
+
settings
|
|
377
|
+
.command("unset")
|
|
378
|
+
.description("Remove a setting (slippageBps.<venue>, builder.<venue>, withdraw.<venue>, bridge.debridgeAffiliate; defaultSlippageBps restores the shipped default)")
|
|
379
|
+
.argument("<key>", "Setting key (e.g. slippageBps.ondo)")
|
|
380
|
+
.action(async (key) => {
|
|
381
|
+
await withJsonErrors(isJson(), async () => {
|
|
382
|
+
if (key === "defaultSlippageBps") {
|
|
383
|
+
const s = loadSettings();
|
|
384
|
+
s.defaultSlippageBps = SHIPPED_DEFAULT_SLIPPAGE_BPS;
|
|
385
|
+
saveSettings(s);
|
|
386
|
+
if (isJson())
|
|
387
|
+
return printJson(jsonOk({ key, value: SHIPPED_DEFAULT_SLIPPAGE_BPS, source: "shipped default" }));
|
|
388
|
+
console.log(chalk.green(`\n defaultSlippageBps = ${SHIPPED_DEFAULT_SLIPPAGE_BPS} (shipped default)\n`));
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (key.startsWith("builder.")) {
|
|
392
|
+
const venue = getVenue(key.slice("builder.".length)).id;
|
|
393
|
+
const s = loadSettings();
|
|
394
|
+
const existed = s.builder[venue] !== undefined;
|
|
395
|
+
delete s.builder[venue];
|
|
396
|
+
saveSettings(s);
|
|
397
|
+
if (isJson())
|
|
398
|
+
return printJson(jsonOk({ key: `builder.${venue}`, removed: existed }));
|
|
399
|
+
console.log(existed ? chalk.green(`\n builder.${venue} removed — no builder fee is attached on ${venue}\n`) : chalk.gray(`\n builder.${venue} was not set\n`));
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (key.startsWith("withdraw.")) {
|
|
403
|
+
// Removing the gate turns API-key withdrawals OFF for that venue — no confirmation needed.
|
|
404
|
+
const venue = getVenue(key.slice("withdraw.".length)).id;
|
|
405
|
+
const s = loadSettings();
|
|
406
|
+
const existed = s.withdraw[venue] !== undefined;
|
|
407
|
+
delete s.withdraw[venue];
|
|
408
|
+
saveSettings(s);
|
|
409
|
+
if (isJson())
|
|
410
|
+
return printJson(jsonOk({ key: `withdraw.${venue}`, removed: existed }));
|
|
411
|
+
console.log(existed ? chalk.green(`\n withdraw.${venue} removed — withdrawals on ${venue} are refused until it is set again\n`) : chalk.gray(`\n withdraw.${venue} was not set\n`));
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (key === "bridge.debridgeAffiliate") {
|
|
415
|
+
const s = loadSettings();
|
|
416
|
+
const existed = s.bridge.debridgeAffiliate !== null;
|
|
417
|
+
s.bridge.debridgeAffiliate = null;
|
|
418
|
+
saveSettings(s);
|
|
419
|
+
if (isJson())
|
|
420
|
+
return printJson(jsonOk({ key, removed: existed }));
|
|
421
|
+
console.log(existed ? chalk.green(`\n ${key} removed\n`) : chalk.gray(`\n ${key} was not set\n`));
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (!key.startsWith("slippageBps.")) {
|
|
425
|
+
throw new PerpError("INVALID_PARAMS", `Cannot unset "${key}"`, { remediation: "Unsettable keys: defaultSlippageBps, slippageBps.<venue>, builder.<venue>, withdraw.<venue>, bridge.debridgeAffiliate" });
|
|
426
|
+
}
|
|
427
|
+
const venue = slippageVenueOf(key);
|
|
428
|
+
const s = loadSettings();
|
|
429
|
+
const existed = s.slippageBps[venue] !== undefined;
|
|
430
|
+
delete s.slippageBps[venue];
|
|
431
|
+
saveSettings(s);
|
|
432
|
+
if (isJson())
|
|
433
|
+
return printJson(jsonOk({ key: `slippageBps.${venue}`, removed: existed }));
|
|
434
|
+
console.log(existed ? chalk.green(`\n slippageBps.${venue} removed\n`) : chalk.gray(`\n slippageBps.${venue} was not set\n`));
|
|
230
435
|
});
|
|
231
436
|
});
|
|
232
437
|
// ── settings env ──
|
|
@@ -261,7 +466,7 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
261
466
|
console.log(chalk.cyan.bold("\n perp-cli Configuration\n"));
|
|
262
467
|
console.log(` File: ${chalk.gray(ENV_FILE)}\n`);
|
|
263
468
|
if (results.length === 0) {
|
|
264
|
-
console.log(chalk.gray(" No keys
|
|
469
|
+
console.log(chalk.gray(" No legacy keys in ~/.perp/.env. Import keys into the OWS vault: 'perp wallet set <exchange>'\n"));
|
|
265
470
|
return;
|
|
266
471
|
}
|
|
267
472
|
for (const { name, address, source } of results) {
|
|
@@ -269,41 +474,29 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
269
474
|
}
|
|
270
475
|
console.log();
|
|
271
476
|
});
|
|
272
|
-
// ── settings env set <
|
|
477
|
+
// ── settings env set <name> <value> ──
|
|
478
|
+
// Non-secret values only (e.g. LIGHTER_REFERRAL_CODE). SSOT Rule #3: key material is never
|
|
479
|
+
// written to ~/.perp/.env nor accepted on argv — exchange keys go to the OWS vault.
|
|
273
480
|
env
|
|
274
481
|
.command("set <name> <value>")
|
|
275
|
-
.description("Set a
|
|
482
|
+
.description("Set a non-secret env value in ~/.perp/.env (private keys are refused: use 'perp wallet set <exchange>')")
|
|
276
483
|
.action(async (name, value) => {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
console.error(chalk.red(`\n Invalid ${resolved.chain} private key.\n`));
|
|
287
|
-
process.exit(1);
|
|
484
|
+
await withJsonErrors(isJson(), async () => {
|
|
485
|
+
const resolved = resolveEnvKey(name);
|
|
486
|
+
if (resolved !== null || isSecretEnvName(name)) {
|
|
487
|
+
throw new PerpError("INVALID_PARAMS", `Refusing to write ${resolved?.envKey ?? name} to ~/.perp/.env: key material is never stored in plaintext or accepted on the command line`, {
|
|
488
|
+
remediation: resolved !== null
|
|
489
|
+
? "Import the key into the OWS vault: perp wallet set <exchange> (hidden prompt or stdin). Clear the key from your shell history."
|
|
490
|
+
: "Secrets live in the OWS vault (perp wallet set / perp wallet import) or agent keystores (perp wallet agent approve <venue>). Clear the value from your shell history.",
|
|
491
|
+
});
|
|
288
492
|
}
|
|
289
|
-
|
|
290
|
-
? (value.startsWith("0x") ? value : `0x${value}`)
|
|
291
|
-
: value;
|
|
292
|
-
setEnvVar(resolved.envKey, normalized);
|
|
293
|
-
if (isJson())
|
|
294
|
-
return printJson(jsonOk({ key: resolved.envKey, address, file: ENV_FILE }));
|
|
295
|
-
console.log(chalk.green(`\n ${resolved.envKey} set.`));
|
|
296
|
-
console.log(` Address: ${chalk.gray(address)}`);
|
|
297
|
-
console.log(` File: ${chalk.gray("~/.perp/.env")}\n`);
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
// Raw env var (e.g. LIGHTER_REFERRAL_CODE, custom vars)
|
|
493
|
+
// Raw non-secret env var (e.g. LIGHTER_REFERRAL_CODE, custom vars)
|
|
301
494
|
setEnvVar(name, value);
|
|
302
495
|
if (isJson())
|
|
303
496
|
return printJson(jsonOk({ key: name, file: ENV_FILE }));
|
|
304
497
|
console.log(chalk.green(`\n ${name} set.`));
|
|
305
498
|
console.log(` File: ${chalk.gray("~/.perp/.env")}\n`);
|
|
306
|
-
}
|
|
499
|
+
});
|
|
307
500
|
});
|
|
308
501
|
// ── settings env remove <name> ──
|
|
309
502
|
env
|
|
@@ -323,12 +516,14 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
323
516
|
}
|
|
324
517
|
delete env[envKey];
|
|
325
518
|
// Rewrite file
|
|
326
|
-
|
|
519
|
+
// Atomic write with an explicit 0600 (writeFileSync's mode only applies when creating the file:
|
|
520
|
+
// a rewrite would keep looser permissions of an existing .env).
|
|
521
|
+
const { writeKeystoreAtomic } = await import("../agent-wallet/venue-keystore.js");
|
|
327
522
|
const lines = ["# perp-cli configuration", "# Generated by 'perp setup' — edit freely", ""];
|
|
328
523
|
for (const [k, v] of Object.entries(env))
|
|
329
524
|
lines.push(`${k}=${v}`);
|
|
330
525
|
lines.push("");
|
|
331
|
-
|
|
526
|
+
writeKeystoreAtomic(ENV_FILE, lines.join("\n"));
|
|
332
527
|
if (isJson())
|
|
333
528
|
return printJson(jsonOk({ removed: envKey }));
|
|
334
529
|
console.log(chalk.yellow(`\n ${envKey} removed from ~/.perp/.env\n`));
|
|
@@ -351,7 +546,7 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
|
|
|
351
546
|
console.log(chalk.yellow("\n 'perp env' is deprecated. Use 'perp settings env' instead.\n"));
|
|
352
547
|
console.log(chalk.gray(" Examples:"));
|
|
353
548
|
console.log(chalk.gray(" perp settings env show"));
|
|
354
|
-
console.log(chalk.gray(" perp settings env set <
|
|
549
|
+
console.log(chalk.gray(" perp settings env set <name> <value> (non-secret values only)"));
|
|
355
550
|
console.log(chalk.gray(" perp settings env remove <name>"));
|
|
356
551
|
console.log(chalk.gray(" perp settings env path\n"));
|
|
357
552
|
});
|
package/dist/commands/trade.d.ts
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import type { ExchangeAdapter } from "../exchanges/index.js";
|
|
3
|
+
import { PerpError } from "../errors.js";
|
|
4
|
+
import "../exchanges/venues/index.js";
|
|
5
|
+
import { type CancelResult } from "../exchanges/venue-types.js";
|
|
6
|
+
/**
|
|
7
|
+
* A cancel with anything not proven cancelled (failed, or pending / still listed open after the
|
|
8
|
+
* verifying re-list) → ORDER_PARTIAL carrying the whole result (non-zero exit, also in --json);
|
|
9
|
+
* all failed (none cancelled, none pending) → ORDER_REJECTED (definitely nothing cancelled).
|
|
10
|
+
*/
|
|
11
|
+
export declare function cancelIncompleteError(r: CancelResult, scope: string): PerpError | null;
|
|
12
|
+
/**
|
|
13
|
+
* Sizes of scaled levels on the venue lot grid: the total is floored to `step`, each level is
|
|
14
|
+
* floor(total × pct / 100) lots and the LAST level takes the remainder — so every level is a
|
|
15
|
+
* multiple of the lot and the levels sum to the floored total. An off-lot level is refused by the
|
|
16
|
+
* venue (Pacifica 422 "Limit order amount 0.00205 is not a multiple of lot size"; Lighter 21706
|
|
17
|
+
* "invalid order base or quote amount" for 0.01475 TSLA at 4 size decimals). A level of zero lots
|
|
18
|
+
* → SIZE_TOO_SMALL.
|
|
19
|
+
*/
|
|
20
|
+
export declare function scaleLevelSizes(total: string, pcts: readonly number[], step: string): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Refuse (SIZE_TOO_SMALL, nothing sent) a scaled order with a level under the venue's published
|
|
23
|
+
* minimum order size / notional (VenueMarket.minSize / minNotional; null = none published on this
|
|
24
|
+
* data path → not checked). Reduce-only levels are held to it too: no venue's docs state an
|
|
25
|
+
* exemption (Pacifica market-info: `min_order_size` "Minimum order size (denominated in USD)",
|
|
26
|
+
* no exception listed).
|
|
27
|
+
*/
|
|
28
|
+
export declare function requireScaleLevelMinimums(venue: string, symbol: string, levels: ReadonlyArray<{
|
|
29
|
+
price: string;
|
|
30
|
+
size: string;
|
|
31
|
+
}>, min: {
|
|
32
|
+
minSize: string | null;
|
|
33
|
+
minNotional: string | null;
|
|
34
|
+
}): void;
|
|
35
|
+
/** Outcome of one scaled level: placed, definitely refused, unknown (may exist), or never sent. */
|
|
36
|
+
export interface ScaleLevelOutcome {
|
|
37
|
+
price: string;
|
|
38
|
+
size: string;
|
|
39
|
+
pct: number;
|
|
40
|
+
outcome: "placed" | "rejected" | "unknown" | "notSent";
|
|
41
|
+
result: Record<string, unknown> | {
|
|
42
|
+
error: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The failure a scaled order reports unless every level was placed: any unknown outcome →
|
|
47
|
+
* ORDER_PENDING; every level definitely refused → ORDER_REJECTED; otherwise ORDER_PARTIAL.
|
|
48
|
+
* details list the placed / failed / unknown / not-sent levels.
|
|
49
|
+
*/
|
|
50
|
+
export declare function scaleIncompleteError(venue: string, what: string, levels: readonly ScaleLevelOutcome[]): PerpError | null;
|
|
51
|
+
/** One-arg `trade cancel <x>`: true when x is an order id (numeric, UUID or 0x-hex), never a symbol. */
|
|
52
|
+
export declare function looksLikeOrderId(x: string): boolean;
|
|
3
53
|
export declare function registerTradeCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, isDryRun?: () => boolean, getAdapterForExchange?: (exchange: string) => Promise<ExchangeAdapter>): void;
|