@owney/sdk 0.7.8 → 0.7.10-beta.0
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 +906 -214
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +225 -190
- package/dist/surfliquid.agent-VNGQUSXN.js +473 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentChainIncompatibleError,
|
|
3
|
+
AgentNotFoundError,
|
|
4
|
+
ERC20_ALLOWANCE_ABI,
|
|
5
|
+
MAX_UINT256,
|
|
6
|
+
NotConnectedError,
|
|
7
|
+
OwneyError,
|
|
8
|
+
PERMIT2_ADDRESS,
|
|
9
|
+
buildPermitTransferFromTypedData,
|
|
10
|
+
randomPermit2Nonce,
|
|
11
|
+
readErc20Balance,
|
|
12
|
+
readPermit2Allowance
|
|
13
|
+
} from "./chunk-PWIKIQOX.js";
|
|
14
|
+
|
|
1
15
|
// src/agents/zyfai/zyfai.agent.ts
|
|
2
16
|
import { SMART_SESSIONS_VALIDATOR, ZyfaiSDK } from "@zyfai/sdk";
|
|
3
17
|
import { createPublicClient, http, parseAbi } from "viem";
|
|
@@ -56,55 +70,6 @@ var SupportedAssets = [
|
|
|
56
70
|
}
|
|
57
71
|
];
|
|
58
72
|
|
|
59
|
-
// src/errors.ts
|
|
60
|
-
var OwneyError = class extends Error {
|
|
61
|
-
code;
|
|
62
|
-
details;
|
|
63
|
-
agentId;
|
|
64
|
-
constructor(code, message, details, agentId) {
|
|
65
|
-
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
66
|
-
super(`${prefix} ${message}`);
|
|
67
|
-
this.name = "OwneyError";
|
|
68
|
-
this.code = code;
|
|
69
|
-
this.details = details;
|
|
70
|
-
this.agentId = agentId;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
var AgentNotFoundError = class extends OwneyError {
|
|
74
|
-
constructor(agentId, available) {
|
|
75
|
-
super(
|
|
76
|
-
"AGENT_NOT_FOUND",
|
|
77
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
78
|
-
{ agentId, available },
|
|
79
|
-
agentId
|
|
80
|
-
);
|
|
81
|
-
this.name = "AgentNotFoundError";
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
var NotConnectedError = class extends OwneyError {
|
|
85
|
-
constructor() {
|
|
86
|
-
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
87
|
-
this.name = "NotConnectedError";
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
var AgentChainIncompatibleError = class extends OwneyError {
|
|
91
|
-
incompatibleAgents;
|
|
92
|
-
connectedChainId;
|
|
93
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
94
|
-
const details = incompatibleAgents.map(
|
|
95
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
96
|
-
).join("; ");
|
|
97
|
-
super(
|
|
98
|
-
"AGENT_CHAIN_INCOMPATIBLE",
|
|
99
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
100
|
-
{ incompatibleAgents, connectedChainId }
|
|
101
|
-
);
|
|
102
|
-
this.name = "AgentChainIncompatibleError";
|
|
103
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
104
|
-
this.connectedChainId = connectedChainId;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
73
|
// src/lib/utils.ts
|
|
109
74
|
var isValidChainId = (chainId) => {
|
|
110
75
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -116,6 +81,12 @@ var isValidChainId = (chainId) => {
|
|
|
116
81
|
}
|
|
117
82
|
return chainId;
|
|
118
83
|
};
|
|
84
|
+
function isSameAsset(tokenSymbol, asset) {
|
|
85
|
+
const token = tokenSymbol.toLowerCase();
|
|
86
|
+
const target = asset.toLowerCase();
|
|
87
|
+
if (token === target) return true;
|
|
88
|
+
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
89
|
+
}
|
|
119
90
|
function hexToDecimal(hex, decimals = 6) {
|
|
120
91
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
121
92
|
const parsed = BigInt(normalized);
|
|
@@ -149,6 +120,10 @@ var DECIMALS_BY_SYMBOL = {
|
|
|
149
120
|
wbtc: 8,
|
|
150
121
|
cbbtc: 8
|
|
151
122
|
};
|
|
123
|
+
function canonicalSymbol(symbol) {
|
|
124
|
+
const upper = symbol.toUpperCase();
|
|
125
|
+
return upper === "ETH" ? "WETH" : upper;
|
|
126
|
+
}
|
|
152
127
|
function tokenDecimals(symbol, explicit) {
|
|
153
128
|
if (typeof explicit === "number" && Number.isFinite(explicit))
|
|
154
129
|
return explicit;
|
|
@@ -213,54 +188,89 @@ function mapPendingAllocations(raw) {
|
|
|
213
188
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
214
189
|
const portfolio = raw.portfolio;
|
|
215
190
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
191
|
+
const rawPositions = portfolio.positions ?? [];
|
|
192
|
+
const detailByKey = /* @__PURE__ */ new Map();
|
|
193
|
+
for (const p of rawPositions) {
|
|
194
|
+
const cid = resolveChainId(p.chain ?? "");
|
|
195
|
+
const symbol = canonicalSymbol(p.token_symbol ?? "");
|
|
196
|
+
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
197
|
+
}
|
|
216
198
|
let totalBalance = 0;
|
|
217
199
|
const tokens = [];
|
|
200
|
+
const positions = [];
|
|
218
201
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
219
202
|
const positionChainId = Number(chainIdKey);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
203
|
+
const chainName2 = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
204
|
+
for (const [
|
|
205
|
+
symbol,
|
|
206
|
+
{ balance, balanceWithFee, decimals }
|
|
207
|
+
] of Object.entries(tokensBySymbol ?? {})) {
|
|
208
|
+
const amount = hexToDecimal(
|
|
209
|
+
balanceWithFee ?? balance ?? "0",
|
|
210
|
+
tokenDecimals(symbol, decimals)
|
|
211
|
+
);
|
|
224
212
|
totalBalance += amount;
|
|
225
213
|
tokens.push({
|
|
226
|
-
chain:
|
|
214
|
+
chain: chainName2,
|
|
227
215
|
chainId: positionChainId,
|
|
228
216
|
asset: symbol,
|
|
229
217
|
amount: String(amount)
|
|
230
218
|
});
|
|
219
|
+
const detail = detailByKey.get(
|
|
220
|
+
`${positionChainId}:${canonicalSymbol(symbol)}`
|
|
221
|
+
);
|
|
222
|
+
positions.push({
|
|
223
|
+
chain: chainName2,
|
|
224
|
+
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
225
|
+
protocolId: detail?.protocol_id,
|
|
226
|
+
pool: detail?.pool,
|
|
227
|
+
// Report the token the way the rest of owney spells it ("WETH", as the
|
|
228
|
+
// pre-portfolioByChain mapper did), not Zyfai's internal "eth".
|
|
229
|
+
asset: canonicalSymbol(symbol),
|
|
230
|
+
amount: String(amount),
|
|
231
|
+
apy: detail?.pool_apy,
|
|
232
|
+
tvl: detail?.pool_tvl,
|
|
233
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
234
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
235
|
+
liquidity: detail?.liquidity
|
|
236
|
+
});
|
|
231
237
|
}
|
|
232
238
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
239
|
+
if (positions.length === 0) {
|
|
240
|
+
positions.push(
|
|
241
|
+
...(portfolio.positions ?? []).map((p) => ({
|
|
242
|
+
chain: p.chain ?? "",
|
|
243
|
+
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
244
|
+
protocolId: p.protocol_id,
|
|
245
|
+
pool: p.pool,
|
|
246
|
+
asset: p.token_symbol ?? "",
|
|
247
|
+
// Fee-adjusted underlying amounts are decimal base-unit strings; the
|
|
248
|
+
// legacy `amount` fallback is hex. Runtime getBalances payloads often
|
|
249
|
+
// carry `decimals` (e.g. 18 for WETH) — prefer it when present,
|
|
250
|
+
// otherwise fall back to the per-symbol lookup.
|
|
251
|
+
amount: String(
|
|
252
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ? normalizeDecimalPlace(
|
|
253
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0",
|
|
254
|
+
tokenDecimals(
|
|
255
|
+
p.token_symbol,
|
|
256
|
+
p.decimals
|
|
257
|
+
)
|
|
258
|
+
) : hexToDecimal(
|
|
259
|
+
p.amount || "0",
|
|
260
|
+
tokenDecimals(
|
|
261
|
+
p.token_symbol,
|
|
262
|
+
p.decimals
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
),
|
|
266
|
+
apy: p.pool_apy,
|
|
267
|
+
tvl: p.pool_tvl,
|
|
268
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
269
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
270
|
+
liquidity: p.liquidity
|
|
271
|
+
}))
|
|
272
|
+
);
|
|
273
|
+
}
|
|
264
274
|
const pendingAllocations = mapPendingAllocations(
|
|
265
275
|
portfolio.staleBalances
|
|
266
276
|
);
|
|
@@ -358,6 +368,11 @@ function mapEntries(rawEntries, chainId) {
|
|
|
358
368
|
"Top up wallet": "Top up",
|
|
359
369
|
"Partial withdraw from protocol": "Withdraw",
|
|
360
370
|
"Withdraw from protocol": "Withdraw",
|
|
371
|
+
// The agent's own leg of a top up: the funds the user sent moving into the
|
|
372
|
+
// pool that earns the APY. Zyfai emits it as a separate entry seconds after
|
|
373
|
+
// "Top up wallet" and for slightly less (gas). `Deposit` already exists in
|
|
374
|
+
// the public HistoryAction union, so no consumer type change is needed.
|
|
375
|
+
"Deposit to protocol": "Deposit",
|
|
361
376
|
Rebalance: "Rebalance"
|
|
362
377
|
};
|
|
363
378
|
void chainId;
|
|
@@ -398,12 +413,19 @@ function mapEntries(rawEntries, chainId) {
|
|
|
398
413
|
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
399
414
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
400
415
|
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
416
|
+
const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
|
|
417
|
+
protocol: p.protocol_name,
|
|
418
|
+
pool: p.pool ?? void 0,
|
|
419
|
+
tokenSymbol: p.token_symbol ?? void 0,
|
|
420
|
+
amount: mappedAction !== "Withdraw" && typeof p.amount === "string" && p.amount !== "" && p.amount !== "0x" ? String(hexToDecimal(p.amount, tokenDecimals(p.token_symbol))) : void 0
|
|
421
|
+
}));
|
|
401
422
|
return {
|
|
402
423
|
agent: "zyfai",
|
|
403
424
|
action: mappedAction,
|
|
404
425
|
date: entry.date || "",
|
|
405
426
|
newApy: newApy === null ? null : String(newApy),
|
|
406
427
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
428
|
+
...mappedPositions.length ? { positions: mappedPositions } : {},
|
|
407
429
|
transactions: [
|
|
408
430
|
{
|
|
409
431
|
txHashes: entry.transactionHash ? [entry.transactionHash] : [],
|
|
@@ -1331,6 +1353,37 @@ var ZyfaiAgent = class {
|
|
|
1331
1353
|
);
|
|
1332
1354
|
}
|
|
1333
1355
|
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Records the deposit with Zyfai, retrying transient failures.
|
|
1358
|
+
*
|
|
1359
|
+
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
1360
|
+
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
1361
|
+
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
1362
|
+
* balance it detects either way, so when this call is lost the user's deposit
|
|
1363
|
+
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
1364
|
+
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
1365
|
+
*/
|
|
1366
|
+
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
1367
|
+
const ATTEMPTS = 3;
|
|
1368
|
+
const RETRY_DELAY_MS = 1e3;
|
|
1369
|
+
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
1370
|
+
try {
|
|
1371
|
+
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
1372
|
+
return;
|
|
1373
|
+
} catch (logError) {
|
|
1374
|
+
if (attempt === ATTEMPTS) {
|
|
1375
|
+
console.error(
|
|
1376
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
1377
|
+
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
1378
|
+
);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
await new Promise(
|
|
1382
|
+
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1334
1387
|
/**
|
|
1335
1388
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1336
1389
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1634,14 +1687,12 @@ var ZyfaiAgent = class {
|
|
|
1634
1687
|
);
|
|
1635
1688
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1636
1689
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1690
|
+
await this.logDepositWithRetry(
|
|
1691
|
+
validChainId,
|
|
1692
|
+
txHash,
|
|
1693
|
+
amount,
|
|
1694
|
+
tokenAddress
|
|
1695
|
+
);
|
|
1645
1696
|
return { txHash, smartWallet, amount };
|
|
1646
1697
|
}
|
|
1647
1698
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1728,7 +1779,7 @@ var ZyfaiAgent = class {
|
|
|
1728
1779
|
toDate
|
|
1729
1780
|
});
|
|
1730
1781
|
raw.data.forEach((entry, idx) => {
|
|
1731
|
-
if (entry.chainId === validChainId
|
|
1782
|
+
if (entry.chainId === validChainId) {
|
|
1732
1783
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1733
1784
|
}
|
|
1734
1785
|
});
|
|
@@ -1896,11 +1947,10 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
1896
1947
|
// src/lib/helpers/withdraw-helper.ts
|
|
1897
1948
|
import { parseUnits } from "viem";
|
|
1898
1949
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
1899
|
-
const target = asset.toUpperCase();
|
|
1900
1950
|
return agents.map((agent) => {
|
|
1901
1951
|
const agentBalance = aggregated[agent.id];
|
|
1902
1952
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1903
|
-
(t) => t.chainId === chainId && t.asset
|
|
1953
|
+
(t) => t.chainId === chainId && isSameAsset(t.asset, asset)
|
|
1904
1954
|
);
|
|
1905
1955
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1906
1956
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2170,84 +2220,6 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2170
2220
|
return parsed.data.relayer;
|
|
2171
2221
|
}
|
|
2172
2222
|
|
|
2173
|
-
// src/lib/permit2.ts
|
|
2174
|
-
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2175
|
-
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2176
|
-
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2177
|
-
var ERC20_ALLOWANCE_ABI = [
|
|
2178
|
-
{
|
|
2179
|
-
type: "function",
|
|
2180
|
-
name: "allowance",
|
|
2181
|
-
stateMutability: "view",
|
|
2182
|
-
inputs: [
|
|
2183
|
-
{ name: "owner", type: "address" },
|
|
2184
|
-
{ name: "spender", type: "address" }
|
|
2185
|
-
],
|
|
2186
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
2187
|
-
},
|
|
2188
|
-
{
|
|
2189
|
-
type: "function",
|
|
2190
|
-
name: "approve",
|
|
2191
|
-
stateMutability: "nonpayable",
|
|
2192
|
-
inputs: [
|
|
2193
|
-
{ name: "spender", type: "address" },
|
|
2194
|
-
{ name: "amount", type: "uint256" }
|
|
2195
|
-
],
|
|
2196
|
-
outputs: [{ name: "", type: "bool" }]
|
|
2197
|
-
},
|
|
2198
|
-
{
|
|
2199
|
-
type: "function",
|
|
2200
|
-
name: "balanceOf",
|
|
2201
|
-
stateMutability: "view",
|
|
2202
|
-
inputs: [{ name: "account", type: "address" }],
|
|
2203
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
2204
|
-
}
|
|
2205
|
-
];
|
|
2206
|
-
function buildPermitTransferFromTypedData(input) {
|
|
2207
|
-
return {
|
|
2208
|
-
domain: {
|
|
2209
|
-
name: "Permit2",
|
|
2210
|
-
chainId: input.chainId,
|
|
2211
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
2212
|
-
},
|
|
2213
|
-
types: {
|
|
2214
|
-
PermitTransferFrom: [
|
|
2215
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
2216
|
-
{ name: "spender", type: "address" },
|
|
2217
|
-
{ name: "nonce", type: "uint256" },
|
|
2218
|
-
{ name: "deadline", type: "uint256" }
|
|
2219
|
-
],
|
|
2220
|
-
TokenPermissions: [
|
|
2221
|
-
{ name: "token", type: "address" },
|
|
2222
|
-
{ name: "amount", type: "uint256" }
|
|
2223
|
-
]
|
|
2224
|
-
},
|
|
2225
|
-
primaryType: "PermitTransferFrom",
|
|
2226
|
-
message: input.message
|
|
2227
|
-
};
|
|
2228
|
-
}
|
|
2229
|
-
function randomPermit2Nonce() {
|
|
2230
|
-
const bytes = new Uint8Array(32);
|
|
2231
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
2232
|
-
return BigInt(bytesToHex2(bytes));
|
|
2233
|
-
}
|
|
2234
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2235
|
-
return publicClient.readContract({
|
|
2236
|
-
address: token,
|
|
2237
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2238
|
-
functionName: "allowance",
|
|
2239
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
2240
|
-
});
|
|
2241
|
-
}
|
|
2242
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
2243
|
-
return publicClient.readContract({
|
|
2244
|
-
address: token,
|
|
2245
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2246
|
-
functionName: "balanceOf",
|
|
2247
|
-
args: [owner]
|
|
2248
|
-
});
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
2223
|
// src/lib/chain-guard.ts
|
|
2252
2224
|
var CHAIN_NAMES = {
|
|
2253
2225
|
1: "Ethereum",
|
|
@@ -2566,6 +2538,7 @@ var VIEM_CHAIN2 = {
|
|
|
2566
2538
|
42161: arbitrum2,
|
|
2567
2539
|
1: mainnet2
|
|
2568
2540
|
};
|
|
2541
|
+
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2569
2542
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2570
2543
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2571
2544
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2594,6 +2567,7 @@ var OwneySDK = class {
|
|
|
2594
2567
|
zyfaiRpcUrls;
|
|
2595
2568
|
routingApiBaseUrl;
|
|
2596
2569
|
referralSource;
|
|
2570
|
+
surfliquidApiBaseUrl;
|
|
2597
2571
|
cachedSponsoredCallback = null;
|
|
2598
2572
|
cachedWethSponsoredCallback = null;
|
|
2599
2573
|
paymasterServiceUrl;
|
|
@@ -2606,6 +2580,7 @@ var OwneySDK = class {
|
|
|
2606
2580
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2607
2581
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2608
2582
|
this.referralSource = config.referralSource;
|
|
2583
|
+
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2609
2584
|
}
|
|
2610
2585
|
/**
|
|
2611
2586
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2835,8 +2810,8 @@ var OwneySDK = class {
|
|
|
2835
2810
|
this.initializingAgentsPromise = (async () => {
|
|
2836
2811
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2837
2812
|
this.disabledAgents.clear();
|
|
2838
|
-
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2839
|
-
const agent = this.createAgent(agent_type, key2);
|
|
2813
|
+
for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
|
|
2814
|
+
const agent = await this.createAgent(agent_type, key2, project_name);
|
|
2840
2815
|
if (!agent) continue;
|
|
2841
2816
|
this.agents.set(agent_type, agent);
|
|
2842
2817
|
if (is_enabled === false) {
|
|
@@ -2857,10 +2832,22 @@ var OwneySDK = class {
|
|
|
2857
2832
|
this.initializingAgentsPromise = null;
|
|
2858
2833
|
}
|
|
2859
2834
|
}
|
|
2860
|
-
createAgent(agentId, key2) {
|
|
2835
|
+
async createAgent(agentId, key2, projectName) {
|
|
2861
2836
|
if (agentId === "zyfai") {
|
|
2862
2837
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2863
2838
|
}
|
|
2839
|
+
if (agentId === "surfliquid") {
|
|
2840
|
+
if (!projectName) return null;
|
|
2841
|
+
const { SurfLiquidAgent } = await import("./surfliquid.agent-VNGQUSXN.js");
|
|
2842
|
+
return new SurfLiquidAgent({
|
|
2843
|
+
projectName,
|
|
2844
|
+
appId: key2,
|
|
2845
|
+
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2846
|
+
// which WebKit (iOS) discards when it is third-party. See
|
|
2847
|
+
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2848
|
+
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2864
2851
|
return null;
|
|
2865
2852
|
}
|
|
2866
2853
|
// --- Account lifecycle ---
|
|
@@ -3015,18 +3002,30 @@ var OwneySDK = class {
|
|
|
3015
3002
|
);
|
|
3016
3003
|
}
|
|
3017
3004
|
const agentResults = {};
|
|
3005
|
+
const agentErrors = {};
|
|
3018
3006
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
3019
|
-
|
|
3020
|
-
agent
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3007
|
+
try {
|
|
3008
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
3009
|
+
agent,
|
|
3010
|
+
state,
|
|
3011
|
+
chainId,
|
|
3012
|
+
agentAmount,
|
|
3013
|
+
asset,
|
|
3014
|
+
effectiveCallback,
|
|
3015
|
+
depositCallback
|
|
3016
|
+
);
|
|
3017
|
+
} catch (error) {
|
|
3018
|
+
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
if (Object.keys(agentResults).length === 0) {
|
|
3022
|
+
throw new OwneyError(
|
|
3023
|
+
"DEPOSIT_ALL_FAILED",
|
|
3024
|
+
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
3025
|
+
{ agentErrors }
|
|
3027
3026
|
);
|
|
3028
3027
|
}
|
|
3029
|
-
return { agentResults };
|
|
3028
|
+
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
3030
3029
|
}
|
|
3031
3030
|
/**
|
|
3032
3031
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3142,9 +3141,8 @@ var OwneySDK = class {
|
|
|
3142
3141
|
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3143
3142
|
try {
|
|
3144
3143
|
const balance = await agent.getBalances(state, chainId);
|
|
3145
|
-
const target = asset.toLowerCase();
|
|
3146
3144
|
const token = balance.tokens.find(
|
|
3147
|
-
(t) => t.chainId === chainId && t.asset
|
|
3145
|
+
(t) => t.chainId === chainId && isSameAsset(t.asset, asset)
|
|
3148
3146
|
);
|
|
3149
3147
|
return !!token && Number(token.amount) > 0;
|
|
3150
3148
|
} catch {
|
|
@@ -3183,6 +3181,34 @@ var OwneySDK = class {
|
|
|
3183
3181
|
}
|
|
3184
3182
|
return eligible;
|
|
3185
3183
|
}
|
|
3184
|
+
/**
|
|
3185
|
+
* Agent ids the routing API provisioned for this org that support the given
|
|
3186
|
+
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3187
|
+
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3188
|
+
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3189
|
+
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3190
|
+
*
|
|
3191
|
+
* This is the source of truth for agent availability: an agent appears here
|
|
3192
|
+
* iff the routing API returned its key. No per-app feature flags.
|
|
3193
|
+
*/
|
|
3194
|
+
async getEligibleAgentIds(chainId, asset) {
|
|
3195
|
+
try {
|
|
3196
|
+
await this.ensureAgentsInitialized();
|
|
3197
|
+
} catch (error) {
|
|
3198
|
+
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3199
|
+
return [];
|
|
3200
|
+
}
|
|
3201
|
+
throw error;
|
|
3202
|
+
}
|
|
3203
|
+
return [...this.agents.values()].filter((agent) => {
|
|
3204
|
+
const chainAssets = agent.supportedAssets.find(
|
|
3205
|
+
(sa) => sa.chainId === chainId
|
|
3206
|
+
);
|
|
3207
|
+
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3208
|
+
}).map((agent) => agent.id).sort(
|
|
3209
|
+
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3210
|
+
);
|
|
3211
|
+
}
|
|
3186
3212
|
// --- Fund operations ---
|
|
3187
3213
|
/**
|
|
3188
3214
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3218,9 +3244,17 @@ var OwneySDK = class {
|
|
|
3218
3244
|
}
|
|
3219
3245
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3220
3246
|
if (!amount) {
|
|
3247
|
+
const aggregated2 = await this.getBalances();
|
|
3248
|
+
const funded = projectAgentBalancesForAsset(
|
|
3249
|
+
eligibleAgents,
|
|
3250
|
+
aggregated2.agentBalances,
|
|
3251
|
+
chainId,
|
|
3252
|
+
asset,
|
|
3253
|
+
assetInfo.decimals
|
|
3254
|
+
).filter((b) => b.balance > 0n);
|
|
3221
3255
|
const results2 = {};
|
|
3222
3256
|
const agentErrors2 = {};
|
|
3223
|
-
for (const agent of
|
|
3257
|
+
for (const { agent } of funded) {
|
|
3224
3258
|
try {
|
|
3225
3259
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3226
3260
|
} catch (err) {
|
|
@@ -3237,9 +3271,10 @@ var OwneySDK = class {
|
|
|
3237
3271
|
{ asset, agentErrors: agentErrors2 }
|
|
3238
3272
|
);
|
|
3239
3273
|
}
|
|
3274
|
+
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3240
3275
|
return {
|
|
3241
3276
|
agentResult: results2,
|
|
3242
|
-
totalWithdrawn:
|
|
3277
|
+
totalWithdrawn: totalWithdrawn.toString()
|
|
3243
3278
|
};
|
|
3244
3279
|
}
|
|
3245
3280
|
const requested = BigInt(amount);
|