@owney/sdk 0.6.9-beta.4 → 0.6.9-beta.6
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/chunk-GMNQBWUB.js +55 -0
- package/dist/index.cjs +860 -140
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +352 -122
- package/dist/surfliquid.agent-OMOYXWLP.js +385 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentChainIncompatibleError,
|
|
3
|
+
AgentNotFoundError,
|
|
4
|
+
NotConnectedError,
|
|
5
|
+
OwneyError
|
|
6
|
+
} from "./chunk-GMNQBWUB.js";
|
|
7
|
+
|
|
1
8
|
// src/agents/zyfai/zyfai.agent.ts
|
|
2
9
|
import { ZyfaiSDK } from "@zyfai/sdk";
|
|
3
10
|
import { createPublicClient, http } from "viem";
|
|
@@ -56,55 +63,6 @@ var SupportedAssets = [
|
|
|
56
63
|
}
|
|
57
64
|
];
|
|
58
65
|
|
|
59
|
-
// src/errors.ts
|
|
60
|
-
var OwneyError = class extends Error {
|
|
61
|
-
code;
|
|
62
|
-
details;
|
|
63
|
-
agentId;
|
|
64
|
-
constructor(code, message, details, agentId) {
|
|
65
|
-
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
66
|
-
super(`${prefix} ${message}`);
|
|
67
|
-
this.name = "OwneyError";
|
|
68
|
-
this.code = code;
|
|
69
|
-
this.details = details;
|
|
70
|
-
this.agentId = agentId;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
var AgentNotFoundError = class extends OwneyError {
|
|
74
|
-
constructor(agentId, available) {
|
|
75
|
-
super(
|
|
76
|
-
"AGENT_NOT_FOUND",
|
|
77
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
78
|
-
{ agentId, available },
|
|
79
|
-
agentId
|
|
80
|
-
);
|
|
81
|
-
this.name = "AgentNotFoundError";
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
var NotConnectedError = class extends OwneyError {
|
|
85
|
-
constructor() {
|
|
86
|
-
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
87
|
-
this.name = "NotConnectedError";
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
var AgentChainIncompatibleError = class extends OwneyError {
|
|
91
|
-
incompatibleAgents;
|
|
92
|
-
connectedChainId;
|
|
93
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
94
|
-
const details = incompatibleAgents.map(
|
|
95
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
96
|
-
).join("; ");
|
|
97
|
-
super(
|
|
98
|
-
"AGENT_CHAIN_INCOMPATIBLE",
|
|
99
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
100
|
-
{ incompatibleAgents, connectedChainId }
|
|
101
|
-
);
|
|
102
|
-
this.name = "AgentChainIncompatibleError";
|
|
103
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
104
|
-
this.connectedChainId = connectedChainId;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
66
|
// src/lib/utils.ts
|
|
109
67
|
var isValidChainId = (chainId) => {
|
|
110
68
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -179,46 +137,46 @@ function resolveChainId(chain) {
|
|
|
179
137
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
180
138
|
const portfolio = raw.portfolio;
|
|
181
139
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
140
|
+
const rawPositions = portfolio.positions ?? [];
|
|
141
|
+
const detailByKey = /* @__PURE__ */ new Map();
|
|
142
|
+
for (const p of rawPositions) {
|
|
143
|
+
const cid = resolveChainId(p.chain ?? "");
|
|
144
|
+
const symbol = (p.token_symbol ?? "").toUpperCase();
|
|
145
|
+
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
146
|
+
}
|
|
182
147
|
let totalBalance = 0;
|
|
183
148
|
const tokens = [];
|
|
149
|
+
const positions = [];
|
|
184
150
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
185
151
|
const positionChainId = Number(chainIdKey);
|
|
152
|
+
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
186
153
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
187
154
|
tokensBySymbol ?? {}
|
|
188
155
|
)) {
|
|
189
|
-
const amount = hexToDecimal(balance || "0", decimals);
|
|
156
|
+
const amount = hexToDecimal(balance || "0", tokenDecimals(symbol, decimals));
|
|
190
157
|
totalBalance += amount;
|
|
191
158
|
tokens.push({
|
|
192
|
-
chain:
|
|
159
|
+
chain: chainName,
|
|
193
160
|
chainId: positionChainId,
|
|
194
161
|
asset: symbol,
|
|
195
162
|
amount: String(amount)
|
|
196
163
|
});
|
|
164
|
+
const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
|
|
165
|
+
positions.push({
|
|
166
|
+
chain: chainName,
|
|
167
|
+
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
168
|
+
protocolId: detail?.protocol_id,
|
|
169
|
+
pool: detail?.pool,
|
|
170
|
+
asset: symbol,
|
|
171
|
+
amount: String(amount),
|
|
172
|
+
apy: detail?.pool_apy,
|
|
173
|
+
tvl: detail?.pool_tvl,
|
|
174
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
175
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
176
|
+
liquidity: detail?.liquidity
|
|
177
|
+
});
|
|
197
178
|
}
|
|
198
179
|
}
|
|
199
|
-
const positions = (portfolio.positions ?? []).map((p) => ({
|
|
200
|
-
chain: p.chain ?? "",
|
|
201
|
-
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
202
|
-
protocolId: p.protocol_id,
|
|
203
|
-
pool: p.pool,
|
|
204
|
-
asset: p.token_symbol ?? "",
|
|
205
|
-
// Position amount is hex-encoded base units (like the token balances
|
|
206
|
-
// above). `PositionSlot` doesn't type a `decimals` field, but runtime
|
|
207
|
-
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
208
|
-
// when present, otherwise fall back to the per-symbol lookup so
|
|
209
|
-
// non-6-decimal assets like WETH don't render 1e12 too large.
|
|
210
|
-
amount: String(
|
|
211
|
-
hexToDecimal(
|
|
212
|
-
p.amount || "0",
|
|
213
|
-
tokenDecimals(p.token_symbol, p.decimals)
|
|
214
|
-
)
|
|
215
|
-
),
|
|
216
|
-
apy: p.pool_apy,
|
|
217
|
-
tvl: p.pool_tvl,
|
|
218
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
219
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
220
|
-
liquidity: p.liquidity
|
|
221
|
-
}));
|
|
222
180
|
return {
|
|
223
181
|
smartWallet,
|
|
224
182
|
totalBalance: String(totalBalance),
|
|
@@ -529,23 +487,23 @@ var readLegacySession = (store, address) => {
|
|
|
529
487
|
const legacyKeys = [];
|
|
530
488
|
try {
|
|
531
489
|
for (let i = 0; i < store.length; i++) {
|
|
532
|
-
const
|
|
533
|
-
if (
|
|
490
|
+
const key2 = store.key(i);
|
|
491
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
534
492
|
}
|
|
535
493
|
} catch {
|
|
536
494
|
return null;
|
|
537
495
|
}
|
|
538
496
|
let adopted = null;
|
|
539
|
-
for (const
|
|
497
|
+
for (const key2 of legacyKeys) {
|
|
540
498
|
if (!adopted) {
|
|
541
499
|
try {
|
|
542
|
-
const parsed = JSON.parse(store.getItem(
|
|
500
|
+
const parsed = JSON.parse(store.getItem(key2) ?? "");
|
|
543
501
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
544
502
|
} catch {
|
|
545
503
|
}
|
|
546
504
|
}
|
|
547
505
|
try {
|
|
548
|
-
store.removeItem(
|
|
506
|
+
store.removeItem(key2);
|
|
549
507
|
} catch {
|
|
550
508
|
}
|
|
551
509
|
}
|
|
@@ -553,11 +511,11 @@ var readLegacySession = (store, address) => {
|
|
|
553
511
|
};
|
|
554
512
|
var readSession = (address, _chainId) => {
|
|
555
513
|
if (typeof window === "undefined") return null;
|
|
556
|
-
const
|
|
514
|
+
const key2 = buildKey(address);
|
|
557
515
|
const store = storage();
|
|
558
516
|
let raw = null;
|
|
559
517
|
try {
|
|
560
|
-
raw = store?.getItem(
|
|
518
|
+
raw = store?.getItem(key2) ?? null;
|
|
561
519
|
} catch {
|
|
562
520
|
raw = null;
|
|
563
521
|
}
|
|
@@ -567,9 +525,9 @@ var readSession = (address, _chainId) => {
|
|
|
567
525
|
if (isFreshSession(parsed)) return parsed;
|
|
568
526
|
} catch {
|
|
569
527
|
}
|
|
570
|
-
memorySessions.delete(
|
|
528
|
+
memorySessions.delete(key2);
|
|
571
529
|
try {
|
|
572
|
-
store?.removeItem(
|
|
530
|
+
store?.removeItem(key2);
|
|
573
531
|
} catch {
|
|
574
532
|
}
|
|
575
533
|
return null;
|
|
@@ -579,27 +537,27 @@ var readSession = (address, _chainId) => {
|
|
|
579
537
|
writeSession(address, _chainId, legacy);
|
|
580
538
|
return legacy;
|
|
581
539
|
}
|
|
582
|
-
const cached = memorySessions.get(
|
|
540
|
+
const cached = memorySessions.get(key2);
|
|
583
541
|
if (isFreshSession(cached)) return cached;
|
|
584
|
-
if (cached) memorySessions.delete(
|
|
542
|
+
if (cached) memorySessions.delete(key2);
|
|
585
543
|
return null;
|
|
586
544
|
};
|
|
587
545
|
var writeSession = (address, _chainId, session) => {
|
|
588
546
|
if (typeof window === "undefined") return;
|
|
589
|
-
const
|
|
590
|
-
memorySessions.set(
|
|
547
|
+
const key2 = buildKey(address);
|
|
548
|
+
memorySessions.set(key2, session);
|
|
591
549
|
const store = storage();
|
|
592
550
|
try {
|
|
593
|
-
store?.setItem(
|
|
551
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
594
552
|
} catch {
|
|
595
553
|
}
|
|
596
554
|
};
|
|
597
555
|
var clearSession = (address, _chainId) => {
|
|
598
|
-
const
|
|
599
|
-
memorySessions.delete(
|
|
556
|
+
const key2 = buildKey(address);
|
|
557
|
+
memorySessions.delete(key2);
|
|
600
558
|
const store = storage();
|
|
601
559
|
try {
|
|
602
|
-
store?.removeItem(
|
|
560
|
+
store?.removeItem(key2);
|
|
603
561
|
} catch {
|
|
604
562
|
}
|
|
605
563
|
readLegacySession(store, address);
|
|
@@ -663,6 +621,99 @@ function splittingNeedsUpdate(current, desired) {
|
|
|
663
621
|
return current.minSplits !== desired.minSplits;
|
|
664
622
|
}
|
|
665
623
|
|
|
624
|
+
// src/agents/zyfai/pool-policy.ts
|
|
625
|
+
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
626
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
627
|
+
for (const selection of policy.selections) {
|
|
628
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
629
|
+
}
|
|
630
|
+
const customizations = [];
|
|
631
|
+
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
632
|
+
const available = availableByProtocol.get(protocolId);
|
|
633
|
+
if (available === void 0) {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
const availableSet = new Set(available);
|
|
637
|
+
for (const chainId of chainIds) {
|
|
638
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
639
|
+
if (stored === void 0) {
|
|
640
|
+
customizations.push({
|
|
641
|
+
protocolId,
|
|
642
|
+
chainId,
|
|
643
|
+
pools: [],
|
|
644
|
+
autoselect: true
|
|
645
|
+
});
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
649
|
+
customizations.push({
|
|
650
|
+
protocolId,
|
|
651
|
+
chainId,
|
|
652
|
+
pools,
|
|
653
|
+
autoselect: false
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return customizations;
|
|
658
|
+
}
|
|
659
|
+
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
660
|
+
if (policy.selections.length === 0) {
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
664
|
+
for (const selection of policy.selections) {
|
|
665
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
666
|
+
}
|
|
667
|
+
return universe.filter((protocolId) => {
|
|
668
|
+
const chainIds = chainsByProtocol[protocolId];
|
|
669
|
+
if (chainIds === void 0 || chainIds.length === 0) {
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
const fullyDisabled = chainIds.every((chainId) => {
|
|
673
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
674
|
+
return stored !== void 0 && stored.pools.length === 0;
|
|
675
|
+
});
|
|
676
|
+
return !fullyDisabled;
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
function key(protocolId, chainId) {
|
|
680
|
+
return `${protocolId}:${chainId}`;
|
|
681
|
+
}
|
|
682
|
+
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
683
|
+
const allowed = new Set(dashboardChainIds);
|
|
684
|
+
const result = {};
|
|
685
|
+
for (const protocol of protocols) {
|
|
686
|
+
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
687
|
+
(chainId) => allowed.has(chainId)
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
return result;
|
|
691
|
+
}
|
|
692
|
+
function flattenAvailablePools(raw) {
|
|
693
|
+
const byChain = raw ?? {};
|
|
694
|
+
const names = [];
|
|
695
|
+
for (const byToken of Object.values(byChain ?? {})) {
|
|
696
|
+
for (const entry of Object.values(byToken ?? {})) {
|
|
697
|
+
for (const pool of entry?.pools ?? []) {
|
|
698
|
+
if (pool?.name) names.push(pool.name);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return names;
|
|
703
|
+
}
|
|
704
|
+
function protocolListsEqual(a, b) {
|
|
705
|
+
const left = [...a ?? []].sort();
|
|
706
|
+
const right = [...b ?? []].sort();
|
|
707
|
+
if (left.length !== right.length) return false;
|
|
708
|
+
return left.every((value, index) => value === right[index]);
|
|
709
|
+
}
|
|
710
|
+
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
711
|
+
if (!current) return true;
|
|
712
|
+
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
713
|
+
if (desiredProtocols === null) return false;
|
|
714
|
+
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
715
|
+
}
|
|
716
|
+
|
|
666
717
|
// src/lib/debug.ts
|
|
667
718
|
var configuredDebug = false;
|
|
668
719
|
function setOwneyDebug(enabled) {
|
|
@@ -693,6 +744,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
693
744
|
};
|
|
694
745
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
695
746
|
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
747
|
+
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
696
748
|
function isAlreadyActiveSessionKeyError(error) {
|
|
697
749
|
const message = error instanceof Error ? error.message : String(error);
|
|
698
750
|
return /already has an active session key/i.test(message);
|
|
@@ -1077,6 +1129,9 @@ var ZyfaiAgent = class {
|
|
|
1077
1129
|
await Promise.all(
|
|
1078
1130
|
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1079
1131
|
);
|
|
1132
|
+
if (policy.poolPolicy) {
|
|
1133
|
+
await this.applyPoolPolicy(policy.poolPolicy);
|
|
1134
|
+
}
|
|
1080
1135
|
}
|
|
1081
1136
|
async applySplitting(asset, policy) {
|
|
1082
1137
|
try {
|
|
@@ -1113,6 +1168,117 @@ var ZyfaiAgent = class {
|
|
|
1113
1168
|
);
|
|
1114
1169
|
}
|
|
1115
1170
|
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Apply the org's protocol/pool policy to this user's Zyfai profile.
|
|
1173
|
+
*
|
|
1174
|
+
* Two Zyfai writes, in a strict order:
|
|
1175
|
+
* 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
|
|
1176
|
+
* the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
|
|
1177
|
+
* 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
|
|
1178
|
+
* pool narrowing.
|
|
1179
|
+
*
|
|
1180
|
+
* Order matters: constraining a protocol's pools (step 2) while that
|
|
1181
|
+
* protocol is not yet in the allow-list (step 1 not yet applied) lands the
|
|
1182
|
+
* constraint on something the rebalance engine isn't considering.
|
|
1183
|
+
*
|
|
1184
|
+
* Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
|
|
1185
|
+
* connecting, so a Zyfai hiccup must leave the user connected with their
|
|
1186
|
+
* profile unchanged, never fail activation.
|
|
1187
|
+
*/
|
|
1188
|
+
async applyPoolPolicy(policy) {
|
|
1189
|
+
try {
|
|
1190
|
+
const { protocols: universe } = await this.sdk.getAvailableProtocols(
|
|
1191
|
+
this.supportedChainIds[0]
|
|
1192
|
+
);
|
|
1193
|
+
const universeIds = universe.map((p) => p.id);
|
|
1194
|
+
const chainsByProtocol = buildChainsByProtocol(
|
|
1195
|
+
universe,
|
|
1196
|
+
POOL_POLICY_CHAIN_IDS
|
|
1197
|
+
);
|
|
1198
|
+
debugLog("zyfai:pools", "protocol universe", {
|
|
1199
|
+
universeIds,
|
|
1200
|
+
chainsByProtocol
|
|
1201
|
+
});
|
|
1202
|
+
let strategy;
|
|
1203
|
+
const desiredProtocols = deriveProtocols(
|
|
1204
|
+
policy,
|
|
1205
|
+
universeIds,
|
|
1206
|
+
chainsByProtocol
|
|
1207
|
+
);
|
|
1208
|
+
const desiredAutoSelect = policy.autoApproveProtocols;
|
|
1209
|
+
for (const asset of SPLITTING_ASSETS) {
|
|
1210
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1211
|
+
if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
|
|
1212
|
+
strategy = current.strategy;
|
|
1213
|
+
}
|
|
1214
|
+
const needsUpdate = protocolsPolicyNeedsUpdate(
|
|
1215
|
+
current,
|
|
1216
|
+
desiredProtocols,
|
|
1217
|
+
desiredAutoSelect
|
|
1218
|
+
);
|
|
1219
|
+
debugLog("zyfai:pools", `${asset}: comparing protocols`, {
|
|
1220
|
+
current: {
|
|
1221
|
+
protocols: current.protocols,
|
|
1222
|
+
autoSelectProtocols: current.autoSelectProtocols
|
|
1223
|
+
},
|
|
1224
|
+
desired: {
|
|
1225
|
+
protocols: desiredProtocols,
|
|
1226
|
+
autoSelectProtocols: desiredAutoSelect
|
|
1227
|
+
},
|
|
1228
|
+
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1229
|
+
});
|
|
1230
|
+
if (!needsUpdate) continue;
|
|
1231
|
+
const update = {
|
|
1232
|
+
asset,
|
|
1233
|
+
autoSelectProtocols: desiredAutoSelect
|
|
1234
|
+
};
|
|
1235
|
+
if (desiredProtocols !== null) update.protocols = desiredProtocols;
|
|
1236
|
+
await this.sdk.updateUserProfile(update);
|
|
1237
|
+
debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
|
|
1238
|
+
}
|
|
1239
|
+
const poolResults = await Promise.all(
|
|
1240
|
+
universe.map(async (protocol) => {
|
|
1241
|
+
try {
|
|
1242
|
+
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1243
|
+
return [protocol.id, flattenAvailablePools(raw)];
|
|
1244
|
+
} catch (error) {
|
|
1245
|
+
console.warn(
|
|
1246
|
+
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
1247
|
+
error instanceof Error ? error.message : String(error)
|
|
1248
|
+
);
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
})
|
|
1252
|
+
);
|
|
1253
|
+
const availableByProtocol = /* @__PURE__ */ new Map();
|
|
1254
|
+
for (const result of poolResults) {
|
|
1255
|
+
if (result) availableByProtocol.set(result[0], result[1]);
|
|
1256
|
+
}
|
|
1257
|
+
const customizations = toZyfaiCustomizations(
|
|
1258
|
+
policy,
|
|
1259
|
+
availableByProtocol,
|
|
1260
|
+
chainsByProtocol
|
|
1261
|
+
);
|
|
1262
|
+
debugLog("zyfai:pools", "derived customizeBatch payload", {
|
|
1263
|
+
strategy,
|
|
1264
|
+
availableProtocolCount: availableByProtocol.size,
|
|
1265
|
+
customizations
|
|
1266
|
+
});
|
|
1267
|
+
if (customizations.length === 0) {
|
|
1268
|
+
debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
await this.sdk.customizeBatch(customizations);
|
|
1272
|
+
debugLog("zyfai:pools", "wrote customizeBatch", {
|
|
1273
|
+
count: customizations.length
|
|
1274
|
+
});
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
console.warn(
|
|
1277
|
+
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
1278
|
+
error instanceof Error ? error.message : String(error)
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1116
1282
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1117
1283
|
try {
|
|
1118
1284
|
await this.connectFull(state, chainId);
|
|
@@ -1908,6 +2074,7 @@ var VIEM_CHAIN2 = {
|
|
|
1908
2074
|
42161: arbitrum2,
|
|
1909
2075
|
1: mainnet2
|
|
1910
2076
|
};
|
|
2077
|
+
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
1911
2078
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
1912
2079
|
8453: "0x4200000000000000000000000000000000000006",
|
|
1913
2080
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -1936,6 +2103,7 @@ var OwneySDK = class {
|
|
|
1936
2103
|
zyfaiRpcUrls;
|
|
1937
2104
|
routingApiBaseUrl;
|
|
1938
2105
|
referralSource;
|
|
2106
|
+
surfliquidApiBaseUrl;
|
|
1939
2107
|
cachedSponsoredCallback = null;
|
|
1940
2108
|
cachedWethSponsoredCallback = null;
|
|
1941
2109
|
initializingAgentsPromise = null;
|
|
@@ -1945,6 +2113,7 @@ var OwneySDK = class {
|
|
|
1945
2113
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
1946
2114
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
1947
2115
|
this.referralSource = config.referralSource;
|
|
2116
|
+
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
1948
2117
|
}
|
|
1949
2118
|
/**
|
|
1950
2119
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2152,8 +2321,8 @@ var OwneySDK = class {
|
|
|
2152
2321
|
this.initializingAgentsPromise = (async () => {
|
|
2153
2322
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2154
2323
|
this.disabledAgents.clear();
|
|
2155
|
-
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
2156
|
-
const agent = this.createAgent(agent_type,
|
|
2324
|
+
for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
|
|
2325
|
+
const agent = await this.createAgent(agent_type, key2, project_name);
|
|
2157
2326
|
if (!agent) continue;
|
|
2158
2327
|
this.agents.set(agent_type, agent);
|
|
2159
2328
|
if (is_enabled === false) {
|
|
@@ -2174,9 +2343,21 @@ var OwneySDK = class {
|
|
|
2174
2343
|
this.initializingAgentsPromise = null;
|
|
2175
2344
|
}
|
|
2176
2345
|
}
|
|
2177
|
-
createAgent(agentId,
|
|
2346
|
+
async createAgent(agentId, key2, projectName) {
|
|
2178
2347
|
if (agentId === "zyfai") {
|
|
2179
|
-
return new ZyfaiAgent(
|
|
2348
|
+
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2349
|
+
}
|
|
2350
|
+
if (agentId === "surfliquid") {
|
|
2351
|
+
if (!projectName) return null;
|
|
2352
|
+
const { SurfLiquidAgent } = await import("./surfliquid.agent-OMOYXWLP.js");
|
|
2353
|
+
return new SurfLiquidAgent({
|
|
2354
|
+
projectName,
|
|
2355
|
+
appId: key2,
|
|
2356
|
+
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2357
|
+
// which WebKit (iOS) discards when it is third-party. See
|
|
2358
|
+
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2359
|
+
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2360
|
+
});
|
|
2180
2361
|
}
|
|
2181
2362
|
return null;
|
|
2182
2363
|
}
|
|
@@ -2332,18 +2513,30 @@ var OwneySDK = class {
|
|
|
2332
2513
|
);
|
|
2333
2514
|
}
|
|
2334
2515
|
const agentResults = {};
|
|
2516
|
+
const agentErrors = {};
|
|
2335
2517
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
2336
|
-
|
|
2337
|
-
agent
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2518
|
+
try {
|
|
2519
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2520
|
+
agent,
|
|
2521
|
+
state,
|
|
2522
|
+
chainId,
|
|
2523
|
+
agentAmount,
|
|
2524
|
+
asset,
|
|
2525
|
+
effectiveCallback,
|
|
2526
|
+
depositCallback
|
|
2527
|
+
);
|
|
2528
|
+
} catch (error) {
|
|
2529
|
+
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
if (Object.keys(agentResults).length === 0) {
|
|
2533
|
+
throw new OwneyError(
|
|
2534
|
+
"DEPOSIT_ALL_FAILED",
|
|
2535
|
+
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
2536
|
+
{ agentErrors }
|
|
2344
2537
|
);
|
|
2345
2538
|
}
|
|
2346
|
-
return { agentResults };
|
|
2539
|
+
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
2347
2540
|
}
|
|
2348
2541
|
/**
|
|
2349
2542
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2500,6 +2693,34 @@ var OwneySDK = class {
|
|
|
2500
2693
|
}
|
|
2501
2694
|
return eligible;
|
|
2502
2695
|
}
|
|
2696
|
+
/**
|
|
2697
|
+
* Agent ids the routing API provisioned for this org that support the given
|
|
2698
|
+
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
2699
|
+
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
2700
|
+
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
2701
|
+
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
2702
|
+
*
|
|
2703
|
+
* This is the source of truth for agent availability: an agent appears here
|
|
2704
|
+
* iff the routing API returned its key. No per-app feature flags.
|
|
2705
|
+
*/
|
|
2706
|
+
async getEligibleAgentIds(chainId, asset) {
|
|
2707
|
+
try {
|
|
2708
|
+
await this.ensureAgentsInitialized();
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
2711
|
+
return [];
|
|
2712
|
+
}
|
|
2713
|
+
throw error;
|
|
2714
|
+
}
|
|
2715
|
+
return [...this.agents.values()].filter((agent) => {
|
|
2716
|
+
const chainAssets = agent.supportedAssets.find(
|
|
2717
|
+
(sa) => sa.chainId === chainId
|
|
2718
|
+
);
|
|
2719
|
+
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
2720
|
+
}).map((agent) => agent.id).sort(
|
|
2721
|
+
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2503
2724
|
// --- Fund operations ---
|
|
2504
2725
|
/**
|
|
2505
2726
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2535,9 +2756,17 @@ var OwneySDK = class {
|
|
|
2535
2756
|
}
|
|
2536
2757
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2537
2758
|
if (!amount) {
|
|
2759
|
+
const aggregated2 = await this.getBalances();
|
|
2760
|
+
const funded = projectAgentBalancesForAsset(
|
|
2761
|
+
eligibleAgents,
|
|
2762
|
+
aggregated2.agentBalances,
|
|
2763
|
+
chainId,
|
|
2764
|
+
asset,
|
|
2765
|
+
assetInfo.decimals
|
|
2766
|
+
).filter((b) => b.balance > 0n);
|
|
2538
2767
|
const results2 = {};
|
|
2539
2768
|
const agentErrors2 = {};
|
|
2540
|
-
for (const agent of
|
|
2769
|
+
for (const { agent } of funded) {
|
|
2541
2770
|
try {
|
|
2542
2771
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2543
2772
|
} catch (err) {
|
|
@@ -2554,9 +2783,10 @@ var OwneySDK = class {
|
|
|
2554
2783
|
{ asset, agentErrors: agentErrors2 }
|
|
2555
2784
|
);
|
|
2556
2785
|
}
|
|
2786
|
+
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2557
2787
|
return {
|
|
2558
2788
|
agentResult: results2,
|
|
2559
|
-
totalWithdrawn:
|
|
2789
|
+
totalWithdrawn: totalWithdrawn.toString()
|
|
2560
2790
|
};
|
|
2561
2791
|
}
|
|
2562
2792
|
const requested = BigInt(amount);
|
|
@@ -3073,22 +3303,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3073
3303
|
const legacyKeys = [];
|
|
3074
3304
|
try {
|
|
3075
3305
|
for (let i = 0; i < store.length; i++) {
|
|
3076
|
-
const
|
|
3077
|
-
if (
|
|
3306
|
+
const key2 = store.key(i);
|
|
3307
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
3078
3308
|
}
|
|
3079
3309
|
} catch {
|
|
3080
3310
|
return null;
|
|
3081
3311
|
}
|
|
3082
3312
|
let adopted = null;
|
|
3083
|
-
for (const
|
|
3313
|
+
for (const key2 of legacyKeys) {
|
|
3084
3314
|
if (!adopted) {
|
|
3085
3315
|
try {
|
|
3086
|
-
adopted = JSON.parse(store.getItem(
|
|
3316
|
+
adopted = JSON.parse(store.getItem(key2) ?? "");
|
|
3087
3317
|
} catch {
|
|
3088
3318
|
}
|
|
3089
3319
|
}
|
|
3090
3320
|
try {
|
|
3091
|
-
store.removeItem(
|
|
3321
|
+
store.removeItem(key2);
|
|
3092
3322
|
} catch {
|
|
3093
3323
|
}
|
|
3094
3324
|
}
|
|
@@ -3096,11 +3326,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3096
3326
|
};
|
|
3097
3327
|
var readSiwxSession = (address, chainId) => {
|
|
3098
3328
|
if (typeof window === "undefined") return null;
|
|
3099
|
-
const
|
|
3329
|
+
const key2 = buildKey2(address);
|
|
3100
3330
|
const store = storage2();
|
|
3101
3331
|
let raw = null;
|
|
3102
3332
|
try {
|
|
3103
|
-
raw = store?.getItem(
|
|
3333
|
+
raw = store?.getItem(key2) ?? null;
|
|
3104
3334
|
} catch {
|
|
3105
3335
|
raw = null;
|
|
3106
3336
|
}
|
|
@@ -3108,9 +3338,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3108
3338
|
try {
|
|
3109
3339
|
return JSON.parse(raw);
|
|
3110
3340
|
} catch {
|
|
3111
|
-
memorySiwxSessions.delete(
|
|
3341
|
+
memorySiwxSessions.delete(key2);
|
|
3112
3342
|
try {
|
|
3113
|
-
store?.removeItem(
|
|
3343
|
+
store?.removeItem(key2);
|
|
3114
3344
|
} catch {
|
|
3115
3345
|
}
|
|
3116
3346
|
return null;
|
|
@@ -3121,24 +3351,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3121
3351
|
writeSiwxSession(address, chainId, legacy);
|
|
3122
3352
|
return legacy;
|
|
3123
3353
|
}
|
|
3124
|
-
return memorySiwxSessions.get(
|
|
3354
|
+
return memorySiwxSessions.get(key2) ?? null;
|
|
3125
3355
|
};
|
|
3126
3356
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
3127
3357
|
if (typeof window === "undefined") return;
|
|
3128
|
-
const
|
|
3129
|
-
memorySiwxSessions.set(
|
|
3358
|
+
const key2 = buildKey2(address);
|
|
3359
|
+
memorySiwxSessions.set(key2, session);
|
|
3130
3360
|
const store = storage2();
|
|
3131
3361
|
try {
|
|
3132
|
-
store?.setItem(
|
|
3362
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
3133
3363
|
} catch {
|
|
3134
3364
|
}
|
|
3135
3365
|
};
|
|
3136
3366
|
var clearSiwxSession = (address, _chainId) => {
|
|
3137
|
-
const
|
|
3138
|
-
memorySiwxSessions.delete(
|
|
3367
|
+
const key2 = buildKey2(address);
|
|
3368
|
+
memorySiwxSessions.delete(key2);
|
|
3139
3369
|
const store = storage2();
|
|
3140
3370
|
try {
|
|
3141
|
-
store?.removeItem(
|
|
3371
|
+
store?.removeItem(key2);
|
|
3142
3372
|
} catch {
|
|
3143
3373
|
}
|
|
3144
3374
|
readLegacySiwxSession(store, address);
|