@t2000/engine 0.54.0 → 0.54.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/dist/index.d.ts +24 -1
- package/dist/index.js +69 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2274,6 +2274,20 @@ interface PortfolioResult {
|
|
|
2274
2274
|
totalValue: number;
|
|
2275
2275
|
walletValue: number;
|
|
2276
2276
|
savingsValue: number;
|
|
2277
|
+
/**
|
|
2278
|
+
* [Bug — 2026-04-28] Aggregated DeFi value across non-NAVI protocols
|
|
2279
|
+
* (Cetus LPs, Bluefin, Suilend, etc.) — same field that's been on
|
|
2280
|
+
* `balance_check` since v0.50. Pre-fix this tool ignored DeFi entirely:
|
|
2281
|
+
* a wallet with $1,569 in Cetus LPs reported a $228 totalValue
|
|
2282
|
+
* (wallet only), under-counting net worth by 87% and prompting the LLM
|
|
2283
|
+
* to misclassify the wallet as "concentrated in FAITH" when actually
|
|
2284
|
+
* the bulk was in liquidity pools. Same SSOT-divergence class the v0.54
|
|
2285
|
+
* cache work fixed for FullPortfolioCanvas, manifesting in a different
|
|
2286
|
+
* tool that was written before DeFi support was bolted on.
|
|
2287
|
+
*/
|
|
2288
|
+
defiValue: number;
|
|
2289
|
+
/** Provenance of the DeFi read — used by the UI card to caveat partial/degraded. */
|
|
2290
|
+
defiSource: DefiSummary['source'];
|
|
2277
2291
|
debtValue: number;
|
|
2278
2292
|
healthFactor: number | null;
|
|
2279
2293
|
allocations: AssetAllocation[];
|
|
@@ -2508,12 +2522,21 @@ interface AudricPortfolioResult {
|
|
|
2508
2522
|
portfolio: AddressPortfolio;
|
|
2509
2523
|
/** NAVI lending positions, normalized to the engine's `ServerPositionData`. */
|
|
2510
2524
|
positions: ServerPositionData;
|
|
2511
|
-
/** Net worth derived audric-side (`wallet + savings - borrows`). */
|
|
2525
|
+
/** Net worth derived audric-side (`wallet + savings + defi - borrows`). */
|
|
2512
2526
|
netWorthUsd: number;
|
|
2513
2527
|
/** `savings * savingsRate / 365`, capped at 0. */
|
|
2514
2528
|
estimatedDailyYield: number;
|
|
2515
2529
|
/** Per-symbol balance map — convenient for adapters that already used `WalletBalances`. */
|
|
2516
2530
|
walletAllocations: Record<string, number>;
|
|
2531
|
+
/**
|
|
2532
|
+
* [Bug — 2026-04-28] Aggregated DeFi value (Cetus LPs, Bluefin, Suilend,
|
|
2533
|
+
* etc.) when available. `defiSource === 'degraded'` when audric's wire
|
|
2534
|
+
* didn't include the field — callers should treat that as "fall back to
|
|
2535
|
+
* a direct fetchAddressDefiPortfolio call" (same convention used
|
|
2536
|
+
* inside the audric web app's UI components).
|
|
2537
|
+
*/
|
|
2538
|
+
defiValueUsd: number;
|
|
2539
|
+
defiSource: DefiSummary['source'];
|
|
2517
2540
|
}
|
|
2518
2541
|
/**
|
|
2519
2542
|
* Fetch the canonical portfolio snapshot from audric. Returns `null` if
|
package/dist/index.js
CHANGED
|
@@ -1243,7 +1243,14 @@ async function fetchAudricPortfolio(address, env, signal) {
|
|
|
1243
1243
|
positions,
|
|
1244
1244
|
netWorthUsd: json.netWorthUsd ?? portfolio.totalUsd + positions.savings - positions.borrows,
|
|
1245
1245
|
estimatedDailyYield: json.estimatedDailyYield ?? 0,
|
|
1246
|
-
walletAllocations: json.walletAllocations ?? {}
|
|
1246
|
+
walletAllocations: json.walletAllocations ?? {},
|
|
1247
|
+
// Default to 'degraded' (not 'partial') when the wire shape lacks
|
|
1248
|
+
// DeFi: 'partial' implies "we tried and got partial data" which is
|
|
1249
|
+
// misleading for a route that simply doesn't return the field.
|
|
1250
|
+
// Callers that need DeFi must fall back to a direct fetch on
|
|
1251
|
+
// 'degraded' — exactly the convention BalanceCard already uses.
|
|
1252
|
+
defiValueUsd: typeof json.defiValueUsd === "number" ? json.defiValueUsd : 0,
|
|
1253
|
+
defiSource: json.defiSource ?? "degraded"
|
|
1247
1254
|
};
|
|
1248
1255
|
} catch (err) {
|
|
1249
1256
|
console.warn(`[audric-api] portfolio ${address.slice(0, 10)} fetch failed:`, err);
|
|
@@ -1932,10 +1939,25 @@ var STABLECOIN_SYMBOLS2 = /* @__PURE__ */ new Set([
|
|
|
1932
1939
|
function isStable(symbol) {
|
|
1933
1940
|
return STABLECOIN_SYMBOLS2.has(symbol.toLowerCase());
|
|
1934
1941
|
}
|
|
1942
|
+
var TOKEN_ALIASES = {
|
|
1943
|
+
usdt: ["usdt", "wusdt", "suiusdt"],
|
|
1944
|
+
usdc: ["usdc", "wusdc"],
|
|
1945
|
+
usde: ["usde", "suiusde", "sui_usde"],
|
|
1946
|
+
usdsui: ["usdsui"]
|
|
1947
|
+
};
|
|
1948
|
+
function expandAliases(symbols) {
|
|
1949
|
+
const out = /* @__PURE__ */ new Set();
|
|
1950
|
+
for (const s of symbols) {
|
|
1951
|
+
const norm = s.toLowerCase();
|
|
1952
|
+
const aliases = TOKEN_ALIASES[norm] ?? [norm];
|
|
1953
|
+
for (const a of aliases) out.add(a);
|
|
1954
|
+
}
|
|
1955
|
+
return out;
|
|
1956
|
+
}
|
|
1935
1957
|
function applyFilters(rates, opts) {
|
|
1936
1958
|
let entries = Object.entries(rates);
|
|
1937
1959
|
if (opts.assets && opts.assets.length) {
|
|
1938
|
-
const wanted =
|
|
1960
|
+
const wanted = expandAliases(opts.assets);
|
|
1939
1961
|
entries = entries.filter(([sym]) => wanted.has(sym.toLowerCase()));
|
|
1940
1962
|
} else if (opts.stableOnly) {
|
|
1941
1963
|
entries = entries.filter(([sym]) => isStable(sym));
|
|
@@ -3277,7 +3299,7 @@ var portfolioAnalysisTool = buildTool({
|
|
|
3277
3299
|
context.signal
|
|
3278
3300
|
);
|
|
3279
3301
|
const apiUrl = context.env?.AUDRIC_INTERNAL_API_URL;
|
|
3280
|
-
const [portfolio, positions, weekHistResult] = await Promise.all([
|
|
3302
|
+
const [portfolio, positions, weekHistResult, defiSummary] = await Promise.all([
|
|
3281
3303
|
audricSnapshot ? Promise.resolve(audricSnapshot.portfolio) : (async () => {
|
|
3282
3304
|
if (context.portfolioCache) {
|
|
3283
3305
|
const hit = context.portfolioCache.get(address);
|
|
@@ -3306,7 +3328,23 @@ var portfolioAnalysisTool = buildTool({
|
|
|
3306
3328
|
apiUrl ? fetch(
|
|
3307
3329
|
`${apiUrl}/api/analytics/portfolio-history?days=7`,
|
|
3308
3330
|
{ headers: { "x-sui-address": address }, signal: context.signal }
|
|
3309
|
-
).then((res) => res.ok ? res.json() : null).catch(() => null) : Promise.resolve(null)
|
|
3331
|
+
).then((res) => res.ok ? res.json() : null).catch(() => null) : Promise.resolve(null),
|
|
3332
|
+
// DeFi fetch — prefer the audric snapshot's already-computed value
|
|
3333
|
+
// (when present and not 'degraded'), otherwise call the engine's
|
|
3334
|
+
// direct aggregator. The 'degraded' check prevents the audric
|
|
3335
|
+
// path from masking a useful direct read when the audric route's
|
|
3336
|
+
// own DeFi field came back empty.
|
|
3337
|
+
audricSnapshot && audricSnapshot.defiSource !== "degraded" ? Promise.resolve({
|
|
3338
|
+
totalUsd: audricSnapshot.defiValueUsd,
|
|
3339
|
+
perProtocol: {},
|
|
3340
|
+
pricedAt: Date.now(),
|
|
3341
|
+
source: audricSnapshot.defiSource
|
|
3342
|
+
}) : fetchAddressDefiPortfolio(address, context.blockvisionApiKey).catch(
|
|
3343
|
+
(err) => {
|
|
3344
|
+
console.warn("[portfolio_analysis] defi fetch failed:", err);
|
|
3345
|
+
return { totalUsd: 0, perProtocol: {}, pricedAt: Date.now(), source: "degraded" };
|
|
3346
|
+
}
|
|
3347
|
+
)
|
|
3310
3348
|
]);
|
|
3311
3349
|
let walletValue = 0;
|
|
3312
3350
|
const allAllocations = [];
|
|
@@ -3336,7 +3374,18 @@ var portfolioAnalysisTool = buildTool({
|
|
|
3336
3374
|
if (weekHistResult?.change && weekHistResult.change.absoluteUsd !== 0) {
|
|
3337
3375
|
weekChange = weekHistResult.change;
|
|
3338
3376
|
}
|
|
3339
|
-
const
|
|
3377
|
+
const defiValue = defiSummary.totalUsd;
|
|
3378
|
+
if (defiSummary.source !== "degraded") {
|
|
3379
|
+
for (const [protocol, usdValue] of Object.entries(defiSummary.perProtocol)) {
|
|
3380
|
+
if (typeof usdValue === "number" && usdValue >= DUST_USD) {
|
|
3381
|
+
const label = protocol.charAt(0).toUpperCase() + protocol.slice(1) + " DeFi";
|
|
3382
|
+
allocations.push({ symbol: label, amount: 0, usdValue, percentage: 0 });
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
} else if (defiValue > 0) {
|
|
3386
|
+
allocations.push({ symbol: "DeFi (aggregate)", amount: 0, usdValue: defiValue, percentage: 0 });
|
|
3387
|
+
}
|
|
3388
|
+
const totalValue = walletValue + savingsValue + defiValue;
|
|
3340
3389
|
for (const a of allocations) {
|
|
3341
3390
|
a.percentage = totalValue > 0 ? a.usdValue / totalValue * 100 : 0;
|
|
3342
3391
|
}
|
|
@@ -3374,10 +3423,23 @@ var portfolioAnalysisTool = buildTool({
|
|
|
3374
3423
|
message: "Portfolio is concentrated in a single asset."
|
|
3375
3424
|
});
|
|
3376
3425
|
}
|
|
3426
|
+
if (defiSummary.source === "degraded") {
|
|
3427
|
+
insights.push({
|
|
3428
|
+
type: "warning",
|
|
3429
|
+
message: "DeFi positions could not be loaded \u2014 total may under-count any Cetus/Bluefin/Suilend value."
|
|
3430
|
+
});
|
|
3431
|
+
} else if (defiSummary.source === "partial") {
|
|
3432
|
+
insights.push({
|
|
3433
|
+
type: "warning",
|
|
3434
|
+
message: "DeFi data is partial \u2014 at least one protocol failed; total may under-count."
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3377
3437
|
const result = {
|
|
3378
3438
|
totalValue,
|
|
3379
3439
|
walletValue,
|
|
3380
3440
|
savingsValue,
|
|
3441
|
+
defiValue,
|
|
3442
|
+
defiSource: defiSummary.source,
|
|
3381
3443
|
debtValue,
|
|
3382
3444
|
healthFactor,
|
|
3383
3445
|
allocations: allocations.slice(0, 10),
|
|
@@ -3388,7 +3450,8 @@ var portfolioAnalysisTool = buildTool({
|
|
|
3388
3450
|
weekChange,
|
|
3389
3451
|
priceSource: portfolio.source
|
|
3390
3452
|
};
|
|
3391
|
-
const
|
|
3453
|
+
const defiSegment = defiValue > 0 ? ` | DeFi: $${defiValue.toFixed(2)}${defiSummary.source === "partial" ? " (partial)" : ""}` : "";
|
|
3454
|
+
const topLine = `Total: $${totalValue.toFixed(2)} | Wallet: $${walletValue.toFixed(2)} | Savings: $${savingsValue.toFixed(2)}${defiSegment}`;
|
|
3392
3455
|
const insightLines = insights.map((i) => `${i.type === "warning" ? "\u26A0" : "\u2192"} ${i.message}`).join("\n");
|
|
3393
3456
|
return {
|
|
3394
3457
|
data: result,
|