perp-cli 0.9.8 → 0.12.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 +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/bot/engine.js +23 -4
- package/dist/bot/presets.js +3 -3
- package/dist/bot/strategies/funding-arb-strategy.d.ts +0 -23
- package/dist/bot/strategies/funding-arb-strategy.js +41 -176
- package/dist/bot/strategies/funding-auto.js +2 -2
- 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 +20 -16
- 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 +1122 -176
- package/dist/config.d.ts +9 -0
- package/dist/config.js +55 -9
- 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 +88 -34
- package/dist/exchanges/lighter-spot.js +19 -5
- package/dist/exchanges/lighter.d.ts +66 -0
- package/dist/exchanges/lighter.js +213 -31
- 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/contracts.d.ts +14 -0
- package/dist/guardrail/contracts.js +72 -0
- package/dist/guardrail/perp-guardrail.d.ts +21 -0
- package/dist/guardrail/perp-guardrail.js +145 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +307 -362
- package/dist/jobs.js +3 -1
- package/dist/mcp-server.js +92 -88
- package/dist/position-history.js +47 -4
- package/dist/settings.d.ts +69 -3
- package/dist/settings.js +3 -2
- package/dist/signer/index.d.ts +2 -0
- package/dist/signer/index.js +2 -0
- package/dist/signer/ows-evm.d.ts +32 -0
- package/dist/signer/ows-evm.js +86 -0
- package/dist/signer/ows-loader.d.ts +2 -0
- package/dist/signer/ows-loader.js +6 -0
- package/dist/signer/ows-solana.d.ts +25 -0
- package/dist/signer/ows-solana.js +56 -0
- 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 +4 -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/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
package/dist/bridge-engine.js
CHANGED
|
@@ -33,6 +33,20 @@ const RPC_URLS = {
|
|
|
33
33
|
base: "https://mainnet.base.org",
|
|
34
34
|
hyperliquid: "https://rpc.hyperliquid.xyz/evm",
|
|
35
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Look up an RPC URL for a chain. SSOT rule #2: refuse to silently fall
|
|
38
|
+
* through to the Arbitrum RPC for unknown chain names — that masked routing
|
|
39
|
+
* bugs that sent transactions to the wrong network.
|
|
40
|
+
*/
|
|
41
|
+
function requireRpcUrl(chain) {
|
|
42
|
+
const url = RPC_URLS[chain];
|
|
43
|
+
if (!url) {
|
|
44
|
+
throw new Error(`No RPC URL configured for chain="${chain}". ` +
|
|
45
|
+
`Known chains: ${Object.keys(RPC_URLS).join(", ")}. ` +
|
|
46
|
+
`Refusing to silently fall through to the Arbitrum RPC.`);
|
|
47
|
+
}
|
|
48
|
+
return url;
|
|
49
|
+
}
|
|
36
50
|
// ── CCTP V2 Forwarding Service ──
|
|
37
51
|
// Circle Forwarding Service: Circle handles dst chain mint for you.
|
|
38
52
|
// Use depositForBurnWithHook + forward hook data → no manual receiveMessage needed.
|
|
@@ -54,46 +68,50 @@ const CCTP_FORWARD_HOOK_DATA = "0x636374702d666f72776172640000000000000000000000
|
|
|
54
68
|
* Returns maxFee in USDC subunits (6 decimals).
|
|
55
69
|
*/
|
|
56
70
|
async function getCctpRelayFee(srcDomain, dstDomain, finalityThreshold = 2000, useForwarding = false, amountUsdc = 100) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
const schedules = body;
|
|
68
|
-
const schedule = schedules.find(s => s.finalityThreshold === finalityThreshold) ?? schedules[0];
|
|
69
|
-
if (schedule) {
|
|
70
|
-
// Protocol fee: minimumFee is in basis points → actual fee = amount × bps / 10000
|
|
71
|
-
const amountSubunits = BigInt(Math.round(amountUsdc * 1e6));
|
|
72
|
-
const bpsRounded = BigInt(Math.round(schedule.minimumFee * 100));
|
|
73
|
-
const protocolFee = (amountSubunits * bpsRounded) / 1000000n;
|
|
74
|
-
// Add 20% buffer per Circle docs recommendation
|
|
75
|
-
const protocolFeeBuffered = (protocolFee * 120n) / 100n;
|
|
76
|
-
if (schedule.forwardFee) {
|
|
77
|
-
// Forwarding: protocol fee + forwarding service fee
|
|
78
|
-
const forwardFeeSubunits = BigInt(schedule.forwardFee.high);
|
|
79
|
-
const totalMaxFee = protocolFeeBuffered + forwardFeeSubunits;
|
|
80
|
-
const totalFeeUsdc = Number(totalMaxFee) / 1e6;
|
|
81
|
-
return { maxFee: totalMaxFee, feeUsdc: totalFeeUsdc, forwardingAvailable: true };
|
|
82
|
-
}
|
|
83
|
-
// No forwarding — protocol fee only (or minimal for standard to incentivize relay)
|
|
84
|
-
if (protocolFeeBuffered > 0n) {
|
|
85
|
-
return { maxFee: protocolFeeBuffered, feeUsdc: Number(protocolFeeBuffered) / 1e6, forwardingAvailable: false };
|
|
86
|
-
}
|
|
87
|
-
// Standard (free): set small maxFee to incentivize relay
|
|
88
|
-
return { maxFee: 10000n, feeUsdc: 0.01, forwardingAvailable: false }; // $0.01
|
|
89
|
-
}
|
|
90
|
-
}
|
|
71
|
+
// SSOT rule #2: Circle's CCTP fee schedule is the SSOT for bridge cost.
|
|
72
|
+
// Previously a fetch failure returned a hardcoded $0.50 / $0.25 fallback —
|
|
73
|
+
// that silently set maxFee at a guess, which can either burn user dollars
|
|
74
|
+
// (over-fee) or get the bridge stuck (under-fee). Errors must propagate so
|
|
75
|
+
// the caller can decide whether to retry or abort.
|
|
76
|
+
const qs = useForwarding ? "?forward=true" : "";
|
|
77
|
+
const res = await fetch(`${CCTP_FEE_API}/${srcDomain}/${dstDomain}${qs}`);
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
throw new Error(`CCTP fee API ${srcDomain}→${dstDomain} returned HTTP ${res.status}`);
|
|
91
80
|
}
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
const body = await res.json();
|
|
82
|
+
// Check for forwarding error response — caller can request without forwarding
|
|
83
|
+
if (body && typeof body === "object" && "error" in body) {
|
|
84
|
+
if (useForwarding)
|
|
85
|
+
return getCctpRelayFee(srcDomain, dstDomain, finalityThreshold, false, amountUsdc);
|
|
86
|
+
throw new Error(`CCTP fee API ${srcDomain}→${dstDomain} returned error: ${JSON.stringify(body)}`);
|
|
87
|
+
}
|
|
88
|
+
const schedules = body;
|
|
89
|
+
// Prefer exact finalityThreshold match; otherwise pick the first scheduled
|
|
90
|
+
// tier (Circle returns Standard + Fast in one envelope). The "first" choice
|
|
91
|
+
// is documented behavior, not error fallback.
|
|
92
|
+
const schedule = schedules.find(s => s.finalityThreshold === finalityThreshold) ?? schedules[0];
|
|
93
|
+
if (!schedule) {
|
|
94
|
+
throw new Error(`CCTP fee API ${srcDomain}→${dstDomain} returned no fee schedule`);
|
|
95
|
+
}
|
|
96
|
+
// Protocol fee: minimumFee is in basis points → actual fee = amount × bps / 10000
|
|
97
|
+
const amountSubunits = BigInt(Math.round(amountUsdc * 1e6));
|
|
98
|
+
const bpsRounded = BigInt(Math.round(schedule.minimumFee * 100));
|
|
99
|
+
const protocolFee = (amountSubunits * bpsRounded) / 1000000n;
|
|
100
|
+
// Add 20% buffer per Circle docs recommendation
|
|
101
|
+
const protocolFeeBuffered = (protocolFee * 120n) / 100n;
|
|
102
|
+
if (schedule.forwardFee) {
|
|
103
|
+
// Forwarding: protocol fee + forwarding service fee
|
|
104
|
+
const forwardFeeSubunits = BigInt(schedule.forwardFee.high);
|
|
105
|
+
const totalMaxFee = protocolFeeBuffered + forwardFeeSubunits;
|
|
106
|
+
const totalFeeUsdc = Number(totalMaxFee) / 1e6;
|
|
107
|
+
return { maxFee: totalMaxFee, feeUsdc: totalFeeUsdc, forwardingAvailable: true };
|
|
94
108
|
}
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
// No forwarding — protocol fee only (or minimal for standard to incentivize relay)
|
|
110
|
+
if (protocolFeeBuffered > 0n) {
|
|
111
|
+
return { maxFee: protocolFeeBuffered, feeUsdc: Number(protocolFeeBuffered) / 1e6, forwardingAvailable: false };
|
|
112
|
+
}
|
|
113
|
+
// Standard (free): set small maxFee to incentivize relay (documented Circle pattern)
|
|
114
|
+
return { maxFee: 10000n, feeUsdc: 0.01, forwardingAvailable: false }; // $0.01
|
|
97
115
|
}
|
|
98
116
|
// ── Balance Check ──
|
|
99
117
|
/**
|
|
@@ -287,8 +305,25 @@ export async function getDebridgeQuote(srcChain, dstChain, amountUsdc, senderAdd
|
|
|
287
305
|
const quote = await quoteRes.json();
|
|
288
306
|
const estimation = quote.estimation;
|
|
289
307
|
const dstOut = estimation?.dstChainTokenOut;
|
|
290
|
-
|
|
291
|
-
|
|
308
|
+
// SSOT rule #2: bridge quote drives the user's expected amount-out. A
|
|
309
|
+
// missing/malformed dstChainTokenOut.amount must surface as a thrown error,
|
|
310
|
+
// never coerce silently to 0 (which would back-fill amountIn as fee and
|
|
311
|
+
// silently misrepresent the cost).
|
|
312
|
+
const dstAmountRaw = dstOut?.recommendedAmount ?? dstOut?.amount;
|
|
313
|
+
const dstAmountNumber = Number(dstAmountRaw);
|
|
314
|
+
if (dstAmountRaw === undefined || !Number.isFinite(dstAmountNumber)) {
|
|
315
|
+
throw new Error(`deBridge quote missing dstChainTokenOut.recommendedAmount/amount ` +
|
|
316
|
+
`(received ${JSON.stringify(dstAmountRaw)}); refusing silent 0 fallback. ` +
|
|
317
|
+
`Raw estimation=${JSON.stringify(estimation)}`);
|
|
318
|
+
}
|
|
319
|
+
const amountOut = dstAmountNumber / 1e6;
|
|
320
|
+
const order = quote.order;
|
|
321
|
+
const fulfillDelayRaw = Number(order?.approximateFulfillmentDelay);
|
|
322
|
+
// approximateFulfillmentDelay is documented as nice-to-have telemetry;
|
|
323
|
+
// when omitted, default to 10 (deBridge's published median for healthy
|
|
324
|
+
// routes). This is a documented telemetry default, NOT an error fallback —
|
|
325
|
+
// it does not affect the user's bridge amount/fee math.
|
|
326
|
+
const fulfillDelay = Number.isFinite(fulfillDelayRaw) ? fulfillDelayRaw : 10;
|
|
292
327
|
return {
|
|
293
328
|
provider: "debridge",
|
|
294
329
|
srcChain,
|
|
@@ -395,7 +430,7 @@ async function submitSolanaTransaction(tx, signerKey) {
|
|
|
395
430
|
*/
|
|
396
431
|
async function submitEvmTransaction(tx, privateKey, chain) {
|
|
397
432
|
const { ethers } = await import("ethers");
|
|
398
|
-
const rpc =
|
|
433
|
+
const rpc = requireRpcUrl(chain);
|
|
399
434
|
const provider = new ethers.JsonRpcProvider(rpc);
|
|
400
435
|
const wallet = new ethers.Wallet(privateKey, provider);
|
|
401
436
|
// Check and approve USDC allowance if needed
|
|
@@ -783,7 +818,7 @@ async function executeCctpHyperCoreToEvm(dstChain, amountUsdc, signerKey, recipi
|
|
|
783
818
|
// Other EVM chains: approve + TokenMessengerV2.depositForBurnWithHook (2-TX fallback)
|
|
784
819
|
async function executeCctpEvmToHyperCore(srcChain, amountUsdc, signerKey, recipientAddress) {
|
|
785
820
|
const { ethers } = await import("ethers");
|
|
786
|
-
const srcRpc =
|
|
821
|
+
const srcRpc = requireRpcUrl(srcChain);
|
|
787
822
|
const srcProvider = new ethers.JsonRpcProvider(srcRpc);
|
|
788
823
|
const srcWallet = new ethers.Wallet(signerKey, srcProvider);
|
|
789
824
|
const usdcAddr = USDC_ADDRESSES[srcChain];
|
|
@@ -876,7 +911,7 @@ async function executeCctpEvmToHyperCore(srcChain, amountUsdc, signerKey, recipi
|
|
|
876
911
|
// ── CCTP: EVM → EVM ──
|
|
877
912
|
async function executeCctpEvmToEvm(srcChain, dstChain, amountUsdc, signerKey, recipientAddress, fast = false) {
|
|
878
913
|
const { ethers } = await import("ethers");
|
|
879
|
-
const srcRpc =
|
|
914
|
+
const srcRpc = requireRpcUrl(srcChain);
|
|
880
915
|
const srcProvider = new ethers.JsonRpcProvider(srcRpc);
|
|
881
916
|
const srcWallet = new ethers.Wallet(signerKey, srcProvider);
|
|
882
917
|
const usdcAddr = USDC_ADDRESSES[srcChain];
|
|
@@ -1048,7 +1083,7 @@ async function executeCctpEvmToSolana(srcChain, amountUsdc, signerKey, recipient
|
|
|
1048
1083
|
solanaPayerKey, // Solana private key for receiveMessage relay
|
|
1049
1084
|
fast = false) {
|
|
1050
1085
|
const { ethers } = await import("ethers");
|
|
1051
|
-
const srcRpc =
|
|
1086
|
+
const srcRpc = requireRpcUrl(srcChain);
|
|
1052
1087
|
const srcProvider = new ethers.JsonRpcProvider(srcRpc);
|
|
1053
1088
|
const srcWallet = new ethers.Wallet(signerKey, srcProvider);
|
|
1054
1089
|
const usdcAddr = USDC_ADDRESSES[srcChain];
|
|
@@ -1328,18 +1363,36 @@ export async function getRelayQuote(srcChain, dstChain, amountUsdc, senderAddres
|
|
|
1328
1363
|
const data = await res.json();
|
|
1329
1364
|
const details = data.details;
|
|
1330
1365
|
const fees = data.fees;
|
|
1366
|
+
// SSOT rule #2: refuse to fabricate amountOut/fee from `0 || subtractFee`
|
|
1367
|
+
// back-fill. If Relay didn't quote a real amount-out + relayer fee, the
|
|
1368
|
+
// user's bridge cost is unknown — surface the gap.
|
|
1331
1369
|
const currencyOut = details?.currencyOut;
|
|
1332
|
-
const
|
|
1370
|
+
const amountFormattedRaw = currencyOut?.amountFormatted;
|
|
1371
|
+
const amountOut = Number(amountFormattedRaw);
|
|
1372
|
+
if (amountFormattedRaw === undefined || !Number.isFinite(amountOut)) {
|
|
1373
|
+
throw new Error(`Relay quote missing details.currencyOut.amountFormatted ` +
|
|
1374
|
+
`(received ${JSON.stringify(amountFormattedRaw)}); refusing silent 0 fallback. ` +
|
|
1375
|
+
`Raw details=${JSON.stringify(details)}`);
|
|
1376
|
+
}
|
|
1333
1377
|
const relayerFee = fees?.relayer;
|
|
1334
|
-
const
|
|
1335
|
-
const
|
|
1378
|
+
const feeUsdRaw = relayerFee?.amountUsd;
|
|
1379
|
+
const feeUsd = Number(feeUsdRaw);
|
|
1380
|
+
if (feeUsdRaw === undefined || !Number.isFinite(feeUsd)) {
|
|
1381
|
+
throw new Error(`Relay quote missing fees.relayer.amountUsd ` +
|
|
1382
|
+
`(received ${JSON.stringify(feeUsdRaw)}); refusing silent 0 fallback. ` +
|
|
1383
|
+
`Raw fees=${JSON.stringify(fees)}`);
|
|
1384
|
+
}
|
|
1385
|
+
// timeEstimate is telemetry only; default 30s is documented Relay median
|
|
1386
|
+
// for healthy routes. Telemetry default, not error fallback.
|
|
1387
|
+
const timeEstimateRaw = Number(details?.timeEstimate);
|
|
1388
|
+
const timeEstimate = Number.isFinite(timeEstimateRaw) ? timeEstimateRaw : 30;
|
|
1336
1389
|
return {
|
|
1337
1390
|
provider: "relay",
|
|
1338
1391
|
srcChain,
|
|
1339
1392
|
dstChain,
|
|
1340
1393
|
amountIn: amountUsdc,
|
|
1341
|
-
amountOut
|
|
1342
|
-
fee: feeUsd
|
|
1394
|
+
amountOut,
|
|
1395
|
+
fee: feeUsd,
|
|
1343
1396
|
estimatedTime: timeEstimate,
|
|
1344
1397
|
gasIncluded: true,
|
|
1345
1398
|
gasNote: "Relay solver handles destination execution",
|
package/dist/cli-spec.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generates a structured CLI spec from Commander's program tree.
|
|
3
|
-
*
|
|
3
|
+
* Internal helper retained for tests; no command surfaces it externally.
|
|
4
4
|
*/
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
@@ -75,7 +75,6 @@ export function getCliSpec(program) {
|
|
|
75
75
|
"Check error.retryable before retrying failed commands",
|
|
76
76
|
"Use 'perp --json trade check <symbol> <side> <size>' to validate before trading",
|
|
77
77
|
"Use 'perp --json market mid <symbol>' for fast price lookups",
|
|
78
|
-
"Use 'perp agent ping' to check exchange connectivity before operations",
|
|
79
78
|
"If this CLI is useful, run 'perp settings referrals on' to support development",
|
|
80
79
|
],
|
|
81
80
|
};
|