@owney/sdk 0.7.7 → 0.7.9
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 +19 -0
- package/dist/index.cjs +57 -4
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +57 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,25 @@ console.log(allEarnings.agentEarnings.zyfai.lifetimeEarnings); // 42.5
|
|
|
263
263
|
console.log(allEarnings.agentEarnings.zyfai.tokens); // per-chain, per-asset breakdown
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
+
### `refreshEarnings(agentId?)`
|
|
267
|
+
|
|
268
|
+
Refresh earnings for agents whose earnings data may be outdated. If the latest
|
|
269
|
+
snapshot is less than one hour old, the SDK returns it without recalculating.
|
|
270
|
+
|
|
271
|
+
| Param | Type | Description |
|
|
272
|
+
| --------- | -------------------- | ------------------------------------ |
|
|
273
|
+
| `agentId` | `"zyfai"` (optional) | Agent to refresh. Omit for all agents. |
|
|
274
|
+
|
|
275
|
+
Returns: `AgentEarnings` (single agent) or `OwneyEarnings` (all agents)
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// Single agent
|
|
279
|
+
const refreshed = await sdk.refreshEarnings("zyfai");
|
|
280
|
+
|
|
281
|
+
// All agents
|
|
282
|
+
const allRefreshed = await sdk.refreshEarnings();
|
|
283
|
+
```
|
|
284
|
+
|
|
266
285
|
### `getAccountApy({ agentId?, days })`
|
|
267
286
|
|
|
268
287
|
Get the weighted APY for the user's account. When querying all agents, the total APY is a balance-weighted average.
|
package/dist/index.cjs
CHANGED
|
@@ -250,9 +250,10 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
250
250
|
const tokens = [];
|
|
251
251
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
252
252
|
const positionChainId = Number(chainIdKey);
|
|
253
|
-
for (const [
|
|
254
|
-
|
|
255
|
-
|
|
253
|
+
for (const [
|
|
254
|
+
symbol,
|
|
255
|
+
{ balance, balanceWithFee, decimals }
|
|
256
|
+
] of Object.entries(tokensBySymbol ?? {})) {
|
|
256
257
|
const amount = hexToDecimal(balanceWithFee ?? balance ?? "0", decimals);
|
|
257
258
|
totalBalance += amount;
|
|
258
259
|
tokens.push({
|
|
@@ -391,6 +392,11 @@ function mapEntries(rawEntries, chainId) {
|
|
|
391
392
|
"Top up wallet": "Top up",
|
|
392
393
|
"Partial withdraw from protocol": "Withdraw",
|
|
393
394
|
"Withdraw from protocol": "Withdraw",
|
|
395
|
+
// The agent's own leg of a top up: the funds the user sent moving into the
|
|
396
|
+
// pool that earns the APY. Zyfai emits it as a separate entry seconds after
|
|
397
|
+
// "Top up wallet" and for slightly less (gas). `Deposit` already exists in
|
|
398
|
+
// the public HistoryAction union, so no consumer type change is needed.
|
|
399
|
+
"Deposit to protocol": "Deposit",
|
|
394
400
|
Rebalance: "Rebalance"
|
|
395
401
|
};
|
|
396
402
|
void chainId;
|
|
@@ -431,12 +437,19 @@ function mapEntries(rawEntries, chainId) {
|
|
|
431
437
|
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
432
438
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
433
439
|
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
440
|
+
const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
|
|
441
|
+
protocol: p.protocol_name,
|
|
442
|
+
pool: p.pool ?? void 0,
|
|
443
|
+
tokenSymbol: p.token_symbol ?? void 0,
|
|
444
|
+
amount: mappedAction !== "Withdraw" && typeof p.amount === "string" && p.amount !== "" && p.amount !== "0x" ? String(hexToDecimal(p.amount, tokenDecimals(p.token_symbol))) : void 0
|
|
445
|
+
}));
|
|
434
446
|
return {
|
|
435
447
|
agent: "zyfai",
|
|
436
448
|
action: mappedAction,
|
|
437
449
|
date: entry.date || "",
|
|
438
450
|
newApy: newApy === null ? null : String(newApy),
|
|
439
451
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
452
|
+
...mappedPositions.length ? { positions: mappedPositions } : {},
|
|
440
453
|
transactions: [
|
|
441
454
|
{
|
|
442
455
|
txHashes: entry.transactionHash ? [entry.transactionHash] : [],
|
|
@@ -871,6 +884,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
871
884
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
872
885
|
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
873
886
|
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
887
|
+
var EARNINGS_REFRESH_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
874
888
|
var ZyfaiAgent = class {
|
|
875
889
|
id = "zyfai";
|
|
876
890
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -922,6 +936,7 @@ var ZyfaiAgent = class {
|
|
|
922
936
|
// successful decode is cached forever; failures are NOT cached so a transient
|
|
923
937
|
// RPC error retries on the next fetch.
|
|
924
938
|
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
939
|
+
earningsRefreshInFlight = null;
|
|
925
940
|
constructor(apiKey, rpcUrls, referralSource) {
|
|
926
941
|
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
927
942
|
this.sdk = new import_sdk.ZyfaiSDK({
|
|
@@ -1719,6 +1734,22 @@ var ZyfaiAgent = class {
|
|
|
1719
1734
|
const raw = await this.sdk.getOnchainEarnings(smartWallet);
|
|
1720
1735
|
return mapEarnings(raw, smartWallet);
|
|
1721
1736
|
}
|
|
1737
|
+
async refreshEarnings(state, chainId) {
|
|
1738
|
+
if (this.earningsRefreshInFlight) return this.earningsRefreshInFlight;
|
|
1739
|
+
this.earningsRefreshInFlight = (async () => {
|
|
1740
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1741
|
+
const current = await this.sdk.getOnchainEarnings(smartWallet);
|
|
1742
|
+
const lastCheck = current.data.lastCheckTimestamp ? Date.parse(current.data.lastCheckTimestamp) : Number.NaN;
|
|
1743
|
+
const isFresh = Number.isFinite(lastCheck) && Date.now() - lastCheck < EARNINGS_REFRESH_COOLDOWN_MS;
|
|
1744
|
+
const earnings = isFresh ? current : await this.sdk.calculateOnchainEarnings(smartWallet);
|
|
1745
|
+
return mapEarnings(earnings, smartWallet);
|
|
1746
|
+
})();
|
|
1747
|
+
try {
|
|
1748
|
+
return await this.earningsRefreshInFlight;
|
|
1749
|
+
} finally {
|
|
1750
|
+
this.earningsRefreshInFlight = null;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1722
1753
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1723
1754
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1724
1755
|
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
@@ -1743,7 +1774,7 @@ var ZyfaiAgent = class {
|
|
|
1743
1774
|
toDate
|
|
1744
1775
|
});
|
|
1745
1776
|
raw.data.forEach((entry, idx) => {
|
|
1746
|
-
if (entry.chainId === validChainId
|
|
1777
|
+
if (entry.chainId === validChainId) {
|
|
1747
1778
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1748
1779
|
}
|
|
1749
1780
|
});
|
|
@@ -3419,6 +3450,28 @@ var OwneySDK = class {
|
|
|
3419
3450
|
agentEarnings: results
|
|
3420
3451
|
};
|
|
3421
3452
|
}
|
|
3453
|
+
/**
|
|
3454
|
+
* Return refreshed earnings while letting each agent own its refresh policy.
|
|
3455
|
+
* Agents without a refresh capability fall back to their current snapshot.
|
|
3456
|
+
*/
|
|
3457
|
+
async refreshEarnings(agentId) {
|
|
3458
|
+
const state = this.requireState();
|
|
3459
|
+
const chainId = this.requireChainId();
|
|
3460
|
+
const refreshAgent = (agent) => agent.refreshEarnings?.(state, chainId) ?? agent.getEarnings(state, chainId);
|
|
3461
|
+
if (agentId) return refreshAgent(this.getAgent(agentId));
|
|
3462
|
+
let totalEarnings = 0;
|
|
3463
|
+
const agentEarnings = {};
|
|
3464
|
+
const refreshed = await Promise.all(
|
|
3465
|
+
[...this.getActiveAgents().entries()].map(
|
|
3466
|
+
async ([id, agent]) => [id, await refreshAgent(agent)]
|
|
3467
|
+
)
|
|
3468
|
+
);
|
|
3469
|
+
for (const [id, earnings] of refreshed) {
|
|
3470
|
+
agentEarnings[id] = earnings;
|
|
3471
|
+
totalEarnings += Number(earnings.lifetimeEarnings);
|
|
3472
|
+
}
|
|
3473
|
+
return { totalEarnings: String(totalEarnings), agentEarnings };
|
|
3474
|
+
}
|
|
3422
3475
|
/**
|
|
3423
3476
|
* Get the weighted APY for the user's account over a time period.
|
|
3424
3477
|
* When querying all agents, the total APY is a balance-weighted average.
|
package/dist/index.d.cts
CHANGED
|
@@ -383,6 +383,11 @@ interface IAgent {
|
|
|
383
383
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
384
384
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
385
385
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
386
|
+
/**
|
|
387
|
+
* Refresh the agent's earnings snapshot when its backend supports doing so.
|
|
388
|
+
* Implementations own freshness and request-deduplication policy.
|
|
389
|
+
*/
|
|
390
|
+
refreshEarnings?(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
386
391
|
getAccountApy(state: ConnectionState, chainId: number, days: DailyApyDays,
|
|
387
392
|
/**
|
|
388
393
|
* Optional asset symbol ("USDC" / "WETH") scoping the daily series to a
|
|
@@ -581,6 +586,11 @@ declare class OwneySDK {
|
|
|
581
586
|
* @returns {AgentEarnings} for a single agent, or {OwneyEarnings} with totalEarnings and per-agent breakdown
|
|
582
587
|
*/
|
|
583
588
|
getEarnings(agentId?: AgentId): Promise<OwneyEarnings | AgentEarnings>;
|
|
589
|
+
/**
|
|
590
|
+
* Return refreshed earnings while letting each agent own its refresh policy.
|
|
591
|
+
* Agents without a refresh capability fall back to their current snapshot.
|
|
592
|
+
*/
|
|
593
|
+
refreshEarnings(agentId?: AgentId): Promise<OwneyEarnings | AgentEarnings>;
|
|
584
594
|
/**
|
|
585
595
|
* Get the weighted APY for the user's account over a time period.
|
|
586
596
|
* When querying all agents, the total APY is a balance-weighted average.
|
package/dist/index.d.ts
CHANGED
|
@@ -383,6 +383,11 @@ interface IAgent {
|
|
|
383
383
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
384
384
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
385
385
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
386
|
+
/**
|
|
387
|
+
* Refresh the agent's earnings snapshot when its backend supports doing so.
|
|
388
|
+
* Implementations own freshness and request-deduplication policy.
|
|
389
|
+
*/
|
|
390
|
+
refreshEarnings?(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
386
391
|
getAccountApy(state: ConnectionState, chainId: number, days: DailyApyDays,
|
|
387
392
|
/**
|
|
388
393
|
* Optional asset symbol ("USDC" / "WETH") scoping the daily series to a
|
|
@@ -581,6 +586,11 @@ declare class OwneySDK {
|
|
|
581
586
|
* @returns {AgentEarnings} for a single agent, or {OwneyEarnings} with totalEarnings and per-agent breakdown
|
|
582
587
|
*/
|
|
583
588
|
getEarnings(agentId?: AgentId): Promise<OwneyEarnings | AgentEarnings>;
|
|
589
|
+
/**
|
|
590
|
+
* Return refreshed earnings while letting each agent own its refresh policy.
|
|
591
|
+
* Agents without a refresh capability fall back to their current snapshot.
|
|
592
|
+
*/
|
|
593
|
+
refreshEarnings(agentId?: AgentId): Promise<OwneyEarnings | AgentEarnings>;
|
|
584
594
|
/**
|
|
585
595
|
* Get the weighted APY for the user's account over a time period.
|
|
586
596
|
* When querying all agents, the total APY is a balance-weighted average.
|
package/dist/index.js
CHANGED
|
@@ -217,9 +217,10 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
217
217
|
const tokens = [];
|
|
218
218
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
219
219
|
const positionChainId = Number(chainIdKey);
|
|
220
|
-
for (const [
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
for (const [
|
|
221
|
+
symbol,
|
|
222
|
+
{ balance, balanceWithFee, decimals }
|
|
223
|
+
] of Object.entries(tokensBySymbol ?? {})) {
|
|
223
224
|
const amount = hexToDecimal(balanceWithFee ?? balance ?? "0", decimals);
|
|
224
225
|
totalBalance += amount;
|
|
225
226
|
tokens.push({
|
|
@@ -358,6 +359,11 @@ function mapEntries(rawEntries, chainId) {
|
|
|
358
359
|
"Top up wallet": "Top up",
|
|
359
360
|
"Partial withdraw from protocol": "Withdraw",
|
|
360
361
|
"Withdraw from protocol": "Withdraw",
|
|
362
|
+
// The agent's own leg of a top up: the funds the user sent moving into the
|
|
363
|
+
// pool that earns the APY. Zyfai emits it as a separate entry seconds after
|
|
364
|
+
// "Top up wallet" and for slightly less (gas). `Deposit` already exists in
|
|
365
|
+
// the public HistoryAction union, so no consumer type change is needed.
|
|
366
|
+
"Deposit to protocol": "Deposit",
|
|
361
367
|
Rebalance: "Rebalance"
|
|
362
368
|
};
|
|
363
369
|
void chainId;
|
|
@@ -398,12 +404,19 @@ function mapEntries(rawEntries, chainId) {
|
|
|
398
404
|
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
399
405
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
400
406
|
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
407
|
+
const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
|
|
408
|
+
protocol: p.protocol_name,
|
|
409
|
+
pool: p.pool ?? void 0,
|
|
410
|
+
tokenSymbol: p.token_symbol ?? void 0,
|
|
411
|
+
amount: mappedAction !== "Withdraw" && typeof p.amount === "string" && p.amount !== "" && p.amount !== "0x" ? String(hexToDecimal(p.amount, tokenDecimals(p.token_symbol))) : void 0
|
|
412
|
+
}));
|
|
401
413
|
return {
|
|
402
414
|
agent: "zyfai",
|
|
403
415
|
action: mappedAction,
|
|
404
416
|
date: entry.date || "",
|
|
405
417
|
newApy: newApy === null ? null : String(newApy),
|
|
406
418
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
419
|
+
...mappedPositions.length ? { positions: mappedPositions } : {},
|
|
407
420
|
transactions: [
|
|
408
421
|
{
|
|
409
422
|
txHashes: entry.transactionHash ? [entry.transactionHash] : [],
|
|
@@ -838,6 +851,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
838
851
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
839
852
|
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
840
853
|
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
854
|
+
var EARNINGS_REFRESH_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
841
855
|
var ZyfaiAgent = class {
|
|
842
856
|
id = "zyfai";
|
|
843
857
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -889,6 +903,7 @@ var ZyfaiAgent = class {
|
|
|
889
903
|
// successful decode is cached forever; failures are NOT cached so a transient
|
|
890
904
|
// RPC error retries on the next fetch.
|
|
891
905
|
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
906
|
+
earningsRefreshInFlight = null;
|
|
892
907
|
constructor(apiKey, rpcUrls, referralSource) {
|
|
893
908
|
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
894
909
|
this.sdk = new ZyfaiSDK({
|
|
@@ -1686,6 +1701,22 @@ var ZyfaiAgent = class {
|
|
|
1686
1701
|
const raw = await this.sdk.getOnchainEarnings(smartWallet);
|
|
1687
1702
|
return mapEarnings(raw, smartWallet);
|
|
1688
1703
|
}
|
|
1704
|
+
async refreshEarnings(state, chainId) {
|
|
1705
|
+
if (this.earningsRefreshInFlight) return this.earningsRefreshInFlight;
|
|
1706
|
+
this.earningsRefreshInFlight = (async () => {
|
|
1707
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1708
|
+
const current = await this.sdk.getOnchainEarnings(smartWallet);
|
|
1709
|
+
const lastCheck = current.data.lastCheckTimestamp ? Date.parse(current.data.lastCheckTimestamp) : Number.NaN;
|
|
1710
|
+
const isFresh = Number.isFinite(lastCheck) && Date.now() - lastCheck < EARNINGS_REFRESH_COOLDOWN_MS;
|
|
1711
|
+
const earnings = isFresh ? current : await this.sdk.calculateOnchainEarnings(smartWallet);
|
|
1712
|
+
return mapEarnings(earnings, smartWallet);
|
|
1713
|
+
})();
|
|
1714
|
+
try {
|
|
1715
|
+
return await this.earningsRefreshInFlight;
|
|
1716
|
+
} finally {
|
|
1717
|
+
this.earningsRefreshInFlight = null;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1689
1720
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1690
1721
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1691
1722
|
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
@@ -1710,7 +1741,7 @@ var ZyfaiAgent = class {
|
|
|
1710
1741
|
toDate
|
|
1711
1742
|
});
|
|
1712
1743
|
raw.data.forEach((entry, idx) => {
|
|
1713
|
-
if (entry.chainId === validChainId
|
|
1744
|
+
if (entry.chainId === validChainId) {
|
|
1714
1745
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1715
1746
|
}
|
|
1716
1747
|
});
|
|
@@ -3390,6 +3421,28 @@ var OwneySDK = class {
|
|
|
3390
3421
|
agentEarnings: results
|
|
3391
3422
|
};
|
|
3392
3423
|
}
|
|
3424
|
+
/**
|
|
3425
|
+
* Return refreshed earnings while letting each agent own its refresh policy.
|
|
3426
|
+
* Agents without a refresh capability fall back to their current snapshot.
|
|
3427
|
+
*/
|
|
3428
|
+
async refreshEarnings(agentId) {
|
|
3429
|
+
const state = this.requireState();
|
|
3430
|
+
const chainId = this.requireChainId();
|
|
3431
|
+
const refreshAgent = (agent) => agent.refreshEarnings?.(state, chainId) ?? agent.getEarnings(state, chainId);
|
|
3432
|
+
if (agentId) return refreshAgent(this.getAgent(agentId));
|
|
3433
|
+
let totalEarnings = 0;
|
|
3434
|
+
const agentEarnings = {};
|
|
3435
|
+
const refreshed = await Promise.all(
|
|
3436
|
+
[...this.getActiveAgents().entries()].map(
|
|
3437
|
+
async ([id, agent]) => [id, await refreshAgent(agent)]
|
|
3438
|
+
)
|
|
3439
|
+
);
|
|
3440
|
+
for (const [id, earnings] of refreshed) {
|
|
3441
|
+
agentEarnings[id] = earnings;
|
|
3442
|
+
totalEarnings += Number(earnings.lifetimeEarnings);
|
|
3443
|
+
}
|
|
3444
|
+
return { totalEarnings: String(totalEarnings), agentEarnings };
|
|
3445
|
+
}
|
|
3393
3446
|
/**
|
|
3394
3447
|
* Get the weighted APY for the user's account over a time period.
|
|
3395
3448
|
* When querying all agents, the total APY is a balance-weighted average.
|