@owney/sdk 0.7.12-beta.0 → 0.7.12-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +251 -901
- package/dist/index.d.cts +24 -30
- package/dist/index.d.ts +24 -30
- package/dist/index.js +227 -220
- package/package.json +1 -3
- package/dist/chunk-PWIKIQOX.js +0 -140
- package/dist/surfliquid.agent-VNGQUSXN.js +0 -473
package/dist/index.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
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
|
-
|
|
15
1
|
// src/agents/zyfai/zyfai.agent.ts
|
|
16
2
|
import { SMART_SESSIONS_VALIDATOR, ZyfaiSDK } from "@zyfai/sdk";
|
|
17
3
|
import { createPublicClient, http, parseAbi } from "viem";
|
|
@@ -70,6 +56,55 @@ var SupportedAssets = [
|
|
|
70
56
|
}
|
|
71
57
|
];
|
|
72
58
|
|
|
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
|
+
|
|
73
108
|
// src/lib/utils.ts
|
|
74
109
|
var isValidChainId = (chainId) => {
|
|
75
110
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -81,12 +116,6 @@ var isValidChainId = (chainId) => {
|
|
|
81
116
|
}
|
|
82
117
|
return chainId;
|
|
83
118
|
};
|
|
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
|
-
}
|
|
90
119
|
function hexToDecimal(hex, decimals = 6) {
|
|
91
120
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
92
121
|
const parsed = BigInt(normalized);
|
|
@@ -120,10 +149,6 @@ var DECIMALS_BY_SYMBOL = {
|
|
|
120
149
|
wbtc: 8,
|
|
121
150
|
cbbtc: 8
|
|
122
151
|
};
|
|
123
|
-
function canonicalSymbol(symbol) {
|
|
124
|
-
const upper = symbol.toUpperCase();
|
|
125
|
-
return upper === "ETH" ? "WETH" : upper;
|
|
126
|
-
}
|
|
127
152
|
function tokenDecimals(symbol, explicit) {
|
|
128
153
|
if (typeof explicit === "number" && Number.isFinite(explicit))
|
|
129
154
|
return explicit;
|
|
@@ -188,89 +213,55 @@ function mapPendingAllocations(raw) {
|
|
|
188
213
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
189
214
|
const portfolio = raw.portfolio;
|
|
190
215
|
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
|
-
}
|
|
198
216
|
let totalBalance = 0;
|
|
199
217
|
const tokens = [];
|
|
200
|
-
const positions = [];
|
|
201
218
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
202
219
|
const positionChainId = Number(chainIdKey);
|
|
203
|
-
const chainName2 = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
204
220
|
for (const [
|
|
205
221
|
symbol,
|
|
206
222
|
{ balance, balanceWithFee, decimals }
|
|
207
223
|
] of Object.entries(tokensBySymbol ?? {})) {
|
|
208
|
-
const amount = hexToDecimal(
|
|
209
|
-
balanceWithFee ?? balance ?? "0",
|
|
210
|
-
tokenDecimals(symbol, decimals)
|
|
211
|
-
);
|
|
224
|
+
const amount = hexToDecimal(balanceWithFee ?? balance ?? "0", decimals);
|
|
212
225
|
totalBalance += amount;
|
|
213
226
|
tokens.push({
|
|
214
|
-
chain:
|
|
227
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
215
228
|
chainId: positionChainId,
|
|
216
229
|
asset: symbol,
|
|
217
230
|
amount: String(amount)
|
|
218
231
|
});
|
|
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
|
-
});
|
|
237
232
|
}
|
|
238
233
|
}
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
liquidity: p.liquidity
|
|
271
|
-
}))
|
|
272
|
-
);
|
|
273
|
-
}
|
|
234
|
+
const positions = (portfolio.positions ?? []).map((p) => ({
|
|
235
|
+
chain: p.chain ?? "",
|
|
236
|
+
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
237
|
+
protocolId: p.protocol_id,
|
|
238
|
+
pool: p.pool,
|
|
239
|
+
asset: p.token_symbol ?? "",
|
|
240
|
+
// Fee-adjusted underlying amounts are decimal base-unit strings. The
|
|
241
|
+
// legacy `amount` fallback is hex. Runtime
|
|
242
|
+
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
243
|
+
// when present, otherwise fall back to the per-symbol lookup.
|
|
244
|
+
amount: String(
|
|
245
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ? normalizeDecimalPlace(
|
|
246
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0",
|
|
247
|
+
tokenDecimals(
|
|
248
|
+
p.token_symbol,
|
|
249
|
+
p.decimals
|
|
250
|
+
)
|
|
251
|
+
) : hexToDecimal(
|
|
252
|
+
p.amount || "0",
|
|
253
|
+
tokenDecimals(
|
|
254
|
+
p.token_symbol,
|
|
255
|
+
p.decimals
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
),
|
|
259
|
+
apy: p.pool_apy,
|
|
260
|
+
tvl: p.pool_tvl,
|
|
261
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
262
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
263
|
+
liquidity: p.liquidity
|
|
264
|
+
}));
|
|
274
265
|
const pendingAllocations = mapPendingAllocations(
|
|
275
266
|
portfolio.staleBalances
|
|
276
267
|
);
|
|
@@ -1353,37 +1344,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1353
1344
|
);
|
|
1354
1345
|
}
|
|
1355
1346
|
}
|
|
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
|
-
}
|
|
1387
1347
|
/**
|
|
1388
1348
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1389
1349
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1687,12 +1647,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1687
1647
|
);
|
|
1688
1648
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1689
1649
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1690
|
-
|
|
1691
|
-
validChainId,
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1650
|
+
try {
|
|
1651
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1652
|
+
} catch (logError) {
|
|
1653
|
+
console.warn(
|
|
1654
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1655
|
+
logError
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1696
1658
|
return { txHash, smartWallet, amount };
|
|
1697
1659
|
}
|
|
1698
1660
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1973,10 +1935,11 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
1973
1935
|
// src/lib/helpers/withdraw-helper.ts
|
|
1974
1936
|
import { parseUnits } from "viem";
|
|
1975
1937
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
1938
|
+
const target = asset.toUpperCase();
|
|
1976
1939
|
return agents.map((agent) => {
|
|
1977
1940
|
const agentBalance = aggregated[agent.id];
|
|
1978
1941
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1979
|
-
(t) => t.chainId === chainId &&
|
|
1942
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
1980
1943
|
);
|
|
1981
1944
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1982
1945
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2246,6 +2209,84 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2246
2209
|
return parsed.data.relayer;
|
|
2247
2210
|
}
|
|
2248
2211
|
|
|
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
|
+
|
|
2249
2290
|
// src/lib/chain-guard.ts
|
|
2250
2291
|
var CHAIN_NAMES = {
|
|
2251
2292
|
1: "Ethereum",
|
|
@@ -2564,7 +2605,6 @@ var VIEM_CHAIN2 = {
|
|
|
2564
2605
|
42161: arbitrum2,
|
|
2565
2606
|
1: mainnet2
|
|
2566
2607
|
};
|
|
2567
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2568
2608
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2569
2609
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2570
2610
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2593,7 +2633,6 @@ var OwneySDK = class {
|
|
|
2593
2633
|
zyfaiRpcUrls;
|
|
2594
2634
|
routingApiBaseUrl;
|
|
2595
2635
|
referralSource;
|
|
2596
|
-
surfliquidApiBaseUrl;
|
|
2597
2636
|
cachedSponsoredCallback = null;
|
|
2598
2637
|
cachedWethSponsoredCallback = null;
|
|
2599
2638
|
paymasterServiceUrl;
|
|
@@ -2606,7 +2645,6 @@ var OwneySDK = class {
|
|
|
2606
2645
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2607
2646
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2608
2647
|
this.referralSource = config.referralSource;
|
|
2609
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2610
2648
|
}
|
|
2611
2649
|
/**
|
|
2612
2650
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2836,8 +2874,8 @@ var OwneySDK = class {
|
|
|
2836
2874
|
this.initializingAgentsPromise = (async () => {
|
|
2837
2875
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2838
2876
|
this.disabledAgents.clear();
|
|
2839
|
-
for (const { key: key2, agent_type,
|
|
2840
|
-
const agent =
|
|
2877
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2878
|
+
const agent = this.createAgent(agent_type, key2);
|
|
2841
2879
|
if (!agent) continue;
|
|
2842
2880
|
this.agents.set(agent_type, agent);
|
|
2843
2881
|
if (is_enabled === false) {
|
|
@@ -2858,22 +2896,10 @@ var OwneySDK = class {
|
|
|
2858
2896
|
this.initializingAgentsPromise = null;
|
|
2859
2897
|
}
|
|
2860
2898
|
}
|
|
2861
|
-
|
|
2899
|
+
createAgent(agentId, key2) {
|
|
2862
2900
|
if (agentId === "zyfai") {
|
|
2863
2901
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2864
2902
|
}
|
|
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
|
-
}
|
|
2877
2903
|
return null;
|
|
2878
2904
|
}
|
|
2879
2905
|
// --- Account lifecycle ---
|
|
@@ -2923,12 +2949,7 @@ var OwneySDK = class {
|
|
|
2923
2949
|
this.activeAgents.add(id);
|
|
2924
2950
|
}
|
|
2925
2951
|
state.chainId = chainId;
|
|
2926
|
-
|
|
2927
|
-
agents.map(async (agent) => {
|
|
2928
|
-
await agent.activateAgent(state, chainId);
|
|
2929
|
-
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2930
|
-
})
|
|
2931
|
-
).catch((error) => {
|
|
2952
|
+
this.activateAgentsInTurn(agents, state, chainId).catch((error) => {
|
|
2932
2953
|
console.error("activateAgent background init failed:", error);
|
|
2933
2954
|
});
|
|
2934
2955
|
return;
|
|
@@ -2951,14 +2972,48 @@ var OwneySDK = class {
|
|
|
2951
2972
|
const enabledCompatible = compatible.filter(
|
|
2952
2973
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
2953
2974
|
);
|
|
2954
|
-
|
|
2955
|
-
|
|
2975
|
+
this.activateAgentsInTurn(enabledCompatible, state, chainId).catch(
|
|
2976
|
+
(error) => {
|
|
2977
|
+
console.error("activateAgent background init failed:", error);
|
|
2978
|
+
}
|
|
2979
|
+
);
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
2983
|
+
*
|
|
2984
|
+
* Every agent opens its activation with its own wallet signature, each
|
|
2985
|
+
* exchanged for that agent's own backend session — Zyfai's SIWX for a JWT,
|
|
2986
|
+
* Sail's SIWE. Run in parallel, that puts two `personal_sign` requests on one
|
|
2987
|
+
* wallet connection in the same instant. Over WalletConnect both are
|
|
2988
|
+
* delivered to the wallet, which renders one signing request at a time and
|
|
2989
|
+
* queues or silently drops the other: neither promise settles, so activation
|
|
2990
|
+
* hangs until the caller's timeout with no prompt the user can act on. The
|
|
2991
|
+
* single-agent era never hit this — there was no second prompt to collide
|
|
2992
|
+
* with — so it appeared the moment a second agent became eligible.
|
|
2993
|
+
*
|
|
2994
|
+
* Serializing costs no real wall-clock: the user can only approve one prompt
|
|
2995
|
+
* at a time anyway.
|
|
2996
|
+
*
|
|
2997
|
+
* Every agent is attempted even if an earlier one fails, so one declined
|
|
2998
|
+
* signature can't deny the remaining agents their turn. The first failure is
|
|
2999
|
+
* rethrown (matching the previous `Promise.all` rejection) once all agents
|
|
3000
|
+
* have had a chance to activate.
|
|
3001
|
+
*/
|
|
3002
|
+
async activateAgentsInTurn(agents, state, chainId) {
|
|
3003
|
+
let firstError = null;
|
|
3004
|
+
for (const agent of agents) {
|
|
3005
|
+
try {
|
|
2956
3006
|
await agent.activateAgent(state, chainId);
|
|
2957
3007
|
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2958
|
-
})
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3008
|
+
} catch (error) {
|
|
3009
|
+
if (firstError === null) {
|
|
3010
|
+
firstError = error;
|
|
3011
|
+
} else {
|
|
3012
|
+
console.error(`activateAgent(${agent.id}) failed:`, error);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
if (firstError !== null) throw firstError;
|
|
2962
3017
|
}
|
|
2963
3018
|
/**
|
|
2964
3019
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -3028,30 +3083,18 @@ var OwneySDK = class {
|
|
|
3028
3083
|
);
|
|
3029
3084
|
}
|
|
3030
3085
|
const agentResults = {};
|
|
3031
|
-
const agentErrors = {};
|
|
3032
3086
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
depositCallback
|
|
3042
|
-
);
|
|
3043
|
-
} catch (error) {
|
|
3044
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
3045
|
-
}
|
|
3046
|
-
}
|
|
3047
|
-
if (Object.keys(agentResults).length === 0) {
|
|
3048
|
-
throw new OwneyError(
|
|
3049
|
-
"DEPOSIT_ALL_FAILED",
|
|
3050
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
3051
|
-
{ agentErrors }
|
|
3087
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
3088
|
+
agent,
|
|
3089
|
+
state,
|
|
3090
|
+
chainId,
|
|
3091
|
+
agentAmount,
|
|
3092
|
+
asset,
|
|
3093
|
+
effectiveCallback,
|
|
3094
|
+
depositCallback
|
|
3052
3095
|
);
|
|
3053
3096
|
}
|
|
3054
|
-
return
|
|
3097
|
+
return { agentResults };
|
|
3055
3098
|
}
|
|
3056
3099
|
/**
|
|
3057
3100
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3167,8 +3210,9 @@ var OwneySDK = class {
|
|
|
3167
3210
|
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3168
3211
|
try {
|
|
3169
3212
|
const balance = await agent.getBalances(state, chainId);
|
|
3213
|
+
const target = asset.toLowerCase();
|
|
3170
3214
|
const token = balance.tokens.find(
|
|
3171
|
-
(t) => t.chainId === chainId &&
|
|
3215
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
3172
3216
|
);
|
|
3173
3217
|
return !!token && Number(token.amount) > 0;
|
|
3174
3218
|
} catch {
|
|
@@ -3207,34 +3251,6 @@ var OwneySDK = class {
|
|
|
3207
3251
|
}
|
|
3208
3252
|
return eligible;
|
|
3209
3253
|
}
|
|
3210
|
-
/**
|
|
3211
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
3212
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3213
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3214
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3215
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3216
|
-
*
|
|
3217
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
3218
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
3219
|
-
*/
|
|
3220
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
3221
|
-
try {
|
|
3222
|
-
await this.ensureAgentsInitialized();
|
|
3223
|
-
} catch (error) {
|
|
3224
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3225
|
-
return [];
|
|
3226
|
-
}
|
|
3227
|
-
throw error;
|
|
3228
|
-
}
|
|
3229
|
-
return [...this.agents.values()].filter((agent) => {
|
|
3230
|
-
const chainAssets = agent.supportedAssets.find(
|
|
3231
|
-
(sa) => sa.chainId === chainId
|
|
3232
|
-
);
|
|
3233
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3234
|
-
}).map((agent) => agent.id).sort(
|
|
3235
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3236
|
-
);
|
|
3237
|
-
}
|
|
3238
3254
|
// --- Fund operations ---
|
|
3239
3255
|
/**
|
|
3240
3256
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3270,17 +3286,9 @@ var OwneySDK = class {
|
|
|
3270
3286
|
}
|
|
3271
3287
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3272
3288
|
if (!amount) {
|
|
3273
|
-
const aggregated2 = await this.getBalances();
|
|
3274
|
-
const funded = projectAgentBalancesForAsset(
|
|
3275
|
-
eligibleAgents,
|
|
3276
|
-
aggregated2.agentBalances,
|
|
3277
|
-
chainId,
|
|
3278
|
-
asset,
|
|
3279
|
-
assetInfo.decimals
|
|
3280
|
-
).filter((b) => b.balance > 0n);
|
|
3281
3289
|
const results2 = {};
|
|
3282
3290
|
const agentErrors2 = {};
|
|
3283
|
-
for (const
|
|
3291
|
+
for (const agent of eligibleAgents) {
|
|
3284
3292
|
try {
|
|
3285
3293
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3286
3294
|
} catch (err) {
|
|
@@ -3297,10 +3305,9 @@ var OwneySDK = class {
|
|
|
3297
3305
|
{ asset, agentErrors: agentErrors2 }
|
|
3298
3306
|
);
|
|
3299
3307
|
}
|
|
3300
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3301
3308
|
return {
|
|
3302
3309
|
agentResult: results2,
|
|
3303
|
-
totalWithdrawn:
|
|
3310
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
3304
3311
|
};
|
|
3305
3312
|
}
|
|
3306
3313
|
const requested = BigInt(amount);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owney/sdk",
|
|
3
|
-
"version": "0.7.12-beta.
|
|
3
|
+
"version": "0.7.12-beta.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -23,9 +23,7 @@
|
|
|
23
23
|
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@surf_liquid/core-sdk": "^0.4.0",
|
|
27
26
|
"@zyfai/sdk": "0.2.50",
|
|
28
|
-
"ethers": "^6.17.0",
|
|
29
27
|
"siwe": "^3.0.0",
|
|
30
28
|
"viem": "^2.48.1"
|
|
31
29
|
},
|