@owney/sdk 0.6.9-beta.0 → 0.6.9-beta.2
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 +300 -608
- package/dist/index.d.cts +74 -20
- package/dist/index.d.ts +74 -20
- package/dist/index.js +283 -102
- 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, {
|
|
@@ -506,7 +26,8 @@ __export(index_exports, {
|
|
|
506
26
|
NotConnectedError: () => NotConnectedError,
|
|
507
27
|
OwneyError: () => OwneyError,
|
|
508
28
|
OwneySDK: () => OwneySDK,
|
|
509
|
-
createOwneySIWX: () => createOwneySIWX
|
|
29
|
+
createOwneySIWX: () => createOwneySIWX,
|
|
30
|
+
setOwneyDebug: () => setOwneyDebug
|
|
510
31
|
});
|
|
511
32
|
module.exports = __toCommonJS(index_exports);
|
|
512
33
|
|
|
@@ -568,8 +89,56 @@ var SupportedAssets = [
|
|
|
568
89
|
}
|
|
569
90
|
];
|
|
570
91
|
|
|
92
|
+
// src/errors.ts
|
|
93
|
+
var OwneyError = class extends Error {
|
|
94
|
+
code;
|
|
95
|
+
details;
|
|
96
|
+
agentId;
|
|
97
|
+
constructor(code, message, details, agentId) {
|
|
98
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
99
|
+
super(`${prefix} ${message}`);
|
|
100
|
+
this.name = "OwneyError";
|
|
101
|
+
this.code = code;
|
|
102
|
+
this.details = details;
|
|
103
|
+
this.agentId = agentId;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
107
|
+
constructor(agentId, available) {
|
|
108
|
+
super(
|
|
109
|
+
"AGENT_NOT_FOUND",
|
|
110
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
111
|
+
{ agentId, available },
|
|
112
|
+
agentId
|
|
113
|
+
);
|
|
114
|
+
this.name = "AgentNotFoundError";
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var NotConnectedError = class extends OwneyError {
|
|
118
|
+
constructor() {
|
|
119
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
120
|
+
this.name = "NotConnectedError";
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
124
|
+
incompatibleAgents;
|
|
125
|
+
connectedChainId;
|
|
126
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
127
|
+
const details = incompatibleAgents.map(
|
|
128
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
129
|
+
).join("; ");
|
|
130
|
+
super(
|
|
131
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
132
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
133
|
+
{ incompatibleAgents, connectedChainId }
|
|
134
|
+
);
|
|
135
|
+
this.name = "AgentChainIncompatibleError";
|
|
136
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
137
|
+
this.connectedChainId = connectedChainId;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
571
141
|
// src/lib/utils.ts
|
|
572
|
-
init_errors();
|
|
573
142
|
var isValidChainId = (chainId) => {
|
|
574
143
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
575
144
|
throw new OwneyError(
|
|
@@ -643,46 +212,46 @@ function resolveChainId(chain) {
|
|
|
643
212
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
644
213
|
const portfolio = raw.portfolio;
|
|
645
214
|
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
215
|
let totalBalance = 0;
|
|
654
216
|
const tokens = [];
|
|
655
|
-
const positions = [];
|
|
656
217
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
657
218
|
const positionChainId = Number(chainIdKey);
|
|
658
|
-
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
659
219
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
660
220
|
tokensBySymbol ?? {}
|
|
661
221
|
)) {
|
|
662
|
-
const amount = hexToDecimal(balance || "0",
|
|
222
|
+
const amount = hexToDecimal(balance || "0", decimals);
|
|
663
223
|
totalBalance += amount;
|
|
664
224
|
tokens.push({
|
|
665
|
-
chain:
|
|
225
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
666
226
|
chainId: positionChainId,
|
|
667
227
|
asset: symbol,
|
|
668
228
|
amount: String(amount)
|
|
669
229
|
});
|
|
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
230
|
}
|
|
685
231
|
}
|
|
232
|
+
const positions = (portfolio.positions ?? []).map((p) => ({
|
|
233
|
+
chain: p.chain ?? "",
|
|
234
|
+
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
235
|
+
protocolId: p.protocol_id,
|
|
236
|
+
pool: p.pool,
|
|
237
|
+
asset: p.token_symbol ?? "",
|
|
238
|
+
// Position amount is hex-encoded base units (like the token balances
|
|
239
|
+
// above). `PositionSlot` doesn't type a `decimals` field, but runtime
|
|
240
|
+
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
241
|
+
// when present, otherwise fall back to the per-symbol lookup so
|
|
242
|
+
// non-6-decimal assets like WETH don't render 1e12 too large.
|
|
243
|
+
amount: String(
|
|
244
|
+
hexToDecimal(
|
|
245
|
+
p.amount || "0",
|
|
246
|
+
tokenDecimals(p.token_symbol, p.decimals)
|
|
247
|
+
)
|
|
248
|
+
),
|
|
249
|
+
apy: p.pool_apy,
|
|
250
|
+
tvl: p.pool_tvl,
|
|
251
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
252
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
253
|
+
liquidity: p.liquidity
|
|
254
|
+
}));
|
|
686
255
|
return {
|
|
687
256
|
smartWallet,
|
|
688
257
|
totalBalance: String(totalBalance),
|
|
@@ -957,9 +526,6 @@ function decodeHistoryCursor(token) {
|
|
|
957
526
|
return parsed;
|
|
958
527
|
}
|
|
959
528
|
|
|
960
|
-
// src/agents/zyfai/zyfai.agent.ts
|
|
961
|
-
init_errors();
|
|
962
|
-
|
|
963
529
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
964
530
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
965
531
|
var storage = () => {
|
|
@@ -1095,6 +661,56 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
1095
661
|
};
|
|
1096
662
|
}
|
|
1097
663
|
|
|
664
|
+
// src/agents/zyfai/splitting.ts
|
|
665
|
+
var MAX_MIN_SPLITS = 4;
|
|
666
|
+
var MIN_FORCE_SPLITS = 2;
|
|
667
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
668
|
+
function toZyfaiSplitting(policy) {
|
|
669
|
+
switch (policy.splittingMode) {
|
|
670
|
+
case "none":
|
|
671
|
+
return { splitting: false };
|
|
672
|
+
case "automatic":
|
|
673
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
674
|
+
case "force":
|
|
675
|
+
return {
|
|
676
|
+
splitting: true,
|
|
677
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
function clampForceSplits(minSplits) {
|
|
682
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
683
|
+
return MIN_FORCE_SPLITS;
|
|
684
|
+
}
|
|
685
|
+
const rounded = Math.round(minSplits);
|
|
686
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
687
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
688
|
+
return rounded;
|
|
689
|
+
}
|
|
690
|
+
function splittingNeedsUpdate(current, desired) {
|
|
691
|
+
if (!current) return true;
|
|
692
|
+
if (current.splitting !== desired.splitting) return true;
|
|
693
|
+
if (desired.minSplits === void 0) return false;
|
|
694
|
+
return current.minSplits !== desired.minSplits;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/lib/debug.ts
|
|
698
|
+
var configuredDebug = false;
|
|
699
|
+
function setOwneyDebug(enabled) {
|
|
700
|
+
configuredDebug = enabled;
|
|
701
|
+
}
|
|
702
|
+
function isOwneyDebug() {
|
|
703
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
704
|
+
}
|
|
705
|
+
function debugLog(scope, message, data) {
|
|
706
|
+
if (!isOwneyDebug()) return;
|
|
707
|
+
if (data === void 0) {
|
|
708
|
+
console.log(`[${scope}] ${message}`);
|
|
709
|
+
} else {
|
|
710
|
+
console.log(`[${scope}] ${message}`, data);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
1098
714
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1099
715
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
1100
716
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -1107,6 +723,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
1107
723
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
1108
724
|
};
|
|
1109
725
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
726
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
1110
727
|
function isAlreadyActiveSessionKeyError(error) {
|
|
1111
728
|
const message = error instanceof Error ? error.message : String(error);
|
|
1112
729
|
return /already has an active session key/i.test(message);
|
|
@@ -1471,6 +1088,62 @@ var ZyfaiAgent = class {
|
|
|
1471
1088
|
throw error;
|
|
1472
1089
|
}
|
|
1473
1090
|
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1093
|
+
*
|
|
1094
|
+
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1095
|
+
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1096
|
+
* WETH holder's real setting untouched.
|
|
1097
|
+
*
|
|
1098
|
+
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1099
|
+
* must leave the user connected with their profile unchanged, never fail
|
|
1100
|
+
* activation.
|
|
1101
|
+
*/
|
|
1102
|
+
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1103
|
+
debugLog("zyfai:splitting", "applying org policy", {
|
|
1104
|
+
policy,
|
|
1105
|
+
// Per asset because Zyfai stores splitting under assetTypeSettings[asset].
|
|
1106
|
+
assets: SPLITTING_ASSETS
|
|
1107
|
+
});
|
|
1108
|
+
await Promise.all(
|
|
1109
|
+
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
async applySplitting(asset, policy) {
|
|
1113
|
+
try {
|
|
1114
|
+
const desired = toZyfaiSplitting(policy);
|
|
1115
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1116
|
+
const currentSplitting = {
|
|
1117
|
+
splitting: current?.splitting,
|
|
1118
|
+
minSplits: current?.minSplits
|
|
1119
|
+
};
|
|
1120
|
+
const needsUpdate = splittingNeedsUpdate(current, desired);
|
|
1121
|
+
debugLog("zyfai:splitting", `${asset}: comparing`, {
|
|
1122
|
+
mode: policy.splittingMode,
|
|
1123
|
+
current: currentSplitting,
|
|
1124
|
+
desired,
|
|
1125
|
+
// Spelled out because the "why" is the non-obvious part: minSplits is
|
|
1126
|
+
// what separates automatic (1) from force (2-4), not `splitting`.
|
|
1127
|
+
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1128
|
+
});
|
|
1129
|
+
if (!needsUpdate) return;
|
|
1130
|
+
const result = await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1131
|
+
debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
|
|
1132
|
+
sent: { asset, ...desired },
|
|
1133
|
+
// updateUserProfile re-reads the profile after PATCHing, so this is
|
|
1134
|
+
// Zyfai's own view of the result rather than an echo of what we sent.
|
|
1135
|
+
zyfaiNowReports: {
|
|
1136
|
+
splitting: result?.splitting,
|
|
1137
|
+
minSplits: result?.minSplits
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
console.warn(
|
|
1142
|
+
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1143
|
+
error instanceof Error ? error.message : String(error)
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1474
1147
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1475
1148
|
try {
|
|
1476
1149
|
await this.connectFull(state, chainId);
|
|
@@ -1622,12 +1295,42 @@ var ZyfaiAgent = class {
|
|
|
1622
1295
|
}
|
|
1623
1296
|
};
|
|
1624
1297
|
|
|
1625
|
-
// src/client.ts
|
|
1626
|
-
init_errors();
|
|
1627
|
-
|
|
1628
1298
|
// src/lib/routing-api.ts
|
|
1629
|
-
init_errors();
|
|
1630
1299
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1300
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1301
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1302
|
+
try {
|
|
1303
|
+
const res = await fetch(url, {
|
|
1304
|
+
method: "GET",
|
|
1305
|
+
headers: {
|
|
1306
|
+
"Content-Type": "application/json",
|
|
1307
|
+
"x-owney-api-key": `${apiKey}`
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
if (!res.ok) {
|
|
1311
|
+
if (res.status !== 404) {
|
|
1312
|
+
console.warn(
|
|
1313
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
return null;
|
|
1317
|
+
}
|
|
1318
|
+
const json = await res.json();
|
|
1319
|
+
const policy = json.success ? json.data ?? null : null;
|
|
1320
|
+
debugLog(
|
|
1321
|
+
"owney-sdk",
|
|
1322
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
1323
|
+
policy ?? void 0
|
|
1324
|
+
);
|
|
1325
|
+
return policy;
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
console.warn(
|
|
1328
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1329
|
+
error instanceof Error ? error.message : String(error)
|
|
1330
|
+
);
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1631
1334
|
async function fetchAgentKeys(apiKey) {
|
|
1632
1335
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1633
1336
|
const res = await fetch(url, {
|
|
@@ -1657,7 +1360,6 @@ async function fetchAgentKeys(apiKey) {
|
|
|
1657
1360
|
}
|
|
1658
1361
|
|
|
1659
1362
|
// src/lib/health-report.ts
|
|
1660
|
-
init_errors();
|
|
1661
1363
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1662
1364
|
async function reportAgentFailure(apiKey, agentType, errorCode) {
|
|
1663
1365
|
try {
|
|
@@ -1807,12 +1509,9 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1807
1509
|
}
|
|
1808
1510
|
|
|
1809
1511
|
// src/client.ts
|
|
1810
|
-
var
|
|
1512
|
+
var import_viem5 = require("viem");
|
|
1811
1513
|
var import_chains2 = require("viem/chains");
|
|
1812
1514
|
|
|
1813
|
-
// src/lib/sponsored-deposit.ts
|
|
1814
|
-
init_errors();
|
|
1815
|
-
|
|
1816
1515
|
// src/lib/transfer-auth.ts
|
|
1817
1516
|
var import_viem3 = require("viem");
|
|
1818
1517
|
var ERC20_META_ABI = [
|
|
@@ -1850,7 +1549,6 @@ function randomAuthNonce() {
|
|
|
1850
1549
|
}
|
|
1851
1550
|
|
|
1852
1551
|
// src/lib/sponsor-client.ts
|
|
1853
|
-
init_errors();
|
|
1854
1552
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1855
1553
|
async function postSponsorTransferAuth(input) {
|
|
1856
1554
|
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
@@ -2119,7 +1817,6 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2119
1817
|
}
|
|
2120
1818
|
|
|
2121
1819
|
// src/lib/sponsored-weth-deposit.ts
|
|
2122
|
-
init_errors();
|
|
2123
1820
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2124
1821
|
function makeSponsoredWethCallback(deps) {
|
|
2125
1822
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -2228,7 +1925,6 @@ var VIEM_CHAIN2 = {
|
|
|
2228
1925
|
42161: import_chains2.arbitrum,
|
|
2229
1926
|
1: import_chains2.mainnet
|
|
2230
1927
|
};
|
|
2231
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2232
1928
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2233
1929
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2234
1930
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2248,6 +1944,12 @@ var OwneySDK = class {
|
|
|
2248
1944
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
2249
1945
|
state = null;
|
|
2250
1946
|
apiKey;
|
|
1947
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
1948
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
1949
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
1950
|
+
// leave every user's agent profile alone.
|
|
1951
|
+
orgAgentConfig;
|
|
1952
|
+
orgAgentConfigPromise = null;
|
|
2251
1953
|
zyfaiRpcUrls;
|
|
2252
1954
|
routingApiBaseUrl;
|
|
2253
1955
|
referralSource;
|
|
@@ -2256,6 +1958,7 @@ var OwneySDK = class {
|
|
|
2256
1958
|
initializingAgentsPromise = null;
|
|
2257
1959
|
constructor(config) {
|
|
2258
1960
|
this.apiKey = config.apiKey;
|
|
1961
|
+
if (config.debug) setOwneyDebug(true);
|
|
2259
1962
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2260
1963
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2261
1964
|
this.referralSource = config.referralSource;
|
|
@@ -2356,14 +2059,14 @@ var OwneySDK = class {
|
|
|
2356
2059
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2357
2060
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2358
2061
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2359
|
-
getPublicClient: (cid) => (0,
|
|
2062
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2360
2063
|
chain: VIEM_CHAIN2[cid],
|
|
2361
|
-
transport: (0,
|
|
2064
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2362
2065
|
}),
|
|
2363
|
-
getWalletClient: (cid) => (0,
|
|
2066
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2364
2067
|
account: owner,
|
|
2365
2068
|
chain: VIEM_CHAIN2[cid],
|
|
2366
|
-
transport: (0,
|
|
2069
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2367
2070
|
})
|
|
2368
2071
|
});
|
|
2369
2072
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2389,14 +2092,14 @@ var OwneySDK = class {
|
|
|
2389
2092
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2390
2093
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2391
2094
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2392
|
-
getPublicClient: (cid) => (0,
|
|
2095
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2393
2096
|
chain: VIEM_CHAIN2[cid],
|
|
2394
|
-
transport: (0,
|
|
2097
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2395
2098
|
}),
|
|
2396
|
-
getWalletClient: (cid) => (0,
|
|
2099
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2397
2100
|
account: owner,
|
|
2398
2101
|
chain: VIEM_CHAIN2[cid],
|
|
2399
|
-
transport: (0,
|
|
2102
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2400
2103
|
})
|
|
2401
2104
|
});
|
|
2402
2105
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2417,14 +2120,57 @@ var OwneySDK = class {
|
|
|
2417
2120
|
}
|
|
2418
2121
|
return active;
|
|
2419
2122
|
}
|
|
2123
|
+
/**
|
|
2124
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2125
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2126
|
+
*/
|
|
2127
|
+
async getOrgAgentConfig() {
|
|
2128
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2129
|
+
if (!this.orgAgentConfigPromise) {
|
|
2130
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2131
|
+
(config) => {
|
|
2132
|
+
this.orgAgentConfig = config;
|
|
2133
|
+
return config;
|
|
2134
|
+
}
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
return this.orgAgentConfigPromise;
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2141
|
+
*
|
|
2142
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2143
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2144
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2145
|
+
* user's connect over.
|
|
2146
|
+
*/
|
|
2147
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2148
|
+
if (!agent.applyOrgPolicy) {
|
|
2149
|
+
debugLog(
|
|
2150
|
+
"owney-sdk",
|
|
2151
|
+
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2152
|
+
);
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
try {
|
|
2156
|
+
const policy = await this.getOrgAgentConfig();
|
|
2157
|
+
if (!policy) return;
|
|
2158
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2159
|
+
} catch (error) {
|
|
2160
|
+
console.warn(
|
|
2161
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2162
|
+
error instanceof Error ? error.message : String(error)
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2420
2166
|
async ensureAgentsInitialized() {
|
|
2421
2167
|
if (this.agents.size > 0) return;
|
|
2422
2168
|
if (!this.initializingAgentsPromise) {
|
|
2423
2169
|
this.initializingAgentsPromise = (async () => {
|
|
2424
2170
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2425
2171
|
this.disabledAgents.clear();
|
|
2426
|
-
for (const { key, agent_type,
|
|
2427
|
-
const agent =
|
|
2172
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
2173
|
+
const agent = this.createAgent(agent_type, key);
|
|
2428
2174
|
if (!agent) continue;
|
|
2429
2175
|
this.agents.set(agent_type, agent);
|
|
2430
2176
|
if (is_enabled === false) {
|
|
@@ -2445,15 +2191,10 @@ var OwneySDK = class {
|
|
|
2445
2191
|
this.initializingAgentsPromise = null;
|
|
2446
2192
|
}
|
|
2447
2193
|
}
|
|
2448
|
-
|
|
2194
|
+
createAgent(agentId, key) {
|
|
2449
2195
|
if (agentId === "zyfai") {
|
|
2450
2196
|
return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
|
|
2451
2197
|
}
|
|
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
2198
|
return null;
|
|
2458
2199
|
}
|
|
2459
2200
|
// --- Account lifecycle ---
|
|
@@ -2506,6 +2247,7 @@ var OwneySDK = class {
|
|
|
2506
2247
|
Promise.all(
|
|
2507
2248
|
agents.map(async (agent) => {
|
|
2508
2249
|
await agent.activateAgent(state, chainId);
|
|
2250
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2509
2251
|
})
|
|
2510
2252
|
).catch((error) => {
|
|
2511
2253
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2533,6 +2275,7 @@ var OwneySDK = class {
|
|
|
2533
2275
|
Promise.all(
|
|
2534
2276
|
enabledCompatible.map(async (agent) => {
|
|
2535
2277
|
await agent.activateAgent(state, chainId);
|
|
2278
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2536
2279
|
})
|
|
2537
2280
|
).catch((error) => {
|
|
2538
2281
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2606,30 +2349,18 @@ var OwneySDK = class {
|
|
|
2606
2349
|
);
|
|
2607
2350
|
}
|
|
2608
2351
|
const agentResults = {};
|
|
2609
|
-
const agentErrors = {};
|
|
2610
2352
|
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 }
|
|
2353
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2354
|
+
agent,
|
|
2355
|
+
state,
|
|
2356
|
+
chainId,
|
|
2357
|
+
agentAmount,
|
|
2358
|
+
asset,
|
|
2359
|
+
effectiveCallback,
|
|
2360
|
+
depositCallback
|
|
2630
2361
|
);
|
|
2631
2362
|
}
|
|
2632
|
-
return
|
|
2363
|
+
return { agentResults };
|
|
2633
2364
|
}
|
|
2634
2365
|
/**
|
|
2635
2366
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2786,34 +2517,6 @@ var OwneySDK = class {
|
|
|
2786
2517
|
}
|
|
2787
2518
|
return eligible;
|
|
2788
2519
|
}
|
|
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
2520
|
// --- Fund operations ---
|
|
2818
2521
|
/**
|
|
2819
2522
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2849,17 +2552,9 @@ var OwneySDK = class {
|
|
|
2849
2552
|
}
|
|
2850
2553
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2851
2554
|
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
2555
|
const results2 = {};
|
|
2861
2556
|
const agentErrors2 = {};
|
|
2862
|
-
for (const
|
|
2557
|
+
for (const agent of eligibleAgents) {
|
|
2863
2558
|
try {
|
|
2864
2559
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2865
2560
|
} catch (err) {
|
|
@@ -2876,10 +2571,9 @@ var OwneySDK = class {
|
|
|
2876
2571
|
{ asset, agentErrors: agentErrors2 }
|
|
2877
2572
|
);
|
|
2878
2573
|
}
|
|
2879
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2880
2574
|
return {
|
|
2881
2575
|
agentResult: results2,
|
|
2882
|
-
totalWithdrawn:
|
|
2576
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
2883
2577
|
};
|
|
2884
2578
|
}
|
|
2885
2579
|
const requested = BigInt(amount);
|
|
@@ -3249,10 +2943,10 @@ var OwneySDK = class {
|
|
|
3249
2943
|
);
|
|
3250
2944
|
}
|
|
3251
2945
|
const provider = this.requireConnectedProvider();
|
|
3252
|
-
const wallet = (0,
|
|
2946
|
+
const wallet = (0, import_viem5.createWalletClient)({
|
|
3253
2947
|
account: state.walletAddress,
|
|
3254
2948
|
chain: VIEM_CHAIN2[chainId],
|
|
3255
|
-
transport: (0,
|
|
2949
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3256
2950
|
});
|
|
3257
2951
|
const hash = await wallet.writeContract({
|
|
3258
2952
|
address: token,
|
|
@@ -3262,9 +2956,9 @@ var OwneySDK = class {
|
|
|
3262
2956
|
account: state.walletAddress,
|
|
3263
2957
|
chain: VIEM_CHAIN2[chainId]
|
|
3264
2958
|
});
|
|
3265
|
-
const publicClient = (0,
|
|
2959
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
3266
2960
|
chain: VIEM_CHAIN2[chainId],
|
|
3267
|
-
transport: (0,
|
|
2961
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3268
2962
|
});
|
|
3269
2963
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3270
2964
|
hash,
|
|
@@ -3372,11 +3066,8 @@ var OwneySDK = class {
|
|
|
3372
3066
|
}
|
|
3373
3067
|
};
|
|
3374
3068
|
|
|
3375
|
-
// src/index.ts
|
|
3376
|
-
init_errors();
|
|
3377
|
-
|
|
3378
3069
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3379
|
-
var
|
|
3070
|
+
var import_viem6 = require("viem");
|
|
3380
3071
|
var import_siwe = require("siwe");
|
|
3381
3072
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3382
3073
|
|
|
@@ -3503,7 +3194,7 @@ function buildSIWXConfig(deps) {
|
|
|
3503
3194
|
issuedAt,
|
|
3504
3195
|
toString() {
|
|
3505
3196
|
return new import_siwe.SiweMessage({
|
|
3506
|
-
address: (0,
|
|
3197
|
+
address: (0, import_viem6.getAddress)(accountAddress),
|
|
3507
3198
|
chainId: numericChainId(chainId),
|
|
3508
3199
|
domain,
|
|
3509
3200
|
uri,
|
|
@@ -3594,5 +3285,6 @@ function createOwneySIWX(config) {
|
|
|
3594
3285
|
NotConnectedError,
|
|
3595
3286
|
OwneyError,
|
|
3596
3287
|
OwneySDK,
|
|
3597
|
-
createOwneySIWX
|
|
3288
|
+
createOwneySIWX,
|
|
3289
|
+
setOwneyDebug
|
|
3598
3290
|
});
|