@owney/sdk 0.7.0-beta.1 → 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.js
CHANGED
|
@@ -380,7 +380,9 @@ function mapUserProfile(raw, userAddress) {
|
|
|
380
380
|
chains: raw.chains || [],
|
|
381
381
|
strategy: raw.strategy,
|
|
382
382
|
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
383
|
-
protocols: raw.protocols || []
|
|
383
|
+
protocols: raw.protocols || [],
|
|
384
|
+
splitting: raw.splitting,
|
|
385
|
+
minSplits: raw.minSplits
|
|
384
386
|
};
|
|
385
387
|
}
|
|
386
388
|
function mapApyByStrategy(raw) {
|
|
@@ -527,23 +529,23 @@ var readLegacySession = (store, address) => {
|
|
|
527
529
|
const legacyKeys = [];
|
|
528
530
|
try {
|
|
529
531
|
for (let i = 0; i < store.length; i++) {
|
|
530
|
-
const
|
|
531
|
-
if (
|
|
532
|
+
const key2 = store.key(i);
|
|
533
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
532
534
|
}
|
|
533
535
|
} catch {
|
|
534
536
|
return null;
|
|
535
537
|
}
|
|
536
538
|
let adopted = null;
|
|
537
|
-
for (const
|
|
539
|
+
for (const key2 of legacyKeys) {
|
|
538
540
|
if (!adopted) {
|
|
539
541
|
try {
|
|
540
|
-
const parsed = JSON.parse(store.getItem(
|
|
542
|
+
const parsed = JSON.parse(store.getItem(key2) ?? "");
|
|
541
543
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
542
544
|
} catch {
|
|
543
545
|
}
|
|
544
546
|
}
|
|
545
547
|
try {
|
|
546
|
-
store.removeItem(
|
|
548
|
+
store.removeItem(key2);
|
|
547
549
|
} catch {
|
|
548
550
|
}
|
|
549
551
|
}
|
|
@@ -551,11 +553,11 @@ var readLegacySession = (store, address) => {
|
|
|
551
553
|
};
|
|
552
554
|
var readSession = (address, _chainId) => {
|
|
553
555
|
if (typeof window === "undefined") return null;
|
|
554
|
-
const
|
|
556
|
+
const key2 = buildKey(address);
|
|
555
557
|
const store = storage();
|
|
556
558
|
let raw = null;
|
|
557
559
|
try {
|
|
558
|
-
raw = store?.getItem(
|
|
560
|
+
raw = store?.getItem(key2) ?? null;
|
|
559
561
|
} catch {
|
|
560
562
|
raw = null;
|
|
561
563
|
}
|
|
@@ -565,9 +567,9 @@ var readSession = (address, _chainId) => {
|
|
|
565
567
|
if (isFreshSession(parsed)) return parsed;
|
|
566
568
|
} catch {
|
|
567
569
|
}
|
|
568
|
-
memorySessions.delete(
|
|
570
|
+
memorySessions.delete(key2);
|
|
569
571
|
try {
|
|
570
|
-
store?.removeItem(
|
|
572
|
+
store?.removeItem(key2);
|
|
571
573
|
} catch {
|
|
572
574
|
}
|
|
573
575
|
return null;
|
|
@@ -577,27 +579,27 @@ var readSession = (address, _chainId) => {
|
|
|
577
579
|
writeSession(address, _chainId, legacy);
|
|
578
580
|
return legacy;
|
|
579
581
|
}
|
|
580
|
-
const cached = memorySessions.get(
|
|
582
|
+
const cached = memorySessions.get(key2);
|
|
581
583
|
if (isFreshSession(cached)) return cached;
|
|
582
|
-
if (cached) memorySessions.delete(
|
|
584
|
+
if (cached) memorySessions.delete(key2);
|
|
583
585
|
return null;
|
|
584
586
|
};
|
|
585
587
|
var writeSession = (address, _chainId, session) => {
|
|
586
588
|
if (typeof window === "undefined") return;
|
|
587
|
-
const
|
|
588
|
-
memorySessions.set(
|
|
589
|
+
const key2 = buildKey(address);
|
|
590
|
+
memorySessions.set(key2, session);
|
|
589
591
|
const store = storage();
|
|
590
592
|
try {
|
|
591
|
-
store?.setItem(
|
|
593
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
592
594
|
} catch {
|
|
593
595
|
}
|
|
594
596
|
};
|
|
595
597
|
var clearSession = (address, _chainId) => {
|
|
596
|
-
const
|
|
597
|
-
memorySessions.delete(
|
|
598
|
+
const key2 = buildKey(address);
|
|
599
|
+
memorySessions.delete(key2);
|
|
598
600
|
const store = storage();
|
|
599
601
|
try {
|
|
600
|
-
store?.removeItem(
|
|
602
|
+
store?.removeItem(key2);
|
|
601
603
|
} catch {
|
|
602
604
|
}
|
|
603
605
|
readLegacySession(store, address);
|
|
@@ -628,6 +630,149 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
628
630
|
};
|
|
629
631
|
}
|
|
630
632
|
|
|
633
|
+
// src/agents/zyfai/splitting.ts
|
|
634
|
+
var MAX_MIN_SPLITS = 4;
|
|
635
|
+
var MIN_FORCE_SPLITS = 2;
|
|
636
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
637
|
+
function toZyfaiSplitting(policy) {
|
|
638
|
+
switch (policy.splittingMode) {
|
|
639
|
+
case "none":
|
|
640
|
+
return { splitting: false };
|
|
641
|
+
case "automatic":
|
|
642
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
643
|
+
case "force":
|
|
644
|
+
return {
|
|
645
|
+
splitting: true,
|
|
646
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function clampForceSplits(minSplits) {
|
|
651
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
652
|
+
return MIN_FORCE_SPLITS;
|
|
653
|
+
}
|
|
654
|
+
const rounded = Math.round(minSplits);
|
|
655
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
656
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
657
|
+
return rounded;
|
|
658
|
+
}
|
|
659
|
+
function splittingNeedsUpdate(current, desired) {
|
|
660
|
+
if (!current) return true;
|
|
661
|
+
if (current.splitting !== desired.splitting) return true;
|
|
662
|
+
if (desired.minSplits === void 0) return false;
|
|
663
|
+
return current.minSplits !== desired.minSplits;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/agents/zyfai/pool-policy.ts
|
|
667
|
+
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
668
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
669
|
+
for (const selection of policy.selections) {
|
|
670
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
671
|
+
}
|
|
672
|
+
const customizations = [];
|
|
673
|
+
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
674
|
+
const available = availableByProtocol.get(protocolId);
|
|
675
|
+
if (available === void 0) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
const availableSet = new Set(available);
|
|
679
|
+
for (const chainId of chainIds) {
|
|
680
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
681
|
+
if (stored === void 0) {
|
|
682
|
+
customizations.push({
|
|
683
|
+
protocolId,
|
|
684
|
+
chainId,
|
|
685
|
+
pools: [],
|
|
686
|
+
autoselect: true
|
|
687
|
+
});
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
691
|
+
customizations.push({
|
|
692
|
+
protocolId,
|
|
693
|
+
chainId,
|
|
694
|
+
pools,
|
|
695
|
+
autoselect: false
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return customizations;
|
|
700
|
+
}
|
|
701
|
+
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
702
|
+
if (policy.selections.length === 0) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
const selectionByKey = /* @__PURE__ */ new Map();
|
|
706
|
+
for (const selection of policy.selections) {
|
|
707
|
+
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
708
|
+
}
|
|
709
|
+
return universe.filter((protocolId) => {
|
|
710
|
+
const chainIds = chainsByProtocol[protocolId];
|
|
711
|
+
if (chainIds === void 0 || chainIds.length === 0) {
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
const fullyDisabled = chainIds.every((chainId) => {
|
|
715
|
+
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
716
|
+
return stored !== void 0 && stored.pools.length === 0;
|
|
717
|
+
});
|
|
718
|
+
return !fullyDisabled;
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
function key(protocolId, chainId) {
|
|
722
|
+
return `${protocolId}:${chainId}`;
|
|
723
|
+
}
|
|
724
|
+
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
725
|
+
const allowed = new Set(dashboardChainIds);
|
|
726
|
+
const result = {};
|
|
727
|
+
for (const protocol of protocols) {
|
|
728
|
+
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
729
|
+
(chainId) => allowed.has(chainId)
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
return result;
|
|
733
|
+
}
|
|
734
|
+
function flattenAvailablePools(raw) {
|
|
735
|
+
const byChain = raw ?? {};
|
|
736
|
+
const names = [];
|
|
737
|
+
for (const byToken of Object.values(byChain ?? {})) {
|
|
738
|
+
for (const entry of Object.values(byToken ?? {})) {
|
|
739
|
+
for (const pool of entry?.pools ?? []) {
|
|
740
|
+
if (pool?.name) names.push(pool.name);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return names;
|
|
745
|
+
}
|
|
746
|
+
function protocolListsEqual(a, b) {
|
|
747
|
+
const left = [...a ?? []].sort();
|
|
748
|
+
const right = [...b ?? []].sort();
|
|
749
|
+
if (left.length !== right.length) return false;
|
|
750
|
+
return left.every((value, index) => value === right[index]);
|
|
751
|
+
}
|
|
752
|
+
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
753
|
+
if (!current) return true;
|
|
754
|
+
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
755
|
+
if (desiredProtocols === null) return false;
|
|
756
|
+
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/lib/debug.ts
|
|
760
|
+
var configuredDebug = false;
|
|
761
|
+
function setOwneyDebug(enabled) {
|
|
762
|
+
configuredDebug = enabled;
|
|
763
|
+
}
|
|
764
|
+
function isOwneyDebug() {
|
|
765
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
766
|
+
}
|
|
767
|
+
function debugLog(scope, message, data) {
|
|
768
|
+
if (!isOwneyDebug()) return;
|
|
769
|
+
if (data === void 0) {
|
|
770
|
+
console.log(`[${scope}] ${message}`);
|
|
771
|
+
} else {
|
|
772
|
+
console.log(`[${scope}] ${message}`, data);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
631
776
|
// src/agents/zyfai/zyfai.agent.ts
|
|
632
777
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
633
778
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -640,6 +785,8 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
640
785
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
641
786
|
};
|
|
642
787
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
788
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
789
|
+
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
643
790
|
var ZyfaiAgent = class {
|
|
644
791
|
id = "zyfai";
|
|
645
792
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -950,6 +1097,176 @@ var ZyfaiAgent = class {
|
|
|
950
1097
|
throw error;
|
|
951
1098
|
}
|
|
952
1099
|
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1102
|
+
*
|
|
1103
|
+
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1104
|
+
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1105
|
+
* WETH holder's real setting untouched.
|
|
1106
|
+
*
|
|
1107
|
+
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1108
|
+
* must leave the user connected with their profile unchanged, never fail
|
|
1109
|
+
* activation.
|
|
1110
|
+
*/
|
|
1111
|
+
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1112
|
+
debugLog("zyfai:splitting", "applying org policy", {
|
|
1113
|
+
policy,
|
|
1114
|
+
// Per asset because Zyfai stores splitting under assetTypeSettings[asset].
|
|
1115
|
+
assets: SPLITTING_ASSETS
|
|
1116
|
+
});
|
|
1117
|
+
await Promise.all(
|
|
1118
|
+
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1119
|
+
);
|
|
1120
|
+
if (policy.poolPolicy) {
|
|
1121
|
+
await this.applyPoolPolicy(policy.poolPolicy);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
async applySplitting(asset, policy) {
|
|
1125
|
+
try {
|
|
1126
|
+
const desired = toZyfaiSplitting(policy);
|
|
1127
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1128
|
+
const currentSplitting = {
|
|
1129
|
+
splitting: current?.splitting,
|
|
1130
|
+
minSplits: current?.minSplits
|
|
1131
|
+
};
|
|
1132
|
+
const needsUpdate = splittingNeedsUpdate(current, desired);
|
|
1133
|
+
debugLog("zyfai:splitting", `${asset}: comparing`, {
|
|
1134
|
+
mode: policy.splittingMode,
|
|
1135
|
+
current: currentSplitting,
|
|
1136
|
+
desired,
|
|
1137
|
+
// Spelled out because the "why" is the non-obvious part: minSplits is
|
|
1138
|
+
// what separates automatic (1) from force (2-4), not `splitting`.
|
|
1139
|
+
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1140
|
+
});
|
|
1141
|
+
if (!needsUpdate) return;
|
|
1142
|
+
const result = await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1143
|
+
debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
|
|
1144
|
+
sent: { asset, ...desired },
|
|
1145
|
+
// updateUserProfile re-reads the profile after PATCHing, so this is
|
|
1146
|
+
// Zyfai's own view of the result rather than an echo of what we sent.
|
|
1147
|
+
zyfaiNowReports: {
|
|
1148
|
+
splitting: result?.splitting,
|
|
1149
|
+
minSplits: result?.minSplits
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
console.warn(
|
|
1154
|
+
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1155
|
+
error instanceof Error ? error.message : String(error)
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Apply the org's protocol/pool policy to this user's Zyfai profile.
|
|
1161
|
+
*
|
|
1162
|
+
* Two Zyfai writes, in a strict order:
|
|
1163
|
+
* 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
|
|
1164
|
+
* the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
|
|
1165
|
+
* 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
|
|
1166
|
+
* pool narrowing.
|
|
1167
|
+
*
|
|
1168
|
+
* Order matters: constraining a protocol's pools (step 2) while that
|
|
1169
|
+
* protocol is not yet in the allow-list (step 1 not yet applied) lands the
|
|
1170
|
+
* constraint on something the rebalance engine isn't considering.
|
|
1171
|
+
*
|
|
1172
|
+
* Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
|
|
1173
|
+
* connecting, so a Zyfai hiccup must leave the user connected with their
|
|
1174
|
+
* profile unchanged, never fail activation.
|
|
1175
|
+
*/
|
|
1176
|
+
async applyPoolPolicy(policy) {
|
|
1177
|
+
try {
|
|
1178
|
+
const { protocols: universe } = await this.sdk.getAvailableProtocols(
|
|
1179
|
+
this.supportedChainIds[0]
|
|
1180
|
+
);
|
|
1181
|
+
const universeIds = universe.map((p) => p.id);
|
|
1182
|
+
const chainsByProtocol = buildChainsByProtocol(
|
|
1183
|
+
universe,
|
|
1184
|
+
POOL_POLICY_CHAIN_IDS
|
|
1185
|
+
);
|
|
1186
|
+
debugLog("zyfai:pools", "protocol universe", {
|
|
1187
|
+
universeIds,
|
|
1188
|
+
chainsByProtocol
|
|
1189
|
+
});
|
|
1190
|
+
let strategy;
|
|
1191
|
+
const desiredProtocols = deriveProtocols(
|
|
1192
|
+
policy,
|
|
1193
|
+
universeIds,
|
|
1194
|
+
chainsByProtocol
|
|
1195
|
+
);
|
|
1196
|
+
const desiredAutoSelect = policy.autoApproveProtocols;
|
|
1197
|
+
for (const asset of SPLITTING_ASSETS) {
|
|
1198
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1199
|
+
if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
|
|
1200
|
+
strategy = current.strategy;
|
|
1201
|
+
}
|
|
1202
|
+
const needsUpdate = protocolsPolicyNeedsUpdate(
|
|
1203
|
+
current,
|
|
1204
|
+
desiredProtocols,
|
|
1205
|
+
desiredAutoSelect
|
|
1206
|
+
);
|
|
1207
|
+
debugLog("zyfai:pools", `${asset}: comparing protocols`, {
|
|
1208
|
+
current: {
|
|
1209
|
+
protocols: current.protocols,
|
|
1210
|
+
autoSelectProtocols: current.autoSelectProtocols
|
|
1211
|
+
},
|
|
1212
|
+
desired: {
|
|
1213
|
+
protocols: desiredProtocols,
|
|
1214
|
+
autoSelectProtocols: desiredAutoSelect
|
|
1215
|
+
},
|
|
1216
|
+
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1217
|
+
});
|
|
1218
|
+
if (!needsUpdate) continue;
|
|
1219
|
+
const update = {
|
|
1220
|
+
asset,
|
|
1221
|
+
autoSelectProtocols: desiredAutoSelect
|
|
1222
|
+
};
|
|
1223
|
+
if (desiredProtocols !== null) update.protocols = desiredProtocols;
|
|
1224
|
+
await this.sdk.updateUserProfile(update);
|
|
1225
|
+
debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
|
|
1226
|
+
}
|
|
1227
|
+
const poolResults = await Promise.all(
|
|
1228
|
+
universe.map(async (protocol) => {
|
|
1229
|
+
try {
|
|
1230
|
+
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1231
|
+
return [protocol.id, flattenAvailablePools(raw)];
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
console.warn(
|
|
1234
|
+
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
1235
|
+
error instanceof Error ? error.message : String(error)
|
|
1236
|
+
);
|
|
1237
|
+
return null;
|
|
1238
|
+
}
|
|
1239
|
+
})
|
|
1240
|
+
);
|
|
1241
|
+
const availableByProtocol = /* @__PURE__ */ new Map();
|
|
1242
|
+
for (const result of poolResults) {
|
|
1243
|
+
if (result) availableByProtocol.set(result[0], result[1]);
|
|
1244
|
+
}
|
|
1245
|
+
const customizations = toZyfaiCustomizations(
|
|
1246
|
+
policy,
|
|
1247
|
+
availableByProtocol,
|
|
1248
|
+
chainsByProtocol
|
|
1249
|
+
);
|
|
1250
|
+
debugLog("zyfai:pools", "derived customizeBatch payload", {
|
|
1251
|
+
strategy,
|
|
1252
|
+
availableProtocolCount: availableByProtocol.size,
|
|
1253
|
+
customizations
|
|
1254
|
+
});
|
|
1255
|
+
if (customizations.length === 0) {
|
|
1256
|
+
debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
await this.sdk.customizeBatch(customizations);
|
|
1260
|
+
debugLog("zyfai:pools", "wrote customizeBatch", {
|
|
1261
|
+
count: customizations.length
|
|
1262
|
+
});
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
console.warn(
|
|
1265
|
+
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
1266
|
+
error instanceof Error ? error.message : String(error)
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
953
1270
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
954
1271
|
try {
|
|
955
1272
|
const validChainId = isValidChainId(chainId);
|
|
@@ -1070,6 +1387,16 @@ var ZyfaiAgent = class {
|
|
|
1070
1387
|
async getUserProfile(state, chainId) {
|
|
1071
1388
|
await this.connectAuth(state, chainId);
|
|
1072
1389
|
const raw = await this.sdk.getUserDetails();
|
|
1390
|
+
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1391
|
+
asset: "USDC (default \u2014 no asset passed)",
|
|
1392
|
+
splitting: raw.splitting,
|
|
1393
|
+
minSplits: raw.minSplits,
|
|
1394
|
+
strategy: raw.strategy,
|
|
1395
|
+
chains: raw.chains,
|
|
1396
|
+
protocolCount: raw.protocols?.length,
|
|
1397
|
+
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
1398
|
+
smartWallet: raw.smartWallet
|
|
1399
|
+
});
|
|
1073
1400
|
return mapUserProfile(raw, this.connectedAddress);
|
|
1074
1401
|
}
|
|
1075
1402
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
@@ -1102,6 +1429,40 @@ var ZyfaiAgent = class {
|
|
|
1102
1429
|
|
|
1103
1430
|
// src/lib/routing-api.ts
|
|
1104
1431
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1432
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1433
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1434
|
+
try {
|
|
1435
|
+
const res = await fetch(url, {
|
|
1436
|
+
method: "GET",
|
|
1437
|
+
headers: {
|
|
1438
|
+
"Content-Type": "application/json",
|
|
1439
|
+
"x-owney-api-key": `${apiKey}`
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
if (!res.ok) {
|
|
1443
|
+
if (res.status !== 404) {
|
|
1444
|
+
console.warn(
|
|
1445
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
const json = await res.json();
|
|
1451
|
+
const policy = json.success ? json.data ?? null : null;
|
|
1452
|
+
debugLog(
|
|
1453
|
+
"owney-sdk",
|
|
1454
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
1455
|
+
policy ?? void 0
|
|
1456
|
+
);
|
|
1457
|
+
return policy;
|
|
1458
|
+
} catch (error) {
|
|
1459
|
+
console.warn(
|
|
1460
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1461
|
+
error instanceof Error ? error.message : String(error)
|
|
1462
|
+
);
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1105
1466
|
async function fetchAgentKeys(apiKey) {
|
|
1106
1467
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1107
1468
|
const res = await fetch(url, {
|
|
@@ -1719,6 +2080,12 @@ var OwneySDK = class {
|
|
|
1719
2080
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
1720
2081
|
state = null;
|
|
1721
2082
|
apiKey;
|
|
2083
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
2084
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
2085
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
2086
|
+
// leave every user's agent profile alone.
|
|
2087
|
+
orgAgentConfig;
|
|
2088
|
+
orgAgentConfigPromise = null;
|
|
1722
2089
|
zyfaiRpcUrls;
|
|
1723
2090
|
routingApiBaseUrl;
|
|
1724
2091
|
referralSource;
|
|
@@ -1727,6 +2094,7 @@ var OwneySDK = class {
|
|
|
1727
2094
|
initializingAgentsPromise = null;
|
|
1728
2095
|
constructor(config) {
|
|
1729
2096
|
this.apiKey = config.apiKey;
|
|
2097
|
+
if (config.debug) setOwneyDebug(true);
|
|
1730
2098
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
1731
2099
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
1732
2100
|
this.referralSource = config.referralSource;
|
|
@@ -1888,14 +2256,57 @@ var OwneySDK = class {
|
|
|
1888
2256
|
}
|
|
1889
2257
|
return active;
|
|
1890
2258
|
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2261
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2262
|
+
*/
|
|
2263
|
+
async getOrgAgentConfig() {
|
|
2264
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2265
|
+
if (!this.orgAgentConfigPromise) {
|
|
2266
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2267
|
+
(config) => {
|
|
2268
|
+
this.orgAgentConfig = config;
|
|
2269
|
+
return config;
|
|
2270
|
+
}
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
return this.orgAgentConfigPromise;
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2277
|
+
*
|
|
2278
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2279
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2280
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2281
|
+
* user's connect over.
|
|
2282
|
+
*/
|
|
2283
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2284
|
+
if (!agent.applyOrgPolicy) {
|
|
2285
|
+
debugLog(
|
|
2286
|
+
"owney-sdk",
|
|
2287
|
+
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2288
|
+
);
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
try {
|
|
2292
|
+
const policy = await this.getOrgAgentConfig();
|
|
2293
|
+
if (!policy) return;
|
|
2294
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2295
|
+
} catch (error) {
|
|
2296
|
+
console.warn(
|
|
2297
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2298
|
+
error instanceof Error ? error.message : String(error)
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
1891
2302
|
async ensureAgentsInitialized() {
|
|
1892
2303
|
if (this.agents.size > 0) return;
|
|
1893
2304
|
if (!this.initializingAgentsPromise) {
|
|
1894
2305
|
this.initializingAgentsPromise = (async () => {
|
|
1895
2306
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1896
2307
|
this.disabledAgents.clear();
|
|
1897
|
-
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
1898
|
-
const agent = this.createAgent(agent_type,
|
|
2308
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2309
|
+
const agent = this.createAgent(agent_type, key2);
|
|
1899
2310
|
if (!agent) continue;
|
|
1900
2311
|
this.agents.set(agent_type, agent);
|
|
1901
2312
|
if (is_enabled === false) {
|
|
@@ -1916,9 +2327,9 @@ var OwneySDK = class {
|
|
|
1916
2327
|
this.initializingAgentsPromise = null;
|
|
1917
2328
|
}
|
|
1918
2329
|
}
|
|
1919
|
-
createAgent(agentId,
|
|
2330
|
+
createAgent(agentId, key2) {
|
|
1920
2331
|
if (agentId === "zyfai") {
|
|
1921
|
-
return new ZyfaiAgent(
|
|
2332
|
+
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
1922
2333
|
}
|
|
1923
2334
|
return null;
|
|
1924
2335
|
}
|
|
@@ -1972,6 +2383,7 @@ var OwneySDK = class {
|
|
|
1972
2383
|
Promise.all(
|
|
1973
2384
|
agents.map(async (agent) => {
|
|
1974
2385
|
await agent.activateAgent(state, chainId);
|
|
2386
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
1975
2387
|
})
|
|
1976
2388
|
).catch((error) => {
|
|
1977
2389
|
console.error("activateAgent background init failed:", error);
|
|
@@ -1999,6 +2411,7 @@ var OwneySDK = class {
|
|
|
1999
2411
|
Promise.all(
|
|
2000
2412
|
enabledCompatible.map(async (agent) => {
|
|
2001
2413
|
await agent.activateAgent(state, chainId);
|
|
2414
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2002
2415
|
})
|
|
2003
2416
|
).catch((error) => {
|
|
2004
2417
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2813,22 +3226,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
2813
3226
|
const legacyKeys = [];
|
|
2814
3227
|
try {
|
|
2815
3228
|
for (let i = 0; i < store.length; i++) {
|
|
2816
|
-
const
|
|
2817
|
-
if (
|
|
3229
|
+
const key2 = store.key(i);
|
|
3230
|
+
if (key2?.startsWith(prefix)) legacyKeys.push(key2);
|
|
2818
3231
|
}
|
|
2819
3232
|
} catch {
|
|
2820
3233
|
return null;
|
|
2821
3234
|
}
|
|
2822
3235
|
let adopted = null;
|
|
2823
|
-
for (const
|
|
3236
|
+
for (const key2 of legacyKeys) {
|
|
2824
3237
|
if (!adopted) {
|
|
2825
3238
|
try {
|
|
2826
|
-
adopted = JSON.parse(store.getItem(
|
|
3239
|
+
adopted = JSON.parse(store.getItem(key2) ?? "");
|
|
2827
3240
|
} catch {
|
|
2828
3241
|
}
|
|
2829
3242
|
}
|
|
2830
3243
|
try {
|
|
2831
|
-
store.removeItem(
|
|
3244
|
+
store.removeItem(key2);
|
|
2832
3245
|
} catch {
|
|
2833
3246
|
}
|
|
2834
3247
|
}
|
|
@@ -2836,11 +3249,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
2836
3249
|
};
|
|
2837
3250
|
var readSiwxSession = (address, chainId) => {
|
|
2838
3251
|
if (typeof window === "undefined") return null;
|
|
2839
|
-
const
|
|
3252
|
+
const key2 = buildKey2(address);
|
|
2840
3253
|
const store = storage2();
|
|
2841
3254
|
let raw = null;
|
|
2842
3255
|
try {
|
|
2843
|
-
raw = store?.getItem(
|
|
3256
|
+
raw = store?.getItem(key2) ?? null;
|
|
2844
3257
|
} catch {
|
|
2845
3258
|
raw = null;
|
|
2846
3259
|
}
|
|
@@ -2848,9 +3261,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
2848
3261
|
try {
|
|
2849
3262
|
return JSON.parse(raw);
|
|
2850
3263
|
} catch {
|
|
2851
|
-
memorySiwxSessions.delete(
|
|
3264
|
+
memorySiwxSessions.delete(key2);
|
|
2852
3265
|
try {
|
|
2853
|
-
store?.removeItem(
|
|
3266
|
+
store?.removeItem(key2);
|
|
2854
3267
|
} catch {
|
|
2855
3268
|
}
|
|
2856
3269
|
return null;
|
|
@@ -2861,24 +3274,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
2861
3274
|
writeSiwxSession(address, chainId, legacy);
|
|
2862
3275
|
return legacy;
|
|
2863
3276
|
}
|
|
2864
|
-
return memorySiwxSessions.get(
|
|
3277
|
+
return memorySiwxSessions.get(key2) ?? null;
|
|
2865
3278
|
};
|
|
2866
3279
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
2867
3280
|
if (typeof window === "undefined") return;
|
|
2868
|
-
const
|
|
2869
|
-
memorySiwxSessions.set(
|
|
3281
|
+
const key2 = buildKey2(address);
|
|
3282
|
+
memorySiwxSessions.set(key2, session);
|
|
2870
3283
|
const store = storage2();
|
|
2871
3284
|
try {
|
|
2872
|
-
store?.setItem(
|
|
3285
|
+
store?.setItem(key2, JSON.stringify(session));
|
|
2873
3286
|
} catch {
|
|
2874
3287
|
}
|
|
2875
3288
|
};
|
|
2876
3289
|
var clearSiwxSession = (address, _chainId) => {
|
|
2877
|
-
const
|
|
2878
|
-
memorySiwxSessions.delete(
|
|
3290
|
+
const key2 = buildKey2(address);
|
|
3291
|
+
memorySiwxSessions.delete(key2);
|
|
2879
3292
|
const store = storage2();
|
|
2880
3293
|
try {
|
|
2881
|
-
store?.removeItem(
|
|
3294
|
+
store?.removeItem(key2);
|
|
2882
3295
|
} catch {
|
|
2883
3296
|
}
|
|
2884
3297
|
readLegacySiwxSession(store, address);
|
|
@@ -3007,5 +3420,6 @@ export {
|
|
|
3007
3420
|
NotConnectedError,
|
|
3008
3421
|
OwneyError,
|
|
3009
3422
|
OwneySDK,
|
|
3010
|
-
createOwneySIWX
|
|
3423
|
+
createOwneySIWX,
|
|
3424
|
+
setOwneyDebug
|
|
3011
3425
|
};
|