@owney/sdk 0.7.22-beta.1 → 0.7.23
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 +352 -1471
- package/dist/index.d.cts +60 -20
- package/dist/index.d.ts +60 -20
- package/dist/index.js +310 -119
- package/package.json +3 -5
- package/dist/chunk-3HL52KM7.js +0 -283
- package/dist/chunk-AURO3C3R.js +0 -58
- package/dist/chunk-XBDJWZXY.js +0 -141
- package/dist/surfliquid.agent-AE7RZ66F.js +0 -638
- package/dist/surfliquid.smart-account-C535356J.js +0 -135
package/dist/index.js
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var OwneyError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
details;
|
|
5
|
+
agentId;
|
|
6
|
+
constructor(code, message, details, agentId) {
|
|
7
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
8
|
+
super(`${prefix} ${message}`);
|
|
9
|
+
this.name = "OwneyError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
this.agentId = agentId;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
16
|
+
constructor(agentId, available) {
|
|
17
|
+
super(
|
|
18
|
+
"AGENT_NOT_FOUND",
|
|
19
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
20
|
+
{ agentId, available },
|
|
21
|
+
agentId
|
|
22
|
+
);
|
|
23
|
+
this.name = "AgentNotFoundError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var NotConnectedError = class extends OwneyError {
|
|
27
|
+
constructor() {
|
|
28
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
29
|
+
this.name = "NotConnectedError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
33
|
+
incompatibleAgents;
|
|
34
|
+
connectedChainId;
|
|
35
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
36
|
+
const details = incompatibleAgents.map(
|
|
37
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
38
|
+
).join("; ");
|
|
39
|
+
super(
|
|
40
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
41
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
42
|
+
{ incompatibleAgents, connectedChainId }
|
|
43
|
+
);
|
|
44
|
+
this.name = "AgentChainIncompatibleError";
|
|
45
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
46
|
+
this.connectedChainId = connectedChainId;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
16
49
|
|
|
17
50
|
// src/lib/rate-limit.ts
|
|
18
51
|
function rateLimitDelay(error, now = Date.now()) {
|
|
@@ -179,6 +212,23 @@ var SupportedAssets = [
|
|
|
179
212
|
}
|
|
180
213
|
];
|
|
181
214
|
|
|
215
|
+
// src/lib/debug.ts
|
|
216
|
+
var configuredDebug = false;
|
|
217
|
+
function setOwneyDebug(enabled) {
|
|
218
|
+
configuredDebug = enabled;
|
|
219
|
+
}
|
|
220
|
+
function isOwneyDebug() {
|
|
221
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
222
|
+
}
|
|
223
|
+
function debugLog(scope, message, data) {
|
|
224
|
+
if (!isOwneyDebug()) return;
|
|
225
|
+
if (data === void 0) {
|
|
226
|
+
console.log(`[${scope}] ${message}`);
|
|
227
|
+
} else {
|
|
228
|
+
console.log(`[${scope}] ${message}`, data);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
182
232
|
// src/lib/utils.ts
|
|
183
233
|
var isValidChainId = (chainId) => {
|
|
184
234
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -190,12 +240,6 @@ var isValidChainId = (chainId) => {
|
|
|
190
240
|
}
|
|
191
241
|
return chainId;
|
|
192
242
|
};
|
|
193
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
194
|
-
const token = tokenSymbol.toLowerCase();
|
|
195
|
-
const target = asset.toLowerCase();
|
|
196
|
-
if (token === target) return true;
|
|
197
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
198
|
-
}
|
|
199
243
|
function hexToDecimal(hex, decimals = 6) {
|
|
200
244
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
201
245
|
const parsed = BigInt(normalized);
|
|
@@ -620,6 +664,63 @@ function computeAllocationApy(positions) {
|
|
|
620
664
|
const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
|
|
621
665
|
return { totalApy, apyByChainAndAsset };
|
|
622
666
|
}
|
|
667
|
+
var ZYFAI_NET_OF_FEE_MULTIPLIER = 0.9;
|
|
668
|
+
function sumEarningsBucket(bucket, chainId, tokenSymbol) {
|
|
669
|
+
const tokens = bucket?.[String(chainId)];
|
|
670
|
+
if (!tokens) return null;
|
|
671
|
+
const wanted = tokenSymbol?.toUpperCase();
|
|
672
|
+
let total = 0;
|
|
673
|
+
let matched = false;
|
|
674
|
+
for (const [symbol, value] of Object.entries(tokens)) {
|
|
675
|
+
if (wanted && symbol.toUpperCase() !== wanted) continue;
|
|
676
|
+
matched = true;
|
|
677
|
+
const amount = Number(value);
|
|
678
|
+
if (!Number.isFinite(amount)) continue;
|
|
679
|
+
total += amount;
|
|
680
|
+
}
|
|
681
|
+
return matched ? total : null;
|
|
682
|
+
}
|
|
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;
|
|
698
|
+
}
|
|
699
|
+
return (lifetime ?? 0) + (unrealized ?? 0) + (current ?? 0) * ZYFAI_NET_OF_FEE_MULTIPLIER;
|
|
700
|
+
}
|
|
701
|
+
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
|
|
715
|
+
);
|
|
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
|
+
};
|
|
723
|
+
}
|
|
623
724
|
|
|
624
725
|
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
625
726
|
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
@@ -1449,37 +1550,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1449
1550
|
);
|
|
1450
1551
|
}
|
|
1451
1552
|
}
|
|
1452
|
-
/**
|
|
1453
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
1454
|
-
*
|
|
1455
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
1456
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
1457
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
1458
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
1459
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
1460
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
1461
|
-
*/
|
|
1462
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
1463
|
-
const ATTEMPTS = 3;
|
|
1464
|
-
const RETRY_DELAY_MS = 1e3;
|
|
1465
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
1466
|
-
try {
|
|
1467
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
1468
|
-
return;
|
|
1469
|
-
} catch (logError) {
|
|
1470
|
-
if (attempt === ATTEMPTS) {
|
|
1471
|
-
console.error(
|
|
1472
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
1473
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
1474
|
-
);
|
|
1475
|
-
return;
|
|
1476
|
-
}
|
|
1477
|
-
await new Promise(
|
|
1478
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
1479
|
-
);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
1553
|
/**
|
|
1484
1554
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1485
1555
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1789,12 +1859,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1789
1859
|
);
|
|
1790
1860
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1791
1861
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1792
|
-
|
|
1793
|
-
validChainId,
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1862
|
+
try {
|
|
1863
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1864
|
+
} catch (logError) {
|
|
1865
|
+
console.warn(
|
|
1866
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1867
|
+
logError
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1798
1870
|
return { txHash, smartWallet, amount };
|
|
1799
1871
|
}
|
|
1800
1872
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1895,6 +1967,15 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1895
1967
|
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
1896
1968
|
return mapApyHistory(raw, chainId, tokenSymbol);
|
|
1897
1969
|
}
|
|
1970
|
+
async getDailyEarnings(state, chainId, days, tokenSymbol) {
|
|
1971
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1972
|
+
const start = new Date(Date.now() - (DayFilterMapping[days] + 1) * 864e5);
|
|
1973
|
+
const raw = await this.sdk.getDailyEarnings(
|
|
1974
|
+
smartWallet,
|
|
1975
|
+
start.toISOString().slice(0, 10)
|
|
1976
|
+
);
|
|
1977
|
+
return mapDailyEarnings(raw, chainId, tokenSymbol);
|
|
1978
|
+
}
|
|
1898
1979
|
/**
|
|
1899
1980
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
1900
1981
|
* takes lowercase `assetType` and denominates WETH as "eth" (the same
|
|
@@ -2008,9 +2089,73 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2008
2089
|
}
|
|
2009
2090
|
};
|
|
2010
2091
|
|
|
2011
|
-
// src/lib/
|
|
2092
|
+
// src/lib/routing-api.ts
|
|
2012
2093
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2013
|
-
async function
|
|
2094
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2095
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2096
|
+
try {
|
|
2097
|
+
const res = await fetch(url, {
|
|
2098
|
+
method: "GET",
|
|
2099
|
+
headers: {
|
|
2100
|
+
"Content-Type": "application/json",
|
|
2101
|
+
"x-owney-api-key": `${apiKey}`
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
if (!res.ok) {
|
|
2105
|
+
if (res.status !== 404) {
|
|
2106
|
+
console.warn(
|
|
2107
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
return null;
|
|
2111
|
+
}
|
|
2112
|
+
const json = await res.json();
|
|
2113
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2114
|
+
debugLog(
|
|
2115
|
+
"owney-sdk",
|
|
2116
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2117
|
+
policy ?? void 0
|
|
2118
|
+
);
|
|
2119
|
+
return policy;
|
|
2120
|
+
} catch (error) {
|
|
2121
|
+
console.warn(
|
|
2122
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2123
|
+
error instanceof Error ? error.message : String(error)
|
|
2124
|
+
);
|
|
2125
|
+
return null;
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2129
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
2130
|
+
const res = await fetch(url, {
|
|
2131
|
+
method: "GET",
|
|
2132
|
+
headers: {
|
|
2133
|
+
"Content-Type": "application/json",
|
|
2134
|
+
"x-owney-api-key": `${apiKey}`
|
|
2135
|
+
}
|
|
2136
|
+
});
|
|
2137
|
+
if (!res.ok) {
|
|
2138
|
+
const text = await res.text().catch(() => "");
|
|
2139
|
+
throw new OwneyError(
|
|
2140
|
+
"API_ROUTING_ERROR",
|
|
2141
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2142
|
+
{ statusCode: res.status, responseBody: text }
|
|
2143
|
+
);
|
|
2144
|
+
}
|
|
2145
|
+
const json = await res.json();
|
|
2146
|
+
if (!json.success) {
|
|
2147
|
+
throw new OwneyError(
|
|
2148
|
+
"API_ROUTING_FAILED",
|
|
2149
|
+
`Routing API request failed: ${json.message}`,
|
|
2150
|
+
{ message: json.message }
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
return json.data;
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
// src/lib/health-report.ts
|
|
2157
|
+
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2158
|
+
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
2014
2159
|
try {
|
|
2015
2160
|
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
2016
2161
|
method: "POST",
|
|
@@ -2044,10 +2189,11 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
2044
2189
|
// src/lib/helpers/withdraw-helper.ts
|
|
2045
2190
|
import { parseUnits } from "viem";
|
|
2046
2191
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2192
|
+
const target = asset.toUpperCase();
|
|
2047
2193
|
return agents.map((agent) => {
|
|
2048
2194
|
const agentBalance = aggregated[agent.id];
|
|
2049
2195
|
const tokenBalance = agentBalance?.tokens.find(
|
|
2050
|
-
(t) => t.chainId === chainId &&
|
|
2196
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
2051
2197
|
);
|
|
2052
2198
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
2053
2199
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2204,10 +2350,46 @@ import {
|
|
|
2204
2350
|
} from "viem";
|
|
2205
2351
|
import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
|
|
2206
2352
|
|
|
2353
|
+
// src/lib/transfer-auth.ts
|
|
2354
|
+
import { bytesToHex } from "viem";
|
|
2355
|
+
var ERC20_META_ABI = [
|
|
2356
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2357
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
2358
|
+
];
|
|
2359
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
2360
|
+
return {
|
|
2361
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
2362
|
+
types: {
|
|
2363
|
+
TransferWithAuthorization: [
|
|
2364
|
+
{ name: "from", type: "address" },
|
|
2365
|
+
{ name: "to", type: "address" },
|
|
2366
|
+
{ name: "value", type: "uint256" },
|
|
2367
|
+
{ name: "validAfter", type: "uint256" },
|
|
2368
|
+
{ name: "validBefore", type: "uint256" },
|
|
2369
|
+
{ name: "nonce", type: "bytes32" }
|
|
2370
|
+
]
|
|
2371
|
+
},
|
|
2372
|
+
primaryType: "TransferWithAuthorization",
|
|
2373
|
+
message: input.message
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
async function readTokenMeta(publicClient, token) {
|
|
2377
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
2378
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
2379
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
2380
|
+
]);
|
|
2381
|
+
return { tokenName, tokenVersion };
|
|
2382
|
+
}
|
|
2383
|
+
function randomAuthNonce() {
|
|
2384
|
+
const bytes = new Uint8Array(32);
|
|
2385
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2386
|
+
return bytesToHex(bytes);
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2207
2389
|
// src/lib/sponsor-client.ts
|
|
2208
|
-
var
|
|
2390
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2209
2391
|
async function postSponsorTransferAuth(input) {
|
|
2210
|
-
const base3 = input.baseUrl ??
|
|
2392
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2211
2393
|
let res;
|
|
2212
2394
|
try {
|
|
2213
2395
|
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
@@ -2247,7 +2429,7 @@ async function postSponsorTransferAuth(input) {
|
|
|
2247
2429
|
return parsed.data;
|
|
2248
2430
|
}
|
|
2249
2431
|
async function postSponsorPermit2Transfer(input) {
|
|
2250
|
-
const base3 = input.baseUrl ??
|
|
2432
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2251
2433
|
let res;
|
|
2252
2434
|
try {
|
|
2253
2435
|
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
@@ -2285,7 +2467,7 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
2285
2467
|
return parsed.data;
|
|
2286
2468
|
}
|
|
2287
2469
|
async function getSponsorRelayerAddress(input) {
|
|
2288
|
-
const base3 = input.baseUrl ??
|
|
2470
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2289
2471
|
let res;
|
|
2290
2472
|
try {
|
|
2291
2473
|
res = await fetch(
|
|
@@ -2322,7 +2504,7 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2322
2504
|
}
|
|
2323
2505
|
|
|
2324
2506
|
// src/lib/permit2.ts
|
|
2325
|
-
import { bytesToHex } from "viem";
|
|
2507
|
+
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2326
2508
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2327
2509
|
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2328
2510
|
var ERC20_ALLOWANCE_ABI = [
|
|
@@ -2380,7 +2562,7 @@ function buildPermitTransferFromTypedData(input) {
|
|
|
2380
2562
|
function randomPermit2Nonce() {
|
|
2381
2563
|
const bytes = new Uint8Array(32);
|
|
2382
2564
|
globalThis.crypto.getRandomValues(bytes);
|
|
2383
|
-
return BigInt(
|
|
2565
|
+
return BigInt(bytesToHex2(bytes));
|
|
2384
2566
|
}
|
|
2385
2567
|
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2386
2568
|
return publicClient.readContract({
|
|
@@ -2725,7 +2907,6 @@ var SPONSORED_WETH_BY_CHAIN = {
|
|
|
2725
2907
|
function shouldFallbackToUserPaid(error, asset, appCallback) {
|
|
2726
2908
|
return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
|
|
2727
2909
|
}
|
|
2728
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai"];
|
|
2729
2910
|
var OwneySDK = class {
|
|
2730
2911
|
agents = /* @__PURE__ */ new Map();
|
|
2731
2912
|
activeAgents = /* @__PURE__ */ new Set();
|
|
@@ -3009,7 +3190,7 @@ var OwneySDK = class {
|
|
|
3009
3190
|
);
|
|
3010
3191
|
this.disabledAgents.clear();
|
|
3011
3192
|
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
3012
|
-
const agent =
|
|
3193
|
+
const agent = this.createAgent(agent_type, key2);
|
|
3013
3194
|
if (!agent) continue;
|
|
3014
3195
|
this.agents.set(agent_type, agent);
|
|
3015
3196
|
if (is_enabled === false) {
|
|
@@ -3030,18 +3211,10 @@ var OwneySDK = class {
|
|
|
3030
3211
|
this.initializingAgentsPromise = null;
|
|
3031
3212
|
}
|
|
3032
3213
|
}
|
|
3033
|
-
|
|
3214
|
+
createAgent(agentId, key2) {
|
|
3034
3215
|
if (agentId === "zyfai") {
|
|
3035
3216
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
3036
3217
|
}
|
|
3037
|
-
if (agentId === "surfliquid") {
|
|
3038
|
-
if (!key2) return null;
|
|
3039
|
-
const { SurfLiquidAgent } = await import("./surfliquid.agent-AE7RZ66F.js");
|
|
3040
|
-
return new SurfLiquidAgent({
|
|
3041
|
-
apiKey: this.apiKey,
|
|
3042
|
-
routingApiBaseUrl: this.routingApiBaseUrl
|
|
3043
|
-
});
|
|
3044
|
-
}
|
|
3045
3218
|
return null;
|
|
3046
3219
|
}
|
|
3047
3220
|
/**
|
|
@@ -3439,14 +3612,15 @@ var OwneySDK = class {
|
|
|
3439
3612
|
async hasExistingBalance(agent, state, chainId, asset, requireReliableRead = false) {
|
|
3440
3613
|
try {
|
|
3441
3614
|
const balance = await agent.getBalances(state, chainId);
|
|
3615
|
+
const target = asset.toLowerCase();
|
|
3442
3616
|
const token = balance.tokens.find(
|
|
3443
|
-
(t) => t.chainId === chainId &&
|
|
3617
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
3444
3618
|
);
|
|
3445
3619
|
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
3446
3620
|
const position = (balance.positions ?? []).find((p) => {
|
|
3447
3621
|
const positionChain = p.chain.trim().toUpperCase();
|
|
3448
3622
|
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
3449
|
-
return matchesChain &&
|
|
3623
|
+
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
3450
3624
|
});
|
|
3451
3625
|
return !!token && Number(token.amount) > 0 || !!position;
|
|
3452
3626
|
} catch (error) {
|
|
@@ -3493,34 +3667,6 @@ var OwneySDK = class {
|
|
|
3493
3667
|
}
|
|
3494
3668
|
return eligible;
|
|
3495
3669
|
}
|
|
3496
|
-
/**
|
|
3497
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
3498
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3499
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3500
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3501
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3502
|
-
*
|
|
3503
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
3504
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
3505
|
-
*/
|
|
3506
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
3507
|
-
try {
|
|
3508
|
-
await this.ensureAgentsInitialized();
|
|
3509
|
-
} catch (error) {
|
|
3510
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3511
|
-
return [];
|
|
3512
|
-
}
|
|
3513
|
-
throw error;
|
|
3514
|
-
}
|
|
3515
|
-
return [...this.agents.values()].filter((agent) => {
|
|
3516
|
-
const chainAssets = agent.supportedAssets.find(
|
|
3517
|
-
(sa) => sa.chainId === chainId
|
|
3518
|
-
);
|
|
3519
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3520
|
-
}).map((agent) => agent.id).sort(
|
|
3521
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3522
|
-
);
|
|
3523
|
-
}
|
|
3524
3670
|
// --- Fund operations ---
|
|
3525
3671
|
/**
|
|
3526
3672
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3557,19 +3703,9 @@ var OwneySDK = class {
|
|
|
3557
3703
|
}
|
|
3558
3704
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3559
3705
|
if (!amount) {
|
|
3560
|
-
const aggregated2 = await this.getBalances();
|
|
3561
|
-
const funded = projectAgentBalancesForAsset(
|
|
3562
|
-
eligibleAgents,
|
|
3563
|
-
aggregated2.agentBalances,
|
|
3564
|
-
chainId,
|
|
3565
|
-
asset,
|
|
3566
|
-
assetInfo.decimals
|
|
3567
|
-
).filter(
|
|
3568
|
-
({ agent, balance }) => balance > 0n || aggregated2.agentErrors?.[agent.id] !== void 0
|
|
3569
|
-
).map(({ agent }) => agent);
|
|
3570
3706
|
const results2 = {};
|
|
3571
3707
|
const agentErrors2 = {};
|
|
3572
|
-
for (const agent of
|
|
3708
|
+
for (const agent of eligibleAgents) {
|
|
3573
3709
|
try {
|
|
3574
3710
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3575
3711
|
} catch (err) {
|
|
@@ -3812,6 +3948,60 @@ var OwneySDK = class {
|
|
|
3812
3948
|
* @param options.days - Lookback period: "7D", "14D", or "30D"
|
|
3813
3949
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
3814
3950
|
*/
|
|
3951
|
+
/**
|
|
3952
|
+
* Daily cumulative NET earnings for the selected chain/asset, backing the
|
|
3953
|
+
* "recent earnings" subline. Net is computed as Zyfai's own
|
|
3954
|
+
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
3955
|
+
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
3956
|
+
*
|
|
3957
|
+
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
3958
|
+
* summed, not weighted, and an agent that fails to report must not silently
|
|
3959
|
+
* subtract from the total. Without an agentId the series is the sum of the
|
|
3960
|
+
* agents that answered.
|
|
3961
|
+
*/
|
|
3962
|
+
async getDailyEarnings({
|
|
3963
|
+
agentId,
|
|
3964
|
+
days,
|
|
3965
|
+
tokenSymbol
|
|
3966
|
+
}) {
|
|
3967
|
+
const state = this.requireState();
|
|
3968
|
+
const chainId = this.requireChainId();
|
|
3969
|
+
if (agentId) {
|
|
3970
|
+
const agent = this.getAgent(agentId);
|
|
3971
|
+
if (!agent.getDailyEarnings) {
|
|
3972
|
+
return { walletAddress: state.walletAddress ?? "", points: [] };
|
|
3973
|
+
}
|
|
3974
|
+
return this.readAgent(
|
|
3975
|
+
agent,
|
|
3976
|
+
"dailyEarnings",
|
|
3977
|
+
() => agent.getDailyEarnings(state, chainId, days, tokenSymbol),
|
|
3978
|
+
{ days, tokenSymbol }
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3981
|
+
const entries = [...this.getActiveAgents().entries()].filter(
|
|
3982
|
+
([, agent]) => agent.getDailyEarnings
|
|
3983
|
+
);
|
|
3984
|
+
const series = await Promise.all(
|
|
3985
|
+
entries.map(
|
|
3986
|
+
([, agent]) => this.readAgent(
|
|
3987
|
+
agent,
|
|
3988
|
+
"dailyEarnings",
|
|
3989
|
+
() => agent.getDailyEarnings(state, chainId, days, tokenSymbol),
|
|
3990
|
+
{ days, tokenSymbol }
|
|
3991
|
+
)
|
|
3992
|
+
)
|
|
3993
|
+
);
|
|
3994
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
3995
|
+
for (const s of series) {
|
|
3996
|
+
for (const point of s.points) {
|
|
3997
|
+
byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.net);
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
return {
|
|
4001
|
+
walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
|
|
4002
|
+
points: [...byDate.entries()].map(([date, net]) => ({ date, net })).sort((a, b) => a.date.localeCompare(b.date))
|
|
4003
|
+
};
|
|
4004
|
+
}
|
|
3815
4005
|
async getAccountApy({
|
|
3816
4006
|
agentId,
|
|
3817
4007
|
days,
|
|
@@ -4372,5 +4562,6 @@ export {
|
|
|
4372
4562
|
OwneyError,
|
|
4373
4563
|
OwneySDK,
|
|
4374
4564
|
createOwneySIWX,
|
|
4565
|
+
recentEarningsFromPoints,
|
|
4375
4566
|
setOwneyDebug
|
|
4376
4567
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owney/sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -20,12 +20,10 @@
|
|
|
20
20
|
"build": "tsup",
|
|
21
21
|
"dev": "tsup --watch",
|
|
22
22
|
"test": "vitest run",
|
|
23
|
-
"test:watch": "vitest"
|
|
24
|
-
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
23
|
+
"test:watch": "vitest"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@zyfai/sdk": "0.2.
|
|
28
|
-
"permissionless": "^0.4.0",
|
|
26
|
+
"@zyfai/sdk": "0.2.55",
|
|
29
27
|
"siwe": "^3.0.0",
|
|
30
28
|
"viem": "^2.48.1"
|
|
31
29
|
},
|