@owney/sdk 0.7.0 → 0.7.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/dist/index.cjs +458 -43
- package/dist/index.d.cts +108 -1
- package/dist/index.d.ts +108 -1
- package/dist/index.js +453 -39
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9,9 +9,9 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
var __copyProps = (to, from, except, desc) => {
|
|
11
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let
|
|
13
|
-
if (!__hasOwnProp.call(to,
|
|
14
|
-
__defProp(to,
|
|
12
|
+
for (let key2 of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
14
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
@@ -26,7 +26,8 @@ __export(index_exports, {
|
|
|
26
26
|
NotConnectedError: () => NotConnectedError,
|
|
27
27
|
OwneyError: () => OwneyError,
|
|
28
28
|
OwneySDK: () => OwneySDK,
|
|
29
|
-
createOwneySIWX: () => createOwneySIWX
|
|
29
|
+
createOwneySIWX: () => createOwneySIWX,
|
|
30
|
+
setOwneyDebug: () => setOwneyDebug
|
|
30
31
|
});
|
|
31
32
|
module.exports = __toCommonJS(index_exports);
|
|
32
33
|
|
|
@@ -412,7 +413,9 @@ function mapUserProfile(raw, userAddress) {
|
|
|
412
413
|
chains: raw.chains || [],
|
|
413
414
|
strategy: raw.strategy,
|
|
414
415
|
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
415
|
-
protocols: raw.protocols || []
|
|
416
|
+
protocols: raw.protocols || [],
|
|
417
|
+
splitting: raw.splitting,
|
|
418
|
+
minSplits: raw.minSplits
|
|
416
419
|
};
|
|
417
420
|
}
|
|
418
421
|
function mapApyByStrategy(raw) {
|
|
@@ -559,23 +562,23 @@ var readLegacySession = (store, address) => {
|
|
|
559
562
|
const legacyKeys = [];
|
|
560
563
|
try {
|
|
561
564
|
for (let i = 0; i < store.length; i++) {
|
|
562
|
-
const
|
|
563
|
-
if (
|
|
565
|
+
const key2 = store.key(i);
|
|
566
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
564
567
|
}
|
|
565
568
|
} catch {
|
|
566
569
|
return null;
|
|
567
570
|
}
|
|
568
571
|
let adopted = null;
|
|
569
|
-
for (const
|
|
572
|
+
for (const key2 of legacyKeys) {
|
|
570
573
|
if (!adopted) {
|
|
571
574
|
try {
|
|
572
|
-
const parsed = JSON.parse(store.getItem(
|
|
575
|
+
const parsed = JSON.parse(store.getItem(key2) ?? "");
|
|
573
576
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
574
577
|
} catch {
|
|
575
578
|
}
|
|
576
579
|
}
|
|
577
580
|
try {
|
|
578
|
-
store.removeItem(
|
|
581
|
+
store.removeItem(key2);
|
|
579
582
|
} catch {
|
|
580
583
|
}
|
|
581
584
|
}
|
|
@@ -583,11 +586,11 @@ var readLegacySession = (store, address) => {
|
|
|
583
586
|
};
|
|
584
587
|
var readSession = (address, _chainId) => {
|
|
585
588
|
if (typeof window === "undefined") return null;
|
|
586
|
-
const
|
|
589
|
+
const key2 = buildKey(address);
|
|
587
590
|
const store = storage();
|
|
588
591
|
let raw = null;
|
|
589
592
|
try {
|
|
590
|
-
raw = store?.getItem(
|
|
593
|
+
raw = store?.getItem(key2) ?? null;
|
|
591
594
|
} catch {
|
|
592
595
|
raw = null;
|
|
593
596
|
}
|
|
@@ -597,9 +600,9 @@ var readSession = (address, _chainId) => {
|
|
|
597
600
|
if (isFreshSession(parsed)) return parsed;
|
|
598
601
|
} catch {
|
|
599
602
|
}
|
|
600
|
-
memorySessions.delete(
|
|
603
|
+
memorySessions.delete(key2);
|
|
601
604
|
try {
|
|
602
|
-
store?.removeItem(
|
|
605
|
+
store?.removeItem(key2);
|
|
603
606
|
} catch {
|
|
604
607
|
}
|
|
605
608
|
return null;
|
|
@@ -609,27 +612,27 @@ var readSession = (address, _chainId) => {
|
|
|
609
612
|
writeSession(address, _chainId, legacy);
|
|
610
613
|
return legacy;
|
|
611
614
|
}
|
|
612
|
-
const cached = memorySessions.get(
|
|
615
|
+
const cached = memorySessions.get(key2);
|
|
613
616
|
if (isFreshSession(cached)) return cached;
|
|
614
|
-
if (cached) memorySessions.delete(
|
|
617
|
+
if (cached) memorySessions.delete(key2);
|
|
615
618
|
return null;
|
|
616
619
|
};
|
|
617
620
|
var writeSession = (address, _chainId, session) => {
|
|
618
621
|
if (typeof window === "undefined") return;
|
|
619
|
-
const
|
|
620
|
-
memorySessions.set(
|
|
622
|
+
const key2 = buildKey(address);
|
|
623
|
+
memorySessions.set(key2, session);
|
|
621
624
|
const store = storage();
|
|
622
625
|
try {
|
|
623
|
-
store?.setItem(
|
|
626
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
624
627
|
} catch {
|
|
625
628
|
}
|
|
626
629
|
};
|
|
627
630
|
var clearSession = (address, _chainId) => {
|
|
628
|
-
const
|
|
629
|
-
memorySessions.delete(
|
|
631
|
+
const key2 = buildKey(address);
|
|
632
|
+
memorySessions.delete(key2);
|
|
630
633
|
const store = storage();
|
|
631
634
|
try {
|
|
632
|
-
store?.removeItem(
|
|
635
|
+
store?.removeItem(key2);
|
|
633
636
|
} catch {
|
|
634
637
|
}
|
|
635
638
|
readLegacySession(store, address);
|
|
@@ -660,6 +663,149 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
660
663
|
};
|
|
661
664
|
}
|
|
662
665
|
|
|
666
|
+
// src/agents/zyfai/splitting.ts
|
|
667
|
+
var MAX_MIN_SPLITS = 4;
|
|
668
|
+
var MIN_FORCE_SPLITS = 2;
|
|
669
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
670
|
+
function toZyfaiSplitting(policy) {
|
|
671
|
+
switch (policy.splittingMode) {
|
|
672
|
+
case "none":
|
|
673
|
+
return { splitting: false };
|
|
674
|
+
case "automatic":
|
|
675
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
676
|
+
case "force":
|
|
677
|
+
return {
|
|
678
|
+
splitting: true,
|
|
679
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function clampForceSplits(minSplits) {
|
|
684
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
685
|
+
return MIN_FORCE_SPLITS;
|
|
686
|
+
}
|
|
687
|
+
const rounded = Math.round(minSplits);
|
|
688
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
689
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
690
|
+
return rounded;
|
|
691
|
+
}
|
|
692
|
+
function splittingNeedsUpdate(current, desired) {
|
|
693
|
+
if (!current) return true;
|
|
694
|
+
if (current.splitting !== desired.splitting) return true;
|
|
695
|
+
if (desired.minSplits === void 0) return false;
|
|
696
|
+
return current.minSplits !== desired.minSplits;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/agents/zyfai/pool-policy.ts
|
|
700
|
+
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
701
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
702
|
+
for (const selection of policy.selections) {
|
|
703
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
704
|
+
}
|
|
705
|
+
const customizations = [];
|
|
706
|
+
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
707
|
+
const available = availableByProtocol.get(protocolId);
|
|
708
|
+
if (available === void 0) {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const availableSet = new Set(available);
|
|
712
|
+
for (const chainId of chainIds) {
|
|
713
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
714
|
+
if (stored === void 0) {
|
|
715
|
+
customizations.push({
|
|
716
|
+
protocolId,
|
|
717
|
+
chainId,
|
|
718
|
+
pools: [],
|
|
719
|
+
autoselect: true
|
|
720
|
+
});
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
724
|
+
customizations.push({
|
|
725
|
+
protocolId,
|
|
726
|
+
chainId,
|
|
727
|
+
pools,
|
|
728
|
+
autoselect: false
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return customizations;
|
|
733
|
+
}
|
|
734
|
+
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
735
|
+
if (policy.selections.length === 0) {
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
739
|
+
for (const selection of policy.selections) {
|
|
740
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
741
|
+
}
|
|
742
|
+
return universe.filter((protocolId) => {
|
|
743
|
+
const chainIds = chainsByProtocol[protocolId];
|
|
744
|
+
if (chainIds === void 0 || chainIds.length === 0) {
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
const fullyDisabled = chainIds.every((chainId) => {
|
|
748
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
749
|
+
return stored !== void 0 && stored.pools.length === 0;
|
|
750
|
+
});
|
|
751
|
+
return !fullyDisabled;
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
function key(protocolId, chainId) {
|
|
755
|
+
return `${protocolId}:${chainId}`;
|
|
756
|
+
}
|
|
757
|
+
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
758
|
+
const allowed = new Set(dashboardChainIds);
|
|
759
|
+
const result = {};
|
|
760
|
+
for (const protocol of protocols) {
|
|
761
|
+
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
762
|
+
(chainId) => allowed.has(chainId)
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
return result;
|
|
766
|
+
}
|
|
767
|
+
function flattenAvailablePools(raw) {
|
|
768
|
+
const byChain = raw ?? {};
|
|
769
|
+
const names = [];
|
|
770
|
+
for (const byToken of Object.values(byChain ?? {})) {
|
|
771
|
+
for (const entry of Object.values(byToken ?? {})) {
|
|
772
|
+
for (const pool of entry?.pools ?? []) {
|
|
773
|
+
if (pool?.name) names.push(pool.name);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return names;
|
|
778
|
+
}
|
|
779
|
+
function protocolListsEqual(a, b) {
|
|
780
|
+
const left = [...a ?? []].sort();
|
|
781
|
+
const right = [...b ?? []].sort();
|
|
782
|
+
if (left.length !== right.length) return false;
|
|
783
|
+
return left.every((value, index) => value === right[index]);
|
|
784
|
+
}
|
|
785
|
+
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
786
|
+
if (!current) return true;
|
|
787
|
+
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
788
|
+
if (desiredProtocols === null) return false;
|
|
789
|
+
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// src/lib/debug.ts
|
|
793
|
+
var configuredDebug = false;
|
|
794
|
+
function setOwneyDebug(enabled) {
|
|
795
|
+
configuredDebug = enabled;
|
|
796
|
+
}
|
|
797
|
+
function isOwneyDebug() {
|
|
798
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
799
|
+
}
|
|
800
|
+
function debugLog(scope, message, data) {
|
|
801
|
+
if (!isOwneyDebug()) return;
|
|
802
|
+
if (data === void 0) {
|
|
803
|
+
console.log(`[${scope}] ${message}`);
|
|
804
|
+
} else {
|
|
805
|
+
console.log(`[${scope}] ${message}`, data);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
663
809
|
// src/agents/zyfai/zyfai.agent.ts
|
|
664
810
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
665
811
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -672,6 +818,8 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
672
818
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
673
819
|
};
|
|
674
820
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
821
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
822
|
+
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
675
823
|
var ZyfaiAgent = class {
|
|
676
824
|
id = "zyfai";
|
|
677
825
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -982,6 +1130,176 @@ var ZyfaiAgent = class {
|
|
|
982
1130
|
throw error;
|
|
983
1131
|
}
|
|
984
1132
|
}
|
|
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
|
+
}
|
|
985
1303
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
986
1304
|
try {
|
|
987
1305
|
const validChainId = isValidChainId(chainId);
|
|
@@ -1102,6 +1420,16 @@ var ZyfaiAgent = class {
|
|
|
1102
1420
|
async getUserProfile(state, chainId) {
|
|
1103
1421
|
await this.connectAuth(state, chainId);
|
|
1104
1422
|
const raw = await this.sdk.getUserDetails();
|
|
1423
|
+
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1424
|
+
asset: "USDC (default \u2014 no asset passed)",
|
|
1425
|
+
splitting: raw.splitting,
|
|
1426
|
+
minSplits: raw.minSplits,
|
|
1427
|
+
strategy: raw.strategy,
|
|
1428
|
+
chains: raw.chains,
|
|
1429
|
+
protocolCount: raw.protocols?.length,
|
|
1430
|
+
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
1431
|
+
smartWallet: raw.smartWallet
|
|
1432
|
+
});
|
|
1105
1433
|
return mapUserProfile(raw, this.connectedAddress);
|
|
1106
1434
|
}
|
|
1107
1435
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
@@ -1134,6 +1462,40 @@ var ZyfaiAgent = class {
|
|
|
1134
1462
|
|
|
1135
1463
|
// src/lib/routing-api.ts
|
|
1136
1464
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1465
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1466
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1467
|
+
try {
|
|
1468
|
+
const res = await fetch(url, {
|
|
1469
|
+
method: "GET",
|
|
1470
|
+
headers: {
|
|
1471
|
+
"Content-Type": "application/json",
|
|
1472
|
+
"x-owney-api-key": `${apiKey}`
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
if (!res.ok) {
|
|
1476
|
+
if (res.status !== 404) {
|
|
1477
|
+
console.warn(
|
|
1478
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
return null;
|
|
1482
|
+
}
|
|
1483
|
+
const json = await res.json();
|
|
1484
|
+
const policy = json.success ? json.data ?? null : null;
|
|
1485
|
+
debugLog(
|
|
1486
|
+
"owney-sdk",
|
|
1487
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
1488
|
+
policy ?? void 0
|
|
1489
|
+
);
|
|
1490
|
+
return policy;
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
console.warn(
|
|
1493
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1494
|
+
error instanceof Error ? error.message : String(error)
|
|
1495
|
+
);
|
|
1496
|
+
return null;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1137
1499
|
async function fetchAgentKeys(apiKey) {
|
|
1138
1500
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1139
1501
|
const res = await fetch(url, {
|
|
@@ -1747,6 +2109,12 @@ var OwneySDK = class {
|
|
|
1747
2109
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
1748
2110
|
state = null;
|
|
1749
2111
|
apiKey;
|
|
2112
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
2113
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
2114
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
2115
|
+
// leave every user's agent profile alone.
|
|
2116
|
+
orgAgentConfig;
|
|
2117
|
+
orgAgentConfigPromise = null;
|
|
1750
2118
|
zyfaiRpcUrls;
|
|
1751
2119
|
routingApiBaseUrl;
|
|
1752
2120
|
referralSource;
|
|
@@ -1755,6 +2123,7 @@ var OwneySDK = class {
|
|
|
1755
2123
|
initializingAgentsPromise = null;
|
|
1756
2124
|
constructor(config) {
|
|
1757
2125
|
this.apiKey = config.apiKey;
|
|
2126
|
+
if (config.debug) setOwneyDebug(true);
|
|
1758
2127
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
1759
2128
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
1760
2129
|
this.referralSource = config.referralSource;
|
|
@@ -1916,14 +2285,57 @@ var OwneySDK = class {
|
|
|
1916
2285
|
}
|
|
1917
2286
|
return active;
|
|
1918
2287
|
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2290
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2291
|
+
*/
|
|
2292
|
+
async getOrgAgentConfig() {
|
|
2293
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2294
|
+
if (!this.orgAgentConfigPromise) {
|
|
2295
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2296
|
+
(config) => {
|
|
2297
|
+
this.orgAgentConfig = config;
|
|
2298
|
+
return config;
|
|
2299
|
+
}
|
|
2300
|
+
);
|
|
2301
|
+
}
|
|
2302
|
+
return this.orgAgentConfigPromise;
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2306
|
+
*
|
|
2307
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2308
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2309
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2310
|
+
* user's connect over.
|
|
2311
|
+
*/
|
|
2312
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2313
|
+
if (!agent.applyOrgPolicy) {
|
|
2314
|
+
debugLog(
|
|
2315
|
+
"owney-sdk",
|
|
2316
|
+
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2317
|
+
);
|
|
2318
|
+
return;
|
|
2319
|
+
}
|
|
2320
|
+
try {
|
|
2321
|
+
const policy = await this.getOrgAgentConfig();
|
|
2322
|
+
if (!policy) return;
|
|
2323
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
console.warn(
|
|
2326
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2327
|
+
error instanceof Error ? error.message : String(error)
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
1919
2331
|
async ensureAgentsInitialized() {
|
|
1920
2332
|
if (this.agents.size > 0) return;
|
|
1921
2333
|
if (!this.initializingAgentsPromise) {
|
|
1922
2334
|
this.initializingAgentsPromise = (async () => {
|
|
1923
2335
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1924
2336
|
this.disabledAgents.clear();
|
|
1925
|
-
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
1926
|
-
const agent = this.createAgent(agent_type,
|
|
2337
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2338
|
+
const agent = this.createAgent(agent_type, key2);
|
|
1927
2339
|
if (!agent) continue;
|
|
1928
2340
|
this.agents.set(agent_type, agent);
|
|
1929
2341
|
if (is_enabled === false) {
|
|
@@ -1944,9 +2356,9 @@ var OwneySDK = class {
|
|
|
1944
2356
|
this.initializingAgentsPromise = null;
|
|
1945
2357
|
}
|
|
1946
2358
|
}
|
|
1947
|
-
createAgent(agentId,
|
|
2359
|
+
createAgent(agentId, key2) {
|
|
1948
2360
|
if (agentId === "zyfai") {
|
|
1949
|
-
return new ZyfaiAgent(
|
|
2361
|
+
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
1950
2362
|
}
|
|
1951
2363
|
return null;
|
|
1952
2364
|
}
|
|
@@ -2000,6 +2412,7 @@ var OwneySDK = class {
|
|
|
2000
2412
|
Promise.all(
|
|
2001
2413
|
agents.map(async (agent) => {
|
|
2002
2414
|
await agent.activateAgent(state, chainId);
|
|
2415
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2003
2416
|
})
|
|
2004
2417
|
).catch((error) => {
|
|
2005
2418
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2027,6 +2440,7 @@ var OwneySDK = class {
|
|
|
2027
2440
|
Promise.all(
|
|
2028
2441
|
enabledCompatible.map(async (agent) => {
|
|
2029
2442
|
await agent.activateAgent(state, chainId);
|
|
2443
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2030
2444
|
})
|
|
2031
2445
|
).catch((error) => {
|
|
2032
2446
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2841,22 +3255,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
2841
3255
|
const legacyKeys = [];
|
|
2842
3256
|
try {
|
|
2843
3257
|
for (let i = 0; i < store.length; i++) {
|
|
2844
|
-
const
|
|
2845
|
-
if (
|
|
3258
|
+
const key2 = store.key(i);
|
|
3259
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
2846
3260
|
}
|
|
2847
3261
|
} catch {
|
|
2848
3262
|
return null;
|
|
2849
3263
|
}
|
|
2850
3264
|
let adopted = null;
|
|
2851
|
-
for (const
|
|
3265
|
+
for (const key2 of legacyKeys) {
|
|
2852
3266
|
if (!adopted) {
|
|
2853
3267
|
try {
|
|
2854
|
-
adopted = JSON.parse(store.getItem(
|
|
3268
|
+
adopted = JSON.parse(store.getItem(key2) ?? "");
|
|
2855
3269
|
} catch {
|
|
2856
3270
|
}
|
|
2857
3271
|
}
|
|
2858
3272
|
try {
|
|
2859
|
-
store.removeItem(
|
|
3273
|
+
store.removeItem(key2);
|
|
2860
3274
|
} catch {
|
|
2861
3275
|
}
|
|
2862
3276
|
}
|
|
@@ -2864,11 +3278,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
2864
3278
|
};
|
|
2865
3279
|
var readSiwxSession = (address, chainId) => {
|
|
2866
3280
|
if (typeof window === "undefined") return null;
|
|
2867
|
-
const
|
|
3281
|
+
const key2 = buildKey2(address);
|
|
2868
3282
|
const store = storage2();
|
|
2869
3283
|
let raw = null;
|
|
2870
3284
|
try {
|
|
2871
|
-
raw = store?.getItem(
|
|
3285
|
+
raw = store?.getItem(key2) ?? null;
|
|
2872
3286
|
} catch {
|
|
2873
3287
|
raw = null;
|
|
2874
3288
|
}
|
|
@@ -2876,9 +3290,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
2876
3290
|
try {
|
|
2877
3291
|
return JSON.parse(raw);
|
|
2878
3292
|
} catch {
|
|
2879
|
-
memorySiwxSessions.delete(
|
|
3293
|
+
memorySiwxSessions.delete(key2);
|
|
2880
3294
|
try {
|
|
2881
|
-
store?.removeItem(
|
|
3295
|
+
store?.removeItem(key2);
|
|
2882
3296
|
} catch {
|
|
2883
3297
|
}
|
|
2884
3298
|
return null;
|
|
@@ -2889,24 +3303,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
2889
3303
|
writeSiwxSession(address, chainId, legacy);
|
|
2890
3304
|
return legacy;
|
|
2891
3305
|
}
|
|
2892
|
-
return memorySiwxSessions.get(
|
|
3306
|
+
return memorySiwxSessions.get(key2) ?? null;
|
|
2893
3307
|
};
|
|
2894
3308
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
2895
3309
|
if (typeof window === "undefined") return;
|
|
2896
|
-
const
|
|
2897
|
-
memorySiwxSessions.set(
|
|
3310
|
+
const key2 = buildKey2(address);
|
|
3311
|
+
memorySiwxSessions.set(key2, session);
|
|
2898
3312
|
const store = storage2();
|
|
2899
3313
|
try {
|
|
2900
|
-
store?.setItem(
|
|
3314
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
2901
3315
|
} catch {
|
|
2902
3316
|
}
|
|
2903
3317
|
};
|
|
2904
3318
|
var clearSiwxSession = (address, _chainId) => {
|
|
2905
|
-
const
|
|
2906
|
-
memorySiwxSessions.delete(
|
|
3319
|
+
const key2 = buildKey2(address);
|
|
3320
|
+
memorySiwxSessions.delete(key2);
|
|
2907
3321
|
const store = storage2();
|
|
2908
3322
|
try {
|
|
2909
|
-
store?.removeItem(
|
|
3323
|
+
store?.removeItem(key2);
|
|
2910
3324
|
} catch {
|
|
2911
3325
|
}
|
|
2912
3326
|
readLegacySiwxSession(store, address);
|
|
@@ -3036,5 +3450,6 @@ function createOwneySIWX(config) {
|
|
|
3036
3450
|
NotConnectedError,
|
|
3037
3451
|
OwneyError,
|
|
3038
3452
|
OwneySDK,
|
|
3039
|
-
createOwneySIWX
|
|
3453
|
+
createOwneySIWX,
|
|
3454
|
+
setOwneyDebug
|
|
3040
3455
|
});
|