@owney/sdk 0.7.25-beta.17 → 0.7.25-beta.19
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 +101 -21
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +101 -21
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3769,6 +3769,35 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3769
3769
|
tokens
|
|
3770
3770
|
};
|
|
3771
3771
|
}
|
|
3772
|
+
function mapYieldseekerDailyEarnings(walletAddress, contexts, days, now = Date.now()) {
|
|
3773
|
+
const today = new Date(now).toISOString().slice(0, 10);
|
|
3774
|
+
const dayCount = { "7D": 7, "14D": 14, "30D": 30 }[days];
|
|
3775
|
+
const cutoff = new Date(Date.parse(today) - dayCount * 864e5).toISOString().slice(0, 10);
|
|
3776
|
+
const assets = contexts.flatMap((context) => {
|
|
3777
|
+
const snapshots = context.historic?.dailyYieldSnapshots;
|
|
3778
|
+
if (!Array.isArray(snapshots)) invalid("historic position", "missing daily yield snapshots");
|
|
3779
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
3780
|
+
for (const snapshot of snapshots) {
|
|
3781
|
+
const time = Date.parse(snapshot.date);
|
|
3782
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(snapshot.date) || !Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== snapshot.date) {
|
|
3783
|
+
invalid("historic position", "expected a UTC snapshot date");
|
|
3784
|
+
}
|
|
3785
|
+
if (snapshot.date > today) continue;
|
|
3786
|
+
if (snapshot.baseAssetDecimals !== YIELDSEEKER_ASSET_METADATA[context.asset].decimals) {
|
|
3787
|
+
invalid("historic position", "base asset decimals do not match the selected asset");
|
|
3788
|
+
}
|
|
3789
|
+
const amount = Number(decimal(snapshot.cumulativeYieldBase, snapshot.baseAssetDecimals, "historic position"));
|
|
3790
|
+
if (!Number.isFinite(amount)) invalid("historic position", "expected finite cumulative yield");
|
|
3791
|
+
byDate.set(snapshot.date, { date: snapshot.date, amount });
|
|
3792
|
+
}
|
|
3793
|
+
const sorted = [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
3794
|
+
const window2 = sorted.filter((point) => point.date >= cutoff);
|
|
3795
|
+
if (!window2.length) return [];
|
|
3796
|
+
const opening = sorted.filter((point) => point.date < cutoff).at(-1);
|
|
3797
|
+
return [{ asset: context.asset, points: opening ? [opening, ...window2] : window2 }];
|
|
3798
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
3799
|
+
return { walletAddress, chainId: 8453, assets };
|
|
3800
|
+
}
|
|
3772
3801
|
function apyForDays(context, days, now) {
|
|
3773
3802
|
if (days === "7D") return percent(context.snapshot.apy7d);
|
|
3774
3803
|
if (days === "30D") return percent(context.snapshot.apy30d);
|
|
@@ -4273,6 +4302,14 @@ function sponsorError(message, safeToFallback, details = {}) {
|
|
|
4273
4302
|
"yieldseeker"
|
|
4274
4303
|
);
|
|
4275
4304
|
}
|
|
4305
|
+
function assertIntentFresh(expiresAt) {
|
|
4306
|
+
if (!Number.isFinite(expiresAt) || Date.now() + 5e3 >= expiresAt * 1e3)
|
|
4307
|
+
throw sponsorError(
|
|
4308
|
+
"The withdrawal sponsorship request expired. Please try again.",
|
|
4309
|
+
true,
|
|
4310
|
+
{ failureCode: "SPONSOR_INTENT_EXPIRED" }
|
|
4311
|
+
);
|
|
4312
|
+
}
|
|
4276
4313
|
function providerReason(value) {
|
|
4277
4314
|
if (typeof value !== "string") return void 0;
|
|
4278
4315
|
return value.replace(/https?:\/\/\S+/gi, "[url]").replace(/0x[0-9a-fA-F]{40,}/g, "[hex]").replace(/[A-Za-z0-9_+=\/-]{48,}/g, "[token]").slice(0, 300);
|
|
@@ -4561,6 +4598,7 @@ async function submitEoa(input) {
|
|
|
4561
4598
|
}
|
|
4562
4599
|
const userOpHash = operationHash(operation);
|
|
4563
4600
|
await assertOwnerSession(input.state, input.owner);
|
|
4601
|
+
assertIntentFresh(input.expiresAt);
|
|
4564
4602
|
const wallet = (0, import_viem11.createWalletClient)({
|
|
4565
4603
|
account: input.owner,
|
|
4566
4604
|
chain: import_chains3.base,
|
|
@@ -4569,6 +4607,7 @@ async function submitEoa(input) {
|
|
|
4569
4607
|
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4570
4608
|
operation = { ...operation, signature };
|
|
4571
4609
|
await assertOwnerSession(input.state, input.owner);
|
|
4610
|
+
assertIntentFresh(input.expiresAt);
|
|
4572
4611
|
const userOperation = {
|
|
4573
4612
|
sender: operation.sender,
|
|
4574
4613
|
nonce: operation.nonce,
|
|
@@ -4646,6 +4685,7 @@ async function submitSmart(input) {
|
|
|
4646
4685
|
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4647
4686
|
await assertOwnerSession(input.state, input.owner);
|
|
4648
4687
|
let sent;
|
|
4688
|
+
assertIntentFresh(input.expiresAt);
|
|
4649
4689
|
const requestedId = (0, import_viem11.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
4650
4690
|
savePending(input.onPending, { callsId: requestedId }, true);
|
|
4651
4691
|
await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
|
|
@@ -4744,7 +4784,8 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
|
4744
4784
|
action: "withdraw",
|
|
4745
4785
|
refreshYieldseekerSignature: input.refreshYieldseekerSignature
|
|
4746
4786
|
});
|
|
4747
|
-
|
|
4787
|
+
assertIntentFresh(intent.expiresAt);
|
|
4788
|
+
const args = { ...input, owner, rpcUrl, expiresAt: intent.expiresAt };
|
|
4748
4789
|
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4749
4790
|
}
|
|
4750
4791
|
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
@@ -4764,7 +4805,8 @@ async function submitYieldseekerSponsoredUpgrade(input) {
|
|
|
4764
4805
|
});
|
|
4765
4806
|
if (intent.ownerPath !== "smart")
|
|
4766
4807
|
throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
|
|
4767
|
-
|
|
4808
|
+
assertIntentFresh(intent.expiresAt);
|
|
4809
|
+
return submitSmart({ ...input, owner, rpcUrl, expiresAt: intent.expiresAt });
|
|
4768
4810
|
}
|
|
4769
4811
|
|
|
4770
4812
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
@@ -6097,6 +6139,17 @@ var YieldseekerAgent = class {
|
|
|
6097
6139
|
});
|
|
6098
6140
|
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
6099
6141
|
}
|
|
6142
|
+
async getDailyEarnings(state, chainId, days, tokenSymbol) {
|
|
6143
|
+
this.assertChain(chainId);
|
|
6144
|
+
const asset = tokenSymbol?.toUpperCase();
|
|
6145
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
6146
|
+
const contexts = await this.loadActivityPortfolio(state, chainId, {
|
|
6147
|
+
...asset ? { asset } : {},
|
|
6148
|
+
historic: true,
|
|
6149
|
+
includePositions: false
|
|
6150
|
+
});
|
|
6151
|
+
return mapYieldseekerDailyEarnings(state.walletAddress, contexts, days);
|
|
6152
|
+
}
|
|
6100
6153
|
async getHistory(state, chainId, options) {
|
|
6101
6154
|
this.assertChain(chainId);
|
|
6102
6155
|
const asset = options?.tokenSymbol?.toUpperCase();
|
|
@@ -6607,7 +6660,7 @@ var YieldseekerAgent = class {
|
|
|
6607
6660
|
}
|
|
6608
6661
|
async loadPortfolioParts(state, chainId, context, options, contextKey) {
|
|
6609
6662
|
const [positions, historic, actions] = await Promise.all([
|
|
6610
|
-
this.cachedRead(
|
|
6663
|
+
options.includePositions === false ? Promise.resolve({ yieldPositions: [] }) : this.cachedRead(
|
|
6611
6664
|
`positions:${contextKey}`,
|
|
6612
6665
|
this.portfolioCacheMs(contextKey),
|
|
6613
6666
|
async () => {
|
|
@@ -7230,6 +7283,43 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
7230
7283
|
return out;
|
|
7231
7284
|
}
|
|
7232
7285
|
|
|
7286
|
+
// src/lib/helpers/daily-earnings-helper.ts
|
|
7287
|
+
function aggregateDailyEarnings(series, tokenSymbol) {
|
|
7288
|
+
const wanted = tokenSymbol?.toUpperCase();
|
|
7289
|
+
const byAsset = /* @__PURE__ */ new Map();
|
|
7290
|
+
for (const account of series) {
|
|
7291
|
+
for (const { asset, points } of account.assets) {
|
|
7292
|
+
const symbol = asset.toUpperCase();
|
|
7293
|
+
if (!points.length || wanted && symbol !== wanted) continue;
|
|
7294
|
+
const components = byAsset.get(symbol) ?? [];
|
|
7295
|
+
components.push([...points].sort((a, b) => a.date.localeCompare(b.date)));
|
|
7296
|
+
byAsset.set(symbol, components);
|
|
7297
|
+
}
|
|
7298
|
+
}
|
|
7299
|
+
return [...byAsset.entries()].map(([asset, components]) => {
|
|
7300
|
+
const dates = [...new Set(components.flatMap((points2) => points2.map((point) => point.date)))].sort();
|
|
7301
|
+
const cursors = components.map((points2) => ({
|
|
7302
|
+
index: 0,
|
|
7303
|
+
// Providers can have different lifetime/window offsets and start dates.
|
|
7304
|
+
// Remove each opening reading before combining their earned amounts.
|
|
7305
|
+
baseline: points2[0].amount,
|
|
7306
|
+
current: points2[0].amount
|
|
7307
|
+
}));
|
|
7308
|
+
const points = dates.map((date) => {
|
|
7309
|
+
let amount = 0;
|
|
7310
|
+
components.forEach((component, index) => {
|
|
7311
|
+
const cursor = cursors[index];
|
|
7312
|
+
while (cursor.index < component.length && component[cursor.index].date <= date) {
|
|
7313
|
+
cursor.current = component[cursor.index++].amount;
|
|
7314
|
+
}
|
|
7315
|
+
amount += cursor.current - cursor.baseline;
|
|
7316
|
+
});
|
|
7317
|
+
return { date, amount };
|
|
7318
|
+
});
|
|
7319
|
+
return { asset, points };
|
|
7320
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
7321
|
+
}
|
|
7322
|
+
|
|
7233
7323
|
// src/client.ts
|
|
7234
7324
|
var import_viem17 = require("viem");
|
|
7235
7325
|
var import_chains5 = require("viem/chains");
|
|
@@ -9612,10 +9702,8 @@ var OwneySDK = class {
|
|
|
9612
9702
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
9613
9703
|
*/
|
|
9614
9704
|
/**
|
|
9615
|
-
* Daily cumulative
|
|
9616
|
-
* "recent earnings" subline.
|
|
9617
|
-
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
9618
|
-
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
9705
|
+
* Daily cumulative earnings in the selected asset's units, backing the
|
|
9706
|
+
* "recent earnings" subline. Each adapter uses its provider's earnings basis.
|
|
9619
9707
|
*
|
|
9620
9708
|
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
9621
9709
|
* summed, not weighted, and an agent that fails to report must not silently
|
|
@@ -9648,7 +9736,7 @@ var OwneySDK = class {
|
|
|
9648
9736
|
const entries = [...this.getActiveAgents().entries()].filter(
|
|
9649
9737
|
([, agent]) => agent.getDailyEarnings
|
|
9650
9738
|
);
|
|
9651
|
-
const
|
|
9739
|
+
const settled = await Promise.allSettled(
|
|
9652
9740
|
entries.map(
|
|
9653
9741
|
([, agent]) => this.readAgent(
|
|
9654
9742
|
agent,
|
|
@@ -9658,23 +9746,15 @@ var OwneySDK = class {
|
|
|
9658
9746
|
)
|
|
9659
9747
|
)
|
|
9660
9748
|
);
|
|
9661
|
-
const
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
for (const point of points) {
|
|
9666
|
-
byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.amount);
|
|
9667
|
-
}
|
|
9668
|
-
byAsset.set(asset, byDate);
|
|
9669
|
-
}
|
|
9749
|
+
const series = settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
9750
|
+
if (entries.length && !series.length) {
|
|
9751
|
+
const failure = settled.find((result) => result.status === "rejected");
|
|
9752
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
9670
9753
|
}
|
|
9671
9754
|
return {
|
|
9672
9755
|
walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
|
|
9673
9756
|
chainId,
|
|
9674
|
-
assets:
|
|
9675
|
-
asset,
|
|
9676
|
-
points: [...byDate.entries()].map(([date, amount]) => ({ date, amount })).sort((a, b) => a.date.localeCompare(b.date))
|
|
9677
|
-
})).sort((a, b) => a.asset.localeCompare(b.asset))
|
|
9757
|
+
assets: aggregateDailyEarnings(series, tokenSymbol)
|
|
9678
9758
|
};
|
|
9679
9759
|
}
|
|
9680
9760
|
async getAccountApy({
|
package/dist/index.d.cts
CHANGED
|
@@ -169,9 +169,9 @@ interface IAgent {
|
|
|
169
169
|
*/
|
|
170
170
|
tokenSymbol?: string): Promise<AccountAgentApy>;
|
|
171
171
|
/**
|
|
172
|
-
* Daily cumulative
|
|
173
|
-
*
|
|
174
|
-
*
|
|
172
|
+
* Daily cumulative earnings in token units, scoped to a chain/asset, using
|
|
173
|
+
* the provider's earnings basis. Include an opening snapshot when available
|
|
174
|
+
* so the "recent earnings" subline can difference the endpoints. (ROUT-452)
|
|
175
175
|
*/
|
|
176
176
|
getDailyEarnings?(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
|
|
177
177
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
@@ -658,15 +658,15 @@ interface AgentApy {
|
|
|
658
658
|
interface OwneyAgentApy {
|
|
659
659
|
agentApy: Record<AgentId, AgentApy>;
|
|
660
660
|
}
|
|
661
|
-
/** One day's cumulative
|
|
661
|
+
/** One day's cumulative earnings for a single asset. */
|
|
662
662
|
interface DailyEarningsPoint {
|
|
663
663
|
/** ISO date string for the day, e.g. "2026-09-01". */
|
|
664
664
|
date: string;
|
|
665
665
|
/**
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
666
|
+
* Cumulative earnings in the asset's own units, using the provider's earnings
|
|
667
|
+
* basis. A provider may return lifetime totals or a running window total;
|
|
668
|
+
* difference the last and opening points to measure earnings over the window.
|
|
669
|
+
* Aggregate series normalize each component's opening value before summing.
|
|
670
670
|
*/
|
|
671
671
|
amount: number;
|
|
672
672
|
}
|
|
@@ -675,8 +675,9 @@ interface AssetDailyEarnings {
|
|
|
675
675
|
/** Asset symbol, e.g. "USDC" / "WETH". */
|
|
676
676
|
asset: string;
|
|
677
677
|
/**
|
|
678
|
-
* Ascending by date
|
|
679
|
-
*
|
|
678
|
+
* Ascending by date, including an opening snapshot before the requested
|
|
679
|
+
* window when available. Provider gaps remain absent; aggregates carry the
|
|
680
|
+
* most recent cumulative value across dates reported by other providers.
|
|
680
681
|
*/
|
|
681
682
|
points: DailyEarningsPoint[];
|
|
682
683
|
}
|
|
@@ -954,10 +955,8 @@ declare class OwneySDK {
|
|
|
954
955
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
955
956
|
*/
|
|
956
957
|
/**
|
|
957
|
-
* Daily cumulative
|
|
958
|
-
* "recent earnings" subline.
|
|
959
|
-
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
960
|
-
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
958
|
+
* Daily cumulative earnings in the selected asset's units, backing the
|
|
959
|
+
* "recent earnings" subline. Each adapter uses its provider's earnings basis.
|
|
961
960
|
*
|
|
962
961
|
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
963
962
|
* summed, not weighted, and an agent that fails to report must not silently
|
|
@@ -1146,6 +1145,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
1146
1145
|
hasExistingDepositFunds(state: ConnectionState, chainId: number, asset: OwneySupportedTokens): Promise<true | undefined>;
|
|
1147
1146
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
1148
1147
|
getAccountApy(state: ConnectionState, chainId: number, days: DailyApyDays, tokenSymbol?: string): Promise<AccountAgentApy>;
|
|
1148
|
+
getDailyEarnings(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
|
|
1149
1149
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
1150
1150
|
getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
|
|
1151
1151
|
getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
|
package/dist/index.d.ts
CHANGED
|
@@ -169,9 +169,9 @@ interface IAgent {
|
|
|
169
169
|
*/
|
|
170
170
|
tokenSymbol?: string): Promise<AccountAgentApy>;
|
|
171
171
|
/**
|
|
172
|
-
* Daily cumulative
|
|
173
|
-
*
|
|
174
|
-
*
|
|
172
|
+
* Daily cumulative earnings in token units, scoped to a chain/asset, using
|
|
173
|
+
* the provider's earnings basis. Include an opening snapshot when available
|
|
174
|
+
* so the "recent earnings" subline can difference the endpoints. (ROUT-452)
|
|
175
175
|
*/
|
|
176
176
|
getDailyEarnings?(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
|
|
177
177
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
@@ -658,15 +658,15 @@ interface AgentApy {
|
|
|
658
658
|
interface OwneyAgentApy {
|
|
659
659
|
agentApy: Record<AgentId, AgentApy>;
|
|
660
660
|
}
|
|
661
|
-
/** One day's cumulative
|
|
661
|
+
/** One day's cumulative earnings for a single asset. */
|
|
662
662
|
interface DailyEarningsPoint {
|
|
663
663
|
/** ISO date string for the day, e.g. "2026-09-01". */
|
|
664
664
|
date: string;
|
|
665
665
|
/**
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
666
|
+
* Cumulative earnings in the asset's own units, using the provider's earnings
|
|
667
|
+
* basis. A provider may return lifetime totals or a running window total;
|
|
668
|
+
* difference the last and opening points to measure earnings over the window.
|
|
669
|
+
* Aggregate series normalize each component's opening value before summing.
|
|
670
670
|
*/
|
|
671
671
|
amount: number;
|
|
672
672
|
}
|
|
@@ -675,8 +675,9 @@ interface AssetDailyEarnings {
|
|
|
675
675
|
/** Asset symbol, e.g. "USDC" / "WETH". */
|
|
676
676
|
asset: string;
|
|
677
677
|
/**
|
|
678
|
-
* Ascending by date
|
|
679
|
-
*
|
|
678
|
+
* Ascending by date, including an opening snapshot before the requested
|
|
679
|
+
* window when available. Provider gaps remain absent; aggregates carry the
|
|
680
|
+
* most recent cumulative value across dates reported by other providers.
|
|
680
681
|
*/
|
|
681
682
|
points: DailyEarningsPoint[];
|
|
682
683
|
}
|
|
@@ -954,10 +955,8 @@ declare class OwneySDK {
|
|
|
954
955
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
955
956
|
*/
|
|
956
957
|
/**
|
|
957
|
-
* Daily cumulative
|
|
958
|
-
* "recent earnings" subline.
|
|
959
|
-
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
960
|
-
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
958
|
+
* Daily cumulative earnings in the selected asset's units, backing the
|
|
959
|
+
* "recent earnings" subline. Each adapter uses its provider's earnings basis.
|
|
961
960
|
*
|
|
962
961
|
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
963
962
|
* summed, not weighted, and an agent that fails to report must not silently
|
|
@@ -1146,6 +1145,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
1146
1145
|
hasExistingDepositFunds(state: ConnectionState, chainId: number, asset: OwneySupportedTokens): Promise<true | undefined>;
|
|
1147
1146
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
1148
1147
|
getAccountApy(state: ConnectionState, chainId: number, days: DailyApyDays, tokenSymbol?: string): Promise<AccountAgentApy>;
|
|
1148
|
+
getDailyEarnings(state: ConnectionState, chainId: number, days: LookbackDays, tokenSymbol?: string): Promise<AccountDailyEarnings>;
|
|
1149
1149
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
1150
1150
|
getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
|
|
1151
1151
|
getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
|
package/dist/index.js
CHANGED
|
@@ -3755,6 +3755,35 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3755
3755
|
tokens
|
|
3756
3756
|
};
|
|
3757
3757
|
}
|
|
3758
|
+
function mapYieldseekerDailyEarnings(walletAddress, contexts, days, now = Date.now()) {
|
|
3759
|
+
const today = new Date(now).toISOString().slice(0, 10);
|
|
3760
|
+
const dayCount = { "7D": 7, "14D": 14, "30D": 30 }[days];
|
|
3761
|
+
const cutoff = new Date(Date.parse(today) - dayCount * 864e5).toISOString().slice(0, 10);
|
|
3762
|
+
const assets = contexts.flatMap((context) => {
|
|
3763
|
+
const snapshots = context.historic?.dailyYieldSnapshots;
|
|
3764
|
+
if (!Array.isArray(snapshots)) invalid("historic position", "missing daily yield snapshots");
|
|
3765
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
3766
|
+
for (const snapshot of snapshots) {
|
|
3767
|
+
const time = Date.parse(snapshot.date);
|
|
3768
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(snapshot.date) || !Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== snapshot.date) {
|
|
3769
|
+
invalid("historic position", "expected a UTC snapshot date");
|
|
3770
|
+
}
|
|
3771
|
+
if (snapshot.date > today) continue;
|
|
3772
|
+
if (snapshot.baseAssetDecimals !== YIELDSEEKER_ASSET_METADATA[context.asset].decimals) {
|
|
3773
|
+
invalid("historic position", "base asset decimals do not match the selected asset");
|
|
3774
|
+
}
|
|
3775
|
+
const amount = Number(decimal(snapshot.cumulativeYieldBase, snapshot.baseAssetDecimals, "historic position"));
|
|
3776
|
+
if (!Number.isFinite(amount)) invalid("historic position", "expected finite cumulative yield");
|
|
3777
|
+
byDate.set(snapshot.date, { date: snapshot.date, amount });
|
|
3778
|
+
}
|
|
3779
|
+
const sorted = [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
3780
|
+
const window2 = sorted.filter((point) => point.date >= cutoff);
|
|
3781
|
+
if (!window2.length) return [];
|
|
3782
|
+
const opening = sorted.filter((point) => point.date < cutoff).at(-1);
|
|
3783
|
+
return [{ asset: context.asset, points: opening ? [opening, ...window2] : window2 }];
|
|
3784
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
3785
|
+
return { walletAddress, chainId: 8453, assets };
|
|
3786
|
+
}
|
|
3758
3787
|
function apyForDays(context, days, now) {
|
|
3759
3788
|
if (days === "7D") return percent(context.snapshot.apy7d);
|
|
3760
3789
|
if (days === "30D") return percent(context.snapshot.apy30d);
|
|
@@ -4268,6 +4297,14 @@ function sponsorError(message, safeToFallback, details = {}) {
|
|
|
4268
4297
|
"yieldseeker"
|
|
4269
4298
|
);
|
|
4270
4299
|
}
|
|
4300
|
+
function assertIntentFresh(expiresAt) {
|
|
4301
|
+
if (!Number.isFinite(expiresAt) || Date.now() + 5e3 >= expiresAt * 1e3)
|
|
4302
|
+
throw sponsorError(
|
|
4303
|
+
"The withdrawal sponsorship request expired. Please try again.",
|
|
4304
|
+
true,
|
|
4305
|
+
{ failureCode: "SPONSOR_INTENT_EXPIRED" }
|
|
4306
|
+
);
|
|
4307
|
+
}
|
|
4271
4308
|
function providerReason(value) {
|
|
4272
4309
|
if (typeof value !== "string") return void 0;
|
|
4273
4310
|
return value.replace(/https?:\/\/\S+/gi, "[url]").replace(/0x[0-9a-fA-F]{40,}/g, "[hex]").replace(/[A-Za-z0-9_+=\/-]{48,}/g, "[token]").slice(0, 300);
|
|
@@ -4556,6 +4593,7 @@ async function submitEoa(input) {
|
|
|
4556
4593
|
}
|
|
4557
4594
|
const userOpHash = operationHash(operation);
|
|
4558
4595
|
await assertOwnerSession(input.state, input.owner);
|
|
4596
|
+
assertIntentFresh(input.expiresAt);
|
|
4559
4597
|
const wallet = createWalletClient2({
|
|
4560
4598
|
account: input.owner,
|
|
4561
4599
|
chain: base3,
|
|
@@ -4564,6 +4602,7 @@ async function submitEoa(input) {
|
|
|
4564
4602
|
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4565
4603
|
operation = { ...operation, signature };
|
|
4566
4604
|
await assertOwnerSession(input.state, input.owner);
|
|
4605
|
+
assertIntentFresh(input.expiresAt);
|
|
4567
4606
|
const userOperation = {
|
|
4568
4607
|
sender: operation.sender,
|
|
4569
4608
|
nonce: operation.nonce,
|
|
@@ -4641,6 +4680,7 @@ async function submitSmart(input) {
|
|
|
4641
4680
|
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4642
4681
|
await assertOwnerSession(input.state, input.owner);
|
|
4643
4682
|
let sent;
|
|
4683
|
+
assertIntentFresh(input.expiresAt);
|
|
4644
4684
|
const requestedId = toHex(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
4645
4685
|
savePending(input.onPending, { callsId: requestedId }, true);
|
|
4646
4686
|
await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
|
|
@@ -4739,7 +4779,8 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
|
4739
4779
|
action: "withdraw",
|
|
4740
4780
|
refreshYieldseekerSignature: input.refreshYieldseekerSignature
|
|
4741
4781
|
});
|
|
4742
|
-
|
|
4782
|
+
assertIntentFresh(intent.expiresAt);
|
|
4783
|
+
const args = { ...input, owner, rpcUrl, expiresAt: intent.expiresAt };
|
|
4743
4784
|
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4744
4785
|
}
|
|
4745
4786
|
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
@@ -4759,7 +4800,8 @@ async function submitYieldseekerSponsoredUpgrade(input) {
|
|
|
4759
4800
|
});
|
|
4760
4801
|
if (intent.ownerPath !== "smart")
|
|
4761
4802
|
throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
|
|
4762
|
-
|
|
4803
|
+
assertIntentFresh(intent.expiresAt);
|
|
4804
|
+
return submitSmart({ ...input, owner, rpcUrl, expiresAt: intent.expiresAt });
|
|
4763
4805
|
}
|
|
4764
4806
|
|
|
4765
4807
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
@@ -6092,6 +6134,17 @@ var YieldseekerAgent = class {
|
|
|
6092
6134
|
});
|
|
6093
6135
|
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
6094
6136
|
}
|
|
6137
|
+
async getDailyEarnings(state, chainId, days, tokenSymbol) {
|
|
6138
|
+
this.assertChain(chainId);
|
|
6139
|
+
const asset = tokenSymbol?.toUpperCase();
|
|
6140
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
6141
|
+
const contexts = await this.loadActivityPortfolio(state, chainId, {
|
|
6142
|
+
...asset ? { asset } : {},
|
|
6143
|
+
historic: true,
|
|
6144
|
+
includePositions: false
|
|
6145
|
+
});
|
|
6146
|
+
return mapYieldseekerDailyEarnings(state.walletAddress, contexts, days);
|
|
6147
|
+
}
|
|
6095
6148
|
async getHistory(state, chainId, options) {
|
|
6096
6149
|
this.assertChain(chainId);
|
|
6097
6150
|
const asset = options?.tokenSymbol?.toUpperCase();
|
|
@@ -6602,7 +6655,7 @@ var YieldseekerAgent = class {
|
|
|
6602
6655
|
}
|
|
6603
6656
|
async loadPortfolioParts(state, chainId, context, options, contextKey) {
|
|
6604
6657
|
const [positions, historic, actions] = await Promise.all([
|
|
6605
|
-
this.cachedRead(
|
|
6658
|
+
options.includePositions === false ? Promise.resolve({ yieldPositions: [] }) : this.cachedRead(
|
|
6606
6659
|
`positions:${contextKey}`,
|
|
6607
6660
|
this.portfolioCacheMs(contextKey),
|
|
6608
6661
|
async () => {
|
|
@@ -7225,6 +7278,43 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
7225
7278
|
return out;
|
|
7226
7279
|
}
|
|
7227
7280
|
|
|
7281
|
+
// src/lib/helpers/daily-earnings-helper.ts
|
|
7282
|
+
function aggregateDailyEarnings(series, tokenSymbol) {
|
|
7283
|
+
const wanted = tokenSymbol?.toUpperCase();
|
|
7284
|
+
const byAsset = /* @__PURE__ */ new Map();
|
|
7285
|
+
for (const account of series) {
|
|
7286
|
+
for (const { asset, points } of account.assets) {
|
|
7287
|
+
const symbol = asset.toUpperCase();
|
|
7288
|
+
if (!points.length || wanted && symbol !== wanted) continue;
|
|
7289
|
+
const components = byAsset.get(symbol) ?? [];
|
|
7290
|
+
components.push([...points].sort((a, b) => a.date.localeCompare(b.date)));
|
|
7291
|
+
byAsset.set(symbol, components);
|
|
7292
|
+
}
|
|
7293
|
+
}
|
|
7294
|
+
return [...byAsset.entries()].map(([asset, components]) => {
|
|
7295
|
+
const dates = [...new Set(components.flatMap((points2) => points2.map((point) => point.date)))].sort();
|
|
7296
|
+
const cursors = components.map((points2) => ({
|
|
7297
|
+
index: 0,
|
|
7298
|
+
// Providers can have different lifetime/window offsets and start dates.
|
|
7299
|
+
// Remove each opening reading before combining their earned amounts.
|
|
7300
|
+
baseline: points2[0].amount,
|
|
7301
|
+
current: points2[0].amount
|
|
7302
|
+
}));
|
|
7303
|
+
const points = dates.map((date) => {
|
|
7304
|
+
let amount = 0;
|
|
7305
|
+
components.forEach((component, index) => {
|
|
7306
|
+
const cursor = cursors[index];
|
|
7307
|
+
while (cursor.index < component.length && component[cursor.index].date <= date) {
|
|
7308
|
+
cursor.current = component[cursor.index++].amount;
|
|
7309
|
+
}
|
|
7310
|
+
amount += cursor.current - cursor.baseline;
|
|
7311
|
+
});
|
|
7312
|
+
return { date, amount };
|
|
7313
|
+
});
|
|
7314
|
+
return { asset, points };
|
|
7315
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7228
7318
|
// src/client.ts
|
|
7229
7319
|
import {
|
|
7230
7320
|
parseUnits as parseUnits3,
|
|
@@ -9616,10 +9706,8 @@ var OwneySDK = class {
|
|
|
9616
9706
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
9617
9707
|
*/
|
|
9618
9708
|
/**
|
|
9619
|
-
* Daily cumulative
|
|
9620
|
-
* "recent earnings" subline.
|
|
9621
|
-
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
9622
|
-
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
9709
|
+
* Daily cumulative earnings in the selected asset's units, backing the
|
|
9710
|
+
* "recent earnings" subline. Each adapter uses its provider's earnings basis.
|
|
9623
9711
|
*
|
|
9624
9712
|
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
9625
9713
|
* summed, not weighted, and an agent that fails to report must not silently
|
|
@@ -9652,7 +9740,7 @@ var OwneySDK = class {
|
|
|
9652
9740
|
const entries = [...this.getActiveAgents().entries()].filter(
|
|
9653
9741
|
([, agent]) => agent.getDailyEarnings
|
|
9654
9742
|
);
|
|
9655
|
-
const
|
|
9743
|
+
const settled = await Promise.allSettled(
|
|
9656
9744
|
entries.map(
|
|
9657
9745
|
([, agent]) => this.readAgent(
|
|
9658
9746
|
agent,
|
|
@@ -9662,23 +9750,15 @@ var OwneySDK = class {
|
|
|
9662
9750
|
)
|
|
9663
9751
|
)
|
|
9664
9752
|
);
|
|
9665
|
-
const
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
for (const point of points) {
|
|
9670
|
-
byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.amount);
|
|
9671
|
-
}
|
|
9672
|
-
byAsset.set(asset, byDate);
|
|
9673
|
-
}
|
|
9753
|
+
const series = settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
9754
|
+
if (entries.length && !series.length) {
|
|
9755
|
+
const failure = settled.find((result) => result.status === "rejected");
|
|
9756
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
9674
9757
|
}
|
|
9675
9758
|
return {
|
|
9676
9759
|
walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
|
|
9677
9760
|
chainId,
|
|
9678
|
-
assets:
|
|
9679
|
-
asset,
|
|
9680
|
-
points: [...byDate.entries()].map(([date, amount]) => ({ date, amount })).sort((a, b) => a.date.localeCompare(b.date))
|
|
9681
|
-
})).sort((a, b) => a.asset.localeCompare(b.asset))
|
|
9761
|
+
assets: aggregateDailyEarnings(series, tokenSymbol)
|
|
9682
9762
|
};
|
|
9683
9763
|
}
|
|
9684
9764
|
async getAccountApy({
|