@owney/sdk 0.6.9-beta.7 → 0.7.0-beta.1
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 +1 -1
- package/dist/index.cjs +243 -1292
- package/dist/index.d.cts +3 -138
- package/dist/index.d.ts +3 -138
- package/dist/index.js +214 -634
- package/package.json +3 -5
- package/dist/chunk-PWIKIQOX.js +0 -140
- package/dist/surfliquid.agent-JOJJ3C5Y.js +0 -448
package/dist/index.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AgentChainIncompatibleError,
|
|
3
|
-
AgentNotFoundError,
|
|
4
|
-
ERC20_ALLOWANCE_ABI,
|
|
5
|
-
MAX_UINT256,
|
|
6
|
-
NotConnectedError,
|
|
7
|
-
OwneyError,
|
|
8
|
-
PERMIT2_ADDRESS,
|
|
9
|
-
buildPermitTransferFromTypedData,
|
|
10
|
-
randomPermit2Nonce,
|
|
11
|
-
readErc20Balance,
|
|
12
|
-
readPermit2Allowance
|
|
13
|
-
} from "./chunk-PWIKIQOX.js";
|
|
14
|
-
|
|
15
1
|
// src/agents/zyfai/zyfai.agent.ts
|
|
16
2
|
import { ZyfaiSDK } from "@zyfai/sdk";
|
|
17
3
|
import { createPublicClient, http } from "viem";
|
|
@@ -70,6 +56,55 @@ var SupportedAssets = [
|
|
|
70
56
|
}
|
|
71
57
|
];
|
|
72
58
|
|
|
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
|
+
|
|
73
108
|
// src/lib/utils.ts
|
|
74
109
|
var isValidChainId = (chainId) => {
|
|
75
110
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -144,46 +179,46 @@ function resolveChainId(chain) {
|
|
|
144
179
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
145
180
|
const portfolio = raw.portfolio;
|
|
146
181
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
147
|
-
const rawPositions = portfolio.positions ?? [];
|
|
148
|
-
const detailByKey = /* @__PURE__ */ new Map();
|
|
149
|
-
for (const p of rawPositions) {
|
|
150
|
-
const cid = resolveChainId(p.chain ?? "");
|
|
151
|
-
const symbol = (p.token_symbol ?? "").toUpperCase();
|
|
152
|
-
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
153
|
-
}
|
|
154
182
|
let totalBalance = 0;
|
|
155
183
|
const tokens = [];
|
|
156
|
-
const positions = [];
|
|
157
184
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
158
185
|
const positionChainId = Number(chainIdKey);
|
|
159
|
-
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
160
186
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
161
187
|
tokensBySymbol ?? {}
|
|
162
188
|
)) {
|
|
163
|
-
const amount = hexToDecimal(balance || "0",
|
|
189
|
+
const amount = hexToDecimal(balance || "0", decimals);
|
|
164
190
|
totalBalance += amount;
|
|
165
191
|
tokens.push({
|
|
166
|
-
chain:
|
|
192
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
167
193
|
chainId: positionChainId,
|
|
168
194
|
asset: symbol,
|
|
169
195
|
amount: String(amount)
|
|
170
196
|
});
|
|
171
|
-
const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
|
|
172
|
-
positions.push({
|
|
173
|
-
chain: chainName,
|
|
174
|
-
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
175
|
-
protocolId: detail?.protocol_id,
|
|
176
|
-
pool: detail?.pool,
|
|
177
|
-
asset: symbol,
|
|
178
|
-
amount: String(amount),
|
|
179
|
-
apy: detail?.pool_apy,
|
|
180
|
-
tvl: detail?.pool_tvl,
|
|
181
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
182
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
183
|
-
liquidity: detail?.liquidity
|
|
184
|
-
});
|
|
185
197
|
}
|
|
186
198
|
}
|
|
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
|
+
}));
|
|
187
222
|
return {
|
|
188
223
|
smartWallet,
|
|
189
224
|
totalBalance: String(totalBalance),
|
|
@@ -345,9 +380,7 @@ function mapUserProfile(raw, userAddress) {
|
|
|
345
380
|
chains: raw.chains || [],
|
|
346
381
|
strategy: raw.strategy,
|
|
347
382
|
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
348
|
-
protocols: raw.protocols || []
|
|
349
|
-
splitting: raw.splitting,
|
|
350
|
-
minSplits: raw.minSplits
|
|
383
|
+
protocols: raw.protocols || []
|
|
351
384
|
};
|
|
352
385
|
}
|
|
353
386
|
function mapApyByStrategy(raw) {
|
|
@@ -494,23 +527,23 @@ var readLegacySession = (store, address) => {
|
|
|
494
527
|
const legacyKeys = [];
|
|
495
528
|
try {
|
|
496
529
|
for (let i = 0; i < store.length; i++) {
|
|
497
|
-
const
|
|
498
|
-
if (
|
|
530
|
+
const key = store.key(i);
|
|
531
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
499
532
|
}
|
|
500
533
|
} catch {
|
|
501
534
|
return null;
|
|
502
535
|
}
|
|
503
536
|
let adopted = null;
|
|
504
|
-
for (const
|
|
537
|
+
for (const key of legacyKeys) {
|
|
505
538
|
if (!adopted) {
|
|
506
539
|
try {
|
|
507
|
-
const parsed = JSON.parse(store.getItem(
|
|
540
|
+
const parsed = JSON.parse(store.getItem(key) ?? "");
|
|
508
541
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
509
542
|
} catch {
|
|
510
543
|
}
|
|
511
544
|
}
|
|
512
545
|
try {
|
|
513
|
-
store.removeItem(
|
|
546
|
+
store.removeItem(key);
|
|
514
547
|
} catch {
|
|
515
548
|
}
|
|
516
549
|
}
|
|
@@ -518,11 +551,11 @@ var readLegacySession = (store, address) => {
|
|
|
518
551
|
};
|
|
519
552
|
var readSession = (address, _chainId) => {
|
|
520
553
|
if (typeof window === "undefined") return null;
|
|
521
|
-
const
|
|
554
|
+
const key = buildKey(address);
|
|
522
555
|
const store = storage();
|
|
523
556
|
let raw = null;
|
|
524
557
|
try {
|
|
525
|
-
raw = store?.getItem(
|
|
558
|
+
raw = store?.getItem(key) ?? null;
|
|
526
559
|
} catch {
|
|
527
560
|
raw = null;
|
|
528
561
|
}
|
|
@@ -532,9 +565,9 @@ var readSession = (address, _chainId) => {
|
|
|
532
565
|
if (isFreshSession(parsed)) return parsed;
|
|
533
566
|
} catch {
|
|
534
567
|
}
|
|
535
|
-
memorySessions.delete(
|
|
568
|
+
memorySessions.delete(key);
|
|
536
569
|
try {
|
|
537
|
-
store?.removeItem(
|
|
570
|
+
store?.removeItem(key);
|
|
538
571
|
} catch {
|
|
539
572
|
}
|
|
540
573
|
return null;
|
|
@@ -544,27 +577,27 @@ var readSession = (address, _chainId) => {
|
|
|
544
577
|
writeSession(address, _chainId, legacy);
|
|
545
578
|
return legacy;
|
|
546
579
|
}
|
|
547
|
-
const cached = memorySessions.get(
|
|
580
|
+
const cached = memorySessions.get(key);
|
|
548
581
|
if (isFreshSession(cached)) return cached;
|
|
549
|
-
if (cached) memorySessions.delete(
|
|
582
|
+
if (cached) memorySessions.delete(key);
|
|
550
583
|
return null;
|
|
551
584
|
};
|
|
552
585
|
var writeSession = (address, _chainId, session) => {
|
|
553
586
|
if (typeof window === "undefined") return;
|
|
554
|
-
const
|
|
555
|
-
memorySessions.set(
|
|
587
|
+
const key = buildKey(address);
|
|
588
|
+
memorySessions.set(key, session);
|
|
556
589
|
const store = storage();
|
|
557
590
|
try {
|
|
558
|
-
store?.setItem(
|
|
591
|
+
store?.setItem(key, JSON.stringify(session));
|
|
559
592
|
} catch {
|
|
560
593
|
}
|
|
561
594
|
};
|
|
562
595
|
var clearSession = (address, _chainId) => {
|
|
563
|
-
const
|
|
564
|
-
memorySessions.delete(
|
|
596
|
+
const key = buildKey(address);
|
|
597
|
+
memorySessions.delete(key);
|
|
565
598
|
const store = storage();
|
|
566
599
|
try {
|
|
567
|
-
store?.removeItem(
|
|
600
|
+
store?.removeItem(key);
|
|
568
601
|
} catch {
|
|
569
602
|
}
|
|
570
603
|
readLegacySession(store, address);
|
|
@@ -595,149 +628,6 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
595
628
|
};
|
|
596
629
|
}
|
|
597
630
|
|
|
598
|
-
// src/agents/zyfai/splitting.ts
|
|
599
|
-
var MAX_MIN_SPLITS = 4;
|
|
600
|
-
var MIN_FORCE_SPLITS = 2;
|
|
601
|
-
var AUTOMATIC_MIN_SPLITS = 1;
|
|
602
|
-
function toZyfaiSplitting(policy) {
|
|
603
|
-
switch (policy.splittingMode) {
|
|
604
|
-
case "none":
|
|
605
|
-
return { splitting: false };
|
|
606
|
-
case "automatic":
|
|
607
|
-
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
608
|
-
case "force":
|
|
609
|
-
return {
|
|
610
|
-
splitting: true,
|
|
611
|
-
minSplits: clampForceSplits(policy.minSplits)
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
function clampForceSplits(minSplits) {
|
|
616
|
-
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
617
|
-
return MIN_FORCE_SPLITS;
|
|
618
|
-
}
|
|
619
|
-
const rounded = Math.round(minSplits);
|
|
620
|
-
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
621
|
-
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
622
|
-
return rounded;
|
|
623
|
-
}
|
|
624
|
-
function splittingNeedsUpdate(current, desired) {
|
|
625
|
-
if (!current) return true;
|
|
626
|
-
if (current.splitting !== desired.splitting) return true;
|
|
627
|
-
if (desired.minSplits === void 0) return false;
|
|
628
|
-
return current.minSplits !== desired.minSplits;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// src/agents/zyfai/pool-policy.ts
|
|
632
|
-
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
633
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
634
|
-
for (const selection of policy.selections) {
|
|
635
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
636
|
-
}
|
|
637
|
-
const customizations = [];
|
|
638
|
-
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
639
|
-
const available = availableByProtocol.get(protocolId);
|
|
640
|
-
if (available === void 0) {
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
const availableSet = new Set(available);
|
|
644
|
-
for (const chainId of chainIds) {
|
|
645
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
646
|
-
if (stored === void 0) {
|
|
647
|
-
customizations.push({
|
|
648
|
-
protocolId,
|
|
649
|
-
chainId,
|
|
650
|
-
pools: [],
|
|
651
|
-
autoselect: true
|
|
652
|
-
});
|
|
653
|
-
continue;
|
|
654
|
-
}
|
|
655
|
-
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
656
|
-
customizations.push({
|
|
657
|
-
protocolId,
|
|
658
|
-
chainId,
|
|
659
|
-
pools,
|
|
660
|
-
autoselect: false
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
return customizations;
|
|
665
|
-
}
|
|
666
|
-
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
667
|
-
if (policy.selections.length === 0) {
|
|
668
|
-
return null;
|
|
669
|
-
}
|
|
670
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
671
|
-
for (const selection of policy.selections) {
|
|
672
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
673
|
-
}
|
|
674
|
-
return universe.filter((protocolId) => {
|
|
675
|
-
const chainIds = chainsByProtocol[protocolId];
|
|
676
|
-
if (chainIds === void 0 || chainIds.length === 0) {
|
|
677
|
-
return true;
|
|
678
|
-
}
|
|
679
|
-
const fullyDisabled = chainIds.every((chainId) => {
|
|
680
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
681
|
-
return stored !== void 0 && stored.pools.length === 0;
|
|
682
|
-
});
|
|
683
|
-
return !fullyDisabled;
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
function key(protocolId, chainId) {
|
|
687
|
-
return `${protocolId}:${chainId}`;
|
|
688
|
-
}
|
|
689
|
-
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
690
|
-
const allowed = new Set(dashboardChainIds);
|
|
691
|
-
const result = {};
|
|
692
|
-
for (const protocol of protocols) {
|
|
693
|
-
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
694
|
-
(chainId) => allowed.has(chainId)
|
|
695
|
-
);
|
|
696
|
-
}
|
|
697
|
-
return result;
|
|
698
|
-
}
|
|
699
|
-
function flattenAvailablePools(raw) {
|
|
700
|
-
const byChain = raw ?? {};
|
|
701
|
-
const names = [];
|
|
702
|
-
for (const byToken of Object.values(byChain ?? {})) {
|
|
703
|
-
for (const entry of Object.values(byToken ?? {})) {
|
|
704
|
-
for (const pool of entry?.pools ?? []) {
|
|
705
|
-
if (pool?.name) names.push(pool.name);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
return names;
|
|
710
|
-
}
|
|
711
|
-
function protocolListsEqual(a, b) {
|
|
712
|
-
const left = [...a ?? []].sort();
|
|
713
|
-
const right = [...b ?? []].sort();
|
|
714
|
-
if (left.length !== right.length) return false;
|
|
715
|
-
return left.every((value, index) => value === right[index]);
|
|
716
|
-
}
|
|
717
|
-
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
718
|
-
if (!current) return true;
|
|
719
|
-
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
720
|
-
if (desiredProtocols === null) return false;
|
|
721
|
-
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// src/lib/debug.ts
|
|
725
|
-
var configuredDebug = false;
|
|
726
|
-
function setOwneyDebug(enabled) {
|
|
727
|
-
configuredDebug = enabled;
|
|
728
|
-
}
|
|
729
|
-
function isOwneyDebug() {
|
|
730
|
-
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
731
|
-
}
|
|
732
|
-
function debugLog(scope, message, data) {
|
|
733
|
-
if (!isOwneyDebug()) return;
|
|
734
|
-
if (data === void 0) {
|
|
735
|
-
console.log(`[${scope}] ${message}`);
|
|
736
|
-
} else {
|
|
737
|
-
console.log(`[${scope}] ${message}`, data);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
|
|
741
631
|
// src/agents/zyfai/zyfai.agent.ts
|
|
742
632
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
743
633
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -750,12 +640,6 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
750
640
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
751
641
|
};
|
|
752
642
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
753
|
-
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
754
|
-
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
755
|
-
function isAlreadyActiveSessionKeyError(error) {
|
|
756
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
757
|
-
return /already has an active session key/i.test(message);
|
|
758
|
-
}
|
|
759
643
|
var ZyfaiAgent = class {
|
|
760
644
|
id = "zyfai";
|
|
761
645
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -982,71 +866,21 @@ var ZyfaiAgent = class {
|
|
|
982
866
|
return await this.sdk.connectAccount(provider, chainId);
|
|
983
867
|
}
|
|
984
868
|
}
|
|
985
|
-
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
986
|
-
async connectFull(state, chainId) {
|
|
987
|
-
await this.connectAuth(state, chainId);
|
|
988
|
-
const validChainId = isValidChainId(chainId);
|
|
989
|
-
const address = this.getAddress();
|
|
990
|
-
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
991
|
-
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
992
|
-
if (!wallet.isDeployed) {
|
|
993
|
-
await this.sdk.deploySafe(address, validChainId, "aggressive", false);
|
|
994
|
-
try {
|
|
995
|
-
if (validChainId === 42161) {
|
|
996
|
-
await this.sdk.updateUserProfile({
|
|
997
|
-
asset: "WETH",
|
|
998
|
-
chains: [validChainId],
|
|
999
|
-
protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
|
|
1000
|
-
// AAVE protocol ID
|
|
1001
|
-
autoSelectProtocols: false
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
} catch (err) {
|
|
1005
|
-
console.warn(
|
|
1006
|
-
"Failed to configure AAVE protocol after Safe deployment:",
|
|
1007
|
-
err instanceof Error ? err.message : String(err)
|
|
1008
|
-
);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
await this.ensureSessionKey(state, address, validChainId);
|
|
1012
|
-
}
|
|
1013
869
|
/**
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
1018
|
-
*
|
|
1019
|
-
*
|
|
1020
|
-
* to (re)create a key per chain — that 400s and blocks the deposit. We only
|
|
1021
|
-
* create when the user has none.
|
|
1022
|
-
*
|
|
1023
|
-
* The one wrapper-side hardening that IS needed: a chain/account switch can
|
|
1024
|
-
* fire the provider's `accountsChanged` → `disconnectAccount`, tearing down
|
|
1025
|
-
* the zyfai connection (walletClient + authenticatedUserId both null) while
|
|
1026
|
-
* our own `connectAuth` guard still believes this chain is connected and
|
|
1027
|
-
* early-returns without reconnecting. `createSessionKey` then fails with
|
|
1028
|
-
* "No account connected". Detect that and reconnect first.
|
|
1029
|
-
*
|
|
1030
|
-
* NOTE: whether a globally-active session key actually authorizes activity on
|
|
1031
|
-
* a freshly-deployed Safe on a new chain is a backend/zyf question — the
|
|
1032
|
-
* wrapper cannot force per-chain activation given the global 400 guard.
|
|
1033
|
-
* See [[zyfai-per-chain-session-key]].
|
|
870
|
+
* Reconnect if the Zyfai connection was torn down behind our back: a
|
|
871
|
+
* chain/account switch fires the provider's `accountsChanged` →
|
|
872
|
+
* `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
|
|
873
|
+
* own `connectAuth` guard still believes this chain is connected and
|
|
874
|
+
* early-returns. Without this, authenticated calls (depositFunds,
|
|
875
|
+
* withdrawFunds) fail with "No account connected".
|
|
1034
876
|
*/
|
|
1035
|
-
async
|
|
877
|
+
async ensureConnected(state, chainId) {
|
|
878
|
+
await this.connectAuth(state, chainId);
|
|
1036
879
|
const internals = this.sdk;
|
|
1037
880
|
if (!internals.walletClient || internals.authenticatedUserId === null) {
|
|
1038
881
|
this.connectedChainId = null;
|
|
1039
882
|
await this.connectAuth(state, chainId);
|
|
1040
883
|
}
|
|
1041
|
-
const user = await this.sdk.getUserDetails();
|
|
1042
|
-
if (!user.hasActiveSessionKey) {
|
|
1043
|
-
try {
|
|
1044
|
-
await this.sdk.createSessionKey(address, chainId);
|
|
1045
|
-
} catch (error) {
|
|
1046
|
-
if (!isAlreadyActiveSessionKeyError(error)) throw error;
|
|
1047
|
-
internals.hasActiveSessionKey = true;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
884
|
}
|
|
1051
885
|
/**
|
|
1052
886
|
* Sync newly-available protocols onto an existing user's profile at wallet
|
|
@@ -1116,180 +950,10 @@ var ZyfaiAgent = class {
|
|
|
1116
950
|
throw error;
|
|
1117
951
|
}
|
|
1118
952
|
}
|
|
1119
|
-
/**
|
|
1120
|
-
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1121
|
-
*
|
|
1122
|
-
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1123
|
-
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1124
|
-
* WETH holder's real setting untouched.
|
|
1125
|
-
*
|
|
1126
|
-
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1127
|
-
* must leave the user connected with their profile unchanged, never fail
|
|
1128
|
-
* activation.
|
|
1129
|
-
*/
|
|
1130
|
-
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1131
|
-
debugLog("zyfai:splitting", "applying org policy", {
|
|
1132
|
-
policy,
|
|
1133
|
-
// Per asset because Zyfai stores splitting under assetTypeSettings[asset].
|
|
1134
|
-
assets: SPLITTING_ASSETS
|
|
1135
|
-
});
|
|
1136
|
-
await Promise.all(
|
|
1137
|
-
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1138
|
-
);
|
|
1139
|
-
if (policy.poolPolicy) {
|
|
1140
|
-
await this.applyPoolPolicy(policy.poolPolicy);
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
async applySplitting(asset, policy) {
|
|
1144
|
-
try {
|
|
1145
|
-
const desired = toZyfaiSplitting(policy);
|
|
1146
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1147
|
-
const currentSplitting = {
|
|
1148
|
-
splitting: current?.splitting,
|
|
1149
|
-
minSplits: current?.minSplits
|
|
1150
|
-
};
|
|
1151
|
-
const needsUpdate = splittingNeedsUpdate(current, desired);
|
|
1152
|
-
debugLog("zyfai:splitting", `${asset}: comparing`, {
|
|
1153
|
-
mode: policy.splittingMode,
|
|
1154
|
-
current: currentSplitting,
|
|
1155
|
-
desired,
|
|
1156
|
-
// Spelled out because the "why" is the non-obvious part: minSplits is
|
|
1157
|
-
// what separates automatic (1) from force (2-4), not `splitting`.
|
|
1158
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1159
|
-
});
|
|
1160
|
-
if (!needsUpdate) return;
|
|
1161
|
-
const result = await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1162
|
-
debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
|
|
1163
|
-
sent: { asset, ...desired },
|
|
1164
|
-
// updateUserProfile re-reads the profile after PATCHing, so this is
|
|
1165
|
-
// Zyfai's own view of the result rather than an echo of what we sent.
|
|
1166
|
-
zyfaiNowReports: {
|
|
1167
|
-
splitting: result?.splitting,
|
|
1168
|
-
minSplits: result?.minSplits
|
|
1169
|
-
}
|
|
1170
|
-
});
|
|
1171
|
-
} catch (error) {
|
|
1172
|
-
console.warn(
|
|
1173
|
-
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1174
|
-
error instanceof Error ? error.message : String(error)
|
|
1175
|
-
);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
/**
|
|
1179
|
-
* Apply the org's protocol/pool policy to this user's Zyfai profile.
|
|
1180
|
-
*
|
|
1181
|
-
* Two Zyfai writes, in a strict order:
|
|
1182
|
-
* 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
|
|
1183
|
-
* the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
|
|
1184
|
-
* 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
|
|
1185
|
-
* pool narrowing.
|
|
1186
|
-
*
|
|
1187
|
-
* Order matters: constraining a protocol's pools (step 2) while that
|
|
1188
|
-
* protocol is not yet in the allow-list (step 1 not yet applied) lands the
|
|
1189
|
-
* constraint on something the rebalance engine isn't considering.
|
|
1190
|
-
*
|
|
1191
|
-
* Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
|
|
1192
|
-
* connecting, so a Zyfai hiccup must leave the user connected with their
|
|
1193
|
-
* profile unchanged, never fail activation.
|
|
1194
|
-
*/
|
|
1195
|
-
async applyPoolPolicy(policy) {
|
|
1196
|
-
try {
|
|
1197
|
-
const { protocols: universe } = await this.sdk.getAvailableProtocols(
|
|
1198
|
-
this.supportedChainIds[0]
|
|
1199
|
-
);
|
|
1200
|
-
const universeIds = universe.map((p) => p.id);
|
|
1201
|
-
const chainsByProtocol = buildChainsByProtocol(
|
|
1202
|
-
universe,
|
|
1203
|
-
POOL_POLICY_CHAIN_IDS
|
|
1204
|
-
);
|
|
1205
|
-
debugLog("zyfai:pools", "protocol universe", {
|
|
1206
|
-
universeIds,
|
|
1207
|
-
chainsByProtocol
|
|
1208
|
-
});
|
|
1209
|
-
let strategy;
|
|
1210
|
-
const desiredProtocols = deriveProtocols(
|
|
1211
|
-
policy,
|
|
1212
|
-
universeIds,
|
|
1213
|
-
chainsByProtocol
|
|
1214
|
-
);
|
|
1215
|
-
const desiredAutoSelect = policy.autoApproveProtocols;
|
|
1216
|
-
for (const asset of SPLITTING_ASSETS) {
|
|
1217
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1218
|
-
if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
|
|
1219
|
-
strategy = current.strategy;
|
|
1220
|
-
}
|
|
1221
|
-
const needsUpdate = protocolsPolicyNeedsUpdate(
|
|
1222
|
-
current,
|
|
1223
|
-
desiredProtocols,
|
|
1224
|
-
desiredAutoSelect
|
|
1225
|
-
);
|
|
1226
|
-
debugLog("zyfai:pools", `${asset}: comparing protocols`, {
|
|
1227
|
-
current: {
|
|
1228
|
-
protocols: current.protocols,
|
|
1229
|
-
autoSelectProtocols: current.autoSelectProtocols
|
|
1230
|
-
},
|
|
1231
|
-
desired: {
|
|
1232
|
-
protocols: desiredProtocols,
|
|
1233
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1234
|
-
},
|
|
1235
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1236
|
-
});
|
|
1237
|
-
if (!needsUpdate) continue;
|
|
1238
|
-
const update = {
|
|
1239
|
-
asset,
|
|
1240
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1241
|
-
};
|
|
1242
|
-
if (desiredProtocols !== null) update.protocols = desiredProtocols;
|
|
1243
|
-
await this.sdk.updateUserProfile(update);
|
|
1244
|
-
debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
|
|
1245
|
-
}
|
|
1246
|
-
const poolResults = await Promise.all(
|
|
1247
|
-
universe.map(async (protocol) => {
|
|
1248
|
-
try {
|
|
1249
|
-
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1250
|
-
return [protocol.id, flattenAvailablePools(raw)];
|
|
1251
|
-
} catch (error) {
|
|
1252
|
-
console.warn(
|
|
1253
|
-
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
1254
|
-
error instanceof Error ? error.message : String(error)
|
|
1255
|
-
);
|
|
1256
|
-
return null;
|
|
1257
|
-
}
|
|
1258
|
-
})
|
|
1259
|
-
);
|
|
1260
|
-
const availableByProtocol = /* @__PURE__ */ new Map();
|
|
1261
|
-
for (const result of poolResults) {
|
|
1262
|
-
if (result) availableByProtocol.set(result[0], result[1]);
|
|
1263
|
-
}
|
|
1264
|
-
const customizations = toZyfaiCustomizations(
|
|
1265
|
-
policy,
|
|
1266
|
-
availableByProtocol,
|
|
1267
|
-
chainsByProtocol
|
|
1268
|
-
);
|
|
1269
|
-
debugLog("zyfai:pools", "derived customizeBatch payload", {
|
|
1270
|
-
strategy,
|
|
1271
|
-
availableProtocolCount: availableByProtocol.size,
|
|
1272
|
-
customizations
|
|
1273
|
-
});
|
|
1274
|
-
if (customizations.length === 0) {
|
|
1275
|
-
debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
|
|
1276
|
-
return;
|
|
1277
|
-
}
|
|
1278
|
-
await this.sdk.customizeBatch(customizations);
|
|
1279
|
-
debugLog("zyfai:pools", "wrote customizeBatch", {
|
|
1280
|
-
count: customizations.length
|
|
1281
|
-
});
|
|
1282
|
-
} catch (error) {
|
|
1283
|
-
console.warn(
|
|
1284
|
-
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
1285
|
-
error instanceof Error ? error.message : String(error)
|
|
1286
|
-
);
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
953
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1290
954
|
try {
|
|
1291
|
-
await this.connectFull(state, chainId);
|
|
1292
955
|
const validChainId = isValidChainId(chainId);
|
|
956
|
+
await this.ensureConnected(state, validChainId);
|
|
1293
957
|
if (depositCallback) {
|
|
1294
958
|
const wallet = await this.sdk.getSmartWalletAddress(
|
|
1295
959
|
this.getAddress(),
|
|
@@ -1315,7 +979,8 @@ var ZyfaiAgent = class {
|
|
|
1315
979
|
this.getAddress(),
|
|
1316
980
|
validChainId,
|
|
1317
981
|
amount,
|
|
1318
|
-
asset
|
|
982
|
+
asset,
|
|
983
|
+
"aggressive"
|
|
1319
984
|
);
|
|
1320
985
|
return mapDeposit(raw);
|
|
1321
986
|
} catch (error) {
|
|
@@ -1324,8 +989,8 @@ var ZyfaiAgent = class {
|
|
|
1324
989
|
}
|
|
1325
990
|
// --- IAgent: Fund operations ---
|
|
1326
991
|
async withdraw(state, chainId, token, amount) {
|
|
1327
|
-
await this.connectFull(state, chainId);
|
|
1328
992
|
const validChainId = isValidChainId(chainId);
|
|
993
|
+
await this.ensureConnected(state, validChainId);
|
|
1329
994
|
const raw = await this.sdk.withdrawFunds(
|
|
1330
995
|
this.getAddress(),
|
|
1331
996
|
validChainId,
|
|
@@ -1404,19 +1069,7 @@ var ZyfaiAgent = class {
|
|
|
1404
1069
|
}
|
|
1405
1070
|
async getUserProfile(state, chainId) {
|
|
1406
1071
|
await this.connectAuth(state, chainId);
|
|
1407
|
-
const validChainId = isValidChainId(chainId);
|
|
1408
1072
|
const raw = await this.sdk.getUserDetails();
|
|
1409
|
-
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1410
|
-
asset: "USDC (default \u2014 no asset passed)",
|
|
1411
|
-
splitting: raw.splitting,
|
|
1412
|
-
minSplits: raw.minSplits,
|
|
1413
|
-
strategy: raw.strategy,
|
|
1414
|
-
chains: raw.chains,
|
|
1415
|
-
protocolCount: raw.protocols?.length,
|
|
1416
|
-
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
1417
|
-
smartWallet: raw.smartWallet
|
|
1418
|
-
});
|
|
1419
|
-
await this.ensureSessionKey(state, this.getAddress(), validChainId);
|
|
1420
1073
|
return mapUserProfile(raw, this.connectedAddress);
|
|
1421
1074
|
}
|
|
1422
1075
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
@@ -1449,40 +1102,6 @@ var ZyfaiAgent = class {
|
|
|
1449
1102
|
|
|
1450
1103
|
// src/lib/routing-api.ts
|
|
1451
1104
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1452
|
-
async function fetchOrgAgentConfig(apiKey) {
|
|
1453
|
-
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1454
|
-
try {
|
|
1455
|
-
const res = await fetch(url, {
|
|
1456
|
-
method: "GET",
|
|
1457
|
-
headers: {
|
|
1458
|
-
"Content-Type": "application/json",
|
|
1459
|
-
"x-owney-api-key": `${apiKey}`
|
|
1460
|
-
}
|
|
1461
|
-
});
|
|
1462
|
-
if (!res.ok) {
|
|
1463
|
-
if (res.status !== 404) {
|
|
1464
|
-
console.warn(
|
|
1465
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1466
|
-
);
|
|
1467
|
-
}
|
|
1468
|
-
return null;
|
|
1469
|
-
}
|
|
1470
|
-
const json = await res.json();
|
|
1471
|
-
const policy = json.success ? json.data ?? null : null;
|
|
1472
|
-
debugLog(
|
|
1473
|
-
"owney-sdk",
|
|
1474
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
1475
|
-
policy ?? void 0
|
|
1476
|
-
);
|
|
1477
|
-
return policy;
|
|
1478
|
-
} catch (error) {
|
|
1479
|
-
console.warn(
|
|
1480
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1481
|
-
error instanceof Error ? error.message : String(error)
|
|
1482
|
-
);
|
|
1483
|
-
return null;
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
1105
|
async function fetchAgentKeys(apiKey) {
|
|
1487
1106
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1488
1107
|
const res = await fetch(url, {
|
|
@@ -1821,6 +1440,84 @@ async function getSponsorRelayerAddress(input) {
|
|
|
1821
1440
|
return parsed.data.relayer;
|
|
1822
1441
|
}
|
|
1823
1442
|
|
|
1443
|
+
// src/lib/permit2.ts
|
|
1444
|
+
import { bytesToHex as bytesToHex2 } from "viem";
|
|
1445
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
1446
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
1447
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
1448
|
+
{
|
|
1449
|
+
type: "function",
|
|
1450
|
+
name: "allowance",
|
|
1451
|
+
stateMutability: "view",
|
|
1452
|
+
inputs: [
|
|
1453
|
+
{ name: "owner", type: "address" },
|
|
1454
|
+
{ name: "spender", type: "address" }
|
|
1455
|
+
],
|
|
1456
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
type: "function",
|
|
1460
|
+
name: "approve",
|
|
1461
|
+
stateMutability: "nonpayable",
|
|
1462
|
+
inputs: [
|
|
1463
|
+
{ name: "spender", type: "address" },
|
|
1464
|
+
{ name: "amount", type: "uint256" }
|
|
1465
|
+
],
|
|
1466
|
+
outputs: [{ name: "", type: "bool" }]
|
|
1467
|
+
},
|
|
1468
|
+
{
|
|
1469
|
+
type: "function",
|
|
1470
|
+
name: "balanceOf",
|
|
1471
|
+
stateMutability: "view",
|
|
1472
|
+
inputs: [{ name: "account", type: "address" }],
|
|
1473
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1474
|
+
}
|
|
1475
|
+
];
|
|
1476
|
+
function buildPermitTransferFromTypedData(input) {
|
|
1477
|
+
return {
|
|
1478
|
+
domain: {
|
|
1479
|
+
name: "Permit2",
|
|
1480
|
+
chainId: input.chainId,
|
|
1481
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
1482
|
+
},
|
|
1483
|
+
types: {
|
|
1484
|
+
PermitTransferFrom: [
|
|
1485
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
1486
|
+
{ name: "spender", type: "address" },
|
|
1487
|
+
{ name: "nonce", type: "uint256" },
|
|
1488
|
+
{ name: "deadline", type: "uint256" }
|
|
1489
|
+
],
|
|
1490
|
+
TokenPermissions: [
|
|
1491
|
+
{ name: "token", type: "address" },
|
|
1492
|
+
{ name: "amount", type: "uint256" }
|
|
1493
|
+
]
|
|
1494
|
+
},
|
|
1495
|
+
primaryType: "PermitTransferFrom",
|
|
1496
|
+
message: input.message
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function randomPermit2Nonce() {
|
|
1500
|
+
const bytes = new Uint8Array(32);
|
|
1501
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1502
|
+
return BigInt(bytesToHex2(bytes));
|
|
1503
|
+
}
|
|
1504
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
1505
|
+
return publicClient.readContract({
|
|
1506
|
+
address: token,
|
|
1507
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1508
|
+
functionName: "allowance",
|
|
1509
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
1513
|
+
return publicClient.readContract({
|
|
1514
|
+
address: token,
|
|
1515
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1516
|
+
functionName: "balanceOf",
|
|
1517
|
+
args: [owner]
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1824
1521
|
// src/lib/sponsored-deposit.ts
|
|
1825
1522
|
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
1826
1523
|
function makeSponsoredDepositCallback(deps) {
|
|
@@ -2003,7 +1700,6 @@ var VIEM_CHAIN2 = {
|
|
|
2003
1700
|
42161: arbitrum2,
|
|
2004
1701
|
1: mainnet2
|
|
2005
1702
|
};
|
|
2006
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2007
1703
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2008
1704
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2009
1705
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2023,26 +1719,17 @@ var OwneySDK = class {
|
|
|
2023
1719
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
2024
1720
|
state = null;
|
|
2025
1721
|
apiKey;
|
|
2026
|
-
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
2027
|
-
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
2028
|
-
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
2029
|
-
// leave every user's agent profile alone.
|
|
2030
|
-
orgAgentConfig;
|
|
2031
|
-
orgAgentConfigPromise = null;
|
|
2032
1722
|
zyfaiRpcUrls;
|
|
2033
1723
|
routingApiBaseUrl;
|
|
2034
1724
|
referralSource;
|
|
2035
|
-
surfliquidApiBaseUrl;
|
|
2036
1725
|
cachedSponsoredCallback = null;
|
|
2037
1726
|
cachedWethSponsoredCallback = null;
|
|
2038
1727
|
initializingAgentsPromise = null;
|
|
2039
1728
|
constructor(config) {
|
|
2040
1729
|
this.apiKey = config.apiKey;
|
|
2041
|
-
if (config.debug) setOwneyDebug(true);
|
|
2042
1730
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2043
1731
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2044
1732
|
this.referralSource = config.referralSource;
|
|
2045
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2046
1733
|
}
|
|
2047
1734
|
/**
|
|
2048
1735
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2201,57 +1888,14 @@ var OwneySDK = class {
|
|
|
2201
1888
|
}
|
|
2202
1889
|
return active;
|
|
2203
1890
|
}
|
|
2204
|
-
/**
|
|
2205
|
-
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2206
|
-
* throws — it degrades to null — so this cannot break activation.
|
|
2207
|
-
*/
|
|
2208
|
-
async getOrgAgentConfig() {
|
|
2209
|
-
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2210
|
-
if (!this.orgAgentConfigPromise) {
|
|
2211
|
-
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2212
|
-
(config) => {
|
|
2213
|
-
this.orgAgentConfig = config;
|
|
2214
|
-
return config;
|
|
2215
|
-
}
|
|
2216
|
-
);
|
|
2217
|
-
}
|
|
2218
|
-
return this.orgAgentConfigPromise;
|
|
2219
|
-
}
|
|
2220
|
-
/**
|
|
2221
|
-
* Apply the org policy to one agent, after it has activated.
|
|
2222
|
-
*
|
|
2223
|
-
* Sequenced after activation rather than alongside it because applying the
|
|
2224
|
-
* policy needs the authenticated session activation establishes. Every failure
|
|
2225
|
-
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2226
|
-
* user's connect over.
|
|
2227
|
-
*/
|
|
2228
|
-
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2229
|
-
if (!agent.applyOrgPolicy) {
|
|
2230
|
-
debugLog(
|
|
2231
|
-
"owney-sdk",
|
|
2232
|
-
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2233
|
-
);
|
|
2234
|
-
return;
|
|
2235
|
-
}
|
|
2236
|
-
try {
|
|
2237
|
-
const policy = await this.getOrgAgentConfig();
|
|
2238
|
-
if (!policy) return;
|
|
2239
|
-
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2240
|
-
} catch (error) {
|
|
2241
|
-
console.warn(
|
|
2242
|
-
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2243
|
-
error instanceof Error ? error.message : String(error)
|
|
2244
|
-
);
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
1891
|
async ensureAgentsInitialized() {
|
|
2248
1892
|
if (this.agents.size > 0) return;
|
|
2249
1893
|
if (!this.initializingAgentsPromise) {
|
|
2250
1894
|
this.initializingAgentsPromise = (async () => {
|
|
2251
1895
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2252
1896
|
this.disabledAgents.clear();
|
|
2253
|
-
for (const { key
|
|
2254
|
-
const agent =
|
|
1897
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
1898
|
+
const agent = this.createAgent(agent_type, key);
|
|
2255
1899
|
if (!agent) continue;
|
|
2256
1900
|
this.agents.set(agent_type, agent);
|
|
2257
1901
|
if (is_enabled === false) {
|
|
@@ -2272,21 +1916,9 @@ var OwneySDK = class {
|
|
|
2272
1916
|
this.initializingAgentsPromise = null;
|
|
2273
1917
|
}
|
|
2274
1918
|
}
|
|
2275
|
-
|
|
1919
|
+
createAgent(agentId, key) {
|
|
2276
1920
|
if (agentId === "zyfai") {
|
|
2277
|
-
return new ZyfaiAgent(
|
|
2278
|
-
}
|
|
2279
|
-
if (agentId === "surfliquid") {
|
|
2280
|
-
if (!projectName) return null;
|
|
2281
|
-
const { SurfLiquidAgent } = await import("./surfliquid.agent-JOJJ3C5Y.js");
|
|
2282
|
-
return new SurfLiquidAgent({
|
|
2283
|
-
projectName,
|
|
2284
|
-
appId: key2,
|
|
2285
|
-
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2286
|
-
// which WebKit (iOS) discards when it is third-party. See
|
|
2287
|
-
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2288
|
-
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2289
|
-
});
|
|
1921
|
+
return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
|
|
2290
1922
|
}
|
|
2291
1923
|
return null;
|
|
2292
1924
|
}
|
|
@@ -2340,7 +1972,6 @@ var OwneySDK = class {
|
|
|
2340
1972
|
Promise.all(
|
|
2341
1973
|
agents.map(async (agent) => {
|
|
2342
1974
|
await agent.activateAgent(state, chainId);
|
|
2343
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2344
1975
|
})
|
|
2345
1976
|
).catch((error) => {
|
|
2346
1977
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2368,7 +1999,6 @@ var OwneySDK = class {
|
|
|
2368
1999
|
Promise.all(
|
|
2369
2000
|
enabledCompatible.map(async (agent) => {
|
|
2370
2001
|
await agent.activateAgent(state, chainId);
|
|
2371
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2372
2002
|
})
|
|
2373
2003
|
).catch((error) => {
|
|
2374
2004
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2442,30 +2072,18 @@ var OwneySDK = class {
|
|
|
2442
2072
|
);
|
|
2443
2073
|
}
|
|
2444
2074
|
const agentResults = {};
|
|
2445
|
-
const agentErrors = {};
|
|
2446
2075
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
depositCallback
|
|
2456
|
-
);
|
|
2457
|
-
} catch (error) {
|
|
2458
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
2459
|
-
}
|
|
2460
|
-
}
|
|
2461
|
-
if (Object.keys(agentResults).length === 0) {
|
|
2462
|
-
throw new OwneyError(
|
|
2463
|
-
"DEPOSIT_ALL_FAILED",
|
|
2464
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
2465
|
-
{ agentErrors }
|
|
2076
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2077
|
+
agent,
|
|
2078
|
+
state,
|
|
2079
|
+
chainId,
|
|
2080
|
+
agentAmount,
|
|
2081
|
+
asset,
|
|
2082
|
+
effectiveCallback,
|
|
2083
|
+
depositCallback
|
|
2466
2084
|
);
|
|
2467
2085
|
}
|
|
2468
|
-
return
|
|
2086
|
+
return { agentResults };
|
|
2469
2087
|
}
|
|
2470
2088
|
/**
|
|
2471
2089
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2622,34 +2240,6 @@ var OwneySDK = class {
|
|
|
2622
2240
|
}
|
|
2623
2241
|
return eligible;
|
|
2624
2242
|
}
|
|
2625
|
-
/**
|
|
2626
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
2627
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
2628
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
2629
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
2630
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
2631
|
-
*
|
|
2632
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
2633
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
2634
|
-
*/
|
|
2635
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
2636
|
-
try {
|
|
2637
|
-
await this.ensureAgentsInitialized();
|
|
2638
|
-
} catch (error) {
|
|
2639
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
2640
|
-
return [];
|
|
2641
|
-
}
|
|
2642
|
-
throw error;
|
|
2643
|
-
}
|
|
2644
|
-
return [...this.agents.values()].filter((agent) => {
|
|
2645
|
-
const chainAssets = agent.supportedAssets.find(
|
|
2646
|
-
(sa) => sa.chainId === chainId
|
|
2647
|
-
);
|
|
2648
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
2649
|
-
}).map((agent) => agent.id).sort(
|
|
2650
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
2651
|
-
);
|
|
2652
|
-
}
|
|
2653
2243
|
// --- Fund operations ---
|
|
2654
2244
|
/**
|
|
2655
2245
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2685,17 +2275,9 @@ var OwneySDK = class {
|
|
|
2685
2275
|
}
|
|
2686
2276
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2687
2277
|
if (!amount) {
|
|
2688
|
-
const aggregated2 = await this.getBalances();
|
|
2689
|
-
const funded = projectAgentBalancesForAsset(
|
|
2690
|
-
eligibleAgents,
|
|
2691
|
-
aggregated2.agentBalances,
|
|
2692
|
-
chainId,
|
|
2693
|
-
asset,
|
|
2694
|
-
assetInfo.decimals
|
|
2695
|
-
).filter((b) => b.balance > 0n);
|
|
2696
2278
|
const results2 = {};
|
|
2697
2279
|
const agentErrors2 = {};
|
|
2698
|
-
for (const
|
|
2280
|
+
for (const agent of eligibleAgents) {
|
|
2699
2281
|
try {
|
|
2700
2282
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2701
2283
|
} catch (err) {
|
|
@@ -2712,10 +2294,9 @@ var OwneySDK = class {
|
|
|
2712
2294
|
{ asset, agentErrors: agentErrors2 }
|
|
2713
2295
|
);
|
|
2714
2296
|
}
|
|
2715
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2716
2297
|
return {
|
|
2717
2298
|
agentResult: results2,
|
|
2718
|
-
totalWithdrawn:
|
|
2299
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
2719
2300
|
};
|
|
2720
2301
|
}
|
|
2721
2302
|
const requested = BigInt(amount);
|
|
@@ -3232,22 +2813,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3232
2813
|
const legacyKeys = [];
|
|
3233
2814
|
try {
|
|
3234
2815
|
for (let i = 0; i < store.length; i++) {
|
|
3235
|
-
const
|
|
3236
|
-
if (
|
|
2816
|
+
const key = store.key(i);
|
|
2817
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
3237
2818
|
}
|
|
3238
2819
|
} catch {
|
|
3239
2820
|
return null;
|
|
3240
2821
|
}
|
|
3241
2822
|
let adopted = null;
|
|
3242
|
-
for (const
|
|
2823
|
+
for (const key of legacyKeys) {
|
|
3243
2824
|
if (!adopted) {
|
|
3244
2825
|
try {
|
|
3245
|
-
adopted = JSON.parse(store.getItem(
|
|
2826
|
+
adopted = JSON.parse(store.getItem(key) ?? "");
|
|
3246
2827
|
} catch {
|
|
3247
2828
|
}
|
|
3248
2829
|
}
|
|
3249
2830
|
try {
|
|
3250
|
-
store.removeItem(
|
|
2831
|
+
store.removeItem(key);
|
|
3251
2832
|
} catch {
|
|
3252
2833
|
}
|
|
3253
2834
|
}
|
|
@@ -3255,11 +2836,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3255
2836
|
};
|
|
3256
2837
|
var readSiwxSession = (address, chainId) => {
|
|
3257
2838
|
if (typeof window === "undefined") return null;
|
|
3258
|
-
const
|
|
2839
|
+
const key = buildKey2(address);
|
|
3259
2840
|
const store = storage2();
|
|
3260
2841
|
let raw = null;
|
|
3261
2842
|
try {
|
|
3262
|
-
raw = store?.getItem(
|
|
2843
|
+
raw = store?.getItem(key) ?? null;
|
|
3263
2844
|
} catch {
|
|
3264
2845
|
raw = null;
|
|
3265
2846
|
}
|
|
@@ -3267,9 +2848,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3267
2848
|
try {
|
|
3268
2849
|
return JSON.parse(raw);
|
|
3269
2850
|
} catch {
|
|
3270
|
-
memorySiwxSessions.delete(
|
|
2851
|
+
memorySiwxSessions.delete(key);
|
|
3271
2852
|
try {
|
|
3272
|
-
store?.removeItem(
|
|
2853
|
+
store?.removeItem(key);
|
|
3273
2854
|
} catch {
|
|
3274
2855
|
}
|
|
3275
2856
|
return null;
|
|
@@ -3280,24 +2861,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3280
2861
|
writeSiwxSession(address, chainId, legacy);
|
|
3281
2862
|
return legacy;
|
|
3282
2863
|
}
|
|
3283
|
-
return memorySiwxSessions.get(
|
|
2864
|
+
return memorySiwxSessions.get(key) ?? null;
|
|
3284
2865
|
};
|
|
3285
2866
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
3286
2867
|
if (typeof window === "undefined") return;
|
|
3287
|
-
const
|
|
3288
|
-
memorySiwxSessions.set(
|
|
2868
|
+
const key = buildKey2(address);
|
|
2869
|
+
memorySiwxSessions.set(key, session);
|
|
3289
2870
|
const store = storage2();
|
|
3290
2871
|
try {
|
|
3291
|
-
store?.setItem(
|
|
2872
|
+
store?.setItem(key, JSON.stringify(session));
|
|
3292
2873
|
} catch {
|
|
3293
2874
|
}
|
|
3294
2875
|
};
|
|
3295
2876
|
var clearSiwxSession = (address, _chainId) => {
|
|
3296
|
-
const
|
|
3297
|
-
memorySiwxSessions.delete(
|
|
2877
|
+
const key = buildKey2(address);
|
|
2878
|
+
memorySiwxSessions.delete(key);
|
|
3298
2879
|
const store = storage2();
|
|
3299
2880
|
try {
|
|
3300
|
-
store?.removeItem(
|
|
2881
|
+
store?.removeItem(key);
|
|
3301
2882
|
} catch {
|
|
3302
2883
|
}
|
|
3303
2884
|
readLegacySiwxSession(store, address);
|
|
@@ -3426,6 +3007,5 @@ export {
|
|
|
3426
3007
|
NotConnectedError,
|
|
3427
3008
|
OwneyError,
|
|
3428
3009
|
OwneySDK,
|
|
3429
|
-
createOwneySIWX
|
|
3430
|
-
setOwneyDebug
|
|
3010
|
+
createOwneySIWX
|
|
3431
3011
|
};
|