@owney/sdk 0.6.9-beta.5 → 0.6.9-beta.7
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/chunk-PWIKIQOX.js +140 -0
- package/dist/index.cjs +770 -191
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +117 -166
- package/dist/surfliquid.agent-JOJJ3C5Y.js +448 -0
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,14 @@ 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
|
+
};
|
|
6
14
|
var __export = (target, all) => {
|
|
7
15
|
for (var name in all)
|
|
8
16
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -17,6 +25,620 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
25
|
};
|
|
18
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
27
|
|
|
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
|
+
|
|
20
642
|
// src/index.ts
|
|
21
643
|
var index_exports = {};
|
|
22
644
|
__export(index_exports, {
|
|
@@ -89,56 +711,8 @@ var SupportedAssets = [
|
|
|
89
711
|
}
|
|
90
712
|
];
|
|
91
713
|
|
|
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
|
-
|
|
141
714
|
// src/lib/utils.ts
|
|
715
|
+
init_errors();
|
|
142
716
|
var isValidChainId = (chainId) => {
|
|
143
717
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
144
718
|
throw new OwneyError(
|
|
@@ -212,46 +786,46 @@ function resolveChainId(chain) {
|
|
|
212
786
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
213
787
|
const portfolio = raw.portfolio;
|
|
214
788
|
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
|
+
}
|
|
215
796
|
let totalBalance = 0;
|
|
216
797
|
const tokens = [];
|
|
798
|
+
const positions = [];
|
|
217
799
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
218
800
|
const positionChainId = Number(chainIdKey);
|
|
801
|
+
const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
219
802
|
for (const [symbol, { balance, decimals }] of Object.entries(
|
|
220
803
|
tokensBySymbol ?? {}
|
|
221
804
|
)) {
|
|
222
|
-
const amount = hexToDecimal(balance || "0", decimals);
|
|
805
|
+
const amount = hexToDecimal(balance || "0", tokenDecimals(symbol, decimals));
|
|
223
806
|
totalBalance += amount;
|
|
224
807
|
tokens.push({
|
|
225
|
-
chain:
|
|
808
|
+
chain: chainName,
|
|
226
809
|
chainId: positionChainId,
|
|
227
810
|
asset: symbol,
|
|
228
811
|
amount: String(amount)
|
|
229
812
|
});
|
|
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
|
+
});
|
|
230
827
|
}
|
|
231
828
|
}
|
|
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
|
-
}));
|
|
255
829
|
return {
|
|
256
830
|
smartWallet,
|
|
257
831
|
totalBalance: String(totalBalance),
|
|
@@ -528,6 +1102,9 @@ function decodeHistoryCursor(token) {
|
|
|
528
1102
|
return parsed;
|
|
529
1103
|
}
|
|
530
1104
|
|
|
1105
|
+
// src/agents/zyfai/zyfai.agent.ts
|
|
1106
|
+
init_errors();
|
|
1107
|
+
|
|
531
1108
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
532
1109
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
533
1110
|
var storage = () => {
|
|
@@ -1515,7 +2092,11 @@ var ZyfaiAgent = class {
|
|
|
1515
2092
|
}
|
|
1516
2093
|
};
|
|
1517
2094
|
|
|
2095
|
+
// src/client.ts
|
|
2096
|
+
init_errors();
|
|
2097
|
+
|
|
1518
2098
|
// src/lib/routing-api.ts
|
|
2099
|
+
init_errors();
|
|
1519
2100
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1520
2101
|
async function fetchOrgAgentConfig(apiKey) {
|
|
1521
2102
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
@@ -1580,6 +2161,7 @@ async function fetchAgentKeys(apiKey) {
|
|
|
1580
2161
|
}
|
|
1581
2162
|
|
|
1582
2163
|
// src/lib/health-report.ts
|
|
2164
|
+
init_errors();
|
|
1583
2165
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1584
2166
|
async function reportAgentFailure(apiKey, agentType, errorCode) {
|
|
1585
2167
|
try {
|
|
@@ -1729,8 +2311,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1729
2311
|
}
|
|
1730
2312
|
|
|
1731
2313
|
// src/client.ts
|
|
1732
|
-
var
|
|
1733
|
-
var
|
|
2314
|
+
var import_viem6 = require("viem");
|
|
2315
|
+
var import_chains3 = require("viem/chains");
|
|
2316
|
+
|
|
2317
|
+
// src/lib/sponsored-deposit.ts
|
|
2318
|
+
init_errors();
|
|
1734
2319
|
|
|
1735
2320
|
// src/lib/transfer-auth.ts
|
|
1736
2321
|
var import_viem3 = require("viem");
|
|
@@ -1769,12 +2354,13 @@ function randomAuthNonce() {
|
|
|
1769
2354
|
}
|
|
1770
2355
|
|
|
1771
2356
|
// src/lib/sponsor-client.ts
|
|
2357
|
+
init_errors();
|
|
1772
2358
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1773
2359
|
async function postSponsorTransferAuth(input) {
|
|
1774
|
-
const
|
|
2360
|
+
const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1775
2361
|
let res;
|
|
1776
2362
|
try {
|
|
1777
|
-
res = await fetch(`${
|
|
2363
|
+
res = await fetch(`${base4}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
1778
2364
|
method: "POST",
|
|
1779
2365
|
headers: {
|
|
1780
2366
|
"content-type": "application/json",
|
|
@@ -1811,10 +2397,10 @@ async function postSponsorTransferAuth(input) {
|
|
|
1811
2397
|
return parsed.data;
|
|
1812
2398
|
}
|
|
1813
2399
|
async function postSponsorPermit2Transfer(input) {
|
|
1814
|
-
const
|
|
2400
|
+
const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1815
2401
|
let res;
|
|
1816
2402
|
try {
|
|
1817
|
-
res = await fetch(`${
|
|
2403
|
+
res = await fetch(`${base4}/api/v1/sponsor/permit2-transfer`, {
|
|
1818
2404
|
method: "POST",
|
|
1819
2405
|
headers: {
|
|
1820
2406
|
"content-type": "application/json",
|
|
@@ -1849,11 +2435,11 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
1849
2435
|
return parsed.data;
|
|
1850
2436
|
}
|
|
1851
2437
|
async function getSponsorRelayerAddress(input) {
|
|
1852
|
-
const
|
|
2438
|
+
const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1853
2439
|
let res;
|
|
1854
2440
|
try {
|
|
1855
2441
|
res = await fetch(
|
|
1856
|
-
`${
|
|
2442
|
+
`${base4}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
1857
2443
|
{
|
|
1858
2444
|
headers: { "x-owney-api-key": input.apiKey }
|
|
1859
2445
|
}
|
|
@@ -1885,85 +2471,8 @@ async function getSponsorRelayerAddress(input) {
|
|
|
1885
2471
|
return parsed.data.relayer;
|
|
1886
2472
|
}
|
|
1887
2473
|
|
|
1888
|
-
// src/lib/permit2.ts
|
|
1889
|
-
var import_viem4 = require("viem");
|
|
1890
|
-
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
1891
|
-
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
1892
|
-
var ERC20_ALLOWANCE_ABI = [
|
|
1893
|
-
{
|
|
1894
|
-
type: "function",
|
|
1895
|
-
name: "allowance",
|
|
1896
|
-
stateMutability: "view",
|
|
1897
|
-
inputs: [
|
|
1898
|
-
{ name: "owner", type: "address" },
|
|
1899
|
-
{ name: "spender", type: "address" }
|
|
1900
|
-
],
|
|
1901
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
1902
|
-
},
|
|
1903
|
-
{
|
|
1904
|
-
type: "function",
|
|
1905
|
-
name: "approve",
|
|
1906
|
-
stateMutability: "nonpayable",
|
|
1907
|
-
inputs: [
|
|
1908
|
-
{ name: "spender", type: "address" },
|
|
1909
|
-
{ name: "amount", type: "uint256" }
|
|
1910
|
-
],
|
|
1911
|
-
outputs: [{ name: "", type: "bool" }]
|
|
1912
|
-
},
|
|
1913
|
-
{
|
|
1914
|
-
type: "function",
|
|
1915
|
-
name: "balanceOf",
|
|
1916
|
-
stateMutability: "view",
|
|
1917
|
-
inputs: [{ name: "account", type: "address" }],
|
|
1918
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
1919
|
-
}
|
|
1920
|
-
];
|
|
1921
|
-
function buildPermitTransferFromTypedData(input) {
|
|
1922
|
-
return {
|
|
1923
|
-
domain: {
|
|
1924
|
-
name: "Permit2",
|
|
1925
|
-
chainId: input.chainId,
|
|
1926
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
1927
|
-
},
|
|
1928
|
-
types: {
|
|
1929
|
-
PermitTransferFrom: [
|
|
1930
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
1931
|
-
{ name: "spender", type: "address" },
|
|
1932
|
-
{ name: "nonce", type: "uint256" },
|
|
1933
|
-
{ name: "deadline", type: "uint256" }
|
|
1934
|
-
],
|
|
1935
|
-
TokenPermissions: [
|
|
1936
|
-
{ name: "token", type: "address" },
|
|
1937
|
-
{ name: "amount", type: "uint256" }
|
|
1938
|
-
]
|
|
1939
|
-
},
|
|
1940
|
-
primaryType: "PermitTransferFrom",
|
|
1941
|
-
message: input.message
|
|
1942
|
-
};
|
|
1943
|
-
}
|
|
1944
|
-
function randomPermit2Nonce() {
|
|
1945
|
-
const bytes = new Uint8Array(32);
|
|
1946
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
1947
|
-
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
1948
|
-
}
|
|
1949
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
1950
|
-
return publicClient.readContract({
|
|
1951
|
-
address: token,
|
|
1952
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
1953
|
-
functionName: "allowance",
|
|
1954
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
1955
|
-
});
|
|
1956
|
-
}
|
|
1957
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
1958
|
-
return publicClient.readContract({
|
|
1959
|
-
address: token,
|
|
1960
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
1961
|
-
functionName: "balanceOf",
|
|
1962
|
-
args: [owner]
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
2474
|
// src/lib/sponsored-deposit.ts
|
|
2475
|
+
init_permit2();
|
|
1967
2476
|
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
1968
2477
|
function makeSponsoredDepositCallback(deps) {
|
|
1969
2478
|
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
@@ -2037,6 +2546,8 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2037
2546
|
}
|
|
2038
2547
|
|
|
2039
2548
|
// src/lib/sponsored-weth-deposit.ts
|
|
2549
|
+
init_errors();
|
|
2550
|
+
init_permit2();
|
|
2040
2551
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2041
2552
|
function makeSponsoredWethCallback(deps) {
|
|
2042
2553
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -2115,6 +2626,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2115
2626
|
}
|
|
2116
2627
|
|
|
2117
2628
|
// src/client.ts
|
|
2629
|
+
init_permit2();
|
|
2118
2630
|
function encodeMultiAgentCursor(map) {
|
|
2119
2631
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
2120
2632
|
}
|
|
@@ -2141,10 +2653,11 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
2141
2653
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
2142
2654
|
};
|
|
2143
2655
|
var VIEM_CHAIN2 = {
|
|
2144
|
-
8453:
|
|
2145
|
-
42161:
|
|
2146
|
-
1:
|
|
2656
|
+
8453: import_chains3.base,
|
|
2657
|
+
42161: import_chains3.arbitrum,
|
|
2658
|
+
1: import_chains3.mainnet
|
|
2147
2659
|
};
|
|
2660
|
+
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2148
2661
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2149
2662
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2150
2663
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2173,6 +2686,7 @@ var OwneySDK = class {
|
|
|
2173
2686
|
zyfaiRpcUrls;
|
|
2174
2687
|
routingApiBaseUrl;
|
|
2175
2688
|
referralSource;
|
|
2689
|
+
surfliquidApiBaseUrl;
|
|
2176
2690
|
cachedSponsoredCallback = null;
|
|
2177
2691
|
cachedWethSponsoredCallback = null;
|
|
2178
2692
|
initializingAgentsPromise = null;
|
|
@@ -2182,6 +2696,7 @@ var OwneySDK = class {
|
|
|
2182
2696
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2183
2697
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2184
2698
|
this.referralSource = config.referralSource;
|
|
2699
|
+
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2185
2700
|
}
|
|
2186
2701
|
/**
|
|
2187
2702
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2279,14 +2794,14 @@ var OwneySDK = class {
|
|
|
2279
2794
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2280
2795
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2281
2796
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2282
|
-
getPublicClient: (cid) => (0,
|
|
2797
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
2283
2798
|
chain: VIEM_CHAIN2[cid],
|
|
2284
|
-
transport: (0,
|
|
2799
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2285
2800
|
}),
|
|
2286
|
-
getWalletClient: (cid) => (0,
|
|
2801
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
2287
2802
|
account: owner,
|
|
2288
2803
|
chain: VIEM_CHAIN2[cid],
|
|
2289
|
-
transport: (0,
|
|
2804
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2290
2805
|
})
|
|
2291
2806
|
});
|
|
2292
2807
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2312,14 +2827,14 @@ var OwneySDK = class {
|
|
|
2312
2827
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2313
2828
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2314
2829
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2315
|
-
getPublicClient: (cid) => (0,
|
|
2830
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
2316
2831
|
chain: VIEM_CHAIN2[cid],
|
|
2317
|
-
transport: (0,
|
|
2832
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2318
2833
|
}),
|
|
2319
|
-
getWalletClient: (cid) => (0,
|
|
2834
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
2320
2835
|
account: owner,
|
|
2321
2836
|
chain: VIEM_CHAIN2[cid],
|
|
2322
|
-
transport: (0,
|
|
2837
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2323
2838
|
})
|
|
2324
2839
|
});
|
|
2325
2840
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2389,8 +2904,8 @@ var OwneySDK = class {
|
|
|
2389
2904
|
this.initializingAgentsPromise = (async () => {
|
|
2390
2905
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2391
2906
|
this.disabledAgents.clear();
|
|
2392
|
-
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2393
|
-
const agent = this.createAgent(agent_type, key2);
|
|
2907
|
+
for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
|
|
2908
|
+
const agent = await this.createAgent(agent_type, key2, project_name);
|
|
2394
2909
|
if (!agent) continue;
|
|
2395
2910
|
this.agents.set(agent_type, agent);
|
|
2396
2911
|
if (is_enabled === false) {
|
|
@@ -2411,10 +2926,22 @@ var OwneySDK = class {
|
|
|
2411
2926
|
this.initializingAgentsPromise = null;
|
|
2412
2927
|
}
|
|
2413
2928
|
}
|
|
2414
|
-
createAgent(agentId, key2) {
|
|
2929
|
+
async createAgent(agentId, key2, projectName) {
|
|
2415
2930
|
if (agentId === "zyfai") {
|
|
2416
2931
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2417
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
|
+
});
|
|
2944
|
+
}
|
|
2418
2945
|
return null;
|
|
2419
2946
|
}
|
|
2420
2947
|
// --- Account lifecycle ---
|
|
@@ -2569,18 +3096,30 @@ var OwneySDK = class {
|
|
|
2569
3096
|
);
|
|
2570
3097
|
}
|
|
2571
3098
|
const agentResults = {};
|
|
3099
|
+
const agentErrors = {};
|
|
2572
3100
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
2573
|
-
|
|
2574
|
-
agent
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
3101
|
+
try {
|
|
3102
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
3103
|
+
agent,
|
|
3104
|
+
state,
|
|
3105
|
+
chainId,
|
|
3106
|
+
agentAmount,
|
|
3107
|
+
asset,
|
|
3108
|
+
effectiveCallback,
|
|
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 }
|
|
2581
3120
|
);
|
|
2582
3121
|
}
|
|
2583
|
-
return { agentResults };
|
|
3122
|
+
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
2584
3123
|
}
|
|
2585
3124
|
/**
|
|
2586
3125
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -2737,6 +3276,34 @@ var OwneySDK = class {
|
|
|
2737
3276
|
}
|
|
2738
3277
|
return eligible;
|
|
2739
3278
|
}
|
|
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
|
+
}
|
|
2740
3307
|
// --- Fund operations ---
|
|
2741
3308
|
/**
|
|
2742
3309
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -2772,9 +3339,17 @@ var OwneySDK = class {
|
|
|
2772
3339
|
}
|
|
2773
3340
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
2774
3341
|
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);
|
|
2775
3350
|
const results2 = {};
|
|
2776
3351
|
const agentErrors2 = {};
|
|
2777
|
-
for (const agent of
|
|
3352
|
+
for (const { agent } of funded) {
|
|
2778
3353
|
try {
|
|
2779
3354
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
2780
3355
|
} catch (err) {
|
|
@@ -2791,9 +3366,10 @@ var OwneySDK = class {
|
|
|
2791
3366
|
{ asset, agentErrors: agentErrors2 }
|
|
2792
3367
|
);
|
|
2793
3368
|
}
|
|
3369
|
+
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
2794
3370
|
return {
|
|
2795
3371
|
agentResult: results2,
|
|
2796
|
-
totalWithdrawn:
|
|
3372
|
+
totalWithdrawn: totalWithdrawn.toString()
|
|
2797
3373
|
};
|
|
2798
3374
|
}
|
|
2799
3375
|
const requested = BigInt(amount);
|
|
@@ -3163,10 +3739,10 @@ var OwneySDK = class {
|
|
|
3163
3739
|
);
|
|
3164
3740
|
}
|
|
3165
3741
|
const provider = this.requireConnectedProvider();
|
|
3166
|
-
const wallet = (0,
|
|
3742
|
+
const wallet = (0, import_viem6.createWalletClient)({
|
|
3167
3743
|
account: state.walletAddress,
|
|
3168
3744
|
chain: VIEM_CHAIN2[chainId],
|
|
3169
|
-
transport: (0,
|
|
3745
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3170
3746
|
});
|
|
3171
3747
|
const hash = await wallet.writeContract({
|
|
3172
3748
|
address: token,
|
|
@@ -3176,9 +3752,9 @@ var OwneySDK = class {
|
|
|
3176
3752
|
account: state.walletAddress,
|
|
3177
3753
|
chain: VIEM_CHAIN2[chainId]
|
|
3178
3754
|
});
|
|
3179
|
-
const publicClient = (0,
|
|
3755
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
3180
3756
|
chain: VIEM_CHAIN2[chainId],
|
|
3181
|
-
transport: (0,
|
|
3757
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3182
3758
|
});
|
|
3183
3759
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3184
3760
|
hash,
|
|
@@ -3286,8 +3862,11 @@ var OwneySDK = class {
|
|
|
3286
3862
|
}
|
|
3287
3863
|
};
|
|
3288
3864
|
|
|
3865
|
+
// src/index.ts
|
|
3866
|
+
init_errors();
|
|
3867
|
+
|
|
3289
3868
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3290
|
-
var
|
|
3869
|
+
var import_viem7 = require("viem");
|
|
3291
3870
|
var import_siwe = require("siwe");
|
|
3292
3871
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3293
3872
|
|
|
@@ -3414,7 +3993,7 @@ function buildSIWXConfig(deps) {
|
|
|
3414
3993
|
issuedAt,
|
|
3415
3994
|
toString() {
|
|
3416
3995
|
return new import_siwe.SiweMessage({
|
|
3417
|
-
address: (0,
|
|
3996
|
+
address: (0, import_viem7.getAddress)(accountAddress),
|
|
3418
3997
|
chainId: numericChainId(chainId),
|
|
3419
3998
|
domain,
|
|
3420
3999
|
uri,
|