@owney/sdk 0.7.11 → 0.7.12-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-PWIKIQOX.js +140 -0
- package/dist/index.cjs +930 -222
- package/dist/index.d.cts +52 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +249 -198
- 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,55 +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);
|
|
203
|
+
const chainName2 = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
220
204
|
for (const [
|
|
221
205
|
symbol,
|
|
222
206
|
{ balance, balanceWithFee, decimals }
|
|
223
207
|
] of Object.entries(tokensBySymbol ?? {})) {
|
|
224
|
-
const amount = hexToDecimal(
|
|
208
|
+
const amount = hexToDecimal(
|
|
209
|
+
balanceWithFee ?? balance ?? "0",
|
|
210
|
+
tokenDecimals(symbol, decimals)
|
|
211
|
+
);
|
|
225
212
|
totalBalance += amount;
|
|
226
213
|
tokens.push({
|
|
227
|
-
chain:
|
|
214
|
+
chain: chainName2,
|
|
228
215
|
chainId: positionChainId,
|
|
229
216
|
asset: symbol,
|
|
230
217
|
amount: String(amount)
|
|
231
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
|
+
});
|
|
232
237
|
}
|
|
233
238
|
}
|
|
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
|
-
|
|
264
|
-
|
|
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
|
+
}
|
|
265
274
|
const pendingAllocations = mapPendingAllocations(
|
|
266
275
|
portfolio.staleBalances
|
|
267
276
|
);
|
|
@@ -1344,6 +1353,37 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1344
1353
|
);
|
|
1345
1354
|
}
|
|
1346
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
|
+
}
|
|
1347
1387
|
/**
|
|
1348
1388
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1349
1389
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1647,14 +1687,12 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1647
1687
|
);
|
|
1648
1688
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1649
1689
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
);
|
|
1657
|
-
}
|
|
1690
|
+
await this.logDepositWithRetry(
|
|
1691
|
+
validChainId,
|
|
1692
|
+
txHash,
|
|
1693
|
+
amount,
|
|
1694
|
+
tokenAddress
|
|
1695
|
+
);
|
|
1658
1696
|
return { txHash, smartWallet, amount };
|
|
1659
1697
|
}
|
|
1660
1698
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1935,11 +1973,10 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
1935
1973
|
// src/lib/helpers/withdraw-helper.ts
|
|
1936
1974
|
import { parseUnits } from "viem";
|
|
1937
1975
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
1938
|
-
const target = asset.toUpperCase();
|
|
1939
1976
|
return agents.map((agent) => {
|
|
1940
1977
|
const agentBalance = aggregated[agent.id];
|
|
1941
1978
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1942
|
-
(t) => t.chainId === chainId && t.asset
|
|
1979
|
+
(t) => t.chainId === chainId && isSameAsset(t.asset, asset)
|
|
1943
1980
|
);
|
|
1944
1981
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1945
1982
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2209,84 +2246,6 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2209
2246
|
return parsed.data.relayer;
|
|
2210
2247
|
}
|
|
2211
2248
|
|
|
2212
|
-
// src/lib/permit2.ts
|
|
2213
|
-
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2214
|
-
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2215
|
-
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2216
|
-
var ERC20_ALLOWANCE_ABI = [
|
|
2217
|
-
{
|
|
2218
|
-
type: "function",
|
|
2219
|
-
name: "allowance",
|
|
2220
|
-
stateMutability: "view",
|
|
2221
|
-
inputs: [
|
|
2222
|
-
{ name: "owner", type: "address" },
|
|
2223
|
-
{ name: "spender", type: "address" }
|
|
2224
|
-
],
|
|
2225
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
2226
|
-
},
|
|
2227
|
-
{
|
|
2228
|
-
type: "function",
|
|
2229
|
-
name: "approve",
|
|
2230
|
-
stateMutability: "nonpayable",
|
|
2231
|
-
inputs: [
|
|
2232
|
-
{ name: "spender", type: "address" },
|
|
2233
|
-
{ name: "amount", type: "uint256" }
|
|
2234
|
-
],
|
|
2235
|
-
outputs: [{ name: "", type: "bool" }]
|
|
2236
|
-
},
|
|
2237
|
-
{
|
|
2238
|
-
type: "function",
|
|
2239
|
-
name: "balanceOf",
|
|
2240
|
-
stateMutability: "view",
|
|
2241
|
-
inputs: [{ name: "account", type: "address" }],
|
|
2242
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
2243
|
-
}
|
|
2244
|
-
];
|
|
2245
|
-
function buildPermitTransferFromTypedData(input) {
|
|
2246
|
-
return {
|
|
2247
|
-
domain: {
|
|
2248
|
-
name: "Permit2",
|
|
2249
|
-
chainId: input.chainId,
|
|
2250
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
2251
|
-
},
|
|
2252
|
-
types: {
|
|
2253
|
-
PermitTransferFrom: [
|
|
2254
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
2255
|
-
{ name: "spender", type: "address" },
|
|
2256
|
-
{ name: "nonce", type: "uint256" },
|
|
2257
|
-
{ name: "deadline", type: "uint256" }
|
|
2258
|
-
],
|
|
2259
|
-
TokenPermissions: [
|
|
2260
|
-
{ name: "token", type: "address" },
|
|
2261
|
-
{ name: "amount", type: "uint256" }
|
|
2262
|
-
]
|
|
2263
|
-
},
|
|
2264
|
-
primaryType: "PermitTransferFrom",
|
|
2265
|
-
message: input.message
|
|
2266
|
-
};
|
|
2267
|
-
}
|
|
2268
|
-
function randomPermit2Nonce() {
|
|
2269
|
-
const bytes = new Uint8Array(32);
|
|
2270
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
2271
|
-
return BigInt(bytesToHex2(bytes));
|
|
2272
|
-
}
|
|
2273
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2274
|
-
return publicClient.readContract({
|
|
2275
|
-
address: token,
|
|
2276
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2277
|
-
functionName: "allowance",
|
|
2278
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
2279
|
-
});
|
|
2280
|
-
}
|
|
2281
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
2282
|
-
return publicClient.readContract({
|
|
2283
|
-
address: token,
|
|
2284
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2285
|
-
functionName: "balanceOf",
|
|
2286
|
-
args: [owner]
|
|
2287
|
-
});
|
|
2288
|
-
}
|
|
2289
|
-
|
|
2290
2249
|
// src/lib/chain-guard.ts
|
|
2291
2250
|
var CHAIN_NAMES = {
|
|
2292
2251
|
1: "Ethereum",
|
|
@@ -2605,6 +2564,7 @@ var VIEM_CHAIN2 = {
|
|
|
2605
2564
|
42161: arbitrum2,
|
|
2606
2565
|
1: mainnet2
|
|
2607
2566
|
};
|
|
2567
|
+
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2608
2568
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2609
2569
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2610
2570
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2633,6 +2593,7 @@ var OwneySDK = class {
|
|
|
2633
2593
|
zyfaiRpcUrls;
|
|
2634
2594
|
routingApiBaseUrl;
|
|
2635
2595
|
referralSource;
|
|
2596
|
+
surfliquidApiBaseUrl;
|
|
2636
2597
|
cachedSponsoredCallback = null;
|
|
2637
2598
|
cachedWethSponsoredCallback = null;
|
|
2638
2599
|
paymasterServiceUrl;
|
|
@@ -2645,6 +2606,7 @@ var OwneySDK = class {
|
|
|
2645
2606
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2646
2607
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2647
2608
|
this.referralSource = config.referralSource;
|
|
2609
|
+
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2648
2610
|
}
|
|
2649
2611
|
/**
|
|
2650
2612
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2874,8 +2836,8 @@ var OwneySDK = class {
|
|
|
2874
2836
|
this.initializingAgentsPromise = (async () => {
|
|
2875
2837
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2876
2838
|
this.disabledAgents.clear();
|
|
2877
|
-
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2878
|
-
const agent = this.createAgent(agent_type, key2);
|
|
2839
|
+
for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
|
|
2840
|
+
const agent = await this.createAgent(agent_type, key2, project_name);
|
|
2879
2841
|
if (!agent) continue;
|
|
2880
2842
|
this.agents.set(agent_type, agent);
|
|
2881
2843
|
if (is_enabled === false) {
|
|
@@ -2896,10 +2858,22 @@ var OwneySDK = class {
|
|
|
2896
2858
|
this.initializingAgentsPromise = null;
|
|
2897
2859
|
}
|
|
2898
2860
|
}
|
|
2899
|
-
createAgent(agentId, key2) {
|
|
2861
|
+
async createAgent(agentId, key2, projectName) {
|
|
2900
2862
|
if (agentId === "zyfai") {
|
|
2901
2863
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2902
2864
|
}
|
|
2865
|
+
if (agentId === "surfliquid") {
|
|
2866
|
+
if (!projectName) return null;
|
|
2867
|
+
const { SurfLiquidAgent } = await import("./surfliquid.agent-VNGQUSXN.js");
|
|
2868
|
+
return new SurfLiquidAgent({
|
|
2869
|
+
projectName,
|
|
2870
|
+
appId: key2,
|
|
2871
|
+
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2872
|
+
// which WebKit (iOS) discards when it is third-party. See
|
|
2873
|
+
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2874
|
+
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2903
2877
|
return null;
|
|
2904
2878
|
}
|
|
2905
2879
|
// --- Account lifecycle ---
|
|
@@ -2949,12 +2923,7 @@ var OwneySDK = class {
|
|
|
2949
2923
|
this.activeAgents.add(id);
|
|
2950
2924
|
}
|
|
2951
2925
|
state.chainId = chainId;
|
|
2952
|
-
|
|
2953
|
-
agents.map(async (agent) => {
|
|
2954
|
-
await agent.activateAgent(state, chainId);
|
|
2955
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2956
|
-
})
|
|
2957
|
-
).catch((error) => {
|
|
2926
|
+
this.activateAgentsInTurn(agents, state, chainId).catch((error) => {
|
|
2958
2927
|
console.error("activateAgent background init failed:", error);
|
|
2959
2928
|
});
|
|
2960
2929
|
return;
|
|
@@ -2977,14 +2946,48 @@ var OwneySDK = class {
|
|
|
2977
2946
|
const enabledCompatible = compatible.filter(
|
|
2978
2947
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
2979
2948
|
);
|
|
2980
|
-
|
|
2981
|
-
|
|
2949
|
+
this.activateAgentsInTurn(enabledCompatible, state, chainId).catch(
|
|
2950
|
+
(error) => {
|
|
2951
|
+
console.error("activateAgent background init failed:", error);
|
|
2952
|
+
}
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
2957
|
+
*
|
|
2958
|
+
* Every agent opens its activation with its own wallet signature — Zyfai's
|
|
2959
|
+
* SIWX (exchanged for a JWT) and SurfLiquid's SIWE (exchanged for an httpOnly
|
|
2960
|
+
* cookie). Run in parallel, that puts two `personal_sign` requests on one
|
|
2961
|
+
* wallet connection in the same instant. Over WalletConnect both are
|
|
2962
|
+
* delivered to the wallet, which renders one signing request at a time and
|
|
2963
|
+
* queues or silently drops the other: neither promise settles, so activation
|
|
2964
|
+
* hangs until the caller's timeout with no prompt the user can act on. The
|
|
2965
|
+
* single-agent era never hit this — there was no second prompt to collide
|
|
2966
|
+
* with — so it appeared the moment a second agent became eligible.
|
|
2967
|
+
*
|
|
2968
|
+
* Serializing costs no real wall-clock: the user can only approve one prompt
|
|
2969
|
+
* at a time anyway.
|
|
2970
|
+
*
|
|
2971
|
+
* Every agent is attempted even if an earlier one fails, so one declined
|
|
2972
|
+
* signature can't deny the remaining agents their turn. The first failure is
|
|
2973
|
+
* rethrown (matching the previous `Promise.all` rejection) once all agents
|
|
2974
|
+
* have had a chance to activate.
|
|
2975
|
+
*/
|
|
2976
|
+
async activateAgentsInTurn(agents, state, chainId) {
|
|
2977
|
+
let firstError = null;
|
|
2978
|
+
for (const agent of agents) {
|
|
2979
|
+
try {
|
|
2982
2980
|
await agent.activateAgent(state, chainId);
|
|
2983
2981
|
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2984
|
-
})
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
if (firstError === null) {
|
|
2984
|
+
firstError = error;
|
|
2985
|
+
} else {
|
|
2986
|
+
console.error(`activateAgent(${agent.id}) failed:`, error);
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
if (firstError !== null) throw firstError;
|
|
2988
2991
|
}
|
|
2989
2992
|
/**
|
|
2990
2993
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -3054,18 +3057,30 @@ var OwneySDK = class {
|
|
|
3054
3057
|
);
|
|
3055
3058
|
}
|
|
3056
3059
|
const agentResults = {};
|
|
3060
|
+
const agentErrors = {};
|
|
3057
3061
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
3058
|
-
|
|
3059
|
-
agent
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3062
|
+
try {
|
|
3063
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
3064
|
+
agent,
|
|
3065
|
+
state,
|
|
3066
|
+
chainId,
|
|
3067
|
+
agentAmount,
|
|
3068
|
+
asset,
|
|
3069
|
+
effectiveCallback,
|
|
3070
|
+
depositCallback
|
|
3071
|
+
);
|
|
3072
|
+
} catch (error) {
|
|
3073
|
+
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
if (Object.keys(agentResults).length === 0) {
|
|
3077
|
+
throw new OwneyError(
|
|
3078
|
+
"DEPOSIT_ALL_FAILED",
|
|
3079
|
+
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
3080
|
+
{ agentErrors }
|
|
3066
3081
|
);
|
|
3067
3082
|
}
|
|
3068
|
-
return { agentResults };
|
|
3083
|
+
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
3069
3084
|
}
|
|
3070
3085
|
/**
|
|
3071
3086
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3181,9 +3196,8 @@ var OwneySDK = class {
|
|
|
3181
3196
|
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3182
3197
|
try {
|
|
3183
3198
|
const balance = await agent.getBalances(state, chainId);
|
|
3184
|
-
const target = asset.toLowerCase();
|
|
3185
3199
|
const token = balance.tokens.find(
|
|
3186
|
-
(t) => t.chainId === chainId && t.asset
|
|
3200
|
+
(t) => t.chainId === chainId && isSameAsset(t.asset, asset)
|
|
3187
3201
|
);
|
|
3188
3202
|
return !!token && Number(token.amount) > 0;
|
|
3189
3203
|
} catch {
|
|
@@ -3222,6 +3236,34 @@ var OwneySDK = class {
|
|
|
3222
3236
|
}
|
|
3223
3237
|
return eligible;
|
|
3224
3238
|
}
|
|
3239
|
+
/**
|
|
3240
|
+
* Agent ids the routing API provisioned for this org that support the given
|
|
3241
|
+
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3242
|
+
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3243
|
+
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3244
|
+
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3245
|
+
*
|
|
3246
|
+
* This is the source of truth for agent availability: an agent appears here
|
|
3247
|
+
* iff the routing API returned its key. No per-app feature flags.
|
|
3248
|
+
*/
|
|
3249
|
+
async getEligibleAgentIds(chainId, asset) {
|
|
3250
|
+
try {
|
|
3251
|
+
await this.ensureAgentsInitialized();
|
|
3252
|
+
} catch (error) {
|
|
3253
|
+
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3254
|
+
return [];
|
|
3255
|
+
}
|
|
3256
|
+
throw error;
|
|
3257
|
+
}
|
|
3258
|
+
return [...this.agents.values()].filter((agent) => {
|
|
3259
|
+
const chainAssets = agent.supportedAssets.find(
|
|
3260
|
+
(sa) => sa.chainId === chainId
|
|
3261
|
+
);
|
|
3262
|
+
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3263
|
+
}).map((agent) => agent.id).sort(
|
|
3264
|
+
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3225
3267
|
// --- Fund operations ---
|
|
3226
3268
|
/**
|
|
3227
3269
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3257,9 +3299,17 @@ var OwneySDK = class {
|
|
|
3257
3299
|
}
|
|
3258
3300
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3259
3301
|
if (!amount) {
|
|
3302
|
+
const aggregated2 = await this.getBalances();
|
|
3303
|
+
const funded = projectAgentBalancesForAsset(
|
|
3304
|
+
eligibleAgents,
|
|
3305
|
+
aggregated2.agentBalances,
|
|
3306
|
+
chainId,
|
|
3307
|
+
asset,
|
|
3308
|
+
assetInfo.decimals
|
|
3309
|
+
).filter((b) => b.balance > 0n);
|
|
3260
3310
|
const results2 = {};
|
|
3261
3311
|
const agentErrors2 = {};
|
|
3262
|
-
for (const agent of
|
|
3312
|
+
for (const { agent } of funded) {
|
|
3263
3313
|
try {
|
|
3264
3314
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3265
3315
|
} catch (err) {
|
|
@@ -3276,9 +3326,10 @@ var OwneySDK = class {
|
|
|
3276
3326
|
{ asset, agentErrors: agentErrors2 }
|
|
3277
3327
|
);
|
|
3278
3328
|
}
|
|
3329
|
+
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3279
3330
|
return {
|
|
3280
3331
|
agentResult: results2,
|
|
3281
|
-
totalWithdrawn:
|
|
3332
|
+
totalWithdrawn: totalWithdrawn.toString()
|
|
3282
3333
|
};
|
|
3283
3334
|
}
|
|
3284
3335
|
const requested = BigInt(amount);
|