perp-cli 0.11.0 → 0.12.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 +30 -25
- package/dist/_stderr-filter.d.ts +0 -0
- package/dist/_stderr-filter.js +30 -0
- package/dist/agent-wallet/expiry.d.ts +15 -0
- package/dist/agent-wallet/expiry.js +26 -0
- package/dist/agent-wallet/lighter-keystore.d.ts +34 -0
- package/dist/agent-wallet/lighter-keystore.js +232 -0
- package/dist/agent-wallet/passphrase.d.ts +13 -0
- package/dist/agent-wallet/passphrase.js +54 -0
- package/dist/agent-wallet/signing-strategy.d.ts +67 -0
- package/dist/agent-wallet/signing-strategy.js +51 -0
- package/dist/agent-wallet/store.d.ts +37 -0
- package/dist/agent-wallet/store.js +172 -0
- package/dist/api/public/_http.d.ts +15 -0
- package/dist/api/public/_http.js +24 -0
- package/dist/api/public/hyperliquid.js +36 -24
- package/dist/api/public/lighter.d.ts +7 -1
- package/dist/api/public/lighter.js +85 -37
- package/dist/api/public/pacifica.js +47 -18
- package/dist/bridge-engine.js +102 -49
- package/dist/cli-spec.js +1 -2
- package/dist/commands/account.js +2 -500
- package/dist/commands/agent.d.ts +8 -2
- package/dist/commands/agent.js +1903 -366
- package/dist/commands/alerts.js +3 -1
- package/dist/commands/arb/index.js +37 -7
- package/dist/commands/arb-auto.js +44 -11
- package/dist/commands/arb.js +83 -34
- package/dist/commands/bot.d.ts +1 -1
- package/dist/commands/bot.js +18 -14
- package/dist/commands/bridge.d.ts +1 -1
- package/dist/commands/bridge.js +4 -4
- package/dist/commands/funds.d.ts +1 -1
- package/dist/commands/funds.js +18 -68
- package/dist/commands/jobs.d.ts +1 -1
- package/dist/commands/jobs.js +2 -2
- package/dist/commands/manage.d.ts +1 -1
- package/dist/commands/manage.js +12 -84
- package/dist/commands/plan.d.ts +1 -1
- package/dist/commands/plan.js +2 -2
- package/dist/commands/portfolio.d.ts +19 -3
- package/dist/commands/portfolio.js +747 -163
- package/dist/commands/rebalance.d.ts +1 -1
- package/dist/commands/rebalance.js +18 -12
- package/dist/commands/risk.js +2 -6
- package/dist/commands/settings.js +30 -53
- package/dist/commands/trade.js +16 -15
- package/dist/commands/wallet.d.ts +2 -1
- package/dist/commands/wallet.js +756 -28
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +82 -2
- package/dist/event-stream.js +12 -1
- package/dist/exchanges/aster-typed-data.d.ts +156 -0
- package/dist/exchanges/aster-typed-data.js +189 -0
- package/dist/exchanges/aster.d.ts +60 -11
- package/dist/exchanges/aster.js +278 -136
- package/dist/exchanges/hyperliquid.d.ts +14 -0
- package/dist/exchanges/hyperliquid.js +84 -34
- package/dist/exchanges/lighter-spot.js +14 -3
- package/dist/exchanges/lighter.d.ts +66 -0
- package/dist/exchanges/lighter.js +199 -27
- package/dist/exchanges/pacifica-typed-data.d.ts +75 -0
- package/dist/exchanges/pacifica-typed-data.js +74 -0
- package/dist/exchanges/pacifica.d.ts +29 -1
- package/dist/exchanges/pacifica.js +94 -6
- package/dist/funding/rates.js +59 -21
- package/dist/guardrail/perp-guardrail.js +9 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +268 -360
- package/dist/jobs.js +3 -1
- package/dist/mcp-server.js +85 -83
- package/dist/position-history.js +47 -4
- package/dist/settings.d.ts +67 -3
- package/dist/settings.js +1 -2
- package/dist/signer/ows-evm.d.ts +14 -0
- package/dist/signer/ows-evm.js +28 -9
- package/dist/smart-order.d.ts +8 -2
- package/dist/smart-order.js +46 -11
- package/dist/strategies/funding-arb.js +29 -8
- package/dist/trade-validator.js +30 -5
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +19 -0
- package/package.json +2 -2
- package/skills/perp-cli/SKILL.md +23 -14
- package/skills/perp-cli/references/agent-operations.md +6 -4
- package/skills/perp-cli/references/commands.md +55 -34
- package/skills/perp-cli/scripts/preflight.sh +4 -4
- package/skills/perp-cli/scripts/spot-perp-scan.sh +2 -2
- package/dist/__tests__/alert-logic.test.d.ts +0 -1
- package/dist/__tests__/alert-logic.test.js +0 -107
- package/dist/__tests__/arb-auto-3dex.test.d.ts +0 -1
- package/dist/__tests__/arb-auto-3dex.test.js +0 -397
- package/dist/__tests__/arb-history-stats.test.d.ts +0 -1
- package/dist/__tests__/arb-history-stats.test.js +0 -176
- package/dist/__tests__/arb-logic.test.d.ts +0 -1
- package/dist/__tests__/arb-logic.test.js +0 -84
- package/dist/__tests__/arb-manage.test.d.ts +0 -1
- package/dist/__tests__/arb-manage.test.js +0 -253
- package/dist/__tests__/arb-new-features.test.d.ts +0 -1
- package/dist/__tests__/arb-new-features.test.js +0 -457
- package/dist/__tests__/arb-sizing.test.d.ts +0 -1
- package/dist/__tests__/arb-sizing.test.js +0 -48
- package/dist/__tests__/arb-state.test.d.ts +0 -1
- package/dist/__tests__/arb-state.test.js +0 -284
- package/dist/__tests__/arb-userflow.test.d.ts +0 -1
- package/dist/__tests__/arb-userflow.test.js +0 -945
- package/dist/__tests__/arb-utils.test.d.ts +0 -1
- package/dist/__tests__/arb-utils.test.js +0 -264
- package/dist/__tests__/bot-conditions.test.d.ts +0 -1
- package/dist/__tests__/bot-conditions.test.js +0 -341
- package/dist/__tests__/client-id-tracker.test.d.ts +0 -1
- package/dist/__tests__/client-id-tracker.test.js +0 -137
- package/dist/__tests__/commands/new-atomic-commands.test.d.ts +0 -1
- package/dist/__tests__/commands/new-atomic-commands.test.js +0 -502
- package/dist/__tests__/commands/order-intent.test.d.ts +0 -1
- package/dist/__tests__/commands/order-intent.test.js +0 -600
- package/dist/__tests__/commands/trade-commands.test.d.ts +0 -1
- package/dist/__tests__/commands/trade-commands.test.js +0 -821
- package/dist/__tests__/config.test.d.ts +0 -1
- package/dist/__tests__/config.test.js +0 -86
- package/dist/__tests__/cross-chain-margin.test.d.ts +0 -1
- package/dist/__tests__/cross-chain-margin.test.js +0 -287
- package/dist/__tests__/dex-asset-map.test.d.ts +0 -1
- package/dist/__tests__/dex-asset-map.test.js +0 -191
- package/dist/__tests__/errors.test.d.ts +0 -1
- package/dist/__tests__/errors.test.js +0 -110
- package/dist/__tests__/event-stream.test.d.ts +0 -1
- package/dist/__tests__/event-stream.test.js +0 -276
- package/dist/__tests__/exchanges/interface.test.d.ts +0 -1
- package/dist/__tests__/exchanges/interface.test.js +0 -132
- package/dist/__tests__/exchanges/mock-adapter.d.ts +0 -69
- package/dist/__tests__/exchanges/mock-adapter.js +0 -137
- package/dist/__tests__/execution-log.test.d.ts +0 -1
- package/dist/__tests__/execution-log.test.js +0 -106
- package/dist/__tests__/funding-calc.test.d.ts +0 -1
- package/dist/__tests__/funding-calc.test.js +0 -71
- package/dist/__tests__/funding-history.test.d.ts +0 -1
- package/dist/__tests__/funding-history.test.js +0 -343
- package/dist/__tests__/funding-rates.test.d.ts +0 -1
- package/dist/__tests__/funding-rates.test.js +0 -342
- package/dist/__tests__/funding.test.d.ts +0 -1
- package/dist/__tests__/funding.test.js +0 -173
- package/dist/__tests__/gap-logic.test.d.ts +0 -1
- package/dist/__tests__/gap-logic.test.js +0 -43
- package/dist/__tests__/hip3-dex.test.d.ts +0 -1
- package/dist/__tests__/hip3-dex.test.js +0 -234
- package/dist/__tests__/integration/agent-features.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/agent-features.integration.test.js +0 -553
- package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +0 -13
- package/dist/__tests__/integration/atomic-commands.integration.test.js +0 -246
- package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge-simulation.integration.test.js +0 -453
- package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge-strict.integration.test.js +0 -812
- package/dist/__tests__/integration/bridge.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge.integration.test.js +0 -309
- package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/cli-e2e.integration.test.js +0 -202
- package/dist/__tests__/integration/dex-arb.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/dex-arb.integration.test.js +0 -116
- package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +0 -13
- package/dist/__tests__/integration/envelope-consistency.integration.test.js +0 -205
- package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/hip3-dex.integration.test.js +0 -147
- package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/hyperliquid.integration.test.js +0 -79
- package/dist/__tests__/integration/lighter.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/lighter.integration.test.js +0 -53
- package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +0 -9
- package/dist/__tests__/integration/new-commands-e2e.integration.test.js +0 -236
- package/dist/__tests__/integration/order-verification.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/order-verification.integration.test.js +0 -321
- package/dist/__tests__/integration/pacifica.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/pacifica.integration.test.js +0 -75
- package/dist/__tests__/integration/response-shapes.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/response-shapes.integration.test.js +0 -278
- package/dist/__tests__/liquidity.test.d.ts +0 -1
- package/dist/__tests__/liquidity.test.js +0 -225
- package/dist/__tests__/plan-executor.test.d.ts +0 -1
- package/dist/__tests__/plan-executor.test.js +0 -314
- package/dist/__tests__/position-history.test.d.ts +0 -1
- package/dist/__tests__/position-history.test.js +0 -367
- package/dist/__tests__/retry.test.d.ts +0 -1
- package/dist/__tests__/retry.test.js +0 -310
- package/dist/__tests__/risk-assessment.test.d.ts +0 -1
- package/dist/__tests__/risk-assessment.test.js +0 -288
- package/dist/__tests__/security-adversarial.test.d.ts +0 -1
- package/dist/__tests__/security-adversarial.test.js +0 -574
- package/dist/__tests__/strategies.test.d.ts +0 -1
- package/dist/__tests__/strategies.test.js +0 -539
- package/dist/__tests__/trade-execution.test.d.ts +0 -1
- package/dist/__tests__/trade-execution.test.js +0 -129
- package/dist/__tests__/trade-validator.test.d.ts +0 -1
- package/dist/__tests__/trade-validator.test.js +0 -655
- package/dist/__tests__/utils.test.d.ts +0 -1
- package/dist/__tests__/utils.test.js +0 -76
- package/dist/arb/reconcile.d.ts +0 -28
- package/dist/arb/reconcile.js +0 -162
- package/dist/commands/alert.d.ts +0 -2
- package/dist/commands/alert.js +0 -421
- package/dist/commands/analytics.d.ts +0 -3
- package/dist/commands/analytics.js +0 -311
- package/dist/commands/arb-manage.d.ts +0 -5
- package/dist/commands/arb-manage.js +0 -5
- package/dist/commands/dashboard.d.ts +0 -3
- package/dist/commands/dashboard.js +0 -176
- package/dist/commands/deposit.d.ts +0 -4
- package/dist/commands/deposit.js +0 -573
- package/dist/commands/dex.d.ts +0 -3
- package/dist/commands/dex.js +0 -120
- package/dist/commands/env.d.ts +0 -2
- package/dist/commands/env.js +0 -136
- package/dist/commands/funding.d.ts +0 -3
- package/dist/commands/funding.js +0 -554
- package/dist/commands/gap.d.ts +0 -2
- package/dist/commands/gap.js +0 -305
- package/dist/commands/health.d.ts +0 -2
- package/dist/commands/health.js +0 -67
- package/dist/commands/multileg.d.ts +0 -16
- package/dist/commands/multileg.js +0 -174
- package/dist/commands/ows.d.ts +0 -2
- package/dist/commands/ows.js +0 -887
- package/dist/commands/pnl.d.ts +0 -12
- package/dist/commands/pnl.js +0 -243
- package/dist/commands/run.d.ts +0 -3
- package/dist/commands/run.js +0 -202
- package/dist/commands/stream.d.ts +0 -5
- package/dist/commands/stream.js +0 -200
- package/dist/commands/withdraw.d.ts +0 -3
- package/dist/commands/withdraw.js +0 -187
- package/dist/exchanges/edgex.d.ts +0 -62
- package/dist/exchanges/edgex.js +0 -552
- package/dist/exchanges/nado.d.ts +0 -52
- package/dist/exchanges/nado.js +0 -223
- package/dist/funding/index.d.ts +0 -3
- package/dist/funding/index.js +0 -3
- package/dist/retry.d.ts +0 -74
- package/dist/retry.js +0 -129
- package/dist/ws/market-feed.d.ts +0 -74
- package/dist/ws/market-feed.js +0 -227
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { PacificaClient } from "../pacifica/index.js";
|
|
2
2
|
import { LocalSolanaSigner } from "../signer/index.js";
|
|
3
|
+
import { isExpired } from "../agent-wallet/expiry.js";
|
|
4
|
+
import { PerpError } from "../errors.js";
|
|
3
5
|
export class PacificaAdapter {
|
|
4
6
|
name = "pacifica";
|
|
5
7
|
chain = "solana";
|
|
6
8
|
aliases = ["pac"];
|
|
7
9
|
client;
|
|
10
|
+
/** Tier 3: PK direct (constructor-supplied keypair). */
|
|
8
11
|
_solanaSigner;
|
|
12
|
+
/** Tier 2: OWS master signer (set via setSigner). */
|
|
13
|
+
_masterSigner;
|
|
14
|
+
/** Tier 1: agent OWS signer (Phase 2c). */
|
|
15
|
+
_agentSigner;
|
|
16
|
+
/** Tier 1 metadata. */
|
|
17
|
+
_agentMeta;
|
|
18
|
+
/** --no-agent bypass flag. */
|
|
19
|
+
_useNoAgent = false;
|
|
20
|
+
/** True when adapter was constructed without a real PK (read-only). */
|
|
9
21
|
_hasRealKey;
|
|
22
|
+
/** Public Solana base58 of the active signer (`_resolveSigner().address`). */
|
|
10
23
|
account;
|
|
24
|
+
/** Bound `signMessage` for the active signer (Phase 2c routes through `_resolveSigner`). */
|
|
11
25
|
signMessage;
|
|
12
26
|
_marketsCache = null;
|
|
13
27
|
_marketsCacheTime = 0;
|
|
@@ -17,18 +31,92 @@ export class PacificaAdapter {
|
|
|
17
31
|
this._hasRealKey = hasRealKey;
|
|
18
32
|
this.account = this._solanaSigner.getPublicKeyBase58();
|
|
19
33
|
this.client = new PacificaClient({ network, builderCode });
|
|
20
|
-
|
|
34
|
+
// Hot-path methods always go through `_resolveSigner()` so the bound
|
|
35
|
+
// `signMessage` reflects the highest-priority active tier.
|
|
36
|
+
this.signMessage = (msg) => this._resolveSigner().signer.signMessage(msg);
|
|
21
37
|
}
|
|
22
38
|
ensureSigner() {
|
|
23
|
-
if
|
|
24
|
-
|
|
25
|
-
}
|
|
39
|
+
// Resolves across all tiers; throws PerpError if none available.
|
|
40
|
+
this._resolveSigner();
|
|
26
41
|
}
|
|
27
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Inject an external Solana signer (Tier 2 — OWS master).
|
|
44
|
+
* Backward-compatible: existing callers (e.g. `perp -e pacifica --ows ...`
|
|
45
|
+
* in `_initWithOws`) continue to work; the master signer is what
|
|
46
|
+
* `_resolveSigner()` falls back to when no agent is registered.
|
|
47
|
+
*/
|
|
28
48
|
setSigner(signer) {
|
|
49
|
+
this._masterSigner = signer;
|
|
29
50
|
this._solanaSigner = signer;
|
|
30
51
|
this.account = signer.getPublicKeyBase58();
|
|
31
|
-
this.
|
|
52
|
+
this._hasRealKey = true;
|
|
53
|
+
this.signMessage = (msg) => this._resolveSigner().signer.signMessage(msg);
|
|
54
|
+
}
|
|
55
|
+
/** Tier 1: inject agent OWS Solana signer (Phase 2c). */
|
|
56
|
+
setAgentSigner(meta, signer) {
|
|
57
|
+
this._agentMeta = meta;
|
|
58
|
+
this._agentSigner = signer;
|
|
59
|
+
// The `account` field is the master Solana address (used in REST envelopes
|
|
60
|
+
// as the `account` key) — agent path puts the master in `account` and the
|
|
61
|
+
// agent in `agent_wallet`. Capture the master Solana address from the
|
|
62
|
+
// AgentMeta so REST flows can reference it.
|
|
63
|
+
if (meta.userSolanaAddress) {
|
|
64
|
+
this.account = meta.userSolanaAddress;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Bypass Tier 1 (agent) — used for `--no-agent` flag. */
|
|
68
|
+
setNoAgent(noAgent) {
|
|
69
|
+
this._useNoAgent = noAgent;
|
|
70
|
+
}
|
|
71
|
+
/** True only when ALL THREE tiers are unconfigured. */
|
|
72
|
+
get isReadOnly() {
|
|
73
|
+
return !this._agentSigner && !this._masterSigner && !this._hasRealKey;
|
|
74
|
+
}
|
|
75
|
+
/** Which signer tier is currently active (for debug/diagnostics). */
|
|
76
|
+
get activeSignerTier() {
|
|
77
|
+
try {
|
|
78
|
+
return this._resolveSigner().tier;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Resolve the active signer across three tiers. Mirrors AsterAdapter._resolveSigner. */
|
|
85
|
+
_resolveSigner() {
|
|
86
|
+
// Tier 1: agent (when registered, not expired, --no-agent NOT set)
|
|
87
|
+
if (!this._useNoAgent && this._agentSigner && this._agentMeta) {
|
|
88
|
+
if (isExpired(this._agentMeta)) {
|
|
89
|
+
// Skip Tier 1 only if Tier 2/3 available; otherwise throw AGENT_EXPIRED
|
|
90
|
+
if (!this._masterSigner && !this._hasRealKey) {
|
|
91
|
+
throw new PerpError("AGENT_EXPIRED", "Agent wallet has expired", {
|
|
92
|
+
remediation: "perp wallet agent approve pacifica --rotate",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// fall through to Tier 2/3
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return { tier: "agent", signer: this._agentSigner, address: this._agentSigner.getPublicKeyBase58() };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Tier 2: OWS master
|
|
102
|
+
if (this._masterSigner) {
|
|
103
|
+
return { tier: "master", signer: this._masterSigner, address: this._masterSigner.getPublicKeyBase58() };
|
|
104
|
+
}
|
|
105
|
+
// Tier 3: PK direct
|
|
106
|
+
if (this._hasRealKey) {
|
|
107
|
+
// Guard: legacy test fixtures (e.g. bugfix-v042.test.ts) construct adapters
|
|
108
|
+
// via `Object.create(PacificaAdapter.prototype)` and only set `_hasRealKey = true`
|
|
109
|
+
// — `_solanaSigner` is undefined in that case. Fall back to the cached
|
|
110
|
+
// `account` field when available.
|
|
111
|
+
const address = this._solanaSigner
|
|
112
|
+
? this._solanaSigner.getPublicKeyBase58()
|
|
113
|
+
: this.account;
|
|
114
|
+
return { tier: "pk", signer: this._solanaSigner, address };
|
|
115
|
+
}
|
|
116
|
+
// No signer at any tier
|
|
117
|
+
throw new PerpError("NO_SIGNER_AVAILABLE", "No signing path configured for Pacifica", {
|
|
118
|
+
remediation: "Run one of: (a) perp wallet agent approve pacifica --master <wallet>; (b) perp wallet generate && perp -e pacifica --ows <wallet>; (c) export PACIFICA_PRIVATE_KEY=...",
|
|
119
|
+
});
|
|
32
120
|
}
|
|
33
121
|
/** Access the underlying Keypair (only available with LocalSolanaSigner). */
|
|
34
122
|
get keypair() {
|
package/dist/funding/rates.js
CHANGED
|
@@ -56,6 +56,9 @@ async function fetchHyperliquidRates() {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
async function fetchLighterRates() {
|
|
59
|
+
// Outer try/catch returning [] is intentional graceful degradation; see
|
|
60
|
+
// fetchAsterRates for the same pattern. Inside, SSOT rule #2 applies —
|
|
61
|
+
// skip rows whose mark price cannot be resolved instead of 0-coercing.
|
|
59
62
|
try {
|
|
60
63
|
const [details, funding] = await Promise.all([
|
|
61
64
|
fetchLighterOrderBookDetails(),
|
|
@@ -63,25 +66,47 @@ async function fetchLighterRates() {
|
|
|
63
66
|
]);
|
|
64
67
|
const priceMap = new Map(details.map(d => [d.marketId, d.lastTradePrice]));
|
|
65
68
|
const symMap = new Map(details.map(d => [d.marketId, d.symbol]));
|
|
66
|
-
|
|
69
|
+
const out = [];
|
|
70
|
+
for (const fr of funding) {
|
|
67
71
|
const symbol = fr.symbol || symMap.get(fr.marketId) || "";
|
|
72
|
+
if (!symbol)
|
|
73
|
+
continue;
|
|
68
74
|
const rate = fr.rate;
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
// Prefer fr.markPrice; fall back to orderBook last-trade as a documented
|
|
76
|
+
// price-source preference (NOT an error fallback).
|
|
77
|
+
const directMark = fr.markPrice;
|
|
78
|
+
const fallbackMark = priceMap.get(fr.marketId);
|
|
79
|
+
let markPrice;
|
|
80
|
+
if (directMark !== null && Number.isFinite(directMark) && directMark > 0) {
|
|
81
|
+
markPrice = directMark;
|
|
82
|
+
}
|
|
83
|
+
else if (fallbackMark !== undefined && Number.isFinite(fallbackMark) && fallbackMark > 0) {
|
|
84
|
+
markPrice = fallbackMark;
|
|
85
|
+
}
|
|
86
|
+
if (!Number.isFinite(rate) || markPrice === undefined)
|
|
87
|
+
continue;
|
|
88
|
+
out.push({
|
|
71
89
|
exchange: "lighter",
|
|
72
90
|
symbol,
|
|
73
91
|
fundingRate: rate,
|
|
74
|
-
hourlyRate:
|
|
92
|
+
hourlyRate: toHourlyRate(rate, "lighter"),
|
|
75
93
|
annualizedPct: annualizeRate(rate, "lighter"),
|
|
76
|
-
markPrice
|
|
77
|
-
};
|
|
78
|
-
}
|
|
94
|
+
markPrice,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
79
98
|
}
|
|
80
99
|
catch {
|
|
81
100
|
return [];
|
|
82
101
|
}
|
|
83
102
|
}
|
|
84
103
|
async function fetchAsterRates() {
|
|
104
|
+
// Outer try/catch returning [] is intentional graceful degradation: when
|
|
105
|
+
// the entire endpoint is unreachable, the cross-DEX comparison should
|
|
106
|
+
// continue with the remaining venues.
|
|
107
|
+
// Inside the try block, SSOT rule #2 applies — refuse to silently 0-coerce
|
|
108
|
+
// missing markPrice / lastFundingRate, since those values feed downstream
|
|
109
|
+
// sizing and any 0 corrupts the comparison.
|
|
85
110
|
try {
|
|
86
111
|
const [premiums, tickers] = await Promise.all([
|
|
87
112
|
fetch("https://fapi.asterdex.com/fapi/v1/premiumIndex").then(r => r.json()),
|
|
@@ -89,25 +114,38 @@ async function fetchAsterRates() {
|
|
|
89
114
|
]);
|
|
90
115
|
const priceMap = new Map();
|
|
91
116
|
for (const t of tickers ?? []) {
|
|
92
|
-
|
|
117
|
+
const last = Number(t.lastPrice);
|
|
118
|
+
if (Number.isFinite(last) && last > 0)
|
|
119
|
+
priceMap.set(String(t.symbol), last);
|
|
93
120
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.map(p => {
|
|
121
|
+
const out = [];
|
|
122
|
+
for (const p of premiums ?? []) {
|
|
97
123
|
const rawSymbol = String(p.symbol ?? "");
|
|
124
|
+
if (!rawSymbol.endsWith("USDT"))
|
|
125
|
+
continue;
|
|
126
|
+
const fundingRate = Number(p.lastFundingRate);
|
|
127
|
+
// Prefer premiumIndex.markPrice; fall back to ticker.lastPrice as a
|
|
128
|
+
// documented price-source preference (NOT an error fallback).
|
|
129
|
+
const markFromPremium = Number(p.markPrice);
|
|
130
|
+
const markPrice = Number.isFinite(markFromPremium) && markFromPremium > 0
|
|
131
|
+
? markFromPremium
|
|
132
|
+
: priceMap.get(rawSymbol);
|
|
133
|
+
if (!Number.isFinite(fundingRate) || markPrice === undefined || !Number.isFinite(markPrice) || markPrice <= 0) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
98
136
|
const symbol = rawSymbol.replace(/USDT$/, "");
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
return {
|
|
137
|
+
const nextFundingTimeRaw = Number(p.nextFundingTime);
|
|
138
|
+
out.push({
|
|
102
139
|
exchange: "aster",
|
|
103
140
|
symbol,
|
|
104
|
-
fundingRate
|
|
105
|
-
hourlyRate:
|
|
106
|
-
annualizedPct: annualizeRate(
|
|
107
|
-
markPrice
|
|
108
|
-
nextFundingTime: Number(
|
|
109
|
-
};
|
|
110
|
-
}
|
|
141
|
+
fundingRate,
|
|
142
|
+
hourlyRate: toHourlyRate(fundingRate, "aster"),
|
|
143
|
+
annualizedPct: annualizeRate(fundingRate, "aster"),
|
|
144
|
+
markPrice,
|
|
145
|
+
nextFundingTime: Number.isFinite(nextFundingTimeRaw) ? nextFundingTimeRaw : 0,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
111
149
|
}
|
|
112
150
|
catch {
|
|
113
151
|
return [];
|
|
@@ -46,7 +46,15 @@ function isWithdrawTx(data) {
|
|
|
46
46
|
return selector === "0x3ccfd60b" || selector === "0x2e1a7d4d";
|
|
47
47
|
}
|
|
48
48
|
function evaluate(ctx) {
|
|
49
|
-
|
|
49
|
+
// SSOT rule #2: policy_config must be explicitly supplied. A missing
|
|
50
|
+
// policy_config previously fell through to silent defaults — that is a
|
|
51
|
+
// safety-critical fallback (the user might assume their custom limits are
|
|
52
|
+
// active when in fact only baked-in defaults are). Fail closed instead.
|
|
53
|
+
if (!ctx.policy_config) {
|
|
54
|
+
return deny("policy_config missing from PolicyContext; refusing to fall through to baked-in defaults. " +
|
|
55
|
+
"Caller must supply policy_config explicitly (max_tx_usd, max_daily_usd, etc.).");
|
|
56
|
+
}
|
|
57
|
+
const config = ctx.policy_config;
|
|
50
58
|
const maxTxUsd = config.max_tx_usd ?? DEFAULT_LIMITS.max_tx_usd;
|
|
51
59
|
const maxDailyUsd = config.max_daily_usd ?? DEFAULT_LIMITS.max_daily_usd;
|
|
52
60
|
const maxWithdrawUsd = config.max_withdraw_usd ?? maxTxUsd;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import "./_stderr-filter.js";
|