@owney/sdk 0.6.9-beta.7 → 0.7.0-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/README.md +1 -1
- package/dist/index.cjs +243 -1292
- package/dist/index.d.cts +3 -138
- package/dist/index.d.ts +3 -138
- package/dist/index.js +214 -634
- package/package.json +3 -5
- package/dist/chunk-PWIKIQOX.js +0 -140
- package/dist/surfliquid.agent-JOJJ3C5Y.js +0 -448
package/dist/index.cjs
CHANGED
|
@@ -3,642 +3,20 @@ 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 });
|
|
17
9
|
};
|
|
18
10
|
var __copyProps = (to, from, except, desc) => {
|
|
19
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
-
for (let
|
|
21
|
-
if (!__hasOwnProp.call(to,
|
|
22
|
-
__defProp(to,
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
15
|
}
|
|
24
16
|
return to;
|
|
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/lib/permit2.ts
|
|
84
|
-
function buildPermitTransferFromTypedData(input) {
|
|
85
|
-
return {
|
|
86
|
-
domain: {
|
|
87
|
-
name: "Permit2",
|
|
88
|
-
chainId: input.chainId,
|
|
89
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
90
|
-
},
|
|
91
|
-
types: {
|
|
92
|
-
PermitTransferFrom: [
|
|
93
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
94
|
-
{ name: "spender", type: "address" },
|
|
95
|
-
{ name: "nonce", type: "uint256" },
|
|
96
|
-
{ name: "deadline", type: "uint256" }
|
|
97
|
-
],
|
|
98
|
-
TokenPermissions: [
|
|
99
|
-
{ name: "token", type: "address" },
|
|
100
|
-
{ name: "amount", type: "uint256" }
|
|
101
|
-
]
|
|
102
|
-
},
|
|
103
|
-
primaryType: "PermitTransferFrom",
|
|
104
|
-
message: input.message
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
function randomPermit2Nonce() {
|
|
108
|
-
const bytes = new Uint8Array(32);
|
|
109
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
110
|
-
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
111
|
-
}
|
|
112
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
113
|
-
return publicClient.readContract({
|
|
114
|
-
address: token,
|
|
115
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
116
|
-
functionName: "allowance",
|
|
117
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
121
|
-
return publicClient.readContract({
|
|
122
|
-
address: token,
|
|
123
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
124
|
-
functionName: "balanceOf",
|
|
125
|
-
args: [owner]
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
var import_viem4, PERMIT2_ADDRESS, MAX_UINT256, ERC20_ALLOWANCE_ABI;
|
|
129
|
-
var init_permit2 = __esm({
|
|
130
|
-
"src/lib/permit2.ts"() {
|
|
131
|
-
"use strict";
|
|
132
|
-
import_viem4 = require("viem");
|
|
133
|
-
PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
134
|
-
MAX_UINT256 = 2n ** 256n - 1n;
|
|
135
|
-
ERC20_ALLOWANCE_ABI = [
|
|
136
|
-
{
|
|
137
|
-
type: "function",
|
|
138
|
-
name: "allowance",
|
|
139
|
-
stateMutability: "view",
|
|
140
|
-
inputs: [
|
|
141
|
-
{ name: "owner", type: "address" },
|
|
142
|
-
{ name: "spender", type: "address" }
|
|
143
|
-
],
|
|
144
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
type: "function",
|
|
148
|
-
name: "approve",
|
|
149
|
-
stateMutability: "nonpayable",
|
|
150
|
-
inputs: [
|
|
151
|
-
{ name: "spender", type: "address" },
|
|
152
|
-
{ name: "amount", type: "uint256" }
|
|
153
|
-
],
|
|
154
|
-
outputs: [{ name: "", type: "bool" }]
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
type: "function",
|
|
158
|
-
name: "balanceOf",
|
|
159
|
-
stateMutability: "view",
|
|
160
|
-
inputs: [{ name: "account", type: "address" }],
|
|
161
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
162
|
-
}
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// src/agents/surfliquid/surfliquid.constants.ts
|
|
168
|
-
var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_APPROVAL_TARGET, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
|
|
169
|
-
var init_surfliquid_constants = __esm({
|
|
170
|
-
"src/agents/surfliquid/surfliquid.constants.ts"() {
|
|
171
|
-
"use strict";
|
|
172
|
-
SURFLIQUID_CHAIN_ID = 8453;
|
|
173
|
-
SURFLIQUID_CHAIN_NAME = "BASE";
|
|
174
|
-
SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
175
|
-
SURFLIQUID_USDC_DECIMALS = 6;
|
|
176
|
-
SURFLIQUID_MIN_DEPOSIT = "0";
|
|
177
|
-
SURFLIQUID_APPROVAL_TARGET = 100000000000n;
|
|
178
|
-
SURFLIQUID_SUPPORTED_ASSETS = [
|
|
179
|
-
{
|
|
180
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
181
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
182
|
-
assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
|
|
183
|
-
}
|
|
184
|
-
];
|
|
185
|
-
SURFLIQUID_ACTION_MAP = {
|
|
186
|
-
// INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
|
|
187
|
-
// other funding ("Top up"). The mini-app intentionally hides the "Deposit"
|
|
188
|
-
// action (it marks Zyfai's smart-account-creation event), which would
|
|
189
|
-
// otherwise drop a SurfLiquid user's only history row.
|
|
190
|
-
INITIAL_DEPOSIT: "Top up",
|
|
191
|
-
DEPOSIT: "Top up",
|
|
192
|
-
USER_DEPOSIT: "Top up",
|
|
193
|
-
WITHDRAWAL: "Withdraw",
|
|
194
|
-
USER_WITHDRAWAL: "Withdraw",
|
|
195
|
-
REBALANCE: "Rebalance",
|
|
196
|
-
REBALANCE_COMPLETED: "Rebalance",
|
|
197
|
-
CROSS_CHAIN_REBALANCE: "Rebalance",
|
|
198
|
-
MERKL_CLAIM: "Earned"
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// src/agents/surfliquid/surfliquid.mapper.ts
|
|
204
|
-
function mapMessage(message) {
|
|
205
|
-
const action = SURFLIQUID_ACTION_MAP[message.transactionType];
|
|
206
|
-
if (!action) return null;
|
|
207
|
-
return {
|
|
208
|
-
agent: "surfliquid",
|
|
209
|
-
action,
|
|
210
|
-
date: message.timestamp,
|
|
211
|
-
oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
|
|
212
|
-
newApy: message.apyAfter != null ? String(message.apyAfter) : null,
|
|
213
|
-
transactions: [
|
|
214
|
-
{
|
|
215
|
-
txHashes: [message.txHash],
|
|
216
|
-
chainId: message.chainId,
|
|
217
|
-
tokenSymbol: message.token ?? void 0,
|
|
218
|
-
amount: message.amount != null ? String(message.amount) : void 0
|
|
219
|
-
}
|
|
220
|
-
],
|
|
221
|
-
rebalanceLog: []
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
function mapHistory(result, _chainId) {
|
|
225
|
-
const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
|
|
226
|
-
const hasMore = result.page < result.pages;
|
|
227
|
-
return {
|
|
228
|
-
data,
|
|
229
|
-
hasMore,
|
|
230
|
-
nextCursor: hasMore ? String(result.page + 1) : void 0
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
function mapBalances2(vault, chainId, morphoStats) {
|
|
234
|
-
const assets = (vault.assets ?? []).filter(
|
|
235
|
-
(asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
|
|
236
|
-
);
|
|
237
|
-
const tokens = assets.map((asset) => ({
|
|
238
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
239
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
240
|
-
asset: "USDC",
|
|
241
|
-
amount: String(asset.currentValueUSD)
|
|
242
|
-
}));
|
|
243
|
-
const positions = assets.map((asset) => {
|
|
244
|
-
const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
|
|
245
|
-
return {
|
|
246
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
247
|
-
protocol: "Morpho",
|
|
248
|
-
// The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
|
|
249
|
-
// Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
|
|
250
|
-
pool: stats?.name ?? void 0,
|
|
251
|
-
asset: "USDC",
|
|
252
|
-
amount: String(asset.currentValueUSD),
|
|
253
|
-
apy: asset.currentAPY,
|
|
254
|
-
// TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
|
|
255
|
-
tvl: stats?.tvlUsd,
|
|
256
|
-
liquidity: stats?.liquidityUsd
|
|
257
|
-
};
|
|
258
|
-
});
|
|
259
|
-
const total = assets.reduce(
|
|
260
|
-
(sum, asset) => sum + asset.currentValueUSD,
|
|
261
|
-
0
|
|
262
|
-
);
|
|
263
|
-
return {
|
|
264
|
-
smartWallet: vault.userVaultAddress ?? void 0,
|
|
265
|
-
totalBalance: String(total),
|
|
266
|
-
totalBalanceAsset: "usdc",
|
|
267
|
-
tokens,
|
|
268
|
-
positions
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
function mapAccountApy(vault, days) {
|
|
272
|
-
const breakdown = vault.apyBreakdown;
|
|
273
|
-
const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
|
|
274
|
-
const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
|
|
275
|
-
return {
|
|
276
|
-
walletAddress: vault.walletAddress ?? "",
|
|
277
|
-
weightedApyAfterFee: apy,
|
|
278
|
-
apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
|
|
279
|
-
// Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
|
|
280
|
-
history: []
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
function mapEarnings2(vault, vaultAddress) {
|
|
284
|
-
return {
|
|
285
|
-
smartWallet: vaultAddress,
|
|
286
|
-
lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
|
|
287
|
-
tokens: []
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
function mapUserProfile2(vault, address) {
|
|
291
|
-
return {
|
|
292
|
-
address,
|
|
293
|
-
smartWallet: vault.userVaultAddress ?? "",
|
|
294
|
-
chains: [SURFLIQUID_CHAIN_ID],
|
|
295
|
-
// SurfLiquid uses cookie-based session auth — no session-key concept.
|
|
296
|
-
hasActiveSessionKey: false,
|
|
297
|
-
protocols: ["SurfLiquid"]
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
var APY_WINDOW_KEY;
|
|
301
|
-
var init_surfliquid_mapper = __esm({
|
|
302
|
-
"src/agents/surfliquid/surfliquid.mapper.ts"() {
|
|
303
|
-
"use strict";
|
|
304
|
-
init_surfliquid_constants();
|
|
305
|
-
APY_WINDOW_KEY = {
|
|
306
|
-
"7D": "apy7d",
|
|
307
|
-
"14D": "apy14d",
|
|
308
|
-
"30D": "apy30d"
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// src/agents/surfliquid/surfliquid.wallet-adapter.ts
|
|
314
|
-
var import_core_sdk, OwneyWalletAdapter;
|
|
315
|
-
var init_surfliquid_wallet_adapter = __esm({
|
|
316
|
-
"src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
|
|
317
|
-
"use strict";
|
|
318
|
-
import_core_sdk = require("@surf_liquid/core-sdk");
|
|
319
|
-
OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
|
|
320
|
-
constructor(eip1193Provider) {
|
|
321
|
-
super();
|
|
322
|
-
this.eip1193Provider = eip1193Provider;
|
|
323
|
-
}
|
|
324
|
-
eip1193Provider;
|
|
325
|
-
name = "owney";
|
|
326
|
-
get installed() {
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
resolveProvider() {
|
|
330
|
-
return this.eip1193Provider;
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// src/agents/surfliquid/surfliquid.morpho.ts
|
|
337
|
-
async function fetchMorphoVaultStats(vaultAddress, chainId) {
|
|
338
|
-
try {
|
|
339
|
-
const res = await fetch(MORPHO_API_URL, {
|
|
340
|
-
method: "POST",
|
|
341
|
-
headers: { "Content-Type": "application/json" },
|
|
342
|
-
body: JSON.stringify({
|
|
343
|
-
query: VAULT_STATS_QUERY,
|
|
344
|
-
variables: { address: vaultAddress, chainId }
|
|
345
|
-
})
|
|
346
|
-
});
|
|
347
|
-
if (!res.ok) return null;
|
|
348
|
-
const json = await res.json();
|
|
349
|
-
if (json.errors) return null;
|
|
350
|
-
const vault = json.data?.vaultByAddress;
|
|
351
|
-
const tvlUsd = vault?.state?.totalAssetsUsd;
|
|
352
|
-
const liquidityUsd = vault?.liquidity?.usd;
|
|
353
|
-
if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
const name = typeof vault?.name === "string" ? vault.name : null;
|
|
357
|
-
return { name, tvlUsd, liquidityUsd };
|
|
358
|
-
} catch (error) {
|
|
359
|
-
console.warn("surfliquid: Morpho vault stats fetch failed", {
|
|
360
|
-
vaultAddress,
|
|
361
|
-
chainId,
|
|
362
|
-
error
|
|
363
|
-
});
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
|
|
368
|
-
const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
|
|
369
|
-
const entries = await Promise.all(
|
|
370
|
-
unique.map(
|
|
371
|
-
async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
|
|
372
|
-
)
|
|
373
|
-
);
|
|
374
|
-
const byVault = /* @__PURE__ */ new Map();
|
|
375
|
-
for (const [address, stats] of entries) {
|
|
376
|
-
if (stats) byVault.set(address, stats);
|
|
377
|
-
}
|
|
378
|
-
return byVault;
|
|
379
|
-
}
|
|
380
|
-
var MORPHO_API_URL, VAULT_STATS_QUERY;
|
|
381
|
-
var init_surfliquid_morpho = __esm({
|
|
382
|
-
"src/agents/surfliquid/surfliquid.morpho.ts"() {
|
|
383
|
-
"use strict";
|
|
384
|
-
MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
385
|
-
VAULT_STATS_QUERY = `
|
|
386
|
-
query VaultStats($address: String!, $chainId: Int!) {
|
|
387
|
-
vaultByAddress(address: $address, chainId: $chainId) {
|
|
388
|
-
name
|
|
389
|
-
state { totalAssetsUsd }
|
|
390
|
-
liquidity { usd }
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
`;
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
// src/agents/surfliquid/surfliquid.agent.ts
|
|
398
|
-
var surfliquid_agent_exports = {};
|
|
399
|
-
__export(surfliquid_agent_exports, {
|
|
400
|
-
SurfLiquidAgent: () => SurfLiquidAgent
|
|
401
|
-
});
|
|
402
|
-
var import_core_sdk2, import_viem5, import_chains2, APY_WINDOW_KEY2, SurfLiquidAgent;
|
|
403
|
-
var init_surfliquid_agent = __esm({
|
|
404
|
-
"src/agents/surfliquid/surfliquid.agent.ts"() {
|
|
405
|
-
"use strict";
|
|
406
|
-
import_core_sdk2 = require("@surf_liquid/core-sdk");
|
|
407
|
-
import_viem5 = require("viem");
|
|
408
|
-
import_chains2 = require("viem/chains");
|
|
409
|
-
init_errors();
|
|
410
|
-
init_surfliquid_constants();
|
|
411
|
-
init_permit2();
|
|
412
|
-
init_surfliquid_mapper();
|
|
413
|
-
init_surfliquid_wallet_adapter();
|
|
414
|
-
init_surfliquid_morpho();
|
|
415
|
-
APY_WINDOW_KEY2 = {
|
|
416
|
-
"7D": "apy7d",
|
|
417
|
-
"14D": "apy14d",
|
|
418
|
-
"30D": "apy30d"
|
|
419
|
-
};
|
|
420
|
-
SurfLiquidAgent = class {
|
|
421
|
-
constructor(config) {
|
|
422
|
-
this.config = config;
|
|
423
|
-
}
|
|
424
|
-
config;
|
|
425
|
-
id = "surfliquid";
|
|
426
|
-
supportedChainIds = [SURFLIQUID_CHAIN_ID];
|
|
427
|
-
supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
|
|
428
|
-
surf = null;
|
|
429
|
-
connectedAddress = null;
|
|
430
|
-
// In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
|
|
431
|
-
connectPromise = null;
|
|
432
|
-
ensureSurf() {
|
|
433
|
-
if (this.surf) return this.surf;
|
|
434
|
-
this.surf = import_core_sdk2.SurfClient.create({
|
|
435
|
-
projectName: this.config.projectName,
|
|
436
|
-
appId: this.config.appId,
|
|
437
|
-
environment: "mainnet",
|
|
438
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
439
|
-
apiBaseUrl: this.config.apiBaseUrl,
|
|
440
|
-
rpcUrl: this.config.rpcUrl,
|
|
441
|
-
// Let the SDK auto-approve USDC to the vault before depositing.
|
|
442
|
-
autoApprove: true
|
|
443
|
-
});
|
|
444
|
-
return this.surf;
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Connects + authenticates the SurfClient against owney's provider. Skips the
|
|
448
|
-
* SIWE prompt when already authenticated for this wallet (cookie session).
|
|
449
|
-
*/
|
|
450
|
-
async connect(state) {
|
|
451
|
-
const surf = this.ensureSurf();
|
|
452
|
-
const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
|
|
453
|
-
if (sameWallet && surf.getAuthState().authenticated) {
|
|
454
|
-
return surf;
|
|
455
|
-
}
|
|
456
|
-
if (this.connectPromise) return this.connectPromise;
|
|
457
|
-
this.connectPromise = (async () => {
|
|
458
|
-
surf.registerWalletAdapter(
|
|
459
|
-
"owney",
|
|
460
|
-
new OwneyWalletAdapter(state.provider)
|
|
461
|
-
);
|
|
462
|
-
await surf.connectWallet("owney");
|
|
463
|
-
await surf.authenticate();
|
|
464
|
-
this.connectedAddress = state.walletAddress;
|
|
465
|
-
return surf;
|
|
466
|
-
})();
|
|
467
|
-
try {
|
|
468
|
-
return await this.connectPromise;
|
|
469
|
-
} finally {
|
|
470
|
-
this.connectPromise = null;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Returns the user's vault address, deploying one on first use. SurfLiquid's
|
|
475
|
-
* deposit requires the vault to exist, so this must run before depositing.
|
|
476
|
-
* Existing vault → returned as-is; otherwise `deployVault()` is sent
|
|
477
|
-
* (user-pays) and the freshly deployed address is returned.
|
|
478
|
-
*/
|
|
479
|
-
async resolveVaultAddress(surf, owner) {
|
|
480
|
-
const vault = await surf.getVault(owner).catch(() => null);
|
|
481
|
-
if (vault?.exists && vault.userVaultAddress) {
|
|
482
|
-
return vault.userVaultAddress;
|
|
483
|
-
}
|
|
484
|
-
const { vaultAddress } = await surf.deployVault();
|
|
485
|
-
return vaultAddress;
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Grants the user's vault a standing USDC allowance so SurfLiquid's
|
|
489
|
-
* `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
|
|
490
|
-
* for why one prompt per deposit is worth removing.
|
|
491
|
-
*
|
|
492
|
-
* Fails OPEN on a read error: if the allowance can't be checked we simply
|
|
493
|
-
* return and let SurfLiquid's own per-deposit approve run, because a flaky
|
|
494
|
-
* RPC must never block a deposit. A failed or rejected APPROVE does
|
|
495
|
-
* propagate — the user declined a transaction, and letting SurfLiquid
|
|
496
|
-
* immediately ask again for a smaller one is exactly the double prompt this
|
|
497
|
-
* removes.
|
|
498
|
-
*/
|
|
499
|
-
async ensureVaultAllowance(state, vaultAddress, amount) {
|
|
500
|
-
const spender = vaultAddress;
|
|
501
|
-
const transport = (0, import_viem5.custom)(state.provider);
|
|
502
|
-
const publicClient = (0, import_viem5.createPublicClient)({ chain: import_chains2.base, transport });
|
|
503
|
-
let allowance;
|
|
504
|
-
try {
|
|
505
|
-
allowance = await publicClient.readContract({
|
|
506
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
507
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
508
|
-
functionName: "allowance",
|
|
509
|
-
args: [state.walletAddress, spender]
|
|
510
|
-
});
|
|
511
|
-
} catch (error) {
|
|
512
|
-
console.warn(
|
|
513
|
-
"[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
|
|
514
|
-
error instanceof Error ? error.message : String(error)
|
|
515
|
-
);
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
if (allowance >= amount) return;
|
|
519
|
-
const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
|
|
520
|
-
const wallet = (0, import_viem5.createWalletClient)({
|
|
521
|
-
account: state.walletAddress,
|
|
522
|
-
chain: import_chains2.base,
|
|
523
|
-
transport
|
|
524
|
-
});
|
|
525
|
-
const hash = await wallet.writeContract({
|
|
526
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
527
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
528
|
-
functionName: "approve",
|
|
529
|
-
args: [spender, target],
|
|
530
|
-
account: state.walletAddress,
|
|
531
|
-
chain: import_chains2.base
|
|
532
|
-
});
|
|
533
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
534
|
-
hash,
|
|
535
|
-
confirmations: 1
|
|
536
|
-
});
|
|
537
|
-
if (receipt.status !== "success") {
|
|
538
|
-
throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
// --- IAgent: lifecycle ---
|
|
542
|
-
async disconnect() {
|
|
543
|
-
if (this.surf) {
|
|
544
|
-
await this.surf.disconnectWallet();
|
|
545
|
-
}
|
|
546
|
-
this.connectedAddress = null;
|
|
547
|
-
}
|
|
548
|
-
async activateAgent(state) {
|
|
549
|
-
await this.connect(state);
|
|
550
|
-
}
|
|
551
|
-
// --- IAgent: funds (user-pays; asset is always USDC, callback ignored) ---
|
|
552
|
-
async deposit(state, _chainId, amount, _asset, _depositCallback) {
|
|
553
|
-
const surf = await this.connect(state);
|
|
554
|
-
const human = (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
|
|
555
|
-
const smartWallet = await this.resolveVaultAddress(
|
|
556
|
-
surf,
|
|
557
|
-
state.walletAddress
|
|
558
|
-
);
|
|
559
|
-
await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
|
|
560
|
-
const tx = await surf.deposit({
|
|
561
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
562
|
-
amount: human
|
|
563
|
-
});
|
|
564
|
-
await tx.wait();
|
|
565
|
-
return { txHash: tx.hash, smartWallet, amount };
|
|
566
|
-
}
|
|
567
|
-
async withdraw(state, _chainId, _token, amount) {
|
|
568
|
-
const surf = await this.connect(state);
|
|
569
|
-
const human = amount != null ? (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
|
|
570
|
-
try {
|
|
571
|
-
const tx = await surf.withdraw({
|
|
572
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
573
|
-
amount: human
|
|
574
|
-
});
|
|
575
|
-
await tx.wait();
|
|
576
|
-
return {
|
|
577
|
-
txHash: tx.hash,
|
|
578
|
-
type: amount != null ? "partial" : "full",
|
|
579
|
-
amount: amount ?? "0"
|
|
580
|
-
};
|
|
581
|
-
} catch (error) {
|
|
582
|
-
throw new OwneyError(
|
|
583
|
-
"WITHDRAW_FAILED",
|
|
584
|
-
error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
|
|
585
|
-
{ chainId: SURFLIQUID_CHAIN_ID, amount },
|
|
586
|
-
this.id
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
// --- IAgent: portfolio reads ---
|
|
591
|
-
async getBalances(state, chainId) {
|
|
592
|
-
const surf = await this.connect(state);
|
|
593
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
594
|
-
const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
|
|
595
|
-
const morphoStats = await fetchMorphoStatsByVault(
|
|
596
|
-
morphoVaultAddresses,
|
|
597
|
-
chainId
|
|
598
|
-
);
|
|
599
|
-
return mapBalances2(vault, chainId, morphoStats);
|
|
600
|
-
}
|
|
601
|
-
async getEarnings(state) {
|
|
602
|
-
const surf = await this.connect(state);
|
|
603
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
604
|
-
return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
|
|
605
|
-
}
|
|
606
|
-
async getAccountApy(state, _chainId, days, _tokenSymbol) {
|
|
607
|
-
const surf = await this.connect(state);
|
|
608
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
609
|
-
return mapAccountApy(vault, days);
|
|
610
|
-
}
|
|
611
|
-
async getHistory(state, chainId, options) {
|
|
612
|
-
const surf = await this.connect(state);
|
|
613
|
-
const page = options?.cursor ? Number(options.cursor) : 1;
|
|
614
|
-
const limit = options?.limit ?? 10;
|
|
615
|
-
const result = await surf.getAgentMessages(
|
|
616
|
-
state.walletAddress,
|
|
617
|
-
page,
|
|
618
|
-
limit,
|
|
619
|
-
options?.fromDate,
|
|
620
|
-
options?.toDate
|
|
621
|
-
);
|
|
622
|
-
return mapHistory(result, chainId);
|
|
623
|
-
}
|
|
624
|
-
async getUserProfile(state) {
|
|
625
|
-
const surf = await this.connect(state);
|
|
626
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
627
|
-
return mapUserProfile2(vault, state.walletAddress);
|
|
628
|
-
}
|
|
629
|
-
// --- IAgent: discovery (no wallet) ---
|
|
630
|
-
async getAgentApy(days, _options) {
|
|
631
|
-
const surf = this.ensureSurf();
|
|
632
|
-
const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
|
|
633
|
-
const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
|
|
634
|
-
if (!usdc) return { averageApy: 0 };
|
|
635
|
-
const windowed = usdc[APY_WINDOW_KEY2[days]];
|
|
636
|
-
return { averageApy: windowed != null ? windowed : usdc.currentAPY };
|
|
637
|
-
}
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
|
|
642
20
|
// src/index.ts
|
|
643
21
|
var index_exports = {};
|
|
644
22
|
__export(index_exports, {
|
|
@@ -648,8 +26,7 @@ __export(index_exports, {
|
|
|
648
26
|
NotConnectedError: () => NotConnectedError,
|
|
649
27
|
OwneyError: () => OwneyError,
|
|
650
28
|
OwneySDK: () => OwneySDK,
|
|
651
|
-
createOwneySIWX: () => createOwneySIWX
|
|
652
|
-
setOwneyDebug: () => setOwneyDebug
|
|
29
|
+
createOwneySIWX: () => createOwneySIWX
|
|
653
30
|
});
|
|
654
31
|
module.exports = __toCommonJS(index_exports);
|
|
655
32
|
|
|
@@ -711,8 +88,56 @@ var SupportedAssets = [
|
|
|
711
88
|
}
|
|
712
89
|
];
|
|
713
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
|
+
|
|
714
140
|
// src/lib/utils.ts
|
|
715
|
-
init_errors();
|
|
716
141
|
var isValidChainId = (chainId) => {
|
|
717
142
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
718
143
|
throw new OwneyError(
|
|
@@ -786,46 +211,46 @@ function resolveChainId(chain) {
|
|
|
786
211
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
787
212
|
const portfolio = raw.portfolio;
|
|
788
213
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
789
|
-
const rawPositions = portfolio.positions ?? [];
|
|
790
|
-
const detailByKey = /* @__PURE__ */ new Map();
|
|
791
|
-
for (const p of rawPositions) {
|
|
792
|
-
const cid = resolveChainId(p.chain ?? "");
|
|
793
|
-
const symbol = (p.token_symbol ?? "").toUpperCase();
|
|
794
|
-
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
795
|
-
}
|
|
796
214
|
let totalBalance = 0;
|
|
797
215
|
const tokens = [];
|
|
798
|
-
const positions = [];
|
|
799
216
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
800
217
|
const positionChainId = Number(chainIdKey);
|
|
801
|
-
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
802
218
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
803
219
|
tokensBySymbol ?? {}
|
|
804
220
|
)) {
|
|
805
|
-
const amount = hexToDecimal(balance || "0",
|
|
221
|
+
const amount = hexToDecimal(balance || "0", decimals);
|
|
806
222
|
totalBalance += amount;
|
|
807
223
|
tokens.push({
|
|
808
|
-
chain:
|
|
224
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
809
225
|
chainId: positionChainId,
|
|
810
226
|
asset: symbol,
|
|
811
227
|
amount: String(amount)
|
|
812
228
|
});
|
|
813
|
-
const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
|
|
814
|
-
positions.push({
|
|
815
|
-
chain: chainName,
|
|
816
|
-
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
817
|
-
protocolId: detail?.protocol_id,
|
|
818
|
-
pool: detail?.pool,
|
|
819
|
-
asset: symbol,
|
|
820
|
-
amount: String(amount),
|
|
821
|
-
apy: detail?.pool_apy,
|
|
822
|
-
tvl: detail?.pool_tvl,
|
|
823
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
824
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
825
|
-
liquidity: detail?.liquidity
|
|
826
|
-
});
|
|
827
229
|
}
|
|
828
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
|
+
}));
|
|
829
254
|
return {
|
|
830
255
|
smartWallet,
|
|
831
256
|
totalBalance: String(totalBalance),
|
|
@@ -987,9 +412,7 @@ function mapUserProfile(raw, userAddress) {
|
|
|
987
412
|
chains: raw.chains || [],
|
|
988
413
|
strategy: raw.strategy,
|
|
989
414
|
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
990
|
-
protocols: raw.protocols || []
|
|
991
|
-
splitting: raw.splitting,
|
|
992
|
-
minSplits: raw.minSplits
|
|
415
|
+
protocols: raw.protocols || []
|
|
993
416
|
};
|
|
994
417
|
}
|
|
995
418
|
function mapApyByStrategy(raw) {
|
|
@@ -1102,9 +525,6 @@ function decodeHistoryCursor(token) {
|
|
|
1102
525
|
return parsed;
|
|
1103
526
|
}
|
|
1104
527
|
|
|
1105
|
-
// src/agents/zyfai/zyfai.agent.ts
|
|
1106
|
-
init_errors();
|
|
1107
|
-
|
|
1108
528
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
1109
529
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
1110
530
|
var storage = () => {
|
|
@@ -1139,23 +559,23 @@ var readLegacySession = (store, address) => {
|
|
|
1139
559
|
const legacyKeys = [];
|
|
1140
560
|
try {
|
|
1141
561
|
for (let i = 0; i < store.length; i++) {
|
|
1142
|
-
const
|
|
1143
|
-
if (
|
|
562
|
+
const key = store.key(i);
|
|
563
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
1144
564
|
}
|
|
1145
565
|
} catch {
|
|
1146
566
|
return null;
|
|
1147
567
|
}
|
|
1148
568
|
let adopted = null;
|
|
1149
|
-
for (const
|
|
569
|
+
for (const key of legacyKeys) {
|
|
1150
570
|
if (!adopted) {
|
|
1151
571
|
try {
|
|
1152
|
-
const parsed = JSON.parse(store.getItem(
|
|
572
|
+
const parsed = JSON.parse(store.getItem(key) ?? "");
|
|
1153
573
|
if (isFreshSession(parsed)) adopted = parsed;
|
|
1154
574
|
} catch {
|
|
1155
575
|
}
|
|
1156
576
|
}
|
|
1157
577
|
try {
|
|
1158
|
-
store.removeItem(
|
|
578
|
+
store.removeItem(key);
|
|
1159
579
|
} catch {
|
|
1160
580
|
}
|
|
1161
581
|
}
|
|
@@ -1163,11 +583,11 @@ var readLegacySession = (store, address) => {
|
|
|
1163
583
|
};
|
|
1164
584
|
var readSession = (address, _chainId) => {
|
|
1165
585
|
if (typeof window === "undefined") return null;
|
|
1166
|
-
const
|
|
586
|
+
const key = buildKey(address);
|
|
1167
587
|
const store = storage();
|
|
1168
588
|
let raw = null;
|
|
1169
589
|
try {
|
|
1170
|
-
raw = store?.getItem(
|
|
590
|
+
raw = store?.getItem(key) ?? null;
|
|
1171
591
|
} catch {
|
|
1172
592
|
raw = null;
|
|
1173
593
|
}
|
|
@@ -1177,9 +597,9 @@ var readSession = (address, _chainId) => {
|
|
|
1177
597
|
if (isFreshSession(parsed)) return parsed;
|
|
1178
598
|
} catch {
|
|
1179
599
|
}
|
|
1180
|
-
memorySessions.delete(
|
|
600
|
+
memorySessions.delete(key);
|
|
1181
601
|
try {
|
|
1182
|
-
store?.removeItem(
|
|
602
|
+
store?.removeItem(key);
|
|
1183
603
|
} catch {
|
|
1184
604
|
}
|
|
1185
605
|
return null;
|
|
@@ -1189,27 +609,27 @@ var readSession = (address, _chainId) => {
|
|
|
1189
609
|
writeSession(address, _chainId, legacy);
|
|
1190
610
|
return legacy;
|
|
1191
611
|
}
|
|
1192
|
-
const cached = memorySessions.get(
|
|
612
|
+
const cached = memorySessions.get(key);
|
|
1193
613
|
if (isFreshSession(cached)) return cached;
|
|
1194
|
-
if (cached) memorySessions.delete(
|
|
614
|
+
if (cached) memorySessions.delete(key);
|
|
1195
615
|
return null;
|
|
1196
616
|
};
|
|
1197
617
|
var writeSession = (address, _chainId, session) => {
|
|
1198
618
|
if (typeof window === "undefined") return;
|
|
1199
|
-
const
|
|
1200
|
-
memorySessions.set(
|
|
619
|
+
const key = buildKey(address);
|
|
620
|
+
memorySessions.set(key, session);
|
|
1201
621
|
const store = storage();
|
|
1202
622
|
try {
|
|
1203
|
-
store?.setItem(
|
|
623
|
+
store?.setItem(key, JSON.stringify(session));
|
|
1204
624
|
} catch {
|
|
1205
625
|
}
|
|
1206
626
|
};
|
|
1207
627
|
var clearSession = (address, _chainId) => {
|
|
1208
|
-
const
|
|
1209
|
-
memorySessions.delete(
|
|
628
|
+
const key = buildKey(address);
|
|
629
|
+
memorySessions.delete(key);
|
|
1210
630
|
const store = storage();
|
|
1211
631
|
try {
|
|
1212
|
-
store?.removeItem(
|
|
632
|
+
store?.removeItem(key);
|
|
1213
633
|
} catch {
|
|
1214
634
|
}
|
|
1215
635
|
readLegacySession(store, address);
|
|
@@ -1240,149 +660,6 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
1240
660
|
};
|
|
1241
661
|
}
|
|
1242
662
|
|
|
1243
|
-
// src/agents/zyfai/splitting.ts
|
|
1244
|
-
var MAX_MIN_SPLITS = 4;
|
|
1245
|
-
var MIN_FORCE_SPLITS = 2;
|
|
1246
|
-
var AUTOMATIC_MIN_SPLITS = 1;
|
|
1247
|
-
function toZyfaiSplitting(policy) {
|
|
1248
|
-
switch (policy.splittingMode) {
|
|
1249
|
-
case "none":
|
|
1250
|
-
return { splitting: false };
|
|
1251
|
-
case "automatic":
|
|
1252
|
-
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
1253
|
-
case "force":
|
|
1254
|
-
return {
|
|
1255
|
-
splitting: true,
|
|
1256
|
-
minSplits: clampForceSplits(policy.minSplits)
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
function clampForceSplits(minSplits) {
|
|
1261
|
-
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
1262
|
-
return MIN_FORCE_SPLITS;
|
|
1263
|
-
}
|
|
1264
|
-
const rounded = Math.round(minSplits);
|
|
1265
|
-
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
1266
|
-
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
1267
|
-
return rounded;
|
|
1268
|
-
}
|
|
1269
|
-
function splittingNeedsUpdate(current, desired) {
|
|
1270
|
-
if (!current) return true;
|
|
1271
|
-
if (current.splitting !== desired.splitting) return true;
|
|
1272
|
-
if (desired.minSplits === void 0) return false;
|
|
1273
|
-
return current.minSplits !== desired.minSplits;
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
// src/agents/zyfai/pool-policy.ts
|
|
1277
|
-
function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
|
|
1278
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
1279
|
-
for (const selection of policy.selections) {
|
|
1280
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
1281
|
-
}
|
|
1282
|
-
const customizations = [];
|
|
1283
|
-
for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
|
|
1284
|
-
const available = availableByProtocol.get(protocolId);
|
|
1285
|
-
if (available === void 0) {
|
|
1286
|
-
continue;
|
|
1287
|
-
}
|
|
1288
|
-
const availableSet = new Set(available);
|
|
1289
|
-
for (const chainId of chainIds) {
|
|
1290
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
1291
|
-
if (stored === void 0) {
|
|
1292
|
-
customizations.push({
|
|
1293
|
-
protocolId,
|
|
1294
|
-
chainId,
|
|
1295
|
-
pools: [],
|
|
1296
|
-
autoselect: true
|
|
1297
|
-
});
|
|
1298
|
-
continue;
|
|
1299
|
-
}
|
|
1300
|
-
const pools = stored.pools.filter((pool) => availableSet.has(pool));
|
|
1301
|
-
customizations.push({
|
|
1302
|
-
protocolId,
|
|
1303
|
-
chainId,
|
|
1304
|
-
pools,
|
|
1305
|
-
autoselect: false
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
return customizations;
|
|
1310
|
-
}
|
|
1311
|
-
function deriveProtocols(policy, universe, chainsByProtocol) {
|
|
1312
|
-
if (policy.selections.length === 0) {
|
|
1313
|
-
return null;
|
|
1314
|
-
}
|
|
1315
|
-
const selectionByKey = /* @__PURE__ */ new Map();
|
|
1316
|
-
for (const selection of policy.selections) {
|
|
1317
|
-
selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
|
|
1318
|
-
}
|
|
1319
|
-
return universe.filter((protocolId) => {
|
|
1320
|
-
const chainIds = chainsByProtocol[protocolId];
|
|
1321
|
-
if (chainIds === void 0 || chainIds.length === 0) {
|
|
1322
|
-
return true;
|
|
1323
|
-
}
|
|
1324
|
-
const fullyDisabled = chainIds.every((chainId) => {
|
|
1325
|
-
const stored = selectionByKey.get(key(protocolId, chainId));
|
|
1326
|
-
return stored !== void 0 && stored.pools.length === 0;
|
|
1327
|
-
});
|
|
1328
|
-
return !fullyDisabled;
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
|
-
function key(protocolId, chainId) {
|
|
1332
|
-
return `${protocolId}:${chainId}`;
|
|
1333
|
-
}
|
|
1334
|
-
function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
1335
|
-
const allowed = new Set(dashboardChainIds);
|
|
1336
|
-
const result = {};
|
|
1337
|
-
for (const protocol of protocols) {
|
|
1338
|
-
result[protocol.id] = (protocol.chains ?? []).filter(
|
|
1339
|
-
(chainId) => allowed.has(chainId)
|
|
1340
|
-
);
|
|
1341
|
-
}
|
|
1342
|
-
return result;
|
|
1343
|
-
}
|
|
1344
|
-
function flattenAvailablePools(raw) {
|
|
1345
|
-
const byChain = raw ?? {};
|
|
1346
|
-
const names = [];
|
|
1347
|
-
for (const byToken of Object.values(byChain ?? {})) {
|
|
1348
|
-
for (const entry of Object.values(byToken ?? {})) {
|
|
1349
|
-
for (const pool of entry?.pools ?? []) {
|
|
1350
|
-
if (pool?.name) names.push(pool.name);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
return names;
|
|
1355
|
-
}
|
|
1356
|
-
function protocolListsEqual(a, b) {
|
|
1357
|
-
const left = [...a ?? []].sort();
|
|
1358
|
-
const right = [...b ?? []].sort();
|
|
1359
|
-
if (left.length !== right.length) return false;
|
|
1360
|
-
return left.every((value, index) => value === right[index]);
|
|
1361
|
-
}
|
|
1362
|
-
function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
|
|
1363
|
-
if (!current) return true;
|
|
1364
|
-
if (current.autoSelectProtocols !== desiredAutoSelect) return true;
|
|
1365
|
-
if (desiredProtocols === null) return false;
|
|
1366
|
-
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// src/lib/debug.ts
|
|
1370
|
-
var configuredDebug = false;
|
|
1371
|
-
function setOwneyDebug(enabled) {
|
|
1372
|
-
configuredDebug = enabled;
|
|
1373
|
-
}
|
|
1374
|
-
function isOwneyDebug() {
|
|
1375
|
-
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
1376
|
-
}
|
|
1377
|
-
function debugLog(scope, message, data) {
|
|
1378
|
-
if (!isOwneyDebug()) return;
|
|
1379
|
-
if (data === void 0) {
|
|
1380
|
-
console.log(`[${scope}] ${message}`);
|
|
1381
|
-
} else {
|
|
1382
|
-
console.log(`[${scope}] ${message}`, data);
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
663
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1387
664
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
1388
665
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -1395,12 +672,6 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
1395
672
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
1396
673
|
};
|
|
1397
674
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
1398
|
-
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
1399
|
-
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
1400
|
-
function isAlreadyActiveSessionKeyError(error) {
|
|
1401
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1402
|
-
return /already has an active session key/i.test(message);
|
|
1403
|
-
}
|
|
1404
675
|
var ZyfaiAgent = class {
|
|
1405
676
|
id = "zyfai";
|
|
1406
677
|
supportedChainIds = [8453, 42161, 1];
|
|
@@ -1627,71 +898,21 @@ var ZyfaiAgent = class {
|
|
|
1627
898
|
return await this.sdk.connectAccount(provider, chainId);
|
|
1628
899
|
}
|
|
1629
900
|
}
|
|
1630
|
-
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
1631
|
-
async connectFull(state, chainId) {
|
|
1632
|
-
await this.connectAuth(state, chainId);
|
|
1633
|
-
const validChainId = isValidChainId(chainId);
|
|
1634
|
-
const address = this.getAddress();
|
|
1635
|
-
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
1636
|
-
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
1637
|
-
if (!wallet.isDeployed) {
|
|
1638
|
-
await this.sdk.deploySafe(address, validChainId, "aggressive", false);
|
|
1639
|
-
try {
|
|
1640
|
-
if (validChainId === 42161) {
|
|
1641
|
-
await this.sdk.updateUserProfile({
|
|
1642
|
-
asset: "WETH",
|
|
1643
|
-
chains: [validChainId],
|
|
1644
|
-
protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
|
|
1645
|
-
// AAVE protocol ID
|
|
1646
|
-
autoSelectProtocols: false
|
|
1647
|
-
});
|
|
1648
|
-
}
|
|
1649
|
-
} catch (err) {
|
|
1650
|
-
console.warn(
|
|
1651
|
-
"Failed to configure AAVE protocol after Safe deployment:",
|
|
1652
|
-
err instanceof Error ? err.message : String(err)
|
|
1653
|
-
);
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
await this.ensureSessionKey(state, address, validChainId);
|
|
1657
|
-
}
|
|
1658
901
|
/**
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1663
|
-
*
|
|
1664
|
-
*
|
|
1665
|
-
* to (re)create a key per chain — that 400s and blocks the deposit. We only
|
|
1666
|
-
* create when the user has none.
|
|
1667
|
-
*
|
|
1668
|
-
* The one wrapper-side hardening that IS needed: a chain/account switch can
|
|
1669
|
-
* fire the provider's `accountsChanged` → `disconnectAccount`, tearing down
|
|
1670
|
-
* the zyfai connection (walletClient + authenticatedUserId both null) while
|
|
1671
|
-
* our own `connectAuth` guard still believes this chain is connected and
|
|
1672
|
-
* early-returns without reconnecting. `createSessionKey` then fails with
|
|
1673
|
-
* "No account connected". Detect that and reconnect first.
|
|
1674
|
-
*
|
|
1675
|
-
* NOTE: whether a globally-active session key actually authorizes activity on
|
|
1676
|
-
* a freshly-deployed Safe on a new chain is a backend/zyf question — the
|
|
1677
|
-
* wrapper cannot force per-chain activation given the global 400 guard.
|
|
1678
|
-
* See [[zyfai-per-chain-session-key]].
|
|
902
|
+
* Reconnect if the Zyfai connection was torn down behind our back: a
|
|
903
|
+
* chain/account switch fires the provider's `accountsChanged` →
|
|
904
|
+
* `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
|
|
905
|
+
* own `connectAuth` guard still believes this chain is connected and
|
|
906
|
+
* early-returns. Without this, authenticated calls (depositFunds,
|
|
907
|
+
* withdrawFunds) fail with "No account connected".
|
|
1679
908
|
*/
|
|
1680
|
-
async
|
|
909
|
+
async ensureConnected(state, chainId) {
|
|
910
|
+
await this.connectAuth(state, chainId);
|
|
1681
911
|
const internals = this.sdk;
|
|
1682
912
|
if (!internals.walletClient || internals.authenticatedUserId === null) {
|
|
1683
913
|
this.connectedChainId = null;
|
|
1684
914
|
await this.connectAuth(state, chainId);
|
|
1685
915
|
}
|
|
1686
|
-
const user = await this.sdk.getUserDetails();
|
|
1687
|
-
if (!user.hasActiveSessionKey) {
|
|
1688
|
-
try {
|
|
1689
|
-
await this.sdk.createSessionKey(address, chainId);
|
|
1690
|
-
} catch (error) {
|
|
1691
|
-
if (!isAlreadyActiveSessionKeyError(error)) throw error;
|
|
1692
|
-
internals.hasActiveSessionKey = true;
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
916
|
}
|
|
1696
917
|
/**
|
|
1697
918
|
* Sync newly-available protocols onto an existing user's profile at wallet
|
|
@@ -1761,180 +982,10 @@ var ZyfaiAgent = class {
|
|
|
1761
982
|
throw error;
|
|
1762
983
|
}
|
|
1763
984
|
}
|
|
1764
|
-
/**
|
|
1765
|
-
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1766
|
-
*
|
|
1767
|
-
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1768
|
-
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1769
|
-
* WETH holder's real setting untouched.
|
|
1770
|
-
*
|
|
1771
|
-
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1772
|
-
* must leave the user connected with their profile unchanged, never fail
|
|
1773
|
-
* activation.
|
|
1774
|
-
*/
|
|
1775
|
-
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1776
|
-
debugLog("zyfai:splitting", "applying org policy", {
|
|
1777
|
-
policy,
|
|
1778
|
-
// Per asset because Zyfai stores splitting under assetTypeSettings[asset].
|
|
1779
|
-
assets: SPLITTING_ASSETS
|
|
1780
|
-
});
|
|
1781
|
-
await Promise.all(
|
|
1782
|
-
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1783
|
-
);
|
|
1784
|
-
if (policy.poolPolicy) {
|
|
1785
|
-
await this.applyPoolPolicy(policy.poolPolicy);
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
async applySplitting(asset, policy) {
|
|
1789
|
-
try {
|
|
1790
|
-
const desired = toZyfaiSplitting(policy);
|
|
1791
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1792
|
-
const currentSplitting = {
|
|
1793
|
-
splitting: current?.splitting,
|
|
1794
|
-
minSplits: current?.minSplits
|
|
1795
|
-
};
|
|
1796
|
-
const needsUpdate = splittingNeedsUpdate(current, desired);
|
|
1797
|
-
debugLog("zyfai:splitting", `${asset}: comparing`, {
|
|
1798
|
-
mode: policy.splittingMode,
|
|
1799
|
-
current: currentSplitting,
|
|
1800
|
-
desired,
|
|
1801
|
-
// Spelled out because the "why" is the non-obvious part: minSplits is
|
|
1802
|
-
// what separates automatic (1) from force (2-4), not `splitting`.
|
|
1803
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1804
|
-
});
|
|
1805
|
-
if (!needsUpdate) return;
|
|
1806
|
-
const result = await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1807
|
-
debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
|
|
1808
|
-
sent: { asset, ...desired },
|
|
1809
|
-
// updateUserProfile re-reads the profile after PATCHing, so this is
|
|
1810
|
-
// Zyfai's own view of the result rather than an echo of what we sent.
|
|
1811
|
-
zyfaiNowReports: {
|
|
1812
|
-
splitting: result?.splitting,
|
|
1813
|
-
minSplits: result?.minSplits
|
|
1814
|
-
}
|
|
1815
|
-
});
|
|
1816
|
-
} catch (error) {
|
|
1817
|
-
console.warn(
|
|
1818
|
-
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1819
|
-
error instanceof Error ? error.message : String(error)
|
|
1820
|
-
);
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
/**
|
|
1824
|
-
* Apply the org's protocol/pool policy to this user's Zyfai profile.
|
|
1825
|
-
*
|
|
1826
|
-
* Two Zyfai writes, in a strict order:
|
|
1827
|
-
* 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
|
|
1828
|
-
* the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
|
|
1829
|
-
* 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
|
|
1830
|
-
* pool narrowing.
|
|
1831
|
-
*
|
|
1832
|
-
* Order matters: constraining a protocol's pools (step 2) while that
|
|
1833
|
-
* protocol is not yet in the allow-list (step 1 not yet applied) lands the
|
|
1834
|
-
* constraint on something the rebalance engine isn't considering.
|
|
1835
|
-
*
|
|
1836
|
-
* Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
|
|
1837
|
-
* connecting, so a Zyfai hiccup must leave the user connected with their
|
|
1838
|
-
* profile unchanged, never fail activation.
|
|
1839
|
-
*/
|
|
1840
|
-
async applyPoolPolicy(policy) {
|
|
1841
|
-
try {
|
|
1842
|
-
const { protocols: universe } = await this.sdk.getAvailableProtocols(
|
|
1843
|
-
this.supportedChainIds[0]
|
|
1844
|
-
);
|
|
1845
|
-
const universeIds = universe.map((p) => p.id);
|
|
1846
|
-
const chainsByProtocol = buildChainsByProtocol(
|
|
1847
|
-
universe,
|
|
1848
|
-
POOL_POLICY_CHAIN_IDS
|
|
1849
|
-
);
|
|
1850
|
-
debugLog("zyfai:pools", "protocol universe", {
|
|
1851
|
-
universeIds,
|
|
1852
|
-
chainsByProtocol
|
|
1853
|
-
});
|
|
1854
|
-
let strategy;
|
|
1855
|
-
const desiredProtocols = deriveProtocols(
|
|
1856
|
-
policy,
|
|
1857
|
-
universeIds,
|
|
1858
|
-
chainsByProtocol
|
|
1859
|
-
);
|
|
1860
|
-
const desiredAutoSelect = policy.autoApproveProtocols;
|
|
1861
|
-
for (const asset of SPLITTING_ASSETS) {
|
|
1862
|
-
const current = await this.sdk.getUserDetails(asset);
|
|
1863
|
-
if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
|
|
1864
|
-
strategy = current.strategy;
|
|
1865
|
-
}
|
|
1866
|
-
const needsUpdate = protocolsPolicyNeedsUpdate(
|
|
1867
|
-
current,
|
|
1868
|
-
desiredProtocols,
|
|
1869
|
-
desiredAutoSelect
|
|
1870
|
-
);
|
|
1871
|
-
debugLog("zyfai:pools", `${asset}: comparing protocols`, {
|
|
1872
|
-
current: {
|
|
1873
|
-
protocols: current.protocols,
|
|
1874
|
-
autoSelectProtocols: current.autoSelectProtocols
|
|
1875
|
-
},
|
|
1876
|
-
desired: {
|
|
1877
|
-
protocols: desiredProtocols,
|
|
1878
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1879
|
-
},
|
|
1880
|
-
decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
|
|
1881
|
-
});
|
|
1882
|
-
if (!needsUpdate) continue;
|
|
1883
|
-
const update = {
|
|
1884
|
-
asset,
|
|
1885
|
-
autoSelectProtocols: desiredAutoSelect
|
|
1886
|
-
};
|
|
1887
|
-
if (desiredProtocols !== null) update.protocols = desiredProtocols;
|
|
1888
|
-
await this.sdk.updateUserProfile(update);
|
|
1889
|
-
debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
|
|
1890
|
-
}
|
|
1891
|
-
const poolResults = await Promise.all(
|
|
1892
|
-
universe.map(async (protocol) => {
|
|
1893
|
-
try {
|
|
1894
|
-
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1895
|
-
return [protocol.id, flattenAvailablePools(raw)];
|
|
1896
|
-
} catch (error) {
|
|
1897
|
-
console.warn(
|
|
1898
|
-
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
1899
|
-
error instanceof Error ? error.message : String(error)
|
|
1900
|
-
);
|
|
1901
|
-
return null;
|
|
1902
|
-
}
|
|
1903
|
-
})
|
|
1904
|
-
);
|
|
1905
|
-
const availableByProtocol = /* @__PURE__ */ new Map();
|
|
1906
|
-
for (const result of poolResults) {
|
|
1907
|
-
if (result) availableByProtocol.set(result[0], result[1]);
|
|
1908
|
-
}
|
|
1909
|
-
const customizations = toZyfaiCustomizations(
|
|
1910
|
-
policy,
|
|
1911
|
-
availableByProtocol,
|
|
1912
|
-
chainsByProtocol
|
|
1913
|
-
);
|
|
1914
|
-
debugLog("zyfai:pools", "derived customizeBatch payload", {
|
|
1915
|
-
strategy,
|
|
1916
|
-
availableProtocolCount: availableByProtocol.size,
|
|
1917
|
-
customizations
|
|
1918
|
-
});
|
|
1919
|
-
if (customizations.length === 0) {
|
|
1920
|
-
debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
|
|
1921
|
-
return;
|
|
1922
|
-
}
|
|
1923
|
-
await this.sdk.customizeBatch(customizations);
|
|
1924
|
-
debugLog("zyfai:pools", "wrote customizeBatch", {
|
|
1925
|
-
count: customizations.length
|
|
1926
|
-
});
|
|
1927
|
-
} catch (error) {
|
|
1928
|
-
console.warn(
|
|
1929
|
-
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
1930
|
-
error instanceof Error ? error.message : String(error)
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
985
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1935
986
|
try {
|
|
1936
|
-
await this.connectFull(state, chainId);
|
|
1937
987
|
const validChainId = isValidChainId(chainId);
|
|
988
|
+
await this.ensureConnected(state, validChainId);
|
|
1938
989
|
if (depositCallback) {
|
|
1939
990
|
const wallet = await this.sdk.getSmartWalletAddress(
|
|
1940
991
|
this.getAddress(),
|
|
@@ -1960,7 +1011,8 @@ var ZyfaiAgent = class {
|
|
|
1960
1011
|
this.getAddress(),
|
|
1961
1012
|
validChainId,
|
|
1962
1013
|
amount,
|
|
1963
|
-
asset
|
|
1014
|
+
asset,
|
|
1015
|
+
"aggressive"
|
|
1964
1016
|
);
|
|
1965
1017
|
return mapDeposit(raw);
|
|
1966
1018
|
} catch (error) {
|
|
@@ -1969,8 +1021,8 @@ var ZyfaiAgent = class {
|
|
|
1969
1021
|
}
|
|
1970
1022
|
// --- IAgent: Fund operations ---
|
|
1971
1023
|
async withdraw(state, chainId, token, amount) {
|
|
1972
|
-
await this.connectFull(state, chainId);
|
|
1973
1024
|
const validChainId = isValidChainId(chainId);
|
|
1025
|
+
await this.ensureConnected(state, validChainId);
|
|
1974
1026
|
const raw = await this.sdk.withdrawFunds(
|
|
1975
1027
|
this.getAddress(),
|
|
1976
1028
|
validChainId,
|
|
@@ -2049,19 +1101,7 @@ var ZyfaiAgent = class {
|
|
|
2049
1101
|
}
|
|
2050
1102
|
async getUserProfile(state, chainId) {
|
|
2051
1103
|
await this.connectAuth(state, chainId);
|
|
2052
|
-
const validChainId = isValidChainId(chainId);
|
|
2053
1104
|
const raw = await this.sdk.getUserDetails();
|
|
2054
|
-
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
2055
|
-
asset: "USDC (default \u2014 no asset passed)",
|
|
2056
|
-
splitting: raw.splitting,
|
|
2057
|
-
minSplits: raw.minSplits,
|
|
2058
|
-
strategy: raw.strategy,
|
|
2059
|
-
chains: raw.chains,
|
|
2060
|
-
protocolCount: raw.protocols?.length,
|
|
2061
|
-
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
2062
|
-
smartWallet: raw.smartWallet
|
|
2063
|
-
});
|
|
2064
|
-
await this.ensureSessionKey(state, this.getAddress(), validChainId);
|
|
2065
1105
|
return mapUserProfile(raw, this.connectedAddress);
|
|
2066
1106
|
}
|
|
2067
1107
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
@@ -2092,46 +1132,8 @@ var ZyfaiAgent = class {
|
|
|
2092
1132
|
}
|
|
2093
1133
|
};
|
|
2094
1134
|
|
|
2095
|
-
// src/client.ts
|
|
2096
|
-
init_errors();
|
|
2097
|
-
|
|
2098
1135
|
// src/lib/routing-api.ts
|
|
2099
|
-
init_errors();
|
|
2100
1136
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2101
|
-
async function fetchOrgAgentConfig(apiKey) {
|
|
2102
|
-
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
2103
|
-
try {
|
|
2104
|
-
const res = await fetch(url, {
|
|
2105
|
-
method: "GET",
|
|
2106
|
-
headers: {
|
|
2107
|
-
"Content-Type": "application/json",
|
|
2108
|
-
"x-owney-api-key": `${apiKey}`
|
|
2109
|
-
}
|
|
2110
|
-
});
|
|
2111
|
-
if (!res.ok) {
|
|
2112
|
-
if (res.status !== 404) {
|
|
2113
|
-
console.warn(
|
|
2114
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2115
|
-
);
|
|
2116
|
-
}
|
|
2117
|
-
return null;
|
|
2118
|
-
}
|
|
2119
|
-
const json = await res.json();
|
|
2120
|
-
const policy = json.success ? json.data ?? null : null;
|
|
2121
|
-
debugLog(
|
|
2122
|
-
"owney-sdk",
|
|
2123
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2124
|
-
policy ?? void 0
|
|
2125
|
-
);
|
|
2126
|
-
return policy;
|
|
2127
|
-
} catch (error) {
|
|
2128
|
-
console.warn(
|
|
2129
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2130
|
-
error instanceof Error ? error.message : String(error)
|
|
2131
|
-
);
|
|
2132
|
-
return null;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
1137
|
async function fetchAgentKeys(apiKey) {
|
|
2136
1138
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
2137
1139
|
const res = await fetch(url, {
|
|
@@ -2161,7 +1163,6 @@ async function fetchAgentKeys(apiKey) {
|
|
|
2161
1163
|
}
|
|
2162
1164
|
|
|
2163
1165
|
// src/lib/health-report.ts
|
|
2164
|
-
init_errors();
|
|
2165
1166
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2166
1167
|
async function reportAgentFailure(apiKey, agentType, errorCode) {
|
|
2167
1168
|
try {
|
|
@@ -2311,11 +1312,8 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
2311
1312
|
}
|
|
2312
1313
|
|
|
2313
1314
|
// src/client.ts
|
|
2314
|
-
var
|
|
2315
|
-
var
|
|
2316
|
-
|
|
2317
|
-
// src/lib/sponsored-deposit.ts
|
|
2318
|
-
init_errors();
|
|
1315
|
+
var import_viem5 = require("viem");
|
|
1316
|
+
var import_chains2 = require("viem/chains");
|
|
2319
1317
|
|
|
2320
1318
|
// src/lib/transfer-auth.ts
|
|
2321
1319
|
var import_viem3 = require("viem");
|
|
@@ -2354,13 +1352,12 @@ function randomAuthNonce() {
|
|
|
2354
1352
|
}
|
|
2355
1353
|
|
|
2356
1354
|
// src/lib/sponsor-client.ts
|
|
2357
|
-
init_errors();
|
|
2358
1355
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2359
1356
|
async function postSponsorTransferAuth(input) {
|
|
2360
|
-
const
|
|
1357
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2361
1358
|
let res;
|
|
2362
1359
|
try {
|
|
2363
|
-
res = await fetch(`${
|
|
1360
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
2364
1361
|
method: "POST",
|
|
2365
1362
|
headers: {
|
|
2366
1363
|
"content-type": "application/json",
|
|
@@ -2397,10 +1394,10 @@ async function postSponsorTransferAuth(input) {
|
|
|
2397
1394
|
return parsed.data;
|
|
2398
1395
|
}
|
|
2399
1396
|
async function postSponsorPermit2Transfer(input) {
|
|
2400
|
-
const
|
|
1397
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2401
1398
|
let res;
|
|
2402
1399
|
try {
|
|
2403
|
-
res = await fetch(`${
|
|
1400
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
2404
1401
|
method: "POST",
|
|
2405
1402
|
headers: {
|
|
2406
1403
|
"content-type": "application/json",
|
|
@@ -2435,11 +1432,11 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
2435
1432
|
return parsed.data;
|
|
2436
1433
|
}
|
|
2437
1434
|
async function getSponsorRelayerAddress(input) {
|
|
2438
|
-
const
|
|
1435
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2439
1436
|
let res;
|
|
2440
1437
|
try {
|
|
2441
1438
|
res = await fetch(
|
|
2442
|
-
`${
|
|
1439
|
+
`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2443
1440
|
{
|
|
2444
1441
|
headers: { "x-owney-api-key": input.apiKey }
|
|
2445
1442
|
}
|
|
@@ -2471,8 +1468,85 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2471
1468
|
return parsed.data.relayer;
|
|
2472
1469
|
}
|
|
2473
1470
|
|
|
1471
|
+
// src/lib/permit2.ts
|
|
1472
|
+
var import_viem4 = require("viem");
|
|
1473
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
1474
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
1475
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
1476
|
+
{
|
|
1477
|
+
type: "function",
|
|
1478
|
+
name: "allowance",
|
|
1479
|
+
stateMutability: "view",
|
|
1480
|
+
inputs: [
|
|
1481
|
+
{ name: "owner", type: "address" },
|
|
1482
|
+
{ name: "spender", type: "address" }
|
|
1483
|
+
],
|
|
1484
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
type: "function",
|
|
1488
|
+
name: "approve",
|
|
1489
|
+
stateMutability: "nonpayable",
|
|
1490
|
+
inputs: [
|
|
1491
|
+
{ name: "spender", type: "address" },
|
|
1492
|
+
{ name: "amount", type: "uint256" }
|
|
1493
|
+
],
|
|
1494
|
+
outputs: [{ name: "", type: "bool" }]
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
type: "function",
|
|
1498
|
+
name: "balanceOf",
|
|
1499
|
+
stateMutability: "view",
|
|
1500
|
+
inputs: [{ name: "account", type: "address" }],
|
|
1501
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1502
|
+
}
|
|
1503
|
+
];
|
|
1504
|
+
function buildPermitTransferFromTypedData(input) {
|
|
1505
|
+
return {
|
|
1506
|
+
domain: {
|
|
1507
|
+
name: "Permit2",
|
|
1508
|
+
chainId: input.chainId,
|
|
1509
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
1510
|
+
},
|
|
1511
|
+
types: {
|
|
1512
|
+
PermitTransferFrom: [
|
|
1513
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
1514
|
+
{ name: "spender", type: "address" },
|
|
1515
|
+
{ name: "nonce", type: "uint256" },
|
|
1516
|
+
{ name: "deadline", type: "uint256" }
|
|
1517
|
+
],
|
|
1518
|
+
TokenPermissions: [
|
|
1519
|
+
{ name: "token", type: "address" },
|
|
1520
|
+
{ name: "amount", type: "uint256" }
|
|
1521
|
+
]
|
|
1522
|
+
},
|
|
1523
|
+
primaryType: "PermitTransferFrom",
|
|
1524
|
+
message: input.message
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
function randomPermit2Nonce() {
|
|
1528
|
+
const bytes = new Uint8Array(32);
|
|
1529
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1530
|
+
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
1531
|
+
}
|
|
1532
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
1533
|
+
return publicClient.readContract({
|
|
1534
|
+
address: token,
|
|
1535
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1536
|
+
functionName: "allowance",
|
|
1537
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
1541
|
+
return publicClient.readContract({
|
|
1542
|
+
address: token,
|
|
1543
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1544
|
+
functionName: "balanceOf",
|
|
1545
|
+
args: [owner]
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
|
|
2474
1549
|
// src/lib/sponsored-deposit.ts
|
|
2475
|
-
init_permit2();
|
|
2476
1550
|
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
2477
1551
|
function makeSponsoredDepositCallback(deps) {
|
|
2478
1552
|
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
@@ -2546,8 +1620,6 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2546
1620
|
}
|
|
2547
1621
|
|
|
2548
1622
|
// src/lib/sponsored-weth-deposit.ts
|
|
2549
|
-
init_errors();
|
|
2550
|
-
init_permit2();
|
|
2551
1623
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2552
1624
|
function makeSponsoredWethCallback(deps) {
|
|
2553
1625
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -2626,7 +1698,6 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2626
1698
|
}
|
|
2627
1699
|
|
|
2628
1700
|
// src/client.ts
|
|
2629
|
-
init_permit2();
|
|
2630
1701
|
function encodeMultiAgentCursor(map) {
|
|
2631
1702
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
2632
1703
|
}
|
|
@@ -2653,11 +1724,10 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
2653
1724
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
2654
1725
|
};
|
|
2655
1726
|
var VIEM_CHAIN2 = {
|
|
2656
|
-
8453:
|
|
2657
|
-
42161:
|
|
2658
|
-
1:
|
|
1727
|
+
8453: import_chains2.base,
|
|
1728
|
+
42161: import_chains2.arbitrum,
|
|
1729
|
+
1: import_chains2.mainnet
|
|
2659
1730
|
};
|
|
2660
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2661
1731
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2662
1732
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2663
1733
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2677,26 +1747,17 @@ var OwneySDK = class {
|
|
|
2677
1747
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
2678
1748
|
state = null;
|
|
2679
1749
|
apiKey;
|
|
2680
|
-
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
2681
|
-
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
2682
|
-
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
2683
|
-
// leave every user's agent profile alone.
|
|
2684
|
-
orgAgentConfig;
|
|
2685
|
-
orgAgentConfigPromise = null;
|
|
2686
1750
|
zyfaiRpcUrls;
|
|
2687
1751
|
routingApiBaseUrl;
|
|
2688
1752
|
referralSource;
|
|
2689
|
-
surfliquidApiBaseUrl;
|
|
2690
1753
|
cachedSponsoredCallback = null;
|
|
2691
1754
|
cachedWethSponsoredCallback = null;
|
|
2692
1755
|
initializingAgentsPromise = null;
|
|
2693
1756
|
constructor(config) {
|
|
2694
1757
|
this.apiKey = config.apiKey;
|
|
2695
|
-
if (config.debug) setOwneyDebug(true);
|
|
2696
1758
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2697
1759
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2698
1760
|
this.referralSource = config.referralSource;
|
|
2699
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2700
1761
|
}
|
|
2701
1762
|
/**
|
|
2702
1763
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2794,14 +1855,14 @@ var OwneySDK = class {
|
|
|
2794
1855
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2795
1856
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2796
1857
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2797
|
-
getPublicClient: (cid) => (0,
|
|
1858
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2798
1859
|
chain: VIEM_CHAIN2[cid],
|
|
2799
|
-
transport: (0,
|
|
1860
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2800
1861
|
}),
|
|
2801
|
-
getWalletClient: (cid) => (0,
|
|
1862
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2802
1863
|
account: owner,
|
|
2803
1864
|
chain: VIEM_CHAIN2[cid],
|
|
2804
|
-
transport: (0,
|
|
1865
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2805
1866
|
})
|
|
2806
1867
|
});
|
|
2807
1868
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2827,14 +1888,14 @@ var OwneySDK = class {
|
|
|
2827
1888
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2828
1889
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2829
1890
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2830
|
-
getPublicClient: (cid) => (0,
|
|
1891
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2831
1892
|
chain: VIEM_CHAIN2[cid],
|
|
2832
|
-
transport: (0,
|
|
1893
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2833
1894
|
}),
|
|
2834
|
-
getWalletClient: (cid) => (0,
|
|
1895
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2835
1896
|
account: owner,
|
|
2836
1897
|
chain: VIEM_CHAIN2[cid],
|
|
2837
|
-
transport: (0,
|
|
1898
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2838
1899
|
})
|
|
2839
1900
|
});
|
|
2840
1901
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2855,57 +1916,14 @@ var OwneySDK = class {
|
|
|
2855
1916
|
}
|
|
2856
1917
|
return active;
|
|
2857
1918
|
}
|
|
2858
|
-
/**
|
|
2859
|
-
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2860
|
-
* throws — it degrades to null — so this cannot break activation.
|
|
2861
|
-
*/
|
|
2862
|
-
async getOrgAgentConfig() {
|
|
2863
|
-
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2864
|
-
if (!this.orgAgentConfigPromise) {
|
|
2865
|
-
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2866
|
-
(config) => {
|
|
2867
|
-
this.orgAgentConfig = config;
|
|
2868
|
-
return config;
|
|
2869
|
-
}
|
|
2870
|
-
);
|
|
2871
|
-
}
|
|
2872
|
-
return this.orgAgentConfigPromise;
|
|
2873
|
-
}
|
|
2874
|
-
/**
|
|
2875
|
-
* Apply the org policy to one agent, after it has activated.
|
|
2876
|
-
*
|
|
2877
|
-
* Sequenced after activation rather than alongside it because applying the
|
|
2878
|
-
* policy needs the authenticated session activation establishes. Every failure
|
|
2879
|
-
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2880
|
-
* user's connect over.
|
|
2881
|
-
*/
|
|
2882
|
-
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2883
|
-
if (!agent.applyOrgPolicy) {
|
|
2884
|
-
debugLog(
|
|
2885
|
-
"owney-sdk",
|
|
2886
|
-
`${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
|
|
2887
|
-
);
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
try {
|
|
2891
|
-
const policy = await this.getOrgAgentConfig();
|
|
2892
|
-
if (!policy) return;
|
|
2893
|
-
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2894
|
-
} catch (error) {
|
|
2895
|
-
console.warn(
|
|
2896
|
-
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2897
|
-
error instanceof Error ? error.message : String(error)
|
|
2898
|
-
);
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
1919
|
async ensureAgentsInitialized() {
|
|
2902
1920
|
if (this.agents.size > 0) return;
|
|
2903
1921
|
if (!this.initializingAgentsPromise) {
|
|
2904
1922
|
this.initializingAgentsPromise = (async () => {
|
|
2905
1923
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2906
1924
|
this.disabledAgents.clear();
|
|
2907
|
-
for (const { key
|
|
2908
|
-
const agent =
|
|
1925
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
1926
|
+
const agent = this.createAgent(agent_type, key);
|
|
2909
1927
|
if (!agent) continue;
|
|
2910
1928
|
this.agents.set(agent_type, agent);
|
|
2911
1929
|
if (is_enabled === false) {
|
|
@@ -2926,21 +1944,9 @@ var OwneySDK = class {
|
|
|
2926
1944
|
this.initializingAgentsPromise = null;
|
|
2927
1945
|
}
|
|
2928
1946
|
}
|
|
2929
|
-
|
|
1947
|
+
createAgent(agentId, key) {
|
|
2930
1948
|
if (agentId === "zyfai") {
|
|
2931
|
-
return new ZyfaiAgent(
|
|
2932
|
-
}
|
|
2933
|
-
if (agentId === "surfliquid") {
|
|
2934
|
-
if (!projectName) return null;
|
|
2935
|
-
const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
|
|
2936
|
-
return new SurfLiquidAgent2({
|
|
2937
|
-
projectName,
|
|
2938
|
-
appId: key2,
|
|
2939
|
-
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2940
|
-
// which WebKit (iOS) discards when it is third-party. See
|
|
2941
|
-
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2942
|
-
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2943
|
-
});
|
|
1949
|
+
return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
|
|
2944
1950
|
}
|
|
2945
1951
|
return null;
|
|
2946
1952
|
}
|
|
@@ -2994,7 +2000,6 @@ var OwneySDK = class {
|
|
|
2994
2000
|
Promise.all(
|
|
2995
2001
|
agents.map(async (agent) => {
|
|
2996
2002
|
await agent.activateAgent(state, chainId);
|
|
2997
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2998
2003
|
})
|
|
2999
2004
|
).catch((error) => {
|
|
3000
2005
|
console.error("activateAgent background init failed:", error);
|
|
@@ -3022,7 +2027,6 @@ var OwneySDK = class {
|
|
|
3022
2027
|
Promise.all(
|
|
3023
2028
|
enabledCompatible.map(async (agent) => {
|
|
3024
2029
|
await agent.activateAgent(state, chainId);
|
|
3025
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
3026
2030
|
})
|
|
3027
2031
|
).catch((error) => {
|
|
3028
2032
|
console.error("activateAgent background init failed:", error);
|
|
@@ -3096,30 +2100,18 @@ var OwneySDK = class {
|
|
|
3096
2100
|
);
|
|
3097
2101
|
}
|
|
3098
2102
|
const agentResults = {};
|
|
3099
|
-
const agentErrors = {};
|
|
3100
2103
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
depositCallback
|
|
3110
|
-
);
|
|
3111
|
-
} catch (error) {
|
|
3112
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
3113
|
-
}
|
|
3114
|
-
}
|
|
3115
|
-
if (Object.keys(agentResults).length === 0) {
|
|
3116
|
-
throw new OwneyError(
|
|
3117
|
-
"DEPOSIT_ALL_FAILED",
|
|
3118
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
3119
|
-
{ agentErrors }
|
|
2104
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
2105
|
+
agent,
|
|
2106
|
+
state,
|
|
2107
|
+
chainId,
|
|
2108
|
+
agentAmount,
|
|
2109
|
+
asset,
|
|
2110
|
+
effectiveCallback,
|
|
2111
|
+
depositCallback
|
|
3120
2112
|
);
|
|
3121
2113
|
}
|
|
3122
|
-
return
|
|
2114
|
+
return { agentResults };
|
|
3123
2115
|
}
|
|
3124
2116
|
/**
|
|
3125
2117
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3276,34 +2268,6 @@ var OwneySDK = class {
|
|
|
3276
2268
|
}
|
|
3277
2269
|
return eligible;
|
|
3278
2270
|
}
|
|
3279
|
-
/**
|
|
3280
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
3281
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3282
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3283
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3284
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3285
|
-
*
|
|
3286
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
3287
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
3288
|
-
*/
|
|
3289
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
3290
|
-
try {
|
|
3291
|
-
await this.ensureAgentsInitialized();
|
|
3292
|
-
} catch (error) {
|
|
3293
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3294
|
-
return [];
|
|
3295
|
-
}
|
|
3296
|
-
throw error;
|
|
3297
|
-
}
|
|
3298
|
-
return [...this.agents.values()].filter((agent) => {
|
|
3299
|
-
const chainAssets = agent.supportedAssets.find(
|
|
3300
|
-
(sa) => sa.chainId === chainId
|
|
3301
|
-
);
|
|
3302
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3303
|
-
}).map((agent) => agent.id).sort(
|
|
3304
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3305
|
-
);
|
|
3306
|
-
}
|
|
3307
2271
|
// --- Fund operations ---
|
|
3308
2272
|
/**
|
|
3309
2273
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3339,17 +2303,9 @@ var OwneySDK = class {
|
|
|
3339
2303
|
}
|
|
3340
2304
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3341
2305
|
if (!amount) {
|
|
3342
|
-
const aggregated2 = await this.getBalances();
|
|
3343
|
-
const funded = projectAgentBalancesForAsset(
|
|
3344
|
-
eligibleAgents,
|
|
3345
|
-
aggregated2.agentBalances,
|
|
3346
|
-
chainId,
|
|
3347
|
-
asset,
|
|
3348
|
-
assetInfo.decimals
|
|
3349
|
-
).filter((b) => b.balance > 0n);
|
|
3350
2306
|
const results2 = {};
|
|
3351
2307
|
const agentErrors2 = {};
|
|
3352
|
-
for (const
|
|
2308
|
+
for (const agent of eligibleAgents) {
|
|
3353
2309
|
try {
|
|
3354
2310
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3355
2311
|
} catch (err) {
|
|
@@ -3366,10 +2322,9 @@ var OwneySDK = class {
|
|
|
3366
2322
|
{ asset, agentErrors: agentErrors2 }
|
|
3367
2323
|
);
|
|
3368
2324
|
}
|
|
3369
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3370
2325
|
return {
|
|
3371
2326
|
agentResult: results2,
|
|
3372
|
-
totalWithdrawn:
|
|
2327
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
3373
2328
|
};
|
|
3374
2329
|
}
|
|
3375
2330
|
const requested = BigInt(amount);
|
|
@@ -3739,10 +2694,10 @@ var OwneySDK = class {
|
|
|
3739
2694
|
);
|
|
3740
2695
|
}
|
|
3741
2696
|
const provider = this.requireConnectedProvider();
|
|
3742
|
-
const wallet = (0,
|
|
2697
|
+
const wallet = (0, import_viem5.createWalletClient)({
|
|
3743
2698
|
account: state.walletAddress,
|
|
3744
2699
|
chain: VIEM_CHAIN2[chainId],
|
|
3745
|
-
transport: (0,
|
|
2700
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3746
2701
|
});
|
|
3747
2702
|
const hash = await wallet.writeContract({
|
|
3748
2703
|
address: token,
|
|
@@ -3752,9 +2707,9 @@ var OwneySDK = class {
|
|
|
3752
2707
|
account: state.walletAddress,
|
|
3753
2708
|
chain: VIEM_CHAIN2[chainId]
|
|
3754
2709
|
});
|
|
3755
|
-
const publicClient = (0,
|
|
2710
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
3756
2711
|
chain: VIEM_CHAIN2[chainId],
|
|
3757
|
-
transport: (0,
|
|
2712
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3758
2713
|
});
|
|
3759
2714
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3760
2715
|
hash,
|
|
@@ -3862,11 +2817,8 @@ var OwneySDK = class {
|
|
|
3862
2817
|
}
|
|
3863
2818
|
};
|
|
3864
2819
|
|
|
3865
|
-
// src/index.ts
|
|
3866
|
-
init_errors();
|
|
3867
|
-
|
|
3868
2820
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3869
|
-
var
|
|
2821
|
+
var import_viem6 = require("viem");
|
|
3870
2822
|
var import_siwe = require("siwe");
|
|
3871
2823
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3872
2824
|
|
|
@@ -3889,22 +2841,22 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3889
2841
|
const legacyKeys = [];
|
|
3890
2842
|
try {
|
|
3891
2843
|
for (let i = 0; i < store.length; i++) {
|
|
3892
|
-
const
|
|
3893
|
-
if (
|
|
2844
|
+
const key = store.key(i);
|
|
2845
|
+
if (key?.startsWith(prefix)) legacyKeys.push(key);
|
|
3894
2846
|
}
|
|
3895
2847
|
} catch {
|
|
3896
2848
|
return null;
|
|
3897
2849
|
}
|
|
3898
2850
|
let adopted = null;
|
|
3899
|
-
for (const
|
|
2851
|
+
for (const key of legacyKeys) {
|
|
3900
2852
|
if (!adopted) {
|
|
3901
2853
|
try {
|
|
3902
|
-
adopted = JSON.parse(store.getItem(
|
|
2854
|
+
adopted = JSON.parse(store.getItem(key) ?? "");
|
|
3903
2855
|
} catch {
|
|
3904
2856
|
}
|
|
3905
2857
|
}
|
|
3906
2858
|
try {
|
|
3907
|
-
store.removeItem(
|
|
2859
|
+
store.removeItem(key);
|
|
3908
2860
|
} catch {
|
|
3909
2861
|
}
|
|
3910
2862
|
}
|
|
@@ -3912,11 +2864,11 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
3912
2864
|
};
|
|
3913
2865
|
var readSiwxSession = (address, chainId) => {
|
|
3914
2866
|
if (typeof window === "undefined") return null;
|
|
3915
|
-
const
|
|
2867
|
+
const key = buildKey2(address);
|
|
3916
2868
|
const store = storage2();
|
|
3917
2869
|
let raw = null;
|
|
3918
2870
|
try {
|
|
3919
|
-
raw = store?.getItem(
|
|
2871
|
+
raw = store?.getItem(key) ?? null;
|
|
3920
2872
|
} catch {
|
|
3921
2873
|
raw = null;
|
|
3922
2874
|
}
|
|
@@ -3924,9 +2876,9 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3924
2876
|
try {
|
|
3925
2877
|
return JSON.parse(raw);
|
|
3926
2878
|
} catch {
|
|
3927
|
-
memorySiwxSessions.delete(
|
|
2879
|
+
memorySiwxSessions.delete(key);
|
|
3928
2880
|
try {
|
|
3929
|
-
store?.removeItem(
|
|
2881
|
+
store?.removeItem(key);
|
|
3930
2882
|
} catch {
|
|
3931
2883
|
}
|
|
3932
2884
|
return null;
|
|
@@ -3937,24 +2889,24 @@ var readSiwxSession = (address, chainId) => {
|
|
|
3937
2889
|
writeSiwxSession(address, chainId, legacy);
|
|
3938
2890
|
return legacy;
|
|
3939
2891
|
}
|
|
3940
|
-
return memorySiwxSessions.get(
|
|
2892
|
+
return memorySiwxSessions.get(key) ?? null;
|
|
3941
2893
|
};
|
|
3942
2894
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
3943
2895
|
if (typeof window === "undefined") return;
|
|
3944
|
-
const
|
|
3945
|
-
memorySiwxSessions.set(
|
|
2896
|
+
const key = buildKey2(address);
|
|
2897
|
+
memorySiwxSessions.set(key, session);
|
|
3946
2898
|
const store = storage2();
|
|
3947
2899
|
try {
|
|
3948
|
-
store?.setItem(
|
|
2900
|
+
store?.setItem(key, JSON.stringify(session));
|
|
3949
2901
|
} catch {
|
|
3950
2902
|
}
|
|
3951
2903
|
};
|
|
3952
2904
|
var clearSiwxSession = (address, _chainId) => {
|
|
3953
|
-
const
|
|
3954
|
-
memorySiwxSessions.delete(
|
|
2905
|
+
const key = buildKey2(address);
|
|
2906
|
+
memorySiwxSessions.delete(key);
|
|
3955
2907
|
const store = storage2();
|
|
3956
2908
|
try {
|
|
3957
|
-
store?.removeItem(
|
|
2909
|
+
store?.removeItem(key);
|
|
3958
2910
|
} catch {
|
|
3959
2911
|
}
|
|
3960
2912
|
readLegacySiwxSession(store, address);
|
|
@@ -3993,7 +2945,7 @@ function buildSIWXConfig(deps) {
|
|
|
3993
2945
|
issuedAt,
|
|
3994
2946
|
toString() {
|
|
3995
2947
|
return new import_siwe.SiweMessage({
|
|
3996
|
-
address: (0,
|
|
2948
|
+
address: (0, import_viem6.getAddress)(accountAddress),
|
|
3997
2949
|
chainId: numericChainId(chainId),
|
|
3998
2950
|
domain,
|
|
3999
2951
|
uri,
|
|
@@ -4084,6 +3036,5 @@ function createOwneySIWX(config) {
|
|
|
4084
3036
|
NotConnectedError,
|
|
4085
3037
|
OwneyError,
|
|
4086
3038
|
OwneySDK,
|
|
4087
|
-
createOwneySIWX
|
|
4088
|
-
setOwneyDebug
|
|
3039
|
+
createOwneySIWX
|
|
4089
3040
|
});
|