@owney/sdk 0.6.9-beta.9 → 0.7.0
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 +255 -1370
- package/dist/index.d.cts +3 -138
- package/dist/index.d.ts +3 -138
- package/dist/index.js +226 -687
- package/package.json +3 -5
- package/dist/chunk-PWIKIQOX.js +0 -140
- package/dist/surfliquid.agent-VNGQUSXN.js +0 -473
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)) {
|
|
@@ -81,12 +116,6 @@ var isValidChainId = (chainId) => {
|
|
|
81
116
|
}
|
|
82
117
|
return chainId;
|
|
83
118
|
};
|
|
84
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
85
|
-
const token = tokenSymbol.toLowerCase();
|
|
86
|
-
const target = asset.toLowerCase();
|
|
87
|
-
if (token === target) return true;
|
|
88
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
89
|
-
}
|
|
90
119
|
function hexToDecimal(hex, decimals = 6) {
|
|
91
120
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
92
121
|
const parsed = BigInt(normalized);
|
|
@@ -112,10 +141,6 @@ var DECIMALS_BY_SYMBOL = {
|
|
|
112
141
|
wbtc: 8,
|
|
113
142
|
cbbtc: 8
|
|
114
143
|
};
|
|
115
|
-
function canonicalSymbol(symbol) {
|
|
116
|
-
const upper = symbol.toUpperCase();
|
|
117
|
-
return upper === "ETH" ? "WETH" : upper;
|
|
118
|
-
}
|
|
119
144
|
function tokenDecimals(symbol, explicit) {
|
|
120
145
|
if (typeof explicit === "number" && Number.isFinite(explicit))
|
|
121
146
|
return explicit;
|
|
@@ -154,50 +179,46 @@ function resolveChainId(chain) {
|
|
|
154
179
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
155
180
|
const portfolio = raw.portfolio;
|
|
156
181
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
157
|
-
const rawPositions = portfolio.positions ?? [];
|
|
158
|
-
const detailByKey = /* @__PURE__ */ new Map();
|
|
159
|
-
for (const p of rawPositions) {
|
|
160
|
-
const cid = resolveChainId(p.chain ?? "");
|
|
161
|
-
const symbol = canonicalSymbol(p.token_symbol ?? "");
|
|
162
|
-
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
163
|
-
}
|
|
164
182
|
let totalBalance = 0;
|
|
165
183
|
const tokens = [];
|
|
166
|
-
const positions = [];
|
|
167
184
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
168
185
|
const positionChainId = Number(chainIdKey);
|
|
169
|
-
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
170
186
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
171
187
|
tokensBySymbol ?? {}
|
|
172
188
|
)) {
|
|
173
|
-
const amount = hexToDecimal(balance || "0",
|
|
189
|
+
const amount = hexToDecimal(balance || "0", decimals);
|
|
174
190
|
totalBalance += amount;
|
|
175
191
|
tokens.push({
|
|
176
|
-
chain:
|
|
192
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
177
193
|
chainId: positionChainId,
|
|
178
194
|
asset: symbol,
|
|
179
195
|
amount: String(amount)
|
|
180
196
|
});
|
|
181
|
-
const detail = detailByKey.get(
|
|
182
|
-
`${positionChainId}:${canonicalSymbol(symbol)}`
|
|
183
|
-
);
|
|
184
|
-
positions.push({
|
|
185
|
-
chain: chainName,
|
|
186
|
-
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
187
|
-
protocolId: detail?.protocol_id,
|
|
188
|
-
pool: detail?.pool,
|
|
189
|
-
// Report the token the way the rest of owney spells it ("WETH", as the
|
|
190
|
-
// pre-portfolioByChain mapper did), not Zyfai's internal "eth".
|
|
191
|
-
asset: canonicalSymbol(symbol),
|
|
192
|
-
amount: String(amount),
|
|
193
|
-
apy: detail?.pool_apy,
|
|
194
|
-
tvl: detail?.pool_tvl,
|
|
195
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
196
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
197
|
-
liquidity: detail?.liquidity
|
|
198
|
-
});
|
|
199
197
|
}
|
|
200
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
|
+
}));
|
|
201
222
|
return {
|
|
202
223
|
smartWallet,
|
|
203
224
|
totalBalance: String(totalBalance),
|
|
@@ -359,9 +380,7 @@ function mapUserProfile(raw, userAddress) {
|
|
|
359
380
|
chains: raw.chains || [],
|
|
360
381
|
strategy: raw.strategy,
|
|
361
382
|
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
362
|
-
protocols: raw.protocols || []
|
|
363
|
-
splitting: raw.splitting,
|
|
364
|
-
minSplits: raw.minSplits
|
|
383
|
+
protocols: raw.protocols || []
|
|
365
384
|
};
|
|
366
385
|
}
|
|
367
386
|
function mapApyByStrategy(raw) {
|
|
@@ -508,23 +527,23 @@ var readLegacySession = (store, address) => {
|
|
|
508
527
|
const legacyKeys = [];
|
|
509
528
|
try {
|
|
510
529
|
for (let i = 0; i < store.length; i++) {
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
530
|
+
const key = store.key(i);
|
|
531
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
513
532
|
}
|
|
514
533
|
} catch {
|
|
515
534
|
return null;
|
|
516
535
|
}
|
|
517
536
|
let adopted = null;
|
|
518
|
-
for (const
|
|
537
|
+
for (const key of legacyKeys) {
|
|
519
538
|
if (!adopted) {
|
|
520
539
|
try {
|
|
521
|
-
const parsed = JSON.parse(store.getItem(
|
|
540
|
+
const parsed = JSON.parse(store.getItem(key) ?? "");
|
|
522
541
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
523
542
|
} catch {
|
|
524
543
|
}
|
|
525
544
|
}
|
|
526
545
|
try {
|
|
527
|
-
store.removeItem(
|
|
546
|
+
store.removeItem(key);
|
|
528
547
|
} catch {
|
|
529
548
|
}
|
|
530
549
|
}
|
|
@@ -532,11 +551,11 @@ var readLegacySession = (store, address) => {
|
|
|
532
551
|
};
|
|
533
552
|
var readSession = (address, _chainId) => {
|
|
534
553
|
if (typeof window === "undefined") return null;
|
|
535
|
-
const
|
|
554
|
+
const key = buildKey(address);
|
|
536
555
|
const store = storage();
|
|
537
556
|
let raw = null;
|
|
538
557
|
try {
|
|
539
|
-
raw = store?.getItem(
|
|
558
|
+
raw = store?.getItem(key) ?? null;
|
|
540
559
|
} catch {
|
|
541
560
|
raw = null;
|
|
542
561
|
}
|
|
@@ -546,9 +565,9 @@ var readSession = (address, _chainId) => {
|
|
|
546
565
|
if (isFreshSession(parsed)) return parsed;
|
|
547
566
|
} catch {
|
|
548
567
|
}
|
|
549
|
-
memorySessions.delete(
|
|
568
|
+
memorySessions.delete(key);
|
|
550
569
|
try {
|
|
551
|
-
store?.removeItem(
|
|
570
|
+
store?.removeItem(key);
|
|
552
571
|
} catch {
|
|
553
572
|
}
|
|
554
573
|
return null;
|
|
@@ -558,27 +577,27 @@ var readSession = (address, _chainId) => {
|
|
|
558
577
|
writeSession(address, _chainId, legacy);
|
|
559
578
|
return legacy;
|
|
560
579
|
}
|
|
561
|
-
const cached = memorySessions.get(
|
|
580
|
+
const cached = memorySessions.get(key);
|
|
562
581
|
if (isFreshSession(cached)) return cached;
|
|
563
|
-
if (cached) memorySessions.delete(
|
|
582
|
+
if (cached) memorySessions.delete(key);
|
|
564
583
|
return null;
|
|
565
584
|
};
|
|
566
585
|
var writeSession = (address, _chainId, session) => {
|
|
567
586
|
if (typeof window === "undefined") return;
|
|
568
|
-
const
|
|
569
|
-
memorySessions.set(
|
|
587
|
+
const key = buildKey(address);
|
|
588
|
+
memorySessions.set(key, session);
|
|
570
589
|
const store = storage();
|
|
571
590
|
try {
|
|
572
|
-
store?.setItem(
|
|
591
|
+
store?.setItem(key, JSON.stringify(session));
|
|
573
592
|
} catch {
|
|
574
593
|
}
|
|
575
594
|
};
|
|
576
595
|
var clearSession = (address, _chainId) => {
|
|
577
|
-
const
|
|
578
|
-
memorySessions.delete(
|
|
596
|
+
const key = buildKey(address);
|
|
597
|
+
memorySessions.delete(key);
|
|
579
598
|
const store = storage();
|
|
580
599
|
try {
|
|
581
|
-
store?.removeItem(
|
|
600
|
+
store?.removeItem(key);
|
|
582
601
|
} catch {
|
|
583
602
|
}
|
|
584
603
|
readLegacySession(store, address);
|
|
@@ -609,149 +628,6 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
609
628
|
};
|
|
610
629
|
}
|
|
611
630
|
|
|
612
|
-
// src/agents/zyfai/splitting.ts
|
|
613
|
-
var MAX_MIN_SPLITS = 4;
|
|
614
|
-
var MIN_FORCE_SPLITS = 2;
|
|
615
|
-
var AUTOMATIC_MIN_SPLITS = 1;
|
|
616
|
-
function toZyfaiSplitting(policy) {
|
|
617
|
-
switch (policy.splittingMode) {
|
|
618
|
-
case "none":
|
|
619
|
-
return { splitting: false };
|
|
620
|
-
case "automatic":
|
|
621
|
-
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
622
|
-
case "force":
|
|
623
|
-
return {
|
|
624
|
-
splitting: true,
|
|
625
|
-
minSplits: clampForceSplits(policy.minSplits)
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
function clampForceSplits(minSplits) {
|
|
630
|
-
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
631
|
-
return MIN_FORCE_SPLITS;
|
|
632
|
-
}
|
|
633
|
-
const rounded = Math.round(minSplits);
|
|
634
|
-
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
635
|
-
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
636
|
-
return rounded;
|
|
637
|
-
}
|
|
638
|
-
function splittingNeedsUpdate(current, desired) {
|
|
639
|
-
if (!current) return true;
|
|
640
|
-
if (current.splitting !== desired.splitting) return true;
|
|
641
|
-
if (desired.minSplits === void 0) return false;
|
|
642
|
-
return current.minSplits !== desired.minSplits;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
// src/agents/zyfai/pool-policy.ts
|
|
646
|
-
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
647
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
648
|
-
for (const selection of policy.selections) {
|
|
649
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
650
|
-
}
|
|
651
|
-
const customizations = [];
|
|
652
|
-
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
653
|
-
const available = availableByProtocol.get(protocolId);
|
|
654
|
-
if (available === void 0) {
|
|
655
|
-
continue;
|
|
656
|
-
}
|
|
657
|
-
const availableSet = new Set(available);
|
|
658
|
-
for (const chainId of chainIds) {
|
|
659
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
660
|
-
if (stored === void 0) {
|
|
661
|
-
customizations.push({
|
|
662
|
-
protocolId,
|
|
663
|
-
chainId,
|
|
664
|
-
pools: [],
|
|
665
|
-
autoselect: true
|
|
666
|
-
});
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
670
|
-
customizations.push({
|
|
671
|
-
protocolId,
|
|
672
|
-
chainId,
|
|
673
|
-
pools,
|
|
674
|
-
autoselect: false
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
return customizations;
|
|
679
|
-
}
|
|
680
|
-
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
681
|
-
if (policy.selections.length === 0) {
|
|
682
|
-
return null;
|
|
683
|
-
}
|
|
684
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
685
|
-
for (const selection of policy.selections) {
|
|
686
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
687
|
-
}
|
|
688
|
-
return universe.filter((protocolId) => {
|
|
689
|
-
const chainIds = chainsByProtocol[protocolId];
|
|
690
|
-
if (chainIds === void 0 || chainIds.length === 0) {
|
|
691
|
-
return true;
|
|
692
|
-
}
|
|
693
|
-
const fullyDisabled = chainIds.every((chainId) => {
|
|
694
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
695
|
-
return stored !== void 0 && stored.pools.length === 0;
|
|
696
|
-
});
|
|
697
|
-
return !fullyDisabled;
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
function key(protocolId, chainId) {
|
|
701
|
-
return `${protocolId}:${chainId}`;
|
|
702
|
-
}
|
|
703
|
-
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
704
|
-
const allowed = new Set(dashboardChainIds);
|
|
705
|
-
const result = {};
|
|
706
|
-
for (const protocol of protocols) {
|
|
707
|
-
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
708
|
-
(chainId) => allowed.has(chainId)
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
return result;
|
|
712
|
-
}
|
|
713
|
-
function flattenAvailablePools(raw) {
|
|
714
|
-
const byChain = raw ?? {};
|
|
715
|
-
const names = [];
|
|
716
|
-
for (const byToken of Object.values(byChain ?? {})) {
|
|
717
|
-
for (const entry of Object.values(byToken ?? {})) {
|
|
718
|
-
for (const pool of entry?.pools ?? []) {
|
|
719
|
-
if (pool?.name) names.push(pool.name);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return names;
|
|
724
|
-
}
|
|
725
|
-
function protocolListsEqual(a, b) {
|
|
726
|
-
const left = [...a ?? []].sort();
|
|
727
|
-
const right = [...b ?? []].sort();
|
|
728
|
-
if (left.length !== right.length) return false;
|
|
729
|
-
return left.every((value, index) => value === right[index]);
|
|
730
|
-
}
|
|
731
|
-
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
732
|
-
if (!current) return true;
|
|
733
|
-
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
734
|
-
if (desiredProtocols === null) return false;
|
|
735
|
-
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// src/lib/debug.ts
|
|
739
|
-
var configuredDebug = false;
|
|
740
|
-
function setOwneyDebug(enabled) {
|
|
741
|
-
configuredDebug = enabled;
|
|
742
|
-
}
|
|
743
|
-
function isOwneyDebug() {
|
|
744
|
-
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
745
|
-
}
|
|
746
|
-
function debugLog(scope, message, data) {
|
|
747
|
-
if (!isOwneyDebug()) return;
|
|
748
|
-
if (data === void 0) {
|
|
749
|
-
console.log(`[${scope}] ${message}`);
|
|
750
|
-
} else {
|
|
751
|
-
console.log(`[${scope}] ${message}`, data);
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
631
|
// src/agents/zyfai/zyfai.agent.ts
|
|
756
632
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
757
633
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -764,12 +640,6 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
764
640
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
765
641
|
};
|
|
766
642
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
767
|
-
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
768
|
-
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
769
|
-
function isAlreadyActiveSessionKeyError(error) {
|
|
770
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
771
|
-
return /already has an active session key/i.test(message);
|
|
772
|
-
}
|
|
773
643
|
var ZyfaiAgent = class {
|
|
774
644
|
id = "zyfai";
|
|
775
645
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -996,71 +866,21 @@ var ZyfaiAgent = class {
|
|
|
996
866
|
return await this.sdk.connectAccount(provider, chainId);
|
|
997
867
|
}
|
|
998
868
|
}
|
|
999
|
-
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
1000
|
-
async connectFull(state, chainId) {
|
|
1001
|
-
await this.connectAuth(state, chainId);
|
|
1002
|
-
const validChainId = isValidChainId(chainId);
|
|
1003
|
-
const address = this.getAddress();
|
|
1004
|
-
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
1005
|
-
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
1006
|
-
if (!wallet.isDeployed) {
|
|
1007
|
-
await this.sdk.deploySafe(address, validChainId, "aggressive", false);
|
|
1008
|
-
try {
|
|
1009
|
-
if (validChainId === 42161) {
|
|
1010
|
-
await this.sdk.updateUserProfile({
|
|
1011
|
-
asset: "WETH",
|
|
1012
|
-
chains: [validChainId],
|
|
1013
|
-
protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
|
|
1014
|
-
// AAVE protocol ID
|
|
1015
|
-
autoSelectProtocols: false
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
} catch (err) {
|
|
1019
|
-
console.warn(
|
|
1020
|
-
"Failed to configure AAVE protocol after Safe deployment:",
|
|
1021
|
-
err instanceof Error ? err.message : String(err)
|
|
1022
|
-
);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
await this.ensureSessionKey(state, address, validChainId);
|
|
1026
|
-
}
|
|
1027
869
|
/**
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1031
|
-
*
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
* to (re)create a key per chain — that 400s and blocks the deposit. We only
|
|
1035
|
-
* create when the user has none.
|
|
1036
|
-
*
|
|
1037
|
-
* The one wrapper-side hardening that IS needed: a chain/account switch can
|
|
1038
|
-
* fire the provider's `accountsChanged` → `disconnectAccount`, tearing down
|
|
1039
|
-
* the zyfai connection (walletClient + authenticatedUserId both null) while
|
|
1040
|
-
* our own `connectAuth` guard still believes this chain is connected and
|
|
1041
|
-
* early-returns without reconnecting. `createSessionKey` then fails with
|
|
1042
|
-
* "No account connected". Detect that and reconnect first.
|
|
1043
|
-
*
|
|
1044
|
-
* NOTE: whether a globally-active session key actually authorizes activity on
|
|
1045
|
-
* a freshly-deployed Safe on a new chain is a backend/zyf question — the
|
|
1046
|
-
* wrapper cannot force per-chain activation given the global 400 guard.
|
|
1047
|
-
* 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".
|
|
1048
876
|
*/
|
|
1049
|
-
async
|
|
877
|
+
async ensureConnected(state, chainId) {
|
|
878
|
+
await this.connectAuth(state, chainId);
|
|
1050
879
|
const internals = this.sdk;
|
|
1051
880
|
if (!internals.walletClient || internals.authenticatedUserId === null) {
|
|
1052
881
|
this.connectedChainId = null;
|
|
1053
882
|
await this.connectAuth(state, chainId);
|
|
1054
883
|
}
|
|
1055
|
-
const user = await this.sdk.getUserDetails();
|
|
1056
|
-
if (!user.hasActiveSessionKey) {
|
|
1057
|
-
try {
|
|
1058
|
-
await this.sdk.createSessionKey(address, chainId);
|
|
1059
|
-
} catch (error) {
|
|
1060
|
-
if (!isAlreadyActiveSessionKeyError(error)) throw error;
|
|
1061
|
-
internals.hasActiveSessionKey = true;
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
884
|
}
|
|
1065
885
|
/**
|
|
1066
886
|
* Sync newly-available protocols onto an existing user's profile at wallet
|
|
@@ -1130,211 +950,10 @@ var ZyfaiAgent = class {
|
|
|
1130
950
|
throw error;
|
|
1131
951
|
}
|
|
1132
952
|
}
|
|
1133
|
-
/**
|
|
1134
|
-
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1135
|
-
*
|
|
1136
|
-
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1137
|
-
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1138
|
-
* WETH holder's real setting untouched.
|
|
1139
|
-
*
|
|
1140
|
-
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1141
|
-
* must leave the user connected with their profile unchanged, never fail
|
|
1142
|
-
* activation.
|
|
1143
|
-
*/
|
|
1144
|
-
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1145
|
-
debugLog("zyfai:splitting", "applying org policy", {
|
|
1146
|
-
policy,
|
|
1147
|
-
// Per asset because Zyfai stores splitting under assetTypeSettings[asset].
|
|
1148
|
-
assets: SPLITTING_ASSETS
|
|
1149
|
-
});
|
|
1150
|
-
await Promise.all(
|
|
1151
|
-
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1152
|
-
);
|
|
1153
|
-
if (policy.poolPolicy) {
|
|
1154
|
-
await this.applyPoolPolicy(policy.poolPolicy);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
async applySplitting(asset, policy) {
|
|
1158
|
-
try {
|
|
1159
|
-
const desired = toZyfaiSplitting(policy);
|
|
1160
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1161
|
-
const currentSplitting = {
|
|
1162
|
-
splitting: current?.splitting,
|
|
1163
|
-
minSplits: current?.minSplits
|
|
1164
|
-
};
|
|
1165
|
-
const needsUpdate = splittingNeedsUpdate(current, desired);
|
|
1166
|
-
debugLog("zyfai:splitting", `${asset}: comparing`, {
|
|
1167
|
-
mode: policy.splittingMode,
|
|
1168
|
-
current: currentSplitting,
|
|
1169
|
-
desired,
|
|
1170
|
-
// Spelled out because the "why" is the non-obvious part: minSplits is
|
|
1171
|
-
// what separates automatic (1) from force (2-4), not `splitting`.
|
|
1172
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1173
|
-
});
|
|
1174
|
-
if (!needsUpdate) return;
|
|
1175
|
-
const result = await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1176
|
-
debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
|
|
1177
|
-
sent: { asset, ...desired },
|
|
1178
|
-
// updateUserProfile re-reads the profile after PATCHing, so this is
|
|
1179
|
-
// Zyfai's own view of the result rather than an echo of what we sent.
|
|
1180
|
-
zyfaiNowReports: {
|
|
1181
|
-
splitting: result?.splitting,
|
|
1182
|
-
minSplits: result?.minSplits
|
|
1183
|
-
}
|
|
1184
|
-
});
|
|
1185
|
-
} catch (error) {
|
|
1186
|
-
console.warn(
|
|
1187
|
-
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1188
|
-
error instanceof Error ? error.message : String(error)
|
|
1189
|
-
);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Apply the org's protocol/pool policy to this user's Zyfai profile.
|
|
1194
|
-
*
|
|
1195
|
-
* Two Zyfai writes, in a strict order:
|
|
1196
|
-
* 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
|
|
1197
|
-
* the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
|
|
1198
|
-
* 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
|
|
1199
|
-
* pool narrowing.
|
|
1200
|
-
*
|
|
1201
|
-
* Order matters: constraining a protocol's pools (step 2) while that
|
|
1202
|
-
* protocol is not yet in the allow-list (step 1 not yet applied) lands the
|
|
1203
|
-
* constraint on something the rebalance engine isn't considering.
|
|
1204
|
-
*
|
|
1205
|
-
* Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
|
|
1206
|
-
* connecting, so a Zyfai hiccup must leave the user connected with their
|
|
1207
|
-
* profile unchanged, never fail activation.
|
|
1208
|
-
*/
|
|
1209
|
-
async applyPoolPolicy(policy) {
|
|
1210
|
-
try {
|
|
1211
|
-
const { protocols: universe } = await this.sdk.getAvailableProtocols(
|
|
1212
|
-
this.supportedChainIds[0]
|
|
1213
|
-
);
|
|
1214
|
-
const universeIds = universe.map((p) => p.id);
|
|
1215
|
-
const chainsByProtocol = buildChainsByProtocol(
|
|
1216
|
-
universe,
|
|
1217
|
-
POOL_POLICY_CHAIN_IDS
|
|
1218
|
-
);
|
|
1219
|
-
debugLog("zyfai:pools", "protocol universe", {
|
|
1220
|
-
universeIds,
|
|
1221
|
-
chainsByProtocol
|
|
1222
|
-
});
|
|
1223
|
-
let strategy;
|
|
1224
|
-
const desiredProtocols = deriveProtocols(
|
|
1225
|
-
policy,
|
|
1226
|
-
universeIds,
|
|
1227
|
-
chainsByProtocol
|
|
1228
|
-
);
|
|
1229
|
-
const desiredAutoSelect = policy.autoApproveProtocols;
|
|
1230
|
-
for (const asset of SPLITTING_ASSETS) {
|
|
1231
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1232
|
-
if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
|
|
1233
|
-
strategy = current.strategy;
|
|
1234
|
-
}
|
|
1235
|
-
const needsUpdate = protocolsPolicyNeedsUpdate(
|
|
1236
|
-
current,
|
|
1237
|
-
desiredProtocols,
|
|
1238
|
-
desiredAutoSelect
|
|
1239
|
-
);
|
|
1240
|
-
debugLog("zyfai:pools", `${asset}: comparing protocols`, {
|
|
1241
|
-
current: {
|
|
1242
|
-
protocols: current.protocols,
|
|
1243
|
-
autoSelectProtocols: current.autoSelectProtocols
|
|
1244
|
-
},
|
|
1245
|
-
desired: {
|
|
1246
|
-
protocols: desiredProtocols,
|
|
1247
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1248
|
-
},
|
|
1249
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1250
|
-
});
|
|
1251
|
-
if (!needsUpdate) continue;
|
|
1252
|
-
const update = {
|
|
1253
|
-
asset,
|
|
1254
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1255
|
-
};
|
|
1256
|
-
if (desiredProtocols !== null) update.protocols = desiredProtocols;
|
|
1257
|
-
await this.sdk.updateUserProfile(update);
|
|
1258
|
-
debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
|
|
1259
|
-
}
|
|
1260
|
-
const poolResults = await Promise.all(
|
|
1261
|
-
universe.map(async (protocol) => {
|
|
1262
|
-
try {
|
|
1263
|
-
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1264
|
-
return [protocol.id, flattenAvailablePools(raw)];
|
|
1265
|
-
} catch (error) {
|
|
1266
|
-
console.warn(
|
|
1267
|
-
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
1268
|
-
error instanceof Error ? error.message : String(error)
|
|
1269
|
-
);
|
|
1270
|
-
return null;
|
|
1271
|
-
}
|
|
1272
|
-
})
|
|
1273
|
-
);
|
|
1274
|
-
const availableByProtocol = /* @__PURE__ */ new Map();
|
|
1275
|
-
for (const result of poolResults) {
|
|
1276
|
-
if (result) availableByProtocol.set(result[0], result[1]);
|
|
1277
|
-
}
|
|
1278
|
-
const customizations = toZyfaiCustomizations(
|
|
1279
|
-
policy,
|
|
1280
|
-
availableByProtocol,
|
|
1281
|
-
chainsByProtocol
|
|
1282
|
-
);
|
|
1283
|
-
debugLog("zyfai:pools", "derived customizeBatch payload", {
|
|
1284
|
-
strategy,
|
|
1285
|
-
availableProtocolCount: availableByProtocol.size,
|
|
1286
|
-
customizations
|
|
1287
|
-
});
|
|
1288
|
-
if (customizations.length === 0) {
|
|
1289
|
-
debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
|
|
1290
|
-
return;
|
|
1291
|
-
}
|
|
1292
|
-
await this.sdk.customizeBatch(customizations);
|
|
1293
|
-
debugLog("zyfai:pools", "wrote customizeBatch", {
|
|
1294
|
-
count: customizations.length
|
|
1295
|
-
});
|
|
1296
|
-
} catch (error) {
|
|
1297
|
-
console.warn(
|
|
1298
|
-
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
1299
|
-
error instanceof Error ? error.message : String(error)
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
/**
|
|
1304
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
1305
|
-
*
|
|
1306
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
1307
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
1308
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
1309
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
1310
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
1311
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
1312
|
-
*/
|
|
1313
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
1314
|
-
const ATTEMPTS = 3;
|
|
1315
|
-
const RETRY_DELAY_MS = 1e3;
|
|
1316
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
1317
|
-
try {
|
|
1318
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
1319
|
-
return;
|
|
1320
|
-
} catch (logError) {
|
|
1321
|
-
if (attempt === ATTEMPTS) {
|
|
1322
|
-
console.error(
|
|
1323
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
1324
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
1325
|
-
);
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
await new Promise(
|
|
1329
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
1330
|
-
);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
953
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1335
954
|
try {
|
|
1336
|
-
await this.connectFull(state, chainId);
|
|
1337
955
|
const validChainId = isValidChainId(chainId);
|
|
956
|
+
await this.ensureConnected(state, validChainId);
|
|
1338
957
|
if (depositCallback) {
|
|
1339
958
|
const wallet = await this.sdk.getSmartWalletAddress(
|
|
1340
959
|
this.getAddress(),
|
|
@@ -1346,19 +965,22 @@ var ZyfaiAgent = class {
|
|
|
1346
965
|
amount
|
|
1347
966
|
);
|
|
1348
967
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1349
|
-
|
|
1350
|
-
validChainId,
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
968
|
+
try {
|
|
969
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
970
|
+
} catch (logError) {
|
|
971
|
+
console.warn(
|
|
972
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
973
|
+
logError
|
|
974
|
+
);
|
|
975
|
+
}
|
|
1355
976
|
return { txHash, smartWallet: wallet.address, amount };
|
|
1356
977
|
}
|
|
1357
978
|
const raw = await this.sdk.depositFunds(
|
|
1358
979
|
this.getAddress(),
|
|
1359
980
|
validChainId,
|
|
1360
981
|
amount,
|
|
1361
|
-
asset
|
|
982
|
+
asset,
|
|
983
|
+
"aggressive"
|
|
1362
984
|
);
|
|
1363
985
|
return mapDeposit(raw);
|
|
1364
986
|
} catch (error) {
|
|
@@ -1367,8 +989,8 @@ var ZyfaiAgent = class {
|
|
|
1367
989
|
}
|
|
1368
990
|
// --- IAgent: Fund operations ---
|
|
1369
991
|
async withdraw(state, chainId, token, amount) {
|
|
1370
|
-
await this.connectFull(state, chainId);
|
|
1371
992
|
const validChainId = isValidChainId(chainId);
|
|
993
|
+
await this.ensureConnected(state, validChainId);
|
|
1372
994
|
const raw = await this.sdk.withdrawFunds(
|
|
1373
995
|
this.getAddress(),
|
|
1374
996
|
validChainId,
|
|
@@ -1447,19 +1069,7 @@ var ZyfaiAgent = class {
|
|
|
1447
1069
|
}
|
|
1448
1070
|
async getUserProfile(state, chainId) {
|
|
1449
1071
|
await this.connectAuth(state, chainId);
|
|
1450
|
-
const validChainId = isValidChainId(chainId);
|
|
1451
1072
|
const raw = await this.sdk.getUserDetails();
|
|
1452
|
-
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1453
|
-
asset: "USDC (default \u2014 no asset passed)",
|
|
1454
|
-
splitting: raw.splitting,
|
|
1455
|
-
minSplits: raw.minSplits,
|
|
1456
|
-
strategy: raw.strategy,
|
|
1457
|
-
chains: raw.chains,
|
|
1458
|
-
protocolCount: raw.protocols?.length,
|
|
1459
|
-
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
1460
|
-
smartWallet: raw.smartWallet
|
|
1461
|
-
});
|
|
1462
|
-
await this.ensureSessionKey(state, this.getAddress(), validChainId);
|
|
1463
1073
|
return mapUserProfile(raw, this.connectedAddress);
|
|
1464
1074
|
}
|
|
1465
1075
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
@@ -1492,40 +1102,6 @@ var ZyfaiAgent = class {
|
|
|
1492
1102
|
|
|
1493
1103
|
// src/lib/routing-api.ts
|
|
1494
1104
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1495
|
-
async function fetchOrgAgentConfig(apiKey) {
|
|
1496
|
-
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1497
|
-
try {
|
|
1498
|
-
const res = await fetch(url, {
|
|
1499
|
-
method: "GET",
|
|
1500
|
-
headers: {
|
|
1501
|
-
"Content-Type": "application/json",
|
|
1502
|
-
"x-owney-api-key": `${apiKey}`
|
|
1503
|
-
}
|
|
1504
|
-
});
|
|
1505
|
-
if (!res.ok) {
|
|
1506
|
-
if (res.status !== 404) {
|
|
1507
|
-
console.warn(
|
|
1508
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
|
-
return null;
|
|
1512
|
-
}
|
|
1513
|
-
const json = await res.json();
|
|
1514
|
-
const policy = json.success ? json.data ?? null : null;
|
|
1515
|
-
debugLog(
|
|
1516
|
-
"owney-sdk",
|
|
1517
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
1518
|
-
policy ?? void 0
|
|
1519
|
-
);
|
|
1520
|
-
return policy;
|
|
1521
|
-
} catch (error) {
|
|
1522
|
-
console.warn(
|
|
1523
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1524
|
-
error instanceof Error ? error.message : String(error)
|
|
1525
|
-
);
|
|
1526
|
-
return null;
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
1105
|
async function fetchAgentKeys(apiKey) {
|
|
1530
1106
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1531
1107
|
const res = await fetch(url, {
|
|
@@ -1590,10 +1166,11 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
1590
1166
|
// src/lib/helpers/withdraw-helper.ts
|
|
1591
1167
|
import { parseUnits } from "viem";
|
|
1592
1168
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
1169
|
+
const target = asset.toUpperCase();
|
|
1593
1170
|
return agents.map((agent) => {
|
|
1594
1171
|
const agentBalance = aggregated[agent.id];
|
|
1595
1172
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1596
|
-
(t) => t.chainId === chainId &&
|
|
1173
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
1597
1174
|
);
|
|
1598
1175
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1599
1176
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -1863,6 +1440,84 @@ async function getSponsorRelayerAddress(input) {
|
|
|
1863
1440
|
return parsed.data.relayer;
|
|
1864
1441
|
}
|
|
1865
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
|
+
|
|
1866
1521
|
// src/lib/sponsored-deposit.ts
|
|
1867
1522
|
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
1868
1523
|
function makeSponsoredDepositCallback(deps) {
|
|
@@ -2045,7 +1700,6 @@ var VIEM_CHAIN2 = {
|
|
|
2045
1700
|
42161: arbitrum2,
|
|
2046
1701
|
1: mainnet2
|
|
2047
1702
|
};
|
|
2048
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2049
1703
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2050
1704
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2051
1705
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2065,26 +1719,17 @@ var OwneySDK = class {
|
|
|
2065
1719
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
2066
1720
|
state = null;
|
|
2067
1721
|
apiKey;
|
|
2068
|
-
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
2069
|
-
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
2070
|
-
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
2071
|
-
// leave every user's agent profile alone.
|
|
2072
|
-
orgAgentConfig;
|
|
2073
|
-
orgAgentConfigPromise = null;
|
|
2074
1722
|
zyfaiRpcUrls;
|
|
2075
1723
|
routingApiBaseUrl;
|
|
2076
1724
|
referralSource;
|
|
2077
|
-
surfliquidApiBaseUrl;
|
|
2078
1725
|
cachedSponsoredCallback = null;
|
|
2079
1726
|
cachedWethSponsoredCallback = null;
|
|
2080
1727
|
initializingAgentsPromise = null;
|
|
2081
1728
|
constructor(config) {
|
|
2082
1729
|
this.apiKey = config.apiKey;
|
|
2083
|
-
if (config.debug) setOwneyDebug(true);
|
|
2084
1730
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2085
1731
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2086
1732
|
this.referralSource = config.referralSource;
|
|
2087
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2088
1733
|
}
|
|
2089
1734
|
/**
|
|
2090
1735
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2243,57 +1888,14 @@ var OwneySDK = class {
|
|
|
2243
1888
|
}
|
|
2244
1889
|
return active;
|
|
2245
1890
|
}
|
|
2246
|
-
/**
|
|
2247
|
-
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2248
|
-
* throws — it degrades to null — so this cannot break activation.
|
|
2249
|
-
*/
|
|
2250
|
-
async getOrgAgentConfig() {
|
|
2251
|
-
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2252
|
-
if (!this.orgAgentConfigPromise) {
|
|
2253
|
-
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2254
|
-
(config) => {
|
|
2255
|
-
this.orgAgentConfig = config;
|
|
2256
|
-
return config;
|
|
2257
|
-
}
|
|
2258
|
-
);
|
|
2259
|
-
}
|
|
2260
|
-
return this.orgAgentConfigPromise;
|
|
2261
|
-
}
|
|
2262
|
-
/**
|
|
2263
|
-
* Apply the org policy to one agent, after it has activated.
|
|
2264
|
-
*
|
|
2265
|
-
* Sequenced after activation rather than alongside it because applying the
|
|
2266
|
-
* policy needs the authenticated session activation establishes. Every failure
|
|
2267
|
-
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2268
|
-
* user's connect over.
|
|
2269
|
-
*/
|
|
2270
|
-
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2271
|
-
if (!agent.applyOrgPolicy) {
|
|
2272
|
-
debugLog(
|
|
2273
|
-
"owney-sdk",
|
|
2274
|
-
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2275
|
-
);
|
|
2276
|
-
return;
|
|
2277
|
-
}
|
|
2278
|
-
try {
|
|
2279
|
-
const policy = await this.getOrgAgentConfig();
|
|
2280
|
-
if (!policy) return;
|
|
2281
|
-
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2282
|
-
} catch (error) {
|
|
2283
|
-
console.warn(
|
|
2284
|
-
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2285
|
-
error instanceof Error ? error.message : String(error)
|
|
2286
|
-
);
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
1891
|
async ensureAgentsInitialized() {
|
|
2290
1892
|
if (this.agents.size > 0) return;
|
|
2291
1893
|
if (!this.initializingAgentsPromise) {
|
|
2292
1894
|
this.initializingAgentsPromise = (async () => {
|
|
2293
1895
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2294
1896
|
this.disabledAgents.clear();
|
|
2295
|
-
for (const { key
|
|
2296
|
-
const agent =
|
|
1897
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
1898
|
+
const agent = this.createAgent(agent_type, key);
|
|
2297
1899
|
if (!agent) continue;
|
|
2298
1900
|
this.agents.set(agent_type, agent);
|
|
2299
1901
|
if (is_enabled === false) {
|
|
@@ -2314,21 +1916,9 @@ var OwneySDK = class {
|
|
|
2314
1916
|
this.initializingAgentsPromise = null;
|
|
2315
1917
|
}
|
|
2316
1918
|
}
|
|
2317
|
-
|
|
1919
|
+
createAgent(agentId, key) {
|
|
2318
1920
|
if (agentId === "zyfai") {
|
|
2319
|
-
return new ZyfaiAgent(
|
|
2320
|
-
}
|
|
2321
|
-
if (agentId === "surfliquid") {
|
|
2322
|
-
if (!projectName) return null;
|
|
2323
|
-
const { SurfLiquidAgent } = await import("./surfliquid.agent-VNGQUSXN.js");
|
|
2324
|
-
return new SurfLiquidAgent({
|
|
2325
|
-
projectName,
|
|
2326
|
-
appId: key2,
|
|
2327
|
-
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2328
|
-
// which WebKit (iOS) discards when it is third-party. See
|
|
2329
|
-
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2330
|
-
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2331
|
-
});
|
|
1921
|
+
return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
|
|
2332
1922
|
}
|
|
2333
1923
|
return null;
|
|
2334
1924
|
}
|
|
@@ -2382,7 +1972,6 @@ var OwneySDK = class {
|
|
|
2382
1972
|
Promise.all(
|
|
2383
1973
|
agents.map(async (agent) => {
|
|
2384
1974
|
await agent.activateAgent(state, chainId);
|
|
2385
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2386
1975
|
})
|
|
2387
1976
|
).catch((error) => {
|
|
2388
1977
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2410,7 +1999,6 @@ var OwneySDK = class {
|
|
|
2410
1999
|
Promise.all(
|
|
2411
2000
|
enabledCompatible.map(async (agent) => {
|
|
2412
2001
|
await agent.activateAgent(state, chainId);
|
|
2413
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2414
2002
|
})
|
|
2415
2003
|
).catch((error) => {
|
|
2416
2004
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2484,30 +2072,18 @@ var OwneySDK = class {
|
|
|
2484
2072
|
);
|
|
2485
2073
|
}
|
|
2486
2074
|
const agentResults = {};
|
|
2487
|
-
const agentErrors = {};
|
|
2488
2075
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
depositCallback
|
|
2498
|
-
);
|
|
2499
|
-
} catch (error) {
|
|
2500
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
2501
|
-
}
|
|
2502
|
-
}
|
|
2503
|
-
if (Object.keys(agentResults).length === 0) {
|
|
2504
|
-
throw new OwneyError(
|
|
2505
|
-
"DEPOSIT_ALL_FAILED",
|
|
2506
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
2507
|
-
{ agentErrors }
|
|
2076
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2077
|
+
agent,
|
|
2078
|
+
state,
|
|
2079
|
+
chainId,
|
|
2080
|
+
agentAmount,
|
|
2081
|
+
asset,
|
|
2082
|
+
effectiveCallback,
|
|
2083
|
+
depositCallback
|
|
2508
2084
|
);
|
|
2509
2085
|
}
|
|
2510
|
-
return
|
|
2086
|
+
return { agentResults };
|
|
2511
2087
|
}
|
|
2512
2088
|
/**
|
|
2513
2089
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2623,8 +2199,9 @@ var OwneySDK = class {
|
|
|
2623
2199
|
async hasExistingBalance(agent, state, chainId, asset) {
|
|
2624
2200
|
try {
|
|
2625
2201
|
const balance = await agent.getBalances(state, chainId);
|
|
2202
|
+
const target = asset.toLowerCase();
|
|
2626
2203
|
const token = balance.tokens.find(
|
|
2627
|
-
(t) => t.chainId === chainId &&
|
|
2204
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
2628
2205
|
);
|
|
2629
2206
|
return !!token && Number(token.amount) > 0;
|
|
2630
2207
|
} catch {
|
|
@@ -2663,34 +2240,6 @@ var OwneySDK = class {
|
|
|
2663
2240
|
}
|
|
2664
2241
|
return eligible;
|
|
2665
2242
|
}
|
|
2666
|
-
/**
|
|
2667
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
2668
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
2669
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
2670
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
2671
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
2672
|
-
*
|
|
2673
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
2674
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
2675
|
-
*/
|
|
2676
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
2677
|
-
try {
|
|
2678
|
-
await this.ensureAgentsInitialized();
|
|
2679
|
-
} catch (error) {
|
|
2680
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
2681
|
-
return [];
|
|
2682
|
-
}
|
|
2683
|
-
throw error;
|
|
2684
|
-
}
|
|
2685
|
-
return [...this.agents.values()].filter((agent) => {
|
|
2686
|
-
const chainAssets = agent.supportedAssets.find(
|
|
2687
|
-
(sa) => sa.chainId === chainId
|
|
2688
|
-
);
|
|
2689
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
2690
|
-
}).map((agent) => agent.id).sort(
|
|
2691
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
2692
|
-
);
|
|
2693
|
-
}
|
|
2694
2243
|
// --- Fund operations ---
|
|
2695
2244
|
/**
|
|
2696
2245
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2726,17 +2275,9 @@ var OwneySDK = class {
|
|
|
2726
2275
|
}
|
|
2727
2276
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2728
2277
|
if (!amount) {
|
|
2729
|
-
const aggregated2 = await this.getBalances();
|
|
2730
|
-
const funded = projectAgentBalancesForAsset(
|
|
2731
|
-
eligibleAgents,
|
|
2732
|
-
aggregated2.agentBalances,
|
|
2733
|
-
chainId,
|
|
2734
|
-
asset,
|
|
2735
|
-
assetInfo.decimals
|
|
2736
|
-
).filter((b) => b.balance > 0n);
|
|
2737
2278
|
const results2 = {};
|
|
2738
2279
|
const agentErrors2 = {};
|
|
2739
|
-
for (const
|
|
2280
|
+
for (const agent of eligibleAgents) {
|
|
2740
2281
|
try {
|
|
2741
2282
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2742
2283
|
} catch (err) {
|
|
@@ -2753,10 +2294,9 @@ var OwneySDK = class {
|
|
|
2753
2294
|
{ asset, agentErrors: agentErrors2 }
|
|
2754
2295
|
);
|
|
2755
2296
|
}
|
|
2756
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2757
2297
|
return {
|
|
2758
2298
|
agentResult: results2,
|
|
2759
|
-
totalWithdrawn:
|
|
2299
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
2760
2300
|
};
|
|
2761
2301
|
}
|
|
2762
2302
|
const requested = BigInt(amount);
|
|
@@ -3273,22 +2813,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3273
2813
|
const legacyKeys = [];
|
|
3274
2814
|
try {
|
|
3275
2815
|
for (let i = 0; i < store.length; i++) {
|
|
3276
|
-
const
|
|
3277
|
-
if (
|
|
2816
|
+
const key = store.key(i);
|
|
2817
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
3278
2818
|
}
|
|
3279
2819
|
} catch {
|
|
3280
2820
|
return null;
|
|
3281
2821
|
}
|
|
3282
2822
|
let adopted = null;
|
|
3283
|
-
for (const
|
|
2823
|
+
for (const key of legacyKeys) {
|
|
3284
2824
|
if (!adopted) {
|
|
3285
2825
|
try {
|
|
3286
|
-
adopted = JSON.parse(store.getItem(
|
|
2826
|
+
adopted = JSON.parse(store.getItem(key) ?? "");
|
|
3287
2827
|
} catch {
|
|
3288
2828
|
}
|
|
3289
2829
|
}
|
|
3290
2830
|
try {
|
|
3291
|
-
store.removeItem(
|
|
2831
|
+
store.removeItem(key);
|
|
3292
2832
|
} catch {
|
|
3293
2833
|
}
|
|
3294
2834
|
}
|
|
@@ -3296,11 +2836,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3296
2836
|
};
|
|
3297
2837
|
var readSiwxSession = (address, chainId) => {
|
|
3298
2838
|
if (typeof window === "undefined") return null;
|
|
3299
|
-
const
|
|
2839
|
+
const key = buildKey2(address);
|
|
3300
2840
|
const store = storage2();
|
|
3301
2841
|
let raw = null;
|
|
3302
2842
|
try {
|
|
3303
|
-
raw = store?.getItem(
|
|
2843
|
+
raw = store?.getItem(key) ?? null;
|
|
3304
2844
|
} catch {
|
|
3305
2845
|
raw = null;
|
|
3306
2846
|
}
|
|
@@ -3308,9 +2848,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3308
2848
|
try {
|
|
3309
2849
|
return JSON.parse(raw);
|
|
3310
2850
|
} catch {
|
|
3311
|
-
memorySiwxSessions.delete(
|
|
2851
|
+
memorySiwxSessions.delete(key);
|
|
3312
2852
|
try {
|
|
3313
|
-
store?.removeItem(
|
|
2853
|
+
store?.removeItem(key);
|
|
3314
2854
|
} catch {
|
|
3315
2855
|
}
|
|
3316
2856
|
return null;
|
|
@@ -3321,24 +2861,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3321
2861
|
writeSiwxSession(address, chainId, legacy);
|
|
3322
2862
|
return legacy;
|
|
3323
2863
|
}
|
|
3324
|
-
return memorySiwxSessions.get(
|
|
2864
|
+
return memorySiwxSessions.get(key) ?? null;
|
|
3325
2865
|
};
|
|
3326
2866
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
3327
2867
|
if (typeof window === "undefined") return;
|
|
3328
|
-
const
|
|
3329
|
-
memorySiwxSessions.set(
|
|
2868
|
+
const key = buildKey2(address);
|
|
2869
|
+
memorySiwxSessions.set(key, session);
|
|
3330
2870
|
const store = storage2();
|
|
3331
2871
|
try {
|
|
3332
|
-
store?.setItem(
|
|
2872
|
+
store?.setItem(key, JSON.stringify(session));
|
|
3333
2873
|
} catch {
|
|
3334
2874
|
}
|
|
3335
2875
|
};
|
|
3336
2876
|
var clearSiwxSession = (address, _chainId) => {
|
|
3337
|
-
const
|
|
3338
|
-
memorySiwxSessions.delete(
|
|
2877
|
+
const key = buildKey2(address);
|
|
2878
|
+
memorySiwxSessions.delete(key);
|
|
3339
2879
|
const store = storage2();
|
|
3340
2880
|
try {
|
|
3341
|
-
store?.removeItem(
|
|
2881
|
+
store?.removeItem(key);
|
|
3342
2882
|
} catch {
|
|
3343
2883
|
}
|
|
3344
2884
|
readLegacySiwxSession(store, address);
|
|
@@ -3467,6 +3007,5 @@ export {
|
|
|
3467
3007
|
NotConnectedError,
|
|
3468
3008
|
OwneyError,
|
|
3469
3009
|
OwneySDK,
|
|
3470
|
-
createOwneySIWX
|
|
3471
|
-
setOwneyDebug
|
|
3010
|
+
createOwneySIWX
|
|
3472
3011
|
};
|