@owney/sdk 0.7.23 → 0.7.24-beta.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/dist/index.cjs CHANGED
@@ -27,7 +27,6 @@ __export(index_exports, {
27
27
  OwneyError: () => OwneyError,
28
28
  OwneySDK: () => OwneySDK,
29
29
  createOwneySIWX: () => createOwneySIWX,
30
- recentEarningsFromPoints: () => recentEarningsFromPoints,
31
30
  setOwneyDebug: () => setOwneyDebug
32
31
  });
33
32
  module.exports = __toCommonJS(index_exports);
@@ -698,62 +697,74 @@ function computeAllocationApy(positions) {
698
697
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
699
698
  return { totalApy, apyByChainAndAsset };
700
699
  }
701
- var ZYFAI_NET_OF_FEE_MULTIPLIER = 0.9;
702
- function sumEarningsBucket(bucket, chainId, tokenSymbol) {
700
+ function earningsForToken(bucket, chainId, asset) {
703
701
  const tokens = bucket?.[String(chainId)];
704
702
  if (!tokens) return null;
705
- const wanted = tokenSymbol?.toUpperCase();
706
- let total = 0;
707
- let matched = false;
703
+ const wanted = asset.toUpperCase();
708
704
  for (const [symbol, value] of Object.entries(tokens)) {
709
- if (wanted && symbol.toUpperCase() !== wanted) continue;
710
- matched = true;
705
+ if (symbol.toUpperCase() !== wanted) continue;
711
706
  const amount = Number(value);
712
- if (!Number.isFinite(amount)) continue;
713
- total += amount;
707
+ return Number.isFinite(amount) ? amount : null;
714
708
  }
715
- return matched ? total : null;
709
+ return null;
716
710
  }
717
- function netEarningsForSnapshot(entry, chainId, tokenSymbol) {
718
- const lifetime = sumEarningsBucket(entry.lifetime_earnings_by_token, chainId, tokenSymbol);
719
- const unrealized = sumEarningsBucket(entry.unrealized_earnings_by_token, chainId, tokenSymbol);
720
- const current = sumEarningsBucket(entry.current_earnings_by_token, chainId, tokenSymbol);
721
- if (lifetime === null && unrealized === null && current === null) {
722
- const gross = sumEarningsBucket(entry.total_earnings_by_token, chainId, tokenSymbol);
723
- if (gross === null) return null;
724
- if (!warnedGrossApyFallbacks.has("daily_earnings_net_components")) {
725
- warnedGrossApyFallbacks.add("daily_earnings_net_components");
726
- console.warn(
727
- `[owney] @zyfai/sdk omitted the daily net-earnings components; falling back to gross totals, which do not deduct Zyfai's performance fee and so read high.`
728
- );
729
- }
730
- debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
731
- return gross;
711
+ function assetsInSnapshot(entry, chainId) {
712
+ const key2 = String(chainId);
713
+ const seen = /* @__PURE__ */ new Set();
714
+ for (const bucket of [
715
+ entry.daily_total_delta_by_token_withoutFee,
716
+ entry.daily_total_delta_by_token,
717
+ entry.lifetime_earnings_by_token,
718
+ entry.unrealized_earnings_by_token,
719
+ entry.current_earnings_by_token,
720
+ entry.total_earnings_by_token
721
+ ]) {
722
+ for (const symbol of Object.keys(bucket?.[key2] ?? {})) {
723
+ seen.add(symbol.toUpperCase());
724
+ }
725
+ }
726
+ return [...seen];
727
+ }
728
+ function netDeltaForSnapshot(entry, chainId, asset) {
729
+ const net = earningsForToken(
730
+ entry.daily_total_delta_by_token_withoutFee,
731
+ chainId,
732
+ asset
733
+ );
734
+ if (net !== null) return net;
735
+ const gross = earningsForToken(
736
+ entry.daily_total_delta_by_token,
737
+ chainId,
738
+ asset
739
+ );
740
+ if (gross === null) return 0;
741
+ if (!warnedGrossApyFallbacks.has("daily_earnings_delta_without_fee")) {
742
+ warnedGrossApyFallbacks.add("daily_earnings_delta_without_fee");
743
+ console.warn(
744
+ `[owney] @zyfai/sdk did not supply daily_total_delta_by_token_withoutFee; falling back to the gross daily delta, which does not deduct Zyfai's performance fee and so reads high.`
745
+ );
732
746
  }
733
- return (lifetime ?? 0) + (unrealized ?? 0) + (current ?? 0) * ZYFAI_NET_OF_FEE_MULTIPLIER;
747
+ debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
748
+ return gross;
734
749
  }
735
750
  function mapDailyEarnings(raw, chainId, tokenSymbol) {
736
- const points = (raw.data ?? []).map((entry) => ({
737
- date: entry.snapshot_date,
738
- net: netEarningsForSnapshot(entry, chainId, tokenSymbol)
739
- })).filter((p) => p.net !== null).sort((a, b) => a.date.localeCompare(b.date));
740
- return { walletAddress: raw.walletAddress, points };
741
- }
742
- var MS_PER_DAY = 24 * 60 * 60 * 1e3;
743
- function recentEarningsFromPoints(points, requestedDays) {
744
- if (points.length === 0) return null;
745
- const first = points[0];
746
- const last = points[points.length - 1];
747
- const spanDays = Math.round(
748
- (Date.parse(last.date) - Date.parse(first.date)) / MS_PER_DAY
751
+ const wanted = tokenSymbol?.toUpperCase();
752
+ const snapshots = [...raw.data ?? []].sort(
753
+ (a, b) => a.snapshot_date.localeCompare(b.snapshot_date)
749
754
  );
750
- const amount = Math.max(0, last.net - first.net);
751
- return {
752
- amount,
753
- spanDays: Number.isFinite(spanDays) ? spanDays : 0,
754
- // A single snapshot spans no window at all, so it is always truncated.
755
- isTruncated: requestedDays === void 0 ? points.length < 2 : spanDays < requestedDays
756
- };
755
+ const byAsset = /* @__PURE__ */ new Map();
756
+ for (const entry of snapshots) {
757
+ for (const asset of assetsInSnapshot(entry, chainId)) {
758
+ if (wanted && asset !== wanted) continue;
759
+ const delta = netDeltaForSnapshot(entry, chainId, asset);
760
+ const series = byAsset.get(asset) ?? { points: [], total: 0 };
761
+ series.total += delta;
762
+ series.points.push({ date: entry.snapshot_date, amount: series.total });
763
+ byAsset.set(asset, series);
764
+ }
765
+ }
766
+ const assets = [...byAsset.entries()].map(([asset, series]) => ({ asset, points: series.points })).sort((a, b) => a.asset.localeCompare(b.asset));
767
+ return { walletAddress: raw.walletAddress, chainId, assets };
757
768
  }
758
769
 
759
770
  // src/agents/zyfai/zyfai.withdraw-amount.ts
@@ -3999,7 +4010,11 @@ var OwneySDK = class {
3999
4010
  if (agentId) {
4000
4011
  const agent = this.getAgent(agentId);
4001
4012
  if (!agent.getDailyEarnings) {
4002
- return { walletAddress: state.walletAddress ?? "", points: [] };
4013
+ return {
4014
+ walletAddress: state.walletAddress ?? "",
4015
+ chainId,
4016
+ assets: []
4017
+ };
4003
4018
  }
4004
4019
  return this.readAgent(
4005
4020
  agent,
@@ -4021,15 +4036,23 @@ var OwneySDK = class {
4021
4036
  )
4022
4037
  )
4023
4038
  );
4024
- const byDate = /* @__PURE__ */ new Map();
4039
+ const byAsset = /* @__PURE__ */ new Map();
4025
4040
  for (const s of series) {
4026
- for (const point of s.points) {
4027
- byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.net);
4041
+ for (const { asset, points } of s.assets) {
4042
+ const byDate = byAsset.get(asset) ?? /* @__PURE__ */ new Map();
4043
+ for (const point of points) {
4044
+ byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.amount);
4045
+ }
4046
+ byAsset.set(asset, byDate);
4028
4047
  }
4029
4048
  }
4030
4049
  return {
4031
4050
  walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
4032
- points: [...byDate.entries()].map(([date, net]) => ({ date, net })).sort((a, b) => a.date.localeCompare(b.date))
4051
+ chainId,
4052
+ assets: [...byAsset.entries()].map(([asset, byDate]) => ({
4053
+ asset,
4054
+ points: [...byDate.entries()].map(([date, amount]) => ({ date, amount })).sort((a, b) => a.date.localeCompare(b.date))
4055
+ })).sort((a, b) => a.asset.localeCompare(b.asset))
4033
4056
  };
4034
4057
  }
4035
4058
  async getAccountApy({
@@ -4593,6 +4616,5 @@ function createOwneySIWX(config) {
4593
4616
  OwneyError,
4594
4617
  OwneySDK,
4595
4618
  createOwneySIWX,
4596
- recentEarningsFromPoints,
4597
4619
  setOwneyDebug
4598
4620
  });
package/dist/index.d.cts CHANGED
@@ -77,7 +77,14 @@ type AvailableAgentsOptions = {
77
77
  /** Disabled agents are omitted by default because they cannot accept funds. */
78
78
  includeDisabled?: boolean;
79
79
  };
80
- type DailyApyDays = "7D" | "14D" | "30D";
80
+ /**
81
+ * A lookback window for any "last N days" read — the APY series, the daily
82
+ * earnings series. Named for the window itself, so nothing borrows the APY's
83
+ * name to ask for something else.
84
+ */
85
+ type LookbackDays = "7D" | "14D" | "30D";
86
+ /** Kept so existing callers keep compiling. Prefer `LookbackDays`. */
87
+ type DailyApyDays = LookbackDays;
81
88
  type HistoryFilters = {
82
89
  fromDate?: string;
83
90
  toDate?: string;
@@ -106,7 +113,7 @@ type WithdrawOptions = {
106
113
  };
107
114
  type AccountApyOptions = {
108
115
  agentId?: AgentId;
109
- days: DailyApyDays;
116
+ days: LookbackDays;
110
117
  /**
111
118
  * Optional asset symbol (e.g. "USDC", "WETH") to scope the daily APY series
112
119
  * to a specific asset on the active chain. Without it the series blends every
@@ -116,6 +123,20 @@ type AccountApyOptions = {
116
123
  */
117
124
  tokenSymbol?: string;
118
125
  };
126
+ /**
127
+ * Options for the daily earnings series. Same shape as `AccountApyOptions` and
128
+ * deliberately its own type: the two reads answer different questions and are
129
+ * free to diverge.
130
+ */
131
+ type DailyEarningsOptions = {
132
+ agentId?: AgentId;
133
+ days: LookbackDays;
134
+ /**
135
+ * Optional asset symbol (e.g. "USDC", "WETH") scoping the series to one
136
+ * asset on the active chain.
137
+ */
138
+ tokenSymbol?: string;
139
+ };
119
140
  type AllocationApyOptions = {
120
141
  agentId?: AgentId;
121
142
  };
@@ -395,29 +416,39 @@ interface AgentApy {
395
416
  interface OwneyAgentApy {
396
417
  agentApy: Record<AgentId, AgentApy>;
397
418
  }
398
- /** One day's cumulative NET earnings for the selected chain/asset. */
419
+ /** One day's cumulative NET earnings for a single asset. */
399
420
  interface DailyEarningsPoint {
400
421
  /** ISO date string for the day, e.g. "2026-09-01". */
401
422
  date: string;
402
- /** Cumulative net-of-fee earnings as of this day, in the asset's units. */
403
- net: number;
423
+ /**
424
+ * Earnings accumulated from the start of the returned series up to and
425
+ * including this day, net of the agent's performance fee, denominated in the
426
+ * asset's own units. A running total of daily deltas, so it measures the
427
+ * window — not the wallet's lifetime.
428
+ */
429
+ amount: number;
404
430
  }
405
- interface AccountDailyEarnings {
406
- walletAddress: string;
431
+ /** One asset's cumulative series on the chain. */
432
+ interface AssetDailyEarnings {
433
+ /** Asset symbol, e.g. "USDC" / "WETH". */
434
+ asset: string;
407
435
  /**
408
- * Cumulative net-earnings series for the requested window, ascending by date.
409
- * Empty when the provider returns no snapshots for this chain/asset.
436
+ * Ascending by date. Days the wallet held nothing of this asset are absent
437
+ * rather than zero — a zero would read as "earned nothing that day".
410
438
  */
411
439
  points: DailyEarningsPoint[];
412
440
  }
413
- /** Earnings accrued across a window, derived from an AccountDailyEarnings series. */
414
- interface RecentEarnings {
415
- /** Net earnings over the window; never negative. */
416
- amount: number;
417
- /** Days actually spanned by the series — not necessarily the days requested. */
418
- spanDays: number;
419
- /** True when the series is shorter than the requested window. */
420
- isTruncated: boolean;
441
+ interface AccountDailyEarnings {
442
+ walletAddress: string;
443
+ chainId: number;
444
+ /**
445
+ * One cumulative series per asset held on the chain, never a single blended
446
+ * series: USDC and WETH amounts are in different units, so adding them
447
+ * produces a number that means nothing (2 + 0.001). Empty when the provider
448
+ * returns no snapshots. Narrowed to one entry when the caller passes
449
+ * `tokenSymbol`.
450
+ */
451
+ assets: AssetDailyEarnings[];
421
452
  }
422
453
 
423
454
  type DepositCallback = (smartWalletAddress: string, chainId: number, amount: string) => Promise<`0x${string}`> | `0x${string}`;
@@ -460,7 +491,7 @@ interface IAgent {
460
491
  * Backs the "recent earnings" subline, whose figure must reconcile with the
461
492
  * balance headline directly above it. (ROUT-452)
462
493
  */
463
- getDailyEarnings?(state: ConnectionState, chainId: number, days: DailyApyDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
494
+ getDailyEarnings?(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
464
495
  getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
465
496
  getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
466
497
  /**
@@ -705,7 +736,7 @@ declare class OwneySDK {
705
736
  * subtract from the total. Without an agentId the series is the sum of the
706
737
  * agents that answered.
707
738
  */
708
- getDailyEarnings({ agentId, days, tokenSymbol, }: AccountApyOptions): Promise<AccountDailyEarnings>;
739
+ getDailyEarnings({ agentId, days, tokenSymbol, }: DailyEarningsOptions): Promise<AccountDailyEarnings>;
709
740
  getAccountApy({ agentId, days, tokenSymbol, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
710
741
  /**
711
742
  * Get transaction history for a specific agent, or all agents.
@@ -824,21 +855,6 @@ declare global {
824
855
  /** Enable/disable debug logging programmatically. */
825
856
  declare function setOwneyDebug(enabled: boolean): void;
826
857
 
827
- /**
828
- * Earnings accrued across a window, as the difference between the series'
829
- * endpoints.
830
- *
831
- * Differencing endpoints rather than summing `daily_total_delta_by_token`
832
- * means a missing day in the middle of the window cannot undercount the
833
- * result — the two endpoints are cumulative totals, so whatever happened in
834
- * between is already priced in.
835
- *
836
- * `requestedDays` is the window the user selected in the APY chart. When the
837
- * series is shorter than that, the caller relabels ("Since you started")
838
- * rather than claiming a window we don't have data for.
839
- */
840
- declare function recentEarningsFromPoints(points: DailyEarningsPoint[], requestedDays?: number): RecentEarnings | null;
841
-
842
858
  type OwneySIWXConfig = {
843
859
  /** Owney/Zyfai API key — same value passed to `new OwneySDK({ apiKey })`. */
844
860
  apiKey: string;
@@ -852,4 +868,4 @@ type OwneySIWXConfig = {
852
868
  */
853
869
  declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
854
870
 
855
- export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type RecentEarnings, type WithdrawOptions, createOwneySIWX, recentEarningsFromPoints, setOwneyDebug };
871
+ export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
package/dist/index.d.ts CHANGED
@@ -77,7 +77,14 @@ type AvailableAgentsOptions = {
77
77
  /** Disabled agents are omitted by default because they cannot accept funds. */
78
78
  includeDisabled?: boolean;
79
79
  };
80
- type DailyApyDays = "7D" | "14D" | "30D";
80
+ /**
81
+ * A lookback window for any "last N days" read — the APY series, the daily
82
+ * earnings series. Named for the window itself, so nothing borrows the APY's
83
+ * name to ask for something else.
84
+ */
85
+ type LookbackDays = "7D" | "14D" | "30D";
86
+ /** Kept so existing callers keep compiling. Prefer `LookbackDays`. */
87
+ type DailyApyDays = LookbackDays;
81
88
  type HistoryFilters = {
82
89
  fromDate?: string;
83
90
  toDate?: string;
@@ -106,7 +113,7 @@ type WithdrawOptions = {
106
113
  };
107
114
  type AccountApyOptions = {
108
115
  agentId?: AgentId;
109
- days: DailyApyDays;
116
+ days: LookbackDays;
110
117
  /**
111
118
  * Optional asset symbol (e.g. "USDC", "WETH") to scope the daily APY series
112
119
  * to a specific asset on the active chain. Without it the series blends every
@@ -116,6 +123,20 @@ type AccountApyOptions = {
116
123
  */
117
124
  tokenSymbol?: string;
118
125
  };
126
+ /**
127
+ * Options for the daily earnings series. Same shape as `AccountApyOptions` and
128
+ * deliberately its own type: the two reads answer different questions and are
129
+ * free to diverge.
130
+ */
131
+ type DailyEarningsOptions = {
132
+ agentId?: AgentId;
133
+ days: LookbackDays;
134
+ /**
135
+ * Optional asset symbol (e.g. "USDC", "WETH") scoping the series to one
136
+ * asset on the active chain.
137
+ */
138
+ tokenSymbol?: string;
139
+ };
119
140
  type AllocationApyOptions = {
120
141
  agentId?: AgentId;
121
142
  };
@@ -395,29 +416,39 @@ interface AgentApy {
395
416
  interface OwneyAgentApy {
396
417
  agentApy: Record<AgentId, AgentApy>;
397
418
  }
398
- /** One day's cumulative NET earnings for the selected chain/asset. */
419
+ /** One day's cumulative NET earnings for a single asset. */
399
420
  interface DailyEarningsPoint {
400
421
  /** ISO date string for the day, e.g. "2026-09-01". */
401
422
  date: string;
402
- /** Cumulative net-of-fee earnings as of this day, in the asset's units. */
403
- net: number;
423
+ /**
424
+ * Earnings accumulated from the start of the returned series up to and
425
+ * including this day, net of the agent's performance fee, denominated in the
426
+ * asset's own units. A running total of daily deltas, so it measures the
427
+ * window — not the wallet's lifetime.
428
+ */
429
+ amount: number;
404
430
  }
405
- interface AccountDailyEarnings {
406
- walletAddress: string;
431
+ /** One asset's cumulative series on the chain. */
432
+ interface AssetDailyEarnings {
433
+ /** Asset symbol, e.g. "USDC" / "WETH". */
434
+ asset: string;
407
435
  /**
408
- * Cumulative net-earnings series for the requested window, ascending by date.
409
- * Empty when the provider returns no snapshots for this chain/asset.
436
+ * Ascending by date. Days the wallet held nothing of this asset are absent
437
+ * rather than zero — a zero would read as "earned nothing that day".
410
438
  */
411
439
  points: DailyEarningsPoint[];
412
440
  }
413
- /** Earnings accrued across a window, derived from an AccountDailyEarnings series. */
414
- interface RecentEarnings {
415
- /** Net earnings over the window; never negative. */
416
- amount: number;
417
- /** Days actually spanned by the series — not necessarily the days requested. */
418
- spanDays: number;
419
- /** True when the series is shorter than the requested window. */
420
- isTruncated: boolean;
441
+ interface AccountDailyEarnings {
442
+ walletAddress: string;
443
+ chainId: number;
444
+ /**
445
+ * One cumulative series per asset held on the chain, never a single blended
446
+ * series: USDC and WETH amounts are in different units, so adding them
447
+ * produces a number that means nothing (2 + 0.001). Empty when the provider
448
+ * returns no snapshots. Narrowed to one entry when the caller passes
449
+ * `tokenSymbol`.
450
+ */
451
+ assets: AssetDailyEarnings[];
421
452
  }
422
453
 
423
454
  type DepositCallback = (smartWalletAddress: string, chainId: number, amount: string) => Promise<`0x${string}`> | `0x${string}`;
@@ -460,7 +491,7 @@ interface IAgent {
460
491
  * Backs the "recent earnings" subline, whose figure must reconcile with the
461
492
  * balance headline directly above it. (ROUT-452)
462
493
  */
463
- getDailyEarnings?(state: ConnectionState, chainId: number, days: DailyApyDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
494
+ getDailyEarnings?(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
464
495
  getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
465
496
  getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
466
497
  /**
@@ -705,7 +736,7 @@ declare class OwneySDK {
705
736
  * subtract from the total. Without an agentId the series is the sum of the
706
737
  * agents that answered.
707
738
  */
708
- getDailyEarnings({ agentId, days, tokenSymbol, }: AccountApyOptions): Promise<AccountDailyEarnings>;
739
+ getDailyEarnings({ agentId, days, tokenSymbol, }: DailyEarningsOptions): Promise<AccountDailyEarnings>;
709
740
  getAccountApy({ agentId, days, tokenSymbol, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
710
741
  /**
711
742
  * Get transaction history for a specific agent, or all agents.
@@ -824,21 +855,6 @@ declare global {
824
855
  /** Enable/disable debug logging programmatically. */
825
856
  declare function setOwneyDebug(enabled: boolean): void;
826
857
 
827
- /**
828
- * Earnings accrued across a window, as the difference between the series'
829
- * endpoints.
830
- *
831
- * Differencing endpoints rather than summing `daily_total_delta_by_token`
832
- * means a missing day in the middle of the window cannot undercount the
833
- * result — the two endpoints are cumulative totals, so whatever happened in
834
- * between is already priced in.
835
- *
836
- * `requestedDays` is the window the user selected in the APY chart. When the
837
- * series is shorter than that, the caller relabels ("Since you started")
838
- * rather than claiming a window we don't have data for.
839
- */
840
- declare function recentEarningsFromPoints(points: DailyEarningsPoint[], requestedDays?: number): RecentEarnings | null;
841
-
842
858
  type OwneySIWXConfig = {
843
859
  /** Owney/Zyfai API key — same value passed to `new OwneySDK({ apiKey })`. */
844
860
  apiKey: string;
@@ -852,4 +868,4 @@ type OwneySIWXConfig = {
852
868
  */
853
869
  declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
854
870
 
855
- export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type RecentEarnings, type WithdrawOptions, createOwneySIWX, recentEarningsFromPoints, setOwneyDebug };
871
+ export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
package/dist/index.js CHANGED
@@ -664,62 +664,74 @@ function computeAllocationApy(positions) {
664
664
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
665
665
  return { totalApy, apyByChainAndAsset };
666
666
  }
667
- var ZYFAI_NET_OF_FEE_MULTIPLIER = 0.9;
668
- function sumEarningsBucket(bucket, chainId, tokenSymbol) {
667
+ function earningsForToken(bucket, chainId, asset) {
669
668
  const tokens = bucket?.[String(chainId)];
670
669
  if (!tokens) return null;
671
- const wanted = tokenSymbol?.toUpperCase();
672
- let total = 0;
673
- let matched = false;
670
+ const wanted = asset.toUpperCase();
674
671
  for (const [symbol, value] of Object.entries(tokens)) {
675
- if (wanted && symbol.toUpperCase() !== wanted) continue;
676
- matched = true;
672
+ if (symbol.toUpperCase() !== wanted) continue;
677
673
  const amount = Number(value);
678
- if (!Number.isFinite(amount)) continue;
679
- total += amount;
674
+ return Number.isFinite(amount) ? amount : null;
680
675
  }
681
- return matched ? total : null;
676
+ return null;
682
677
  }
683
- function netEarningsForSnapshot(entry, chainId, tokenSymbol) {
684
- const lifetime = sumEarningsBucket(entry.lifetime_earnings_by_token, chainId, tokenSymbol);
685
- const unrealized = sumEarningsBucket(entry.unrealized_earnings_by_token, chainId, tokenSymbol);
686
- const current = sumEarningsBucket(entry.current_earnings_by_token, chainId, tokenSymbol);
687
- if (lifetime === null && unrealized === null && current === null) {
688
- const gross = sumEarningsBucket(entry.total_earnings_by_token, chainId, tokenSymbol);
689
- if (gross === null) return null;
690
- if (!warnedGrossApyFallbacks.has("daily_earnings_net_components")) {
691
- warnedGrossApyFallbacks.add("daily_earnings_net_components");
692
- console.warn(
693
- `[owney] @zyfai/sdk omitted the daily net-earnings components; falling back to gross totals, which do not deduct Zyfai's performance fee and so read high.`
694
- );
695
- }
696
- debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
697
- return gross;
678
+ function assetsInSnapshot(entry, chainId) {
679
+ const key2 = String(chainId);
680
+ const seen = /* @__PURE__ */ new Set();
681
+ for (const bucket of [
682
+ entry.daily_total_delta_by_token_withoutFee,
683
+ entry.daily_total_delta_by_token,
684
+ entry.lifetime_earnings_by_token,
685
+ entry.unrealized_earnings_by_token,
686
+ entry.current_earnings_by_token,
687
+ entry.total_earnings_by_token
688
+ ]) {
689
+ for (const symbol of Object.keys(bucket?.[key2] ?? {})) {
690
+ seen.add(symbol.toUpperCase());
691
+ }
692
+ }
693
+ return [...seen];
694
+ }
695
+ function netDeltaForSnapshot(entry, chainId, asset) {
696
+ const net = earningsForToken(
697
+ entry.daily_total_delta_by_token_withoutFee,
698
+ chainId,
699
+ asset
700
+ );
701
+ if (net !== null) return net;
702
+ const gross = earningsForToken(
703
+ entry.daily_total_delta_by_token,
704
+ chainId,
705
+ asset
706
+ );
707
+ if (gross === null) return 0;
708
+ if (!warnedGrossApyFallbacks.has("daily_earnings_delta_without_fee")) {
709
+ warnedGrossApyFallbacks.add("daily_earnings_delta_without_fee");
710
+ console.warn(
711
+ `[owney] @zyfai/sdk did not supply daily_total_delta_by_token_withoutFee; falling back to the gross daily delta, which does not deduct Zyfai's performance fee and so reads high.`
712
+ );
698
713
  }
699
- return (lifetime ?? 0) + (unrealized ?? 0) + (current ?? 0) * ZYFAI_NET_OF_FEE_MULTIPLIER;
714
+ debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
715
+ return gross;
700
716
  }
701
717
  function mapDailyEarnings(raw, chainId, tokenSymbol) {
702
- const points = (raw.data ?? []).map((entry) => ({
703
- date: entry.snapshot_date,
704
- net: netEarningsForSnapshot(entry, chainId, tokenSymbol)
705
- })).filter((p) => p.net !== null).sort((a, b) => a.date.localeCompare(b.date));
706
- return { walletAddress: raw.walletAddress, points };
707
- }
708
- var MS_PER_DAY = 24 * 60 * 60 * 1e3;
709
- function recentEarningsFromPoints(points, requestedDays) {
710
- if (points.length === 0) return null;
711
- const first = points[0];
712
- const last = points[points.length - 1];
713
- const spanDays = Math.round(
714
- (Date.parse(last.date) - Date.parse(first.date)) / MS_PER_DAY
718
+ const wanted = tokenSymbol?.toUpperCase();
719
+ const snapshots = [...raw.data ?? []].sort(
720
+ (a, b) => a.snapshot_date.localeCompare(b.snapshot_date)
715
721
  );
716
- const amount = Math.max(0, last.net - first.net);
717
- return {
718
- amount,
719
- spanDays: Number.isFinite(spanDays) ? spanDays : 0,
720
- // A single snapshot spans no window at all, so it is always truncated.
721
- isTruncated: requestedDays === void 0 ? points.length < 2 : spanDays < requestedDays
722
- };
722
+ const byAsset = /* @__PURE__ */ new Map();
723
+ for (const entry of snapshots) {
724
+ for (const asset of assetsInSnapshot(entry, chainId)) {
725
+ if (wanted && asset !== wanted) continue;
726
+ const delta = netDeltaForSnapshot(entry, chainId, asset);
727
+ const series = byAsset.get(asset) ?? { points: [], total: 0 };
728
+ series.total += delta;
729
+ series.points.push({ date: entry.snapshot_date, amount: series.total });
730
+ byAsset.set(asset, series);
731
+ }
732
+ }
733
+ const assets = [...byAsset.entries()].map(([asset, series]) => ({ asset, points: series.points })).sort((a, b) => a.asset.localeCompare(b.asset));
734
+ return { walletAddress: raw.walletAddress, chainId, assets };
723
735
  }
724
736
 
725
737
  // src/agents/zyfai/zyfai.withdraw-amount.ts
@@ -3969,7 +3981,11 @@ var OwneySDK = class {
3969
3981
  if (agentId) {
3970
3982
  const agent = this.getAgent(agentId);
3971
3983
  if (!agent.getDailyEarnings) {
3972
- return { walletAddress: state.walletAddress ?? "", points: [] };
3984
+ return {
3985
+ walletAddress: state.walletAddress ?? "",
3986
+ chainId,
3987
+ assets: []
3988
+ };
3973
3989
  }
3974
3990
  return this.readAgent(
3975
3991
  agent,
@@ -3991,15 +4007,23 @@ var OwneySDK = class {
3991
4007
  )
3992
4008
  )
3993
4009
  );
3994
- const byDate = /* @__PURE__ */ new Map();
4010
+ const byAsset = /* @__PURE__ */ new Map();
3995
4011
  for (const s of series) {
3996
- for (const point of s.points) {
3997
- byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.net);
4012
+ for (const { asset, points } of s.assets) {
4013
+ const byDate = byAsset.get(asset) ?? /* @__PURE__ */ new Map();
4014
+ for (const point of points) {
4015
+ byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.amount);
4016
+ }
4017
+ byAsset.set(asset, byDate);
3998
4018
  }
3999
4019
  }
4000
4020
  return {
4001
4021
  walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
4002
- points: [...byDate.entries()].map(([date, net]) => ({ date, net })).sort((a, b) => a.date.localeCompare(b.date))
4022
+ chainId,
4023
+ assets: [...byAsset.entries()].map(([asset, byDate]) => ({
4024
+ asset,
4025
+ points: [...byDate.entries()].map(([date, amount]) => ({ date, amount })).sort((a, b) => a.date.localeCompare(b.date))
4026
+ })).sort((a, b) => a.asset.localeCompare(b.asset))
4003
4027
  };
4004
4028
  }
4005
4029
  async getAccountApy({
@@ -4562,6 +4586,5 @@ export {
4562
4586
  OwneyError,
4563
4587
  OwneySDK,
4564
4588
  createOwneySIWX,
4565
- recentEarningsFromPoints,
4566
4589
  setOwneyDebug
4567
4590
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.23",
3
+ "version": "0.7.24-beta.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",