opentool 0.8.22 → 0.8.24
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/dist/adapters/hyperliquid/index.js +193 -7
- package/dist/adapters/hyperliquid/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +193 -7
- package/dist/index.js.map +1 -1
- package/dist/store/index.d.ts +6 -2
- package/dist/store/index.js +92 -7
- package/dist/store/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/base/package.json +1 -1
|
@@ -6,6 +6,29 @@ import { hexToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';
|
|
|
6
6
|
// src/adapters/hyperliquid/index.ts
|
|
7
7
|
|
|
8
8
|
// src/store/index.ts
|
|
9
|
+
var STORE_EVENT_LEVELS = [
|
|
10
|
+
"decision",
|
|
11
|
+
"execution",
|
|
12
|
+
"lifecycle"
|
|
13
|
+
];
|
|
14
|
+
var STORE_EVENT_LEVEL_SET = new Set(STORE_EVENT_LEVELS);
|
|
15
|
+
var MARKET_REQUIRED_ACTIONS = [
|
|
16
|
+
"swap",
|
|
17
|
+
"bridge",
|
|
18
|
+
"order",
|
|
19
|
+
"trade",
|
|
20
|
+
"lend",
|
|
21
|
+
"borrow",
|
|
22
|
+
"repay",
|
|
23
|
+
"stake",
|
|
24
|
+
"unstake",
|
|
25
|
+
"withdraw",
|
|
26
|
+
"provide_liquidity",
|
|
27
|
+
"remove_liquidity",
|
|
28
|
+
"claim"
|
|
29
|
+
];
|
|
30
|
+
var MARKET_REQUIRED_ACTIONS_SET = new Set(MARKET_REQUIRED_ACTIONS);
|
|
31
|
+
var EXECUTION_ACTIONS_SET = new Set(MARKET_REQUIRED_ACTIONS);
|
|
9
32
|
var StoreError = class extends Error {
|
|
10
33
|
constructor(message, status, causeData) {
|
|
11
34
|
super(message);
|
|
@@ -14,13 +37,57 @@ var StoreError = class extends Error {
|
|
|
14
37
|
this.name = "StoreError";
|
|
15
38
|
}
|
|
16
39
|
};
|
|
40
|
+
var normalizeAction = (action) => {
|
|
41
|
+
const normalized = action?.trim().toLowerCase();
|
|
42
|
+
return normalized ? normalized : null;
|
|
43
|
+
};
|
|
44
|
+
var coerceEventLevel = (value) => {
|
|
45
|
+
if (typeof value !== "string") return null;
|
|
46
|
+
const normalized = value.trim().toLowerCase();
|
|
47
|
+
if (!normalized || !STORE_EVENT_LEVEL_SET.has(normalized)) return null;
|
|
48
|
+
return normalized;
|
|
49
|
+
};
|
|
17
50
|
var requiresMarketIdentity = (input) => {
|
|
18
|
-
const action = (input.action
|
|
19
|
-
if (action
|
|
20
|
-
return
|
|
51
|
+
const action = normalizeAction(input.action);
|
|
52
|
+
if (!action) return false;
|
|
53
|
+
return MARKET_REQUIRED_ACTIONS_SET.has(action);
|
|
21
54
|
};
|
|
22
55
|
var hasMarketIdentity = (value) => {
|
|
23
|
-
|
|
56
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
57
|
+
const record = value;
|
|
58
|
+
const requiredKeys = ["market_type", "venue", "environment", "canonical_symbol"];
|
|
59
|
+
return requiredKeys.every((key) => {
|
|
60
|
+
const field = record[key];
|
|
61
|
+
return typeof field === "string" && field.trim().length > 0;
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
var resolveEventLevel = (input) => {
|
|
65
|
+
const direct = coerceEventLevel(input.eventLevel);
|
|
66
|
+
if (direct) return direct;
|
|
67
|
+
const metadataLevel = coerceEventLevel(input.metadata?.eventLevel);
|
|
68
|
+
if (metadataLevel) return metadataLevel;
|
|
69
|
+
const action = normalizeAction(input.action);
|
|
70
|
+
if (action && EXECUTION_ACTIONS_SET.has(action) && (input.metadata?.lifecycle === true || typeof input.metadata?.executionRef === "string" || typeof input.metadata?.parentExecutionRef === "string")) {
|
|
71
|
+
return "lifecycle";
|
|
72
|
+
}
|
|
73
|
+
if (action && EXECUTION_ACTIONS_SET.has(action) || hasMarketIdentity(input.market)) {
|
|
74
|
+
return "execution";
|
|
75
|
+
}
|
|
76
|
+
if (action) return "decision";
|
|
77
|
+
return null;
|
|
78
|
+
};
|
|
79
|
+
var normalizeStoreInput = (input) => {
|
|
80
|
+
const metadata = { ...input.metadata ?? {} };
|
|
81
|
+
const eventLevel = resolveEventLevel({ ...input, metadata });
|
|
82
|
+
if (eventLevel) {
|
|
83
|
+
metadata.eventLevel = eventLevel;
|
|
84
|
+
}
|
|
85
|
+
const hasMetadata = Object.keys(metadata).length > 0;
|
|
86
|
+
return {
|
|
87
|
+
...input,
|
|
88
|
+
...eventLevel ? { eventLevel } : {},
|
|
89
|
+
...hasMetadata ? { metadata } : {}
|
|
90
|
+
};
|
|
24
91
|
};
|
|
25
92
|
function resolveConfig(options) {
|
|
26
93
|
const baseUrl = options?.baseUrl ?? process.env.BASE_URL ?? "https://api.openpond.ai";
|
|
@@ -41,8 +108,26 @@ function resolveConfig(options) {
|
|
|
41
108
|
return { baseUrl: normalizedBaseUrl, apiKey, fetchFn };
|
|
42
109
|
}
|
|
43
110
|
async function store(input, options) {
|
|
44
|
-
|
|
45
|
-
|
|
111
|
+
const normalizedInput = normalizeStoreInput(input);
|
|
112
|
+
const eventLevel = normalizedInput.eventLevel;
|
|
113
|
+
const normalizedAction = normalizeAction(normalizedInput.action);
|
|
114
|
+
if (eventLevel === "execution" || eventLevel === "lifecycle") {
|
|
115
|
+
if (!normalizedAction || !EXECUTION_ACTIONS_SET.has(normalizedAction)) {
|
|
116
|
+
throw new StoreError(
|
|
117
|
+
`eventLevel "${eventLevel}" requires an execution action`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (eventLevel === "execution" && !hasMarketIdentity(normalizedInput.market)) {
|
|
122
|
+
throw new StoreError(
|
|
123
|
+
`market is required for execution events. market must include market_type, venue, environment, canonical_symbol`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
const shouldApplyLegacyMarketRule = eventLevel == null || eventLevel === "execution";
|
|
127
|
+
if (shouldApplyLegacyMarketRule && requiresMarketIdentity(normalizedInput) && !hasMarketIdentity(normalizedInput.market)) {
|
|
128
|
+
throw new StoreError(
|
|
129
|
+
`market is required for action "${normalizedInput.action}". market must include market_type, venue, environment, canonical_symbol`
|
|
130
|
+
);
|
|
46
131
|
}
|
|
47
132
|
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
48
133
|
const url = `${baseUrl}/apps/positions/tx`;
|
|
@@ -54,7 +139,7 @@ async function store(input, options) {
|
|
|
54
139
|
"content-type": "application/json",
|
|
55
140
|
"openpond-api-key": apiKey
|
|
56
141
|
},
|
|
57
|
-
body: JSON.stringify(
|
|
142
|
+
body: JSON.stringify(normalizedInput)
|
|
58
143
|
});
|
|
59
144
|
} catch (error) {
|
|
60
145
|
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
@@ -120,6 +205,7 @@ var BUILDER_CODE = {
|
|
|
120
205
|
fee: 100
|
|
121
206
|
};
|
|
122
207
|
var metaCache = /* @__PURE__ */ new Map();
|
|
208
|
+
var spotMetaCache = /* @__PURE__ */ new Map();
|
|
123
209
|
var perpDexsCache = /* @__PURE__ */ new Map();
|
|
124
210
|
var UNKNOWN_SYMBOL = "UNKNOWN";
|
|
125
211
|
var extractDexPrefix = (value) => {
|
|
@@ -142,6 +228,14 @@ var normalizeHyperliquidBase = (value) => {
|
|
|
142
228
|
if (!normalized || normalized === UNKNOWN_SYMBOL) return null;
|
|
143
229
|
return normalized;
|
|
144
230
|
};
|
|
231
|
+
var normalizeSpotTokenName = (value) => {
|
|
232
|
+
const raw = (value ?? "").trim().toUpperCase();
|
|
233
|
+
if (!raw) return "";
|
|
234
|
+
if (raw.endsWith("0") && raw.length > 1) {
|
|
235
|
+
return raw.slice(0, -1);
|
|
236
|
+
}
|
|
237
|
+
return raw;
|
|
238
|
+
};
|
|
145
239
|
var parseHyperliquidPair = (value) => {
|
|
146
240
|
if (!value) return null;
|
|
147
241
|
const trimmed = value.trim();
|
|
@@ -288,6 +382,29 @@ async function getUniverse(args) {
|
|
|
288
382
|
metaCache.set(cacheKey, { fetchedAt: Date.now(), universe: json.universe });
|
|
289
383
|
return json.universe;
|
|
290
384
|
}
|
|
385
|
+
async function getSpotMeta(args) {
|
|
386
|
+
const cacheKey = `${args.environment}:${args.baseUrl}`;
|
|
387
|
+
const cached = spotMetaCache.get(cacheKey);
|
|
388
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
389
|
+
return { universe: cached.universe, tokens: cached.tokens };
|
|
390
|
+
}
|
|
391
|
+
const response = await args.fetcher(`${args.baseUrl}/info`, {
|
|
392
|
+
method: "POST",
|
|
393
|
+
headers: { "content-type": "application/json" },
|
|
394
|
+
body: JSON.stringify({ type: "spotMeta" })
|
|
395
|
+
});
|
|
396
|
+
const json = await response.json().catch(() => null);
|
|
397
|
+
if (!response.ok || !json?.universe) {
|
|
398
|
+
throw new HyperliquidApiError(
|
|
399
|
+
"Unable to load Hyperliquid spot metadata.",
|
|
400
|
+
json ?? { status: response.status }
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
const universe = json.universe ?? [];
|
|
404
|
+
const tokens = json.tokens ?? [];
|
|
405
|
+
spotMetaCache.set(cacheKey, { fetchedAt: Date.now(), universe, tokens });
|
|
406
|
+
return { universe, tokens };
|
|
407
|
+
}
|
|
291
408
|
function resolveAssetIndex(symbol, universe) {
|
|
292
409
|
const [raw] = symbol.split("-");
|
|
293
410
|
const target = raw.trim();
|
|
@@ -331,11 +448,57 @@ async function resolveDexIndex(args) {
|
|
|
331
448
|
}
|
|
332
449
|
return index;
|
|
333
450
|
}
|
|
451
|
+
function buildSpotTokenIndexMap(tokens) {
|
|
452
|
+
const map = /* @__PURE__ */ new Map();
|
|
453
|
+
for (const token of tokens) {
|
|
454
|
+
const name = normalizeSpotTokenName(token?.name);
|
|
455
|
+
const index = typeof token?.index === "number" && Number.isFinite(token.index) ? token.index : null;
|
|
456
|
+
if (!name || index == null) continue;
|
|
457
|
+
if (!map.has(name) || token?.isCanonical) {
|
|
458
|
+
map.set(name, index);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return map;
|
|
462
|
+
}
|
|
463
|
+
function resolveSpotTokenIndex(tokenMap, value) {
|
|
464
|
+
const normalized = normalizeSpotTokenName(value);
|
|
465
|
+
if (!normalized) return null;
|
|
466
|
+
const direct = tokenMap.get(normalized);
|
|
467
|
+
if (direct != null) return direct;
|
|
468
|
+
if (!normalized.startsWith("U")) {
|
|
469
|
+
const prefixed = tokenMap.get(`U${normalized}`);
|
|
470
|
+
if (prefixed != null) return prefixed;
|
|
471
|
+
}
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
function resolveSpotMarketIndex(args) {
|
|
475
|
+
for (let i = 0; i < args.universe.length; i += 1) {
|
|
476
|
+
const entry = args.universe[i];
|
|
477
|
+
const tokens = Array.isArray(entry?.tokens) ? entry.tokens : null;
|
|
478
|
+
const baseToken = tokens?.[0] ?? entry?.baseToken ?? null;
|
|
479
|
+
const quoteToken = tokens?.[1] ?? entry?.quoteToken ?? null;
|
|
480
|
+
if (baseToken === args.baseToken && quoteToken === args.quoteToken) {
|
|
481
|
+
if (typeof entry?.index === "number" && Number.isFinite(entry.index)) {
|
|
482
|
+
return entry.index;
|
|
483
|
+
}
|
|
484
|
+
return i;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
334
489
|
async function resolveHyperliquidAssetIndex(args) {
|
|
335
490
|
const trimmed = args.symbol.trim();
|
|
336
491
|
if (!trimmed) {
|
|
337
492
|
throw new Error("Hyperliquid symbol must be a non-empty string.");
|
|
338
493
|
}
|
|
494
|
+
if (trimmed.startsWith("@")) {
|
|
495
|
+
const rawIndex = trimmed.slice(1).trim();
|
|
496
|
+
const index = Number(rawIndex);
|
|
497
|
+
if (!Number.isFinite(index)) {
|
|
498
|
+
throw new Error(`Hyperliquid spot market index is invalid: ${trimmed}`);
|
|
499
|
+
}
|
|
500
|
+
return 1e4 + index;
|
|
501
|
+
}
|
|
339
502
|
const separator = trimmed.indexOf(":");
|
|
340
503
|
if (separator > 0) {
|
|
341
504
|
const dex = trimmed.slice(0, separator).trim();
|
|
@@ -362,6 +525,29 @@ async function resolveHyperliquidAssetIndex(args) {
|
|
|
362
525
|
}
|
|
363
526
|
return 1e5 + dexIndex * 1e4 + assetIndex;
|
|
364
527
|
}
|
|
528
|
+
const pair = parseHyperliquidPair(trimmed);
|
|
529
|
+
if (pair) {
|
|
530
|
+
const { universe: universe2, tokens } = await getSpotMeta({
|
|
531
|
+
baseUrl: args.baseUrl,
|
|
532
|
+
environment: args.environment,
|
|
533
|
+
fetcher: args.fetcher
|
|
534
|
+
});
|
|
535
|
+
const tokenMap = buildSpotTokenIndexMap(tokens);
|
|
536
|
+
const baseToken = resolveSpotTokenIndex(tokenMap, pair.base);
|
|
537
|
+
const quoteToken = resolveSpotTokenIndex(tokenMap, pair.quote);
|
|
538
|
+
if (baseToken == null || quoteToken == null) {
|
|
539
|
+
throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
|
|
540
|
+
}
|
|
541
|
+
const marketIndex = resolveSpotMarketIndex({
|
|
542
|
+
universe: universe2,
|
|
543
|
+
baseToken,
|
|
544
|
+
quoteToken
|
|
545
|
+
});
|
|
546
|
+
if (marketIndex == null) {
|
|
547
|
+
throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
|
|
548
|
+
}
|
|
549
|
+
return 1e4 + marketIndex;
|
|
550
|
+
}
|
|
365
551
|
const universe = await getUniverse({
|
|
366
552
|
baseUrl: args.baseUrl,
|
|
367
553
|
environment: args.environment,
|