@owney/sdk 0.6.9-beta.0 → 0.6.9-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +239 -606
- package/dist/index.d.cts +41 -19
- package/dist/index.d.ts +41 -19
- package/dist/index.js +224 -101
- package/package.json +1 -3
- package/dist/chunk-GMNQBWUB.js +0 -55
- package/dist/surfliquid.agent-OMOYXWLP.js +0 -385
package/dist/index.cjs
CHANGED
|
@@ -3,14 +3,6 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __esm = (fn, res, err) => function __init() {
|
|
7
|
-
if (err) throw err[0];
|
|
8
|
-
try {
|
|
9
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
-
} catch (e) {
|
|
11
|
-
throw err = [e], e;
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
6
|
var __export = (target, all) => {
|
|
15
7
|
for (var name in all)
|
|
16
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -25,478 +17,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
25
17
|
};
|
|
26
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
19
|
|
|
28
|
-
// src/errors.ts
|
|
29
|
-
var OwneyError, AgentNotFoundError, NotConnectedError, AgentChainIncompatibleError;
|
|
30
|
-
var init_errors = __esm({
|
|
31
|
-
"src/errors.ts"() {
|
|
32
|
-
"use strict";
|
|
33
|
-
OwneyError = class extends Error {
|
|
34
|
-
code;
|
|
35
|
-
details;
|
|
36
|
-
agentId;
|
|
37
|
-
constructor(code, message, details, agentId) {
|
|
38
|
-
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
39
|
-
super(`${prefix} ${message}`);
|
|
40
|
-
this.name = "OwneyError";
|
|
41
|
-
this.code = code;
|
|
42
|
-
this.details = details;
|
|
43
|
-
this.agentId = agentId;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
AgentNotFoundError = class extends OwneyError {
|
|
47
|
-
constructor(agentId, available) {
|
|
48
|
-
super(
|
|
49
|
-
"AGENT_NOT_FOUND",
|
|
50
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
51
|
-
{ agentId, available },
|
|
52
|
-
agentId
|
|
53
|
-
);
|
|
54
|
-
this.name = "AgentNotFoundError";
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
NotConnectedError = class extends OwneyError {
|
|
58
|
-
constructor() {
|
|
59
|
-
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
60
|
-
this.name = "NotConnectedError";
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
AgentChainIncompatibleError = class extends OwneyError {
|
|
64
|
-
incompatibleAgents;
|
|
65
|
-
connectedChainId;
|
|
66
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
67
|
-
const details = incompatibleAgents.map(
|
|
68
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
69
|
-
).join("; ");
|
|
70
|
-
super(
|
|
71
|
-
"AGENT_CHAIN_INCOMPATIBLE",
|
|
72
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
73
|
-
{ incompatibleAgents, connectedChainId }
|
|
74
|
-
);
|
|
75
|
-
this.name = "AgentChainIncompatibleError";
|
|
76
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
77
|
-
this.connectedChainId = connectedChainId;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// src/agents/surfliquid/surfliquid.constants.ts
|
|
84
|
-
var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
|
|
85
|
-
var init_surfliquid_constants = __esm({
|
|
86
|
-
"src/agents/surfliquid/surfliquid.constants.ts"() {
|
|
87
|
-
"use strict";
|
|
88
|
-
SURFLIQUID_CHAIN_ID = 8453;
|
|
89
|
-
SURFLIQUID_CHAIN_NAME = "BASE";
|
|
90
|
-
SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
91
|
-
SURFLIQUID_USDC_DECIMALS = 6;
|
|
92
|
-
SURFLIQUID_MIN_DEPOSIT = "0";
|
|
93
|
-
SURFLIQUID_SUPPORTED_ASSETS = [
|
|
94
|
-
{
|
|
95
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
96
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
97
|
-
assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
|
|
98
|
-
}
|
|
99
|
-
];
|
|
100
|
-
SURFLIQUID_ACTION_MAP = {
|
|
101
|
-
// INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
|
|
102
|
-
// other funding ("Top up"). The mini-app intentionally hides the "Deposit"
|
|
103
|
-
// action (it marks Zyfai's smart-account-creation event), which would
|
|
104
|
-
// otherwise drop a SurfLiquid user's only history row.
|
|
105
|
-
INITIAL_DEPOSIT: "Top up",
|
|
106
|
-
DEPOSIT: "Top up",
|
|
107
|
-
USER_DEPOSIT: "Top up",
|
|
108
|
-
WITHDRAWAL: "Withdraw",
|
|
109
|
-
USER_WITHDRAWAL: "Withdraw",
|
|
110
|
-
REBALANCE: "Rebalance",
|
|
111
|
-
REBALANCE_COMPLETED: "Rebalance",
|
|
112
|
-
CROSS_CHAIN_REBALANCE: "Rebalance",
|
|
113
|
-
MERKL_CLAIM: "Earned"
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// src/agents/surfliquid/surfliquid.mapper.ts
|
|
119
|
-
function mapMessage(message) {
|
|
120
|
-
const action = SURFLIQUID_ACTION_MAP[message.transactionType];
|
|
121
|
-
if (!action) return null;
|
|
122
|
-
return {
|
|
123
|
-
agent: "surfliquid",
|
|
124
|
-
action,
|
|
125
|
-
date: message.timestamp,
|
|
126
|
-
oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
|
|
127
|
-
newApy: message.apyAfter != null ? String(message.apyAfter) : null,
|
|
128
|
-
transactions: [
|
|
129
|
-
{
|
|
130
|
-
txHashes: [message.txHash],
|
|
131
|
-
chainId: message.chainId,
|
|
132
|
-
tokenSymbol: message.token ?? void 0,
|
|
133
|
-
amount: message.amount != null ? String(message.amount) : void 0
|
|
134
|
-
}
|
|
135
|
-
],
|
|
136
|
-
rebalanceLog: []
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function mapHistory(result, _chainId) {
|
|
140
|
-
const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
|
|
141
|
-
const hasMore = result.page < result.pages;
|
|
142
|
-
return {
|
|
143
|
-
data,
|
|
144
|
-
hasMore,
|
|
145
|
-
nextCursor: hasMore ? String(result.page + 1) : void 0
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function mapBalances2(vault, chainId, morphoStats) {
|
|
149
|
-
const assets = (vault.assets ?? []).filter(
|
|
150
|
-
(asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
|
|
151
|
-
);
|
|
152
|
-
const tokens = assets.map((asset) => ({
|
|
153
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
154
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
155
|
-
asset: "USDC",
|
|
156
|
-
amount: String(asset.currentValueUSD)
|
|
157
|
-
}));
|
|
158
|
-
const positions = assets.map((asset) => {
|
|
159
|
-
const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
|
|
160
|
-
return {
|
|
161
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
162
|
-
protocol: "Morpho",
|
|
163
|
-
// The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
|
|
164
|
-
// Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
|
|
165
|
-
pool: stats?.name ?? void 0,
|
|
166
|
-
asset: "USDC",
|
|
167
|
-
amount: String(asset.currentValueUSD),
|
|
168
|
-
apy: asset.currentAPY,
|
|
169
|
-
// TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
|
|
170
|
-
tvl: stats?.tvlUsd,
|
|
171
|
-
liquidity: stats?.liquidityUsd
|
|
172
|
-
};
|
|
173
|
-
});
|
|
174
|
-
const total = assets.reduce(
|
|
175
|
-
(sum, asset) => sum + asset.currentValueUSD,
|
|
176
|
-
0
|
|
177
|
-
);
|
|
178
|
-
return {
|
|
179
|
-
smartWallet: vault.userVaultAddress ?? void 0,
|
|
180
|
-
totalBalance: String(total),
|
|
181
|
-
totalBalanceAsset: "usdc",
|
|
182
|
-
tokens,
|
|
183
|
-
positions
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function mapAccountApy(vault, days) {
|
|
187
|
-
const breakdown = vault.apyBreakdown;
|
|
188
|
-
const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
|
|
189
|
-
const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
|
|
190
|
-
return {
|
|
191
|
-
walletAddress: vault.walletAddress ?? "",
|
|
192
|
-
weightedApyAfterFee: apy,
|
|
193
|
-
apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
|
|
194
|
-
// Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
|
|
195
|
-
history: []
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
function mapEarnings2(vault, vaultAddress) {
|
|
199
|
-
return {
|
|
200
|
-
smartWallet: vaultAddress,
|
|
201
|
-
lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
|
|
202
|
-
tokens: []
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function mapUserProfile2(vault, address) {
|
|
206
|
-
return {
|
|
207
|
-
address,
|
|
208
|
-
smartWallet: vault.userVaultAddress ?? "",
|
|
209
|
-
chains: [SURFLIQUID_CHAIN_ID],
|
|
210
|
-
// SurfLiquid uses cookie-based session auth — no session-key concept.
|
|
211
|
-
hasActiveSessionKey: false,
|
|
212
|
-
protocols: ["SurfLiquid"]
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
var APY_WINDOW_KEY;
|
|
216
|
-
var init_surfliquid_mapper = __esm({
|
|
217
|
-
"src/agents/surfliquid/surfliquid.mapper.ts"() {
|
|
218
|
-
"use strict";
|
|
219
|
-
init_surfliquid_constants();
|
|
220
|
-
APY_WINDOW_KEY = {
|
|
221
|
-
"7D": "apy7d",
|
|
222
|
-
"14D": "apy14d",
|
|
223
|
-
"30D": "apy30d"
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// src/agents/surfliquid/surfliquid.wallet-adapter.ts
|
|
229
|
-
var import_core_sdk, OwneyWalletAdapter;
|
|
230
|
-
var init_surfliquid_wallet_adapter = __esm({
|
|
231
|
-
"src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
|
|
232
|
-
"use strict";
|
|
233
|
-
import_core_sdk = require("@surf_liquid/core-sdk");
|
|
234
|
-
OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
|
|
235
|
-
constructor(eip1193Provider) {
|
|
236
|
-
super();
|
|
237
|
-
this.eip1193Provider = eip1193Provider;
|
|
238
|
-
}
|
|
239
|
-
eip1193Provider;
|
|
240
|
-
name = "owney";
|
|
241
|
-
get installed() {
|
|
242
|
-
return true;
|
|
243
|
-
}
|
|
244
|
-
resolveProvider() {
|
|
245
|
-
return this.eip1193Provider;
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// src/agents/surfliquid/surfliquid.morpho.ts
|
|
252
|
-
async function fetchMorphoVaultStats(vaultAddress, chainId) {
|
|
253
|
-
try {
|
|
254
|
-
const res = await fetch(MORPHO_API_URL, {
|
|
255
|
-
method: "POST",
|
|
256
|
-
headers: { "Content-Type": "application/json" },
|
|
257
|
-
body: JSON.stringify({
|
|
258
|
-
query: VAULT_STATS_QUERY,
|
|
259
|
-
variables: { address: vaultAddress, chainId }
|
|
260
|
-
})
|
|
261
|
-
});
|
|
262
|
-
if (!res.ok) return null;
|
|
263
|
-
const json = await res.json();
|
|
264
|
-
if (json.errors) return null;
|
|
265
|
-
const vault = json.data?.vaultByAddress;
|
|
266
|
-
const tvlUsd = vault?.state?.totalAssetsUsd;
|
|
267
|
-
const liquidityUsd = vault?.liquidity?.usd;
|
|
268
|
-
if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
const name = typeof vault?.name === "string" ? vault.name : null;
|
|
272
|
-
return { name, tvlUsd, liquidityUsd };
|
|
273
|
-
} catch (error) {
|
|
274
|
-
console.warn("surfliquid: Morpho vault stats fetch failed", {
|
|
275
|
-
vaultAddress,
|
|
276
|
-
chainId,
|
|
277
|
-
error
|
|
278
|
-
});
|
|
279
|
-
return null;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
|
|
283
|
-
const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
|
|
284
|
-
const entries = await Promise.all(
|
|
285
|
-
unique.map(
|
|
286
|
-
async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
|
|
287
|
-
)
|
|
288
|
-
);
|
|
289
|
-
const byVault = /* @__PURE__ */ new Map();
|
|
290
|
-
for (const [address, stats] of entries) {
|
|
291
|
-
if (stats) byVault.set(address, stats);
|
|
292
|
-
}
|
|
293
|
-
return byVault;
|
|
294
|
-
}
|
|
295
|
-
var MORPHO_API_URL, VAULT_STATS_QUERY;
|
|
296
|
-
var init_surfliquid_morpho = __esm({
|
|
297
|
-
"src/agents/surfliquid/surfliquid.morpho.ts"() {
|
|
298
|
-
"use strict";
|
|
299
|
-
MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
300
|
-
VAULT_STATS_QUERY = `
|
|
301
|
-
query VaultStats($address: String!, $chainId: Int!) {
|
|
302
|
-
vaultByAddress(address: $address, chainId: $chainId) {
|
|
303
|
-
name
|
|
304
|
-
state { totalAssetsUsd }
|
|
305
|
-
liquidity { usd }
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
`;
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// src/agents/surfliquid/surfliquid.agent.ts
|
|
313
|
-
var surfliquid_agent_exports = {};
|
|
314
|
-
__export(surfliquid_agent_exports, {
|
|
315
|
-
SurfLiquidAgent: () => SurfLiquidAgent
|
|
316
|
-
});
|
|
317
|
-
var import_core_sdk2, import_viem5, APY_WINDOW_KEY2, SurfLiquidAgent;
|
|
318
|
-
var init_surfliquid_agent = __esm({
|
|
319
|
-
"src/agents/surfliquid/surfliquid.agent.ts"() {
|
|
320
|
-
"use strict";
|
|
321
|
-
import_core_sdk2 = require("@surf_liquid/core-sdk");
|
|
322
|
-
import_viem5 = require("viem");
|
|
323
|
-
init_errors();
|
|
324
|
-
init_surfliquid_constants();
|
|
325
|
-
init_surfliquid_mapper();
|
|
326
|
-
init_surfliquid_wallet_adapter();
|
|
327
|
-
init_surfliquid_morpho();
|
|
328
|
-
APY_WINDOW_KEY2 = {
|
|
329
|
-
"7D": "apy7d",
|
|
330
|
-
"14D": "apy14d",
|
|
331
|
-
"30D": "apy30d"
|
|
332
|
-
};
|
|
333
|
-
SurfLiquidAgent = class {
|
|
334
|
-
constructor(config) {
|
|
335
|
-
this.config = config;
|
|
336
|
-
}
|
|
337
|
-
config;
|
|
338
|
-
id = "surfliquid";
|
|
339
|
-
supportedChainIds = [SURFLIQUID_CHAIN_ID];
|
|
340
|
-
supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
|
|
341
|
-
surf = null;
|
|
342
|
-
connectedAddress = null;
|
|
343
|
-
// In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
|
|
344
|
-
connectPromise = null;
|
|
345
|
-
ensureSurf() {
|
|
346
|
-
if (this.surf) return this.surf;
|
|
347
|
-
this.surf = import_core_sdk2.SurfClient.create({
|
|
348
|
-
projectName: this.config.projectName,
|
|
349
|
-
appId: this.config.appId,
|
|
350
|
-
environment: "mainnet",
|
|
351
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
352
|
-
apiBaseUrl: this.config.apiBaseUrl,
|
|
353
|
-
rpcUrl: this.config.rpcUrl,
|
|
354
|
-
// Let the SDK auto-approve USDC to the vault before depositing.
|
|
355
|
-
autoApprove: true
|
|
356
|
-
});
|
|
357
|
-
return this.surf;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Connects + authenticates the SurfClient against owney's provider. Skips the
|
|
361
|
-
* SIWE prompt when already authenticated for this wallet (cookie session).
|
|
362
|
-
*/
|
|
363
|
-
async connect(state) {
|
|
364
|
-
const surf = this.ensureSurf();
|
|
365
|
-
const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
|
|
366
|
-
if (sameWallet && surf.getAuthState().authenticated) {
|
|
367
|
-
return surf;
|
|
368
|
-
}
|
|
369
|
-
if (this.connectPromise) return this.connectPromise;
|
|
370
|
-
this.connectPromise = (async () => {
|
|
371
|
-
surf.registerWalletAdapter(
|
|
372
|
-
"owney",
|
|
373
|
-
new OwneyWalletAdapter(state.provider)
|
|
374
|
-
);
|
|
375
|
-
await surf.connectWallet("owney");
|
|
376
|
-
await surf.authenticate();
|
|
377
|
-
this.connectedAddress = state.walletAddress;
|
|
378
|
-
return surf;
|
|
379
|
-
})();
|
|
380
|
-
try {
|
|
381
|
-
return await this.connectPromise;
|
|
382
|
-
} finally {
|
|
383
|
-
this.connectPromise = null;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Returns the user's vault address, deploying one on first use. SurfLiquid's
|
|
388
|
-
* deposit requires the vault to exist, so this must run before depositing.
|
|
389
|
-
* Existing vault → returned as-is; otherwise `deployVault()` is sent
|
|
390
|
-
* (user-pays) and the freshly deployed address is returned.
|
|
391
|
-
*/
|
|
392
|
-
async resolveVaultAddress(surf, owner) {
|
|
393
|
-
const vault = await surf.getVault(owner).catch(() => null);
|
|
394
|
-
if (vault?.exists && vault.userVaultAddress) {
|
|
395
|
-
return vault.userVaultAddress;
|
|
396
|
-
}
|
|
397
|
-
const { vaultAddress } = await surf.deployVault();
|
|
398
|
-
return vaultAddress;
|
|
399
|
-
}
|
|
400
|
-
// --- IAgent: lifecycle ---
|
|
401
|
-
async disconnect() {
|
|
402
|
-
if (this.surf) {
|
|
403
|
-
await this.surf.disconnectWallet();
|
|
404
|
-
}
|
|
405
|
-
this.connectedAddress = null;
|
|
406
|
-
}
|
|
407
|
-
async activateAgent(state) {
|
|
408
|
-
await this.connect(state);
|
|
409
|
-
}
|
|
410
|
-
// --- IAgent: funds (user-pays; asset is always USDC, callback ignored) ---
|
|
411
|
-
async deposit(state, _chainId, amount, _asset, _depositCallback) {
|
|
412
|
-
const surf = await this.connect(state);
|
|
413
|
-
const human = (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
|
|
414
|
-
const smartWallet = await this.resolveVaultAddress(
|
|
415
|
-
surf,
|
|
416
|
-
state.walletAddress
|
|
417
|
-
);
|
|
418
|
-
const tx = await surf.deposit({
|
|
419
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
420
|
-
amount: human
|
|
421
|
-
});
|
|
422
|
-
await tx.wait();
|
|
423
|
-
return { txHash: tx.hash, smartWallet, amount };
|
|
424
|
-
}
|
|
425
|
-
async withdraw(state, _chainId, _token, amount) {
|
|
426
|
-
const surf = await this.connect(state);
|
|
427
|
-
const human = amount != null ? (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
|
|
428
|
-
try {
|
|
429
|
-
const tx = await surf.withdraw({
|
|
430
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
431
|
-
amount: human
|
|
432
|
-
});
|
|
433
|
-
await tx.wait();
|
|
434
|
-
return {
|
|
435
|
-
txHash: tx.hash,
|
|
436
|
-
type: amount != null ? "partial" : "full",
|
|
437
|
-
amount: amount ?? "0"
|
|
438
|
-
};
|
|
439
|
-
} catch (error) {
|
|
440
|
-
throw new OwneyError(
|
|
441
|
-
"WITHDRAW_FAILED",
|
|
442
|
-
error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
|
|
443
|
-
{ chainId: SURFLIQUID_CHAIN_ID, amount },
|
|
444
|
-
this.id
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
// --- IAgent: portfolio reads ---
|
|
449
|
-
async getBalances(state, chainId) {
|
|
450
|
-
const surf = await this.connect(state);
|
|
451
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
452
|
-
const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
|
|
453
|
-
const morphoStats = await fetchMorphoStatsByVault(
|
|
454
|
-
morphoVaultAddresses,
|
|
455
|
-
chainId
|
|
456
|
-
);
|
|
457
|
-
return mapBalances2(vault, chainId, morphoStats);
|
|
458
|
-
}
|
|
459
|
-
async getEarnings(state) {
|
|
460
|
-
const surf = await this.connect(state);
|
|
461
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
462
|
-
return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
|
|
463
|
-
}
|
|
464
|
-
async getAccountApy(state, _chainId, days, _tokenSymbol) {
|
|
465
|
-
const surf = await this.connect(state);
|
|
466
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
467
|
-
return mapAccountApy(vault, days);
|
|
468
|
-
}
|
|
469
|
-
async getHistory(state, chainId, options) {
|
|
470
|
-
const surf = await this.connect(state);
|
|
471
|
-
const page = options?.cursor ? Number(options.cursor) : 1;
|
|
472
|
-
const limit = options?.limit ?? 10;
|
|
473
|
-
const result = await surf.getAgentMessages(
|
|
474
|
-
state.walletAddress,
|
|
475
|
-
page,
|
|
476
|
-
limit,
|
|
477
|
-
options?.fromDate,
|
|
478
|
-
options?.toDate
|
|
479
|
-
);
|
|
480
|
-
return mapHistory(result, chainId);
|
|
481
|
-
}
|
|
482
|
-
async getUserProfile(state) {
|
|
483
|
-
const surf = await this.connect(state);
|
|
484
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
485
|
-
return mapUserProfile2(vault, state.walletAddress);
|
|
486
|
-
}
|
|
487
|
-
// --- IAgent: discovery (no wallet) ---
|
|
488
|
-
async getAgentApy(days, _options) {
|
|
489
|
-
const surf = this.ensureSurf();
|
|
490
|
-
const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
|
|
491
|
-
const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
|
|
492
|
-
if (!usdc) return { averageApy: 0 };
|
|
493
|
-
const windowed = usdc[APY_WINDOW_KEY2[days]];
|
|
494
|
-
return { averageApy: windowed != null ? windowed : usdc.currentAPY };
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
|
|
500
20
|
// src/index.ts
|
|
501
21
|
var index_exports = {};
|
|
502
22
|
__export(index_exports, {
|
|
@@ -568,8 +88,56 @@ var SupportedAssets = [
|
|
|
568
88
|
}
|
|
569
89
|
];
|
|
570
90
|
|
|
91
|
+
// src/errors.ts
|
|
92
|
+
var OwneyError = class extends Error {
|
|
93
|
+
code;
|
|
94
|
+
details;
|
|
95
|
+
agentId;
|
|
96
|
+
constructor(code, message, details, agentId) {
|
|
97
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
98
|
+
super(`${prefix} ${message}`);
|
|
99
|
+
this.name = "OwneyError";
|
|
100
|
+
this.code = code;
|
|
101
|
+
this.details = details;
|
|
102
|
+
this.agentId = agentId;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
106
|
+
constructor(agentId, available) {
|
|
107
|
+
super(
|
|
108
|
+
"AGENT_NOT_FOUND",
|
|
109
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
110
|
+
{ agentId, available },
|
|
111
|
+
agentId
|
|
112
|
+
);
|
|
113
|
+
this.name = "AgentNotFoundError";
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var NotConnectedError = class extends OwneyError {
|
|
117
|
+
constructor() {
|
|
118
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
119
|
+
this.name = "NotConnectedError";
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
123
|
+
incompatibleAgents;
|
|
124
|
+
connectedChainId;
|
|
125
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
126
|
+
const details = incompatibleAgents.map(
|
|
127
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
128
|
+
).join("; ");
|
|
129
|
+
super(
|
|
130
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
131
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
132
|
+
{ incompatibleAgents, connectedChainId }
|
|
133
|
+
);
|
|
134
|
+
this.name = "AgentChainIncompatibleError";
|
|
135
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
136
|
+
this.connectedChainId = connectedChainId;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
571
140
|
// src/lib/utils.ts
|
|
572
|
-
init_errors();
|
|
573
141
|
var isValidChainId = (chainId) => {
|
|
574
142
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
575
143
|
throw new OwneyError(
|
|
@@ -643,46 +211,46 @@ function resolveChainId(chain) {
|
|
|
643
211
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
644
212
|
const portfolio = raw.portfolio;
|
|
645
213
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
646
|
-
const rawPositions = portfolio.positions ?? [];
|
|
647
|
-
const detailByKey = /* @__PURE__ */ new Map();
|
|
648
|
-
for (const p of rawPositions) {
|
|
649
|
-
const cid = resolveChainId(p.chain ?? "");
|
|
650
|
-
const symbol = (p.token_symbol ?? "").toUpperCase();
|
|
651
|
-
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
652
|
-
}
|
|
653
214
|
let totalBalance = 0;
|
|
654
215
|
const tokens = [];
|
|
655
|
-
const positions = [];
|
|
656
216
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
657
217
|
const positionChainId = Number(chainIdKey);
|
|
658
|
-
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
659
218
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
660
219
|
tokensBySymbol ?? {}
|
|
661
220
|
)) {
|
|
662
|
-
const amount = hexToDecimal(balance || "0",
|
|
221
|
+
const amount = hexToDecimal(balance || "0", decimals);
|
|
663
222
|
totalBalance += amount;
|
|
664
223
|
tokens.push({
|
|
665
|
-
chain:
|
|
224
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
666
225
|
chainId: positionChainId,
|
|
667
226
|
asset: symbol,
|
|
668
227
|
amount: String(amount)
|
|
669
228
|
});
|
|
670
|
-
const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
|
|
671
|
-
positions.push({
|
|
672
|
-
chain: chainName,
|
|
673
|
-
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
674
|
-
protocolId: detail?.protocol_id,
|
|
675
|
-
pool: detail?.pool,
|
|
676
|
-
asset: symbol,
|
|
677
|
-
amount: String(amount),
|
|
678
|
-
apy: detail?.pool_apy,
|
|
679
|
-
tvl: detail?.pool_tvl,
|
|
680
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
681
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
682
|
-
liquidity: detail?.liquidity
|
|
683
|
-
});
|
|
684
229
|
}
|
|
685
230
|
}
|
|
231
|
+
const positions = (portfolio.positions ?? []).map((p) => ({
|
|
232
|
+
chain: p.chain ?? "",
|
|
233
|
+
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
234
|
+
protocolId: p.protocol_id,
|
|
235
|
+
pool: p.pool,
|
|
236
|
+
asset: p.token_symbol ?? "",
|
|
237
|
+
// Position amount is hex-encoded base units (like the token balances
|
|
238
|
+
// above). `PositionSlot` doesn't type a `decimals` field, but runtime
|
|
239
|
+
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
240
|
+
// when present, otherwise fall back to the per-symbol lookup so
|
|
241
|
+
// non-6-decimal assets like WETH don't render 1e12 too large.
|
|
242
|
+
amount: String(
|
|
243
|
+
hexToDecimal(
|
|
244
|
+
p.amount || "0",
|
|
245
|
+
tokenDecimals(p.token_symbol, p.decimals)
|
|
246
|
+
)
|
|
247
|
+
),
|
|
248
|
+
apy: p.pool_apy,
|
|
249
|
+
tvl: p.pool_tvl,
|
|
250
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
251
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
252
|
+
liquidity: p.liquidity
|
|
253
|
+
}));
|
|
686
254
|
return {
|
|
687
255
|
smartWallet,
|
|
688
256
|
totalBalance: String(totalBalance),
|
|
@@ -957,9 +525,6 @@ function decodeHistoryCursor(token) {
|
|
|
957
525
|
return parsed;
|
|
958
526
|
}
|
|
959
527
|
|
|
960
|
-
// src/agents/zyfai/zyfai.agent.ts
|
|
961
|
-
init_errors();
|
|
962
|
-
|
|
963
528
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
964
529
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
965
530
|
var storage = () => {
|
|
@@ -1095,6 +660,39 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
1095
660
|
};
|
|
1096
661
|
}
|
|
1097
662
|
|
|
663
|
+
// src/agents/zyfai/splitting.ts
|
|
664
|
+
var MAX_MIN_SPLITS = 4;
|
|
665
|
+
var MIN_FORCE_SPLITS = 2;
|
|
666
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
667
|
+
function toZyfaiSplitting(policy) {
|
|
668
|
+
switch (policy.splittingMode) {
|
|
669
|
+
case "none":
|
|
670
|
+
return { splitting: false };
|
|
671
|
+
case "automatic":
|
|
672
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
673
|
+
case "force":
|
|
674
|
+
return {
|
|
675
|
+
splitting: true,
|
|
676
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function clampForceSplits(minSplits) {
|
|
681
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
682
|
+
return MIN_FORCE_SPLITS;
|
|
683
|
+
}
|
|
684
|
+
const rounded = Math.round(minSplits);
|
|
685
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
686
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
687
|
+
return rounded;
|
|
688
|
+
}
|
|
689
|
+
function splittingNeedsUpdate(current, desired) {
|
|
690
|
+
if (!current) return true;
|
|
691
|
+
if (current.splitting !== desired.splitting) return true;
|
|
692
|
+
if (desired.minSplits === void 0) return false;
|
|
693
|
+
return current.minSplits !== desired.minSplits;
|
|
694
|
+
}
|
|
695
|
+
|
|
1098
696
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1099
697
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
1100
698
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -1107,6 +705,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
1107
705
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
1108
706
|
};
|
|
1109
707
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
708
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
1110
709
|
function isAlreadyActiveSessionKeyError(error) {
|
|
1111
710
|
const message = error instanceof Error ? error.message : String(error);
|
|
1112
711
|
return /already has an active session key/i.test(message);
|
|
@@ -1471,6 +1070,35 @@ var ZyfaiAgent = class {
|
|
|
1471
1070
|
throw error;
|
|
1472
1071
|
}
|
|
1473
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1075
|
+
*
|
|
1076
|
+
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1077
|
+
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1078
|
+
* WETH holder's real setting untouched.
|
|
1079
|
+
*
|
|
1080
|
+
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1081
|
+
* must leave the user connected with their profile unchanged, never fail
|
|
1082
|
+
* activation.
|
|
1083
|
+
*/
|
|
1084
|
+
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1085
|
+
await Promise.all(
|
|
1086
|
+
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
async applySplitting(asset, policy) {
|
|
1090
|
+
try {
|
|
1091
|
+
const desired = toZyfaiSplitting(policy);
|
|
1092
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1093
|
+
if (!splittingNeedsUpdate(current, desired)) return;
|
|
1094
|
+
await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
console.warn(
|
|
1097
|
+
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1098
|
+
error instanceof Error ? error.message : String(error)
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1474
1102
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1475
1103
|
try {
|
|
1476
1104
|
await this.connectFull(state, chainId);
|
|
@@ -1622,12 +1250,36 @@ var ZyfaiAgent = class {
|
|
|
1622
1250
|
}
|
|
1623
1251
|
};
|
|
1624
1252
|
|
|
1625
|
-
// src/client.ts
|
|
1626
|
-
init_errors();
|
|
1627
|
-
|
|
1628
1253
|
// src/lib/routing-api.ts
|
|
1629
|
-
init_errors();
|
|
1630
1254
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1255
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1256
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1257
|
+
try {
|
|
1258
|
+
const res = await fetch(url, {
|
|
1259
|
+
method: "GET",
|
|
1260
|
+
headers: {
|
|
1261
|
+
"Content-Type": "application/json",
|
|
1262
|
+
"x-owney-api-key": `${apiKey}`
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
if (!res.ok) {
|
|
1266
|
+
if (res.status !== 404) {
|
|
1267
|
+
console.warn(
|
|
1268
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
const json = await res.json();
|
|
1274
|
+
return json.success ? json.data ?? null : null;
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
console.warn(
|
|
1277
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1278
|
+
error instanceof Error ? error.message : String(error)
|
|
1279
|
+
);
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1631
1283
|
async function fetchAgentKeys(apiKey) {
|
|
1632
1284
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1633
1285
|
const res = await fetch(url, {
|
|
@@ -1657,7 +1309,6 @@ async function fetchAgentKeys(apiKey) {
|
|
|
1657
1309
|
}
|
|
1658
1310
|
|
|
1659
1311
|
// src/lib/health-report.ts
|
|
1660
|
-
init_errors();
|
|
1661
1312
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1662
1313
|
async function reportAgentFailure(apiKey, agentType, errorCode) {
|
|
1663
1314
|
try {
|
|
@@ -1807,12 +1458,9 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1807
1458
|
}
|
|
1808
1459
|
|
|
1809
1460
|
// src/client.ts
|
|
1810
|
-
var
|
|
1461
|
+
var import_viem5 = require("viem");
|
|
1811
1462
|
var import_chains2 = require("viem/chains");
|
|
1812
1463
|
|
|
1813
|
-
// src/lib/sponsored-deposit.ts
|
|
1814
|
-
init_errors();
|
|
1815
|
-
|
|
1816
1464
|
// src/lib/transfer-auth.ts
|
|
1817
1465
|
var import_viem3 = require("viem");
|
|
1818
1466
|
var ERC20_META_ABI = [
|
|
@@ -1850,7 +1498,6 @@ function randomAuthNonce() {
|
|
|
1850
1498
|
}
|
|
1851
1499
|
|
|
1852
1500
|
// src/lib/sponsor-client.ts
|
|
1853
|
-
init_errors();
|
|
1854
1501
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1855
1502
|
async function postSponsorTransferAuth(input) {
|
|
1856
1503
|
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
@@ -2119,7 +1766,6 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2119
1766
|
}
|
|
2120
1767
|
|
|
2121
1768
|
// src/lib/sponsored-weth-deposit.ts
|
|
2122
|
-
init_errors();
|
|
2123
1769
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2124
1770
|
function makeSponsoredWethCallback(deps) {
|
|
2125
1771
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -2228,7 +1874,6 @@ var VIEM_CHAIN2 = {
|
|
|
2228
1874
|
42161: import_chains2.arbitrum,
|
|
2229
1875
|
1: import_chains2.mainnet
|
|
2230
1876
|
};
|
|
2231
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2232
1877
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2233
1878
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2234
1879
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2248,6 +1893,12 @@ var OwneySDK = class {
|
|
|
2248
1893
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
2249
1894
|
state = null;
|
|
2250
1895
|
apiKey;
|
|
1896
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
1897
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
1898
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
1899
|
+
// leave every user's agent profile alone.
|
|
1900
|
+
orgAgentConfig;
|
|
1901
|
+
orgAgentConfigPromise = null;
|
|
2251
1902
|
zyfaiRpcUrls;
|
|
2252
1903
|
routingApiBaseUrl;
|
|
2253
1904
|
referralSource;
|
|
@@ -2356,14 +2007,14 @@ var OwneySDK = class {
|
|
|
2356
2007
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2357
2008
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2358
2009
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2359
|
-
getPublicClient: (cid) => (0,
|
|
2010
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2360
2011
|
chain: VIEM_CHAIN2[cid],
|
|
2361
|
-
transport: (0,
|
|
2012
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2362
2013
|
}),
|
|
2363
|
-
getWalletClient: (cid) => (0,
|
|
2014
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2364
2015
|
account: owner,
|
|
2365
2016
|
chain: VIEM_CHAIN2[cid],
|
|
2366
|
-
transport: (0,
|
|
2017
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2367
2018
|
})
|
|
2368
2019
|
});
|
|
2369
2020
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2389,14 +2040,14 @@ var OwneySDK = class {
|
|
|
2389
2040
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2390
2041
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2391
2042
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2392
|
-
getPublicClient: (cid) => (0,
|
|
2043
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2393
2044
|
chain: VIEM_CHAIN2[cid],
|
|
2394
|
-
transport: (0,
|
|
2045
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2395
2046
|
}),
|
|
2396
|
-
getWalletClient: (cid) => (0,
|
|
2047
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2397
2048
|
account: owner,
|
|
2398
2049
|
chain: VIEM_CHAIN2[cid],
|
|
2399
|
-
transport: (0,
|
|
2050
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2400
2051
|
})
|
|
2401
2052
|
});
|
|
2402
2053
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2417,14 +2068,51 @@ var OwneySDK = class {
|
|
|
2417
2068
|
}
|
|
2418
2069
|
return active;
|
|
2419
2070
|
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2073
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2074
|
+
*/
|
|
2075
|
+
async getOrgAgentConfig() {
|
|
2076
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2077
|
+
if (!this.orgAgentConfigPromise) {
|
|
2078
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2079
|
+
(config) => {
|
|
2080
|
+
this.orgAgentConfig = config;
|
|
2081
|
+
return config;
|
|
2082
|
+
}
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
return this.orgAgentConfigPromise;
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2089
|
+
*
|
|
2090
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2091
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2092
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2093
|
+
* user's connect over.
|
|
2094
|
+
*/
|
|
2095
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2096
|
+
if (!agent.applyOrgPolicy) return;
|
|
2097
|
+
try {
|
|
2098
|
+
const policy = await this.getOrgAgentConfig();
|
|
2099
|
+
if (!policy) return;
|
|
2100
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2101
|
+
} catch (error) {
|
|
2102
|
+
console.warn(
|
|
2103
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2104
|
+
error instanceof Error ? error.message : String(error)
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2420
2108
|
async ensureAgentsInitialized() {
|
|
2421
2109
|
if (this.agents.size > 0) return;
|
|
2422
2110
|
if (!this.initializingAgentsPromise) {
|
|
2423
2111
|
this.initializingAgentsPromise = (async () => {
|
|
2424
2112
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2425
2113
|
this.disabledAgents.clear();
|
|
2426
|
-
for (const { key, agent_type,
|
|
2427
|
-
const agent =
|
|
2114
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
2115
|
+
const agent = this.createAgent(agent_type, key);
|
|
2428
2116
|
if (!agent) continue;
|
|
2429
2117
|
this.agents.set(agent_type, agent);
|
|
2430
2118
|
if (is_enabled === false) {
|
|
@@ -2445,15 +2133,10 @@ var OwneySDK = class {
|
|
|
2445
2133
|
this.initializingAgentsPromise = null;
|
|
2446
2134
|
}
|
|
2447
2135
|
}
|
|
2448
|
-
|
|
2136
|
+
createAgent(agentId, key) {
|
|
2449
2137
|
if (agentId === "zyfai") {
|
|
2450
2138
|
return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
|
|
2451
2139
|
}
|
|
2452
|
-
if (agentId === "surfliquid") {
|
|
2453
|
-
if (!projectName) return null;
|
|
2454
|
-
const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
|
|
2455
|
-
return new SurfLiquidAgent2({ projectName, appId: key });
|
|
2456
|
-
}
|
|
2457
2140
|
return null;
|
|
2458
2141
|
}
|
|
2459
2142
|
// --- Account lifecycle ---
|
|
@@ -2506,6 +2189,7 @@ var OwneySDK = class {
|
|
|
2506
2189
|
Promise.all(
|
|
2507
2190
|
agents.map(async (agent) => {
|
|
2508
2191
|
await agent.activateAgent(state, chainId);
|
|
2192
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2509
2193
|
})
|
|
2510
2194
|
).catch((error) => {
|
|
2511
2195
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2533,6 +2217,7 @@ var OwneySDK = class {
|
|
|
2533
2217
|
Promise.all(
|
|
2534
2218
|
enabledCompatible.map(async (agent) => {
|
|
2535
2219
|
await agent.activateAgent(state, chainId);
|
|
2220
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2536
2221
|
})
|
|
2537
2222
|
).catch((error) => {
|
|
2538
2223
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2606,30 +2291,18 @@ var OwneySDK = class {
|
|
|
2606
2291
|
);
|
|
2607
2292
|
}
|
|
2608
2293
|
const agentResults = {};
|
|
2609
|
-
const agentErrors = {};
|
|
2610
2294
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
depositCallback
|
|
2620
|
-
);
|
|
2621
|
-
} catch (error) {
|
|
2622
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
2623
|
-
}
|
|
2624
|
-
}
|
|
2625
|
-
if (Object.keys(agentResults).length === 0) {
|
|
2626
|
-
throw new OwneyError(
|
|
2627
|
-
"DEPOSIT_ALL_FAILED",
|
|
2628
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
2629
|
-
{ agentErrors }
|
|
2295
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2296
|
+
agent,
|
|
2297
|
+
state,
|
|
2298
|
+
chainId,
|
|
2299
|
+
agentAmount,
|
|
2300
|
+
asset,
|
|
2301
|
+
effectiveCallback,
|
|
2302
|
+
depositCallback
|
|
2630
2303
|
);
|
|
2631
2304
|
}
|
|
2632
|
-
return
|
|
2305
|
+
return { agentResults };
|
|
2633
2306
|
}
|
|
2634
2307
|
/**
|
|
2635
2308
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2786,34 +2459,6 @@ var OwneySDK = class {
|
|
|
2786
2459
|
}
|
|
2787
2460
|
return eligible;
|
|
2788
2461
|
}
|
|
2789
|
-
/**
|
|
2790
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
2791
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
2792
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
2793
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
2794
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
2795
|
-
*
|
|
2796
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
2797
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
2798
|
-
*/
|
|
2799
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
2800
|
-
try {
|
|
2801
|
-
await this.ensureAgentsInitialized();
|
|
2802
|
-
} catch (error) {
|
|
2803
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
2804
|
-
return [];
|
|
2805
|
-
}
|
|
2806
|
-
throw error;
|
|
2807
|
-
}
|
|
2808
|
-
return [...this.agents.values()].filter((agent) => {
|
|
2809
|
-
const chainAssets = agent.supportedAssets.find(
|
|
2810
|
-
(sa) => sa.chainId === chainId
|
|
2811
|
-
);
|
|
2812
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
2813
|
-
}).map((agent) => agent.id).sort(
|
|
2814
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
2815
|
-
);
|
|
2816
|
-
}
|
|
2817
2462
|
// --- Fund operations ---
|
|
2818
2463
|
/**
|
|
2819
2464
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2849,17 +2494,9 @@ var OwneySDK = class {
|
|
|
2849
2494
|
}
|
|
2850
2495
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2851
2496
|
if (!amount) {
|
|
2852
|
-
const aggregated2 = await this.getBalances();
|
|
2853
|
-
const funded = projectAgentBalancesForAsset(
|
|
2854
|
-
eligibleAgents,
|
|
2855
|
-
aggregated2.agentBalances,
|
|
2856
|
-
chainId,
|
|
2857
|
-
asset,
|
|
2858
|
-
assetInfo.decimals
|
|
2859
|
-
).filter((b) => b.balance > 0n);
|
|
2860
2497
|
const results2 = {};
|
|
2861
2498
|
const agentErrors2 = {};
|
|
2862
|
-
for (const
|
|
2499
|
+
for (const agent of eligibleAgents) {
|
|
2863
2500
|
try {
|
|
2864
2501
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2865
2502
|
} catch (err) {
|
|
@@ -2876,10 +2513,9 @@ var OwneySDK = class {
|
|
|
2876
2513
|
{ asset, agentErrors: agentErrors2 }
|
|
2877
2514
|
);
|
|
2878
2515
|
}
|
|
2879
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2880
2516
|
return {
|
|
2881
2517
|
agentResult: results2,
|
|
2882
|
-
totalWithdrawn:
|
|
2518
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
2883
2519
|
};
|
|
2884
2520
|
}
|
|
2885
2521
|
const requested = BigInt(amount);
|
|
@@ -3249,10 +2885,10 @@ var OwneySDK = class {
|
|
|
3249
2885
|
);
|
|
3250
2886
|
}
|
|
3251
2887
|
const provider = this.requireConnectedProvider();
|
|
3252
|
-
const wallet = (0,
|
|
2888
|
+
const wallet = (0, import_viem5.createWalletClient)({
|
|
3253
2889
|
account: state.walletAddress,
|
|
3254
2890
|
chain: VIEM_CHAIN2[chainId],
|
|
3255
|
-
transport: (0,
|
|
2891
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3256
2892
|
});
|
|
3257
2893
|
const hash = await wallet.writeContract({
|
|
3258
2894
|
address: token,
|
|
@@ -3262,9 +2898,9 @@ var OwneySDK = class {
|
|
|
3262
2898
|
account: state.walletAddress,
|
|
3263
2899
|
chain: VIEM_CHAIN2[chainId]
|
|
3264
2900
|
});
|
|
3265
|
-
const publicClient = (0,
|
|
2901
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
3266
2902
|
chain: VIEM_CHAIN2[chainId],
|
|
3267
|
-
transport: (0,
|
|
2903
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3268
2904
|
});
|
|
3269
2905
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3270
2906
|
hash,
|
|
@@ -3372,11 +3008,8 @@ var OwneySDK = class {
|
|
|
3372
3008
|
}
|
|
3373
3009
|
};
|
|
3374
3010
|
|
|
3375
|
-
// src/index.ts
|
|
3376
|
-
init_errors();
|
|
3377
|
-
|
|
3378
3011
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3379
|
-
var
|
|
3012
|
+
var import_viem6 = require("viem");
|
|
3380
3013
|
var import_siwe = require("siwe");
|
|
3381
3014
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3382
3015
|
|
|
@@ -3503,7 +3136,7 @@ function buildSIWXConfig(deps) {
|
|
|
3503
3136
|
issuedAt,
|
|
3504
3137
|
toString() {
|
|
3505
3138
|
return new import_siwe.SiweMessage({
|
|
3506
|
-
address: (0,
|
|
3139
|
+
address: (0, import_viem6.getAddress)(accountAddress),
|
|
3507
3140
|
chainId: numericChainId(chainId),
|
|
3508
3141
|
domain,
|
|
3509
3142
|
uri,
|