@owney/sdk 0.7.7-beta.5 → 0.7.7-beta.6
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 +217 -147
- package/dist/index.d.cts +26 -21
- package/dist/index.d.ts +26 -21
- package/dist/index.js +202 -132
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -217,6 +217,32 @@ function resolveChainId(chain) {
|
|
|
217
217
|
if (Number.isFinite(asNum) && asNum > 0) return asNum;
|
|
218
218
|
return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
|
|
219
219
|
}
|
|
220
|
+
function mapPendingAllocations(raw) {
|
|
221
|
+
if (!Array.isArray(raw)) return void 0;
|
|
222
|
+
const pending = [];
|
|
223
|
+
for (const entry of raw) {
|
|
224
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
225
|
+
const e = entry;
|
|
226
|
+
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
227
|
+
if (typeof e.tokenSymbol !== "string" || e.tokenSymbol === "") continue;
|
|
228
|
+
if (typeof e.balance !== "string") continue;
|
|
229
|
+
let amount;
|
|
230
|
+
try {
|
|
231
|
+
amount = hexToDecimal(e.balance, tokenDecimals(e.tokenSymbol));
|
|
232
|
+
} catch {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (!Number.isFinite(amount) || amount <= 0) continue;
|
|
236
|
+
pending.push({
|
|
237
|
+
chainId: e.chainId,
|
|
238
|
+
asset: e.tokenSymbol,
|
|
239
|
+
amount: String(amount),
|
|
240
|
+
isPending: e.isPending === true,
|
|
241
|
+
...typeof e.updatedAt === "string" && e.updatedAt !== "" ? { since: e.updatedAt } : {}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return pending.length > 0 ? pending : void 0;
|
|
245
|
+
}
|
|
220
246
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
221
247
|
const portfolio = raw.portfolio;
|
|
222
248
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
@@ -268,12 +294,16 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
268
294
|
// structural read keeps it undefined today and auto-populates later.
|
|
269
295
|
liquidity: p.liquidity
|
|
270
296
|
}));
|
|
297
|
+
const pendingAllocations = mapPendingAllocations(
|
|
298
|
+
portfolio.staleBalances
|
|
299
|
+
);
|
|
271
300
|
return {
|
|
272
301
|
smartWallet,
|
|
273
302
|
totalBalance: String(totalBalance),
|
|
274
303
|
totalBalanceAsset: "usdc",
|
|
275
304
|
tokens,
|
|
276
|
-
positions
|
|
305
|
+
positions,
|
|
306
|
+
...pendingAllocations ? { pendingAllocations } : {}
|
|
277
307
|
};
|
|
278
308
|
}
|
|
279
309
|
function sumTokenValues(tokens) {
|
|
@@ -879,6 +909,12 @@ var ZyfaiAgent = class {
|
|
|
879
909
|
connectedAddress = null;
|
|
880
910
|
connectedChainId = null;
|
|
881
911
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
912
|
+
/**
|
|
913
|
+
* `${eoa}:${chainId}` keys we have already tried createSessionKey for. Guards
|
|
914
|
+
* against re-running it on every activation/deposit when Zyfai's
|
|
915
|
+
* `hasActiveSessionKey` does not flip to true — see ensureSessionKey.
|
|
916
|
+
*/
|
|
917
|
+
sessionKeyAttempts = /* @__PURE__ */ new Set();
|
|
882
918
|
connectAuthPromise = null;
|
|
883
919
|
rpcUrls;
|
|
884
920
|
publicClients = /* @__PURE__ */ new Map();
|
|
@@ -1336,10 +1372,74 @@ var ZyfaiAgent = class {
|
|
|
1336
1372
|
* recoverable (ensureWalletDeployed tries the other deploy call), but
|
|
1337
1373
|
* failing the deposit outright is not.
|
|
1338
1374
|
*/
|
|
1375
|
+
/**
|
|
1376
|
+
* Zyfai's own answer to "what kind of wallet is this, and can the agent act on
|
|
1377
|
+
* it", read from the positions payload (`GET /data/position`, which
|
|
1378
|
+
* `getPositions` wraps).
|
|
1379
|
+
*
|
|
1380
|
+
* `predeployed` and `hasActiveSessionKey` are both returned at runtime but
|
|
1381
|
+
* declared on neither `Portfolio` nor their docs, hence the cast. Verified
|
|
1382
|
+
* live: an old wallet reports `{predeployed: false, hasActiveSessionKey:
|
|
1383
|
+
* false}` while a pool wallet reports `{true, true}`.
|
|
1384
|
+
*
|
|
1385
|
+
* Preferred over the SDK's private `isPredeployed`, which is cached from the
|
|
1386
|
+
* login response and can go stale mid-session. Returns an empty object on any
|
|
1387
|
+
* failure so every caller degrades to its own fallback.
|
|
1388
|
+
*/
|
|
1389
|
+
async readWalletState(ownerAddress) {
|
|
1390
|
+
try {
|
|
1391
|
+
const { portfolio } = await this.sdk.getPositions(ownerAddress);
|
|
1392
|
+
const raw = portfolio;
|
|
1393
|
+
debugLog("zyfai:onboard", "wallet state from getPositions", {
|
|
1394
|
+
predeployed: raw?.predeployed,
|
|
1395
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1396
|
+
});
|
|
1397
|
+
return {
|
|
1398
|
+
predeployed: raw?.predeployed,
|
|
1399
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1400
|
+
};
|
|
1401
|
+
} catch (error) {
|
|
1402
|
+
console.warn(
|
|
1403
|
+
"[zyfai] getPositions wallet-state read failed (non-fatal):",
|
|
1404
|
+
error instanceof Error ? error.message : String(error)
|
|
1405
|
+
);
|
|
1406
|
+
return {};
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1339
1409
|
async isPredeployedPoolWallet(ownerAddress, smartWallet) {
|
|
1410
|
+
const { predeployed } = await this.readWalletState(ownerAddress);
|
|
1411
|
+
if (typeof predeployed === "boolean") {
|
|
1412
|
+
debugLog(
|
|
1413
|
+
"zyfai:onboard",
|
|
1414
|
+
`wallet class: ${predeployed ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1415
|
+
{ source: "getPositions.predeployed", predeployed }
|
|
1416
|
+
);
|
|
1417
|
+
return predeployed;
|
|
1418
|
+
}
|
|
1419
|
+
const internals = this.sdk;
|
|
1420
|
+
if (typeof internals.isPredeployed === "boolean") {
|
|
1421
|
+
debugLog(
|
|
1422
|
+
"zyfai:onboard",
|
|
1423
|
+
`wallet class: ${internals.isPredeployed ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1424
|
+
{
|
|
1425
|
+
source: "login response (cached)",
|
|
1426
|
+
predeployed: internals.isPredeployed
|
|
1427
|
+
}
|
|
1428
|
+
);
|
|
1429
|
+
return internals.isPredeployed;
|
|
1430
|
+
}
|
|
1340
1431
|
try {
|
|
1341
1432
|
const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
|
|
1342
|
-
|
|
1433
|
+
const isPool = typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
|
|
1434
|
+
debugLog(
|
|
1435
|
+
"zyfai:onboard",
|
|
1436
|
+
`wallet class: ${isPool ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1437
|
+
{
|
|
1438
|
+
source: "getSmartWalletByEOA fallback",
|
|
1439
|
+
poolRecord: byEoa?.smartWallet
|
|
1440
|
+
}
|
|
1441
|
+
);
|
|
1442
|
+
return isPool;
|
|
1343
1443
|
} catch (error) {
|
|
1344
1444
|
console.warn(
|
|
1345
1445
|
"[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
|
|
@@ -1377,8 +1477,24 @@ var ZyfaiAgent = class {
|
|
|
1377
1477
|
ownerAddress,
|
|
1378
1478
|
chainId
|
|
1379
1479
|
);
|
|
1380
|
-
|
|
1381
|
-
|
|
1480
|
+
debugLog("zyfai:onboard", `activation check on chain ${chainId}`, {
|
|
1481
|
+
smartWallet: wallet.address,
|
|
1482
|
+
isDeployed: wallet.isDeployed
|
|
1483
|
+
});
|
|
1484
|
+
if (!wallet.isDeployed) {
|
|
1485
|
+
debugLog(
|
|
1486
|
+
"zyfai:onboard",
|
|
1487
|
+
"Safe not deployed on this chain; activation does nothing (deposit owns deploys)"
|
|
1488
|
+
);
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1492
|
+
await this.ensureSessionKey(
|
|
1493
|
+
ownerAddress,
|
|
1494
|
+
chainId,
|
|
1495
|
+
wallet.address,
|
|
1496
|
+
hasActiveSessionKey
|
|
1497
|
+
);
|
|
1382
1498
|
} catch (error) {
|
|
1383
1499
|
console.warn(
|
|
1384
1500
|
"[zyfai] session-key check at activation failed (non-fatal):",
|
|
@@ -1386,20 +1502,51 @@ var ZyfaiAgent = class {
|
|
|
1386
1502
|
);
|
|
1387
1503
|
}
|
|
1388
1504
|
}
|
|
1389
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1505
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet, hasActiveSessionKey) {
|
|
1506
|
+
const attemptKey = `${ownerAddress.toLowerCase()}:${chainId}`;
|
|
1507
|
+
if (this.sessionKeyAttempts.has(attemptKey)) {
|
|
1508
|
+
debugLog(
|
|
1509
|
+
"zyfai:onboard",
|
|
1510
|
+
"session key: already attempted this session, skipping",
|
|
1511
|
+
{ chainId }
|
|
1512
|
+
);
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1390
1515
|
try {
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1516
|
+
if (hasActiveSessionKey === true) {
|
|
1517
|
+
debugLog(
|
|
1518
|
+
"zyfai:onboard",
|
|
1519
|
+
"session key: already on record -> nothing to do",
|
|
1520
|
+
{ chainId }
|
|
1521
|
+
);
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
if (hasActiveSessionKey === void 0) {
|
|
1525
|
+
const installed = await this.readSmartSessionsInstalled(
|
|
1526
|
+
chainId,
|
|
1527
|
+
smartWallet
|
|
1528
|
+
);
|
|
1529
|
+
debugLog(
|
|
1530
|
+
"zyfai:onboard",
|
|
1531
|
+
`session key: Zyfai state unavailable; on-chain validator ${installed ? "INSTALLED" : "MISSING"}`,
|
|
1532
|
+
{ smartWallet, chainId }
|
|
1533
|
+
);
|
|
1534
|
+
if (installed) return;
|
|
1535
|
+
}
|
|
1536
|
+
this.sessionKeyAttempts.add(attemptKey);
|
|
1399
1537
|
console.warn(
|
|
1400
|
-
`[zyfai]
|
|
1538
|
+
`[zyfai] no session key for ${smartWallet} on chain ${chainId}; creating one so the agent can allocate.`
|
|
1401
1539
|
);
|
|
1540
|
+
debugLog("zyfai:onboard", "session key: calling createSessionKey", {
|
|
1541
|
+
chainId,
|
|
1542
|
+
smartWallet,
|
|
1543
|
+
hasActiveSessionKey
|
|
1544
|
+
});
|
|
1402
1545
|
await this.sdk.createSessionKey(ownerAddress, chainId);
|
|
1546
|
+
debugLog("zyfai:onboard", "session key: createSessionKey succeeded", {
|
|
1547
|
+
chainId,
|
|
1548
|
+
smartWallet
|
|
1549
|
+
});
|
|
1403
1550
|
} catch (error) {
|
|
1404
1551
|
console.warn(
|
|
1405
1552
|
"[zyfai] createSessionKey skipped (non-fatal):",
|
|
@@ -1407,6 +1554,16 @@ var ZyfaiAgent = class {
|
|
|
1407
1554
|
);
|
|
1408
1555
|
}
|
|
1409
1556
|
}
|
|
1557
|
+
/** Ground truth for "can Zyfai's automation act on this Safe, on this chain". */
|
|
1558
|
+
async readSmartSessionsInstalled(chainId, smartWallet) {
|
|
1559
|
+
return this.getPublicClient(chainId).readContract({
|
|
1560
|
+
address: smartWallet,
|
|
1561
|
+
abi: ERC7579_IS_MODULE_INSTALLED_ABI,
|
|
1562
|
+
functionName: "isModuleInstalled",
|
|
1563
|
+
// moduleTypeId 1 = validator (ERC-7579)
|
|
1564
|
+
args: [1n, import_sdk.SMART_SESSIONS_VALIDATOR, "0x"]
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1410
1567
|
/**
|
|
1411
1568
|
* Guarantee the user's Safe has code on `chainId` before anything transfers
|
|
1412
1569
|
* funds into it, and return its address.
|
|
@@ -1427,8 +1584,24 @@ var ZyfaiAgent = class {
|
|
|
1427
1584
|
*/
|
|
1428
1585
|
async ensureWalletDeployed(ownerAddress, chainId) {
|
|
1429
1586
|
const wallet = await this.sdk.getSmartWalletAddress(ownerAddress, chainId);
|
|
1587
|
+
debugLog("zyfai:onboard", `--- deposit onboarding, chain ${chainId} ---`, {
|
|
1588
|
+
eoa: ownerAddress,
|
|
1589
|
+
smartWallet: wallet.address,
|
|
1590
|
+
isDeployed: wallet.isDeployed,
|
|
1591
|
+
isOwner: wallet.isOwner
|
|
1592
|
+
});
|
|
1430
1593
|
if (wallet.isDeployed) {
|
|
1431
|
-
|
|
1594
|
+
debugLog(
|
|
1595
|
+
"zyfai:onboard",
|
|
1596
|
+
"Safe already has code -> no deploy needed, checking the session key"
|
|
1597
|
+
);
|
|
1598
|
+
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1599
|
+
await this.ensureSessionKey(
|
|
1600
|
+
ownerAddress,
|
|
1601
|
+
chainId,
|
|
1602
|
+
wallet.address,
|
|
1603
|
+
hasActiveSessionKey
|
|
1604
|
+
);
|
|
1432
1605
|
return wallet.address;
|
|
1433
1606
|
}
|
|
1434
1607
|
const poolFirst = await this.isPredeployedPoolWallet(
|
|
@@ -1444,14 +1617,27 @@ var ZyfaiAgent = class {
|
|
|
1444
1617
|
this.sdk.deploySafe(ownerAddress, chainId, "aggressive", true)
|
|
1445
1618
|
);
|
|
1446
1619
|
const [first, second] = poolFirst ? [deployAsPool, deployAsLegacy] : [deployAsLegacy, deployAsPool];
|
|
1620
|
+
debugLog(
|
|
1621
|
+
"zyfai:onboard",
|
|
1622
|
+
`Safe has no code on chain ${chainId} -> deploying via ${poolFirst ? "deployOnChains (pool path)" : "deploySafe(createSessionKey=true) (legacy path)"}`
|
|
1623
|
+
);
|
|
1447
1624
|
try {
|
|
1448
1625
|
await first();
|
|
1626
|
+
debugLog(
|
|
1627
|
+
"zyfai:onboard",
|
|
1628
|
+
`${poolFirst ? "deployOnChains" : "deploySafe"} succeeded`
|
|
1629
|
+
);
|
|
1449
1630
|
} catch (error) {
|
|
1450
1631
|
console.warn(
|
|
1451
1632
|
`[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
|
|
1452
1633
|
error instanceof Error ? error.message : String(error)
|
|
1453
1634
|
);
|
|
1635
|
+
debugLog(
|
|
1636
|
+
"zyfai:onboard",
|
|
1637
|
+
`falling back to ${poolFirst ? "deploySafe (legacy path)" : "deployOnChains (pool path)"}`
|
|
1638
|
+
);
|
|
1454
1639
|
await second();
|
|
1640
|
+
debugLog("zyfai:onboard", "fallback deploy path succeeded");
|
|
1455
1641
|
}
|
|
1456
1642
|
const redeployed = await this.sdk.getSmartWalletAddress(
|
|
1457
1643
|
ownerAddress,
|
|
@@ -1839,7 +2025,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1839
2025
|
}
|
|
1840
2026
|
|
|
1841
2027
|
// src/client.ts
|
|
1842
|
-
var
|
|
2028
|
+
var import_viem5 = require("viem");
|
|
1843
2029
|
var import_chains2 = require("viem/chains");
|
|
1844
2030
|
|
|
1845
2031
|
// src/lib/transfer-auth.ts
|
|
@@ -2269,97 +2455,6 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2269
2455
|
};
|
|
2270
2456
|
}
|
|
2271
2457
|
|
|
2272
|
-
// src/lib/sponsored-calls-deposit.ts
|
|
2273
|
-
var import_viem5 = require("viem");
|
|
2274
|
-
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
2275
|
-
var DEFAULT_MAX_POLLS = 30;
|
|
2276
|
-
async function paymasterSupported(provider, owner, chainId) {
|
|
2277
|
-
const caps = await provider.request({
|
|
2278
|
-
method: "wallet_getCapabilities",
|
|
2279
|
-
params: [owner]
|
|
2280
|
-
});
|
|
2281
|
-
const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
2282
|
-
return Boolean(forChain?.paymasterService?.supported);
|
|
2283
|
-
}
|
|
2284
|
-
function makeSponsoredCallsCallback(deps) {
|
|
2285
|
-
const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
2286
|
-
const maxPolls = deps.maxPolls ?? DEFAULT_MAX_POLLS;
|
|
2287
|
-
const absolutePaymasterUrl = () => {
|
|
2288
|
-
const configured = deps.paymasterServiceUrl;
|
|
2289
|
-
if (/^https?:\/\//i.test(configured)) return configured;
|
|
2290
|
-
const origin = globalThis.location?.origin;
|
|
2291
|
-
if (!origin) {
|
|
2292
|
-
throw new OwneyError(
|
|
2293
|
-
"SPONSORED_CALLS_UNSUPPORTED",
|
|
2294
|
-
`paymasterServiceUrl "${configured}" is relative and no page origin is available to resolve it.`
|
|
2295
|
-
);
|
|
2296
|
-
}
|
|
2297
|
-
return new URL(configured, origin).toString();
|
|
2298
|
-
};
|
|
2299
|
-
return async (smartWallet, chainId, amount) => {
|
|
2300
|
-
const cid = chainId;
|
|
2301
|
-
const token = deps.tokenAddressByChain[cid];
|
|
2302
|
-
if (!token) {
|
|
2303
|
-
throw new OwneyError(
|
|
2304
|
-
"CHAIN_UNSUPPORTED",
|
|
2305
|
-
`No sponsored token configured for chain ${chainId}`
|
|
2306
|
-
);
|
|
2307
|
-
}
|
|
2308
|
-
if (!await paymasterSupported(deps.provider, deps.ownerAddress, chainId)) {
|
|
2309
|
-
throw new OwneyError(
|
|
2310
|
-
"SPONSORED_CALLS_UNSUPPORTED",
|
|
2311
|
-
`Wallet does not advertise paymasterService on chain ${chainId}.`,
|
|
2312
|
-
{ chainId }
|
|
2313
|
-
);
|
|
2314
|
-
}
|
|
2315
|
-
const data = (0, import_viem5.encodeFunctionData)({
|
|
2316
|
-
abi: import_viem5.erc20Abi,
|
|
2317
|
-
functionName: "transfer",
|
|
2318
|
-
args: [smartWallet, BigInt(amount)]
|
|
2319
|
-
});
|
|
2320
|
-
const sendResult = await deps.provider.request({
|
|
2321
|
-
method: "wallet_sendCalls",
|
|
2322
|
-
params: [
|
|
2323
|
-
{
|
|
2324
|
-
version: "2.0.0",
|
|
2325
|
-
from: deps.ownerAddress,
|
|
2326
|
-
chainId: (0, import_viem5.toHex)(chainId),
|
|
2327
|
-
atomicRequired: false,
|
|
2328
|
-
calls: [{ to: token, value: "0x0", data }],
|
|
2329
|
-
capabilities: {
|
|
2330
|
-
paymasterService: { url: absolutePaymasterUrl() }
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
]
|
|
2334
|
-
});
|
|
2335
|
-
deps.onApproved?.();
|
|
2336
|
-
const callsId = typeof sendResult === "string" ? sendResult : sendResult?.id;
|
|
2337
|
-
if (!callsId) {
|
|
2338
|
-
throw new OwneyError(
|
|
2339
|
-
"SPONSORED_CALLS_NO_ID",
|
|
2340
|
-
"Wallet accepted wallet_sendCalls but returned no calls id.",
|
|
2341
|
-
{ chainId }
|
|
2342
|
-
);
|
|
2343
|
-
}
|
|
2344
|
-
for (let attempt = 0; attempt < maxPolls; attempt += 1) {
|
|
2345
|
-
const status = await deps.provider.request({
|
|
2346
|
-
method: "wallet_getCallsStatus",
|
|
2347
|
-
params: [callsId]
|
|
2348
|
-
});
|
|
2349
|
-
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
2350
|
-
if (txHash) return txHash;
|
|
2351
|
-
if (pollIntervalMs > 0) {
|
|
2352
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
throw new OwneyError(
|
|
2356
|
-
"SPONSORED_CALLS_NO_RECEIPT",
|
|
2357
|
-
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
2358
|
-
{ chainId, callsId }
|
|
2359
|
-
);
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
2458
|
// src/client.ts
|
|
2364
2459
|
function encodeMultiAgentCursor(map) {
|
|
2365
2460
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -2421,15 +2516,12 @@ var OwneySDK = class {
|
|
|
2421
2516
|
referralSource;
|
|
2422
2517
|
cachedSponsoredCallback = null;
|
|
2423
2518
|
cachedWethSponsoredCallback = null;
|
|
2424
|
-
paymasterServiceUrl;
|
|
2425
|
-
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2426
2519
|
initializingAgentsPromise = null;
|
|
2427
2520
|
constructor(config) {
|
|
2428
2521
|
this.apiKey = config.apiKey;
|
|
2429
2522
|
if (config.debug) setOwneyDebug(true);
|
|
2430
2523
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2431
2524
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2432
|
-
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2433
2525
|
this.referralSource = config.referralSource;
|
|
2434
2526
|
}
|
|
2435
2527
|
/**
|
|
@@ -2452,7 +2544,6 @@ var OwneySDK = class {
|
|
|
2452
2544
|
this.state = { provider, walletAddress, chainId: null };
|
|
2453
2545
|
this.cachedSponsoredCallback = null;
|
|
2454
2546
|
this.cachedWethSponsoredCallback = null;
|
|
2455
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
2456
2547
|
}
|
|
2457
2548
|
/**
|
|
2458
2549
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2467,7 +2558,6 @@ var OwneySDK = class {
|
|
|
2467
2558
|
this.state = null;
|
|
2468
2559
|
this.cachedSponsoredCallback = null;
|
|
2469
2560
|
this.cachedWethSponsoredCallback = null;
|
|
2470
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
2471
2561
|
}
|
|
2472
2562
|
isAgentDisabled(agentId) {
|
|
2473
2563
|
return this.disabledAgents.has(agentId);
|
|
@@ -2530,14 +2620,14 @@ var OwneySDK = class {
|
|
|
2530
2620
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2531
2621
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2532
2622
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2533
|
-
getPublicClient: (cid) => (0,
|
|
2623
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2534
2624
|
chain: VIEM_CHAIN2[cid],
|
|
2535
|
-
transport: (0,
|
|
2625
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2536
2626
|
}),
|
|
2537
|
-
getWalletClient: (cid) => (0,
|
|
2627
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2538
2628
|
account: owner,
|
|
2539
2629
|
chain: VIEM_CHAIN2[cid],
|
|
2540
|
-
transport: (0,
|
|
2630
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2541
2631
|
})
|
|
2542
2632
|
});
|
|
2543
2633
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2549,26 +2639,6 @@ var OwneySDK = class {
|
|
|
2549
2639
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2550
2640
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2551
2641
|
*/
|
|
2552
|
-
getDefaultSponsoredCallsCallback(asset, onApproved) {
|
|
2553
|
-
const cached = this.cachedSponsoredCallsCallbacks.get(asset);
|
|
2554
|
-
if (!onApproved && cached) return cached;
|
|
2555
|
-
const provider = this.requireConnectedProvider();
|
|
2556
|
-
const callback = makeSponsoredCallsCallback({
|
|
2557
|
-
provider,
|
|
2558
|
-
ownerAddress: this.state.walletAddress,
|
|
2559
|
-
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
2560
|
-
onApproved,
|
|
2561
|
-
tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
|
|
2562
|
-
});
|
|
2563
|
-
if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
2564
|
-
return callback;
|
|
2565
|
-
}
|
|
2566
|
-
/**
|
|
2567
|
-
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
2568
|
-
* callback used when the caller omits `depositCallback` for a WETH deposit.
|
|
2569
|
-
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2570
|
-
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2571
|
-
*/
|
|
2572
2642
|
getDefaultWethSponsoredCallback(onApproved) {
|
|
2573
2643
|
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
2574
2644
|
return this.cachedWethSponsoredCallback;
|
|
@@ -2583,14 +2653,14 @@ var OwneySDK = class {
|
|
|
2583
2653
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2584
2654
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2585
2655
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2586
|
-
getPublicClient: (cid) => (0,
|
|
2656
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2587
2657
|
chain: VIEM_CHAIN2[cid],
|
|
2588
|
-
transport: (0,
|
|
2658
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2589
2659
|
}),
|
|
2590
|
-
getWalletClient: (cid) => (0,
|
|
2660
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
2591
2661
|
account: owner,
|
|
2592
2662
|
chain: VIEM_CHAIN2[cid],
|
|
2593
|
-
transport: (0,
|
|
2663
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2594
2664
|
})
|
|
2595
2665
|
});
|
|
2596
2666
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2791,7 +2861,7 @@ var OwneySDK = class {
|
|
|
2791
2861
|
}
|
|
2792
2862
|
const state = this.requireState();
|
|
2793
2863
|
const chainId = this.requireChainId();
|
|
2794
|
-
const effectiveCallback = depositCallback ?? (
|
|
2864
|
+
const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2795
2865
|
if (agentId) {
|
|
2796
2866
|
if (this.isAgentDisabled(agentId)) {
|
|
2797
2867
|
throw new OwneyError(
|
|
@@ -3434,10 +3504,10 @@ var OwneySDK = class {
|
|
|
3434
3504
|
);
|
|
3435
3505
|
}
|
|
3436
3506
|
const provider = this.requireConnectedProvider();
|
|
3437
|
-
const wallet = (0,
|
|
3507
|
+
const wallet = (0, import_viem5.createWalletClient)({
|
|
3438
3508
|
account: state.walletAddress,
|
|
3439
3509
|
chain: VIEM_CHAIN2[chainId],
|
|
3440
|
-
transport: (0,
|
|
3510
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3441
3511
|
});
|
|
3442
3512
|
const hash = await wallet.writeContract({
|
|
3443
3513
|
address: token,
|
|
@@ -3447,9 +3517,9 @@ var OwneySDK = class {
|
|
|
3447
3517
|
account: state.walletAddress,
|
|
3448
3518
|
chain: VIEM_CHAIN2[chainId]
|
|
3449
3519
|
});
|
|
3450
|
-
const publicClient = (0,
|
|
3520
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
3451
3521
|
chain: VIEM_CHAIN2[chainId],
|
|
3452
|
-
transport: (0,
|
|
3522
|
+
transport: (0, import_viem5.custom)(provider)
|
|
3453
3523
|
});
|
|
3454
3524
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3455
3525
|
hash,
|
|
@@ -3558,7 +3628,7 @@ var OwneySDK = class {
|
|
|
3558
3628
|
};
|
|
3559
3629
|
|
|
3560
3630
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3561
|
-
var
|
|
3631
|
+
var import_viem6 = require("viem");
|
|
3562
3632
|
var import_siwe = require("siwe");
|
|
3563
3633
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3564
3634
|
|
|
@@ -3685,7 +3755,7 @@ function buildSIWXConfig(deps) {
|
|
|
3685
3755
|
issuedAt,
|
|
3686
3756
|
toString() {
|
|
3687
3757
|
return new import_siwe.SiweMessage({
|
|
3688
|
-
address: (0,
|
|
3758
|
+
address: (0, import_viem6.getAddress)(accountAddress),
|
|
3689
3759
|
chainId: numericChainId(chainId),
|
|
3690
3760
|
domain,
|
|
3691
3761
|
uri,
|
package/dist/index.d.cts
CHANGED
|
@@ -30,17 +30,6 @@ interface OwneySDKConfig {
|
|
|
30
30
|
* already-deployed app: set `globalThis.__OWNEY_DEBUG__ = true` in devtools.
|
|
31
31
|
*/
|
|
32
32
|
debug?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Absolute URL of an ERC-7677 paymaster service. When set, deposits go out as
|
|
35
|
-
* an EIP-5792 `wallet_sendCalls` with `capabilities.paymasterService`, so a
|
|
36
|
-
* wallet that advertises sponsorship pays no native gas — the case EIP-3009
|
|
37
|
-
* cannot serve, because USDC verifies it with `ecrecover` and a smart account
|
|
38
|
-
* signs via ERC-1271.
|
|
39
|
-
*
|
|
40
|
-
* MUST be absolute: the wallet fetches this URL itself, so a relative path is
|
|
41
|
-
* unresolvable. Omit it and every rail behaves exactly as before.
|
|
42
|
-
*/
|
|
43
|
-
paymasterServiceUrl?: string;
|
|
44
33
|
}
|
|
45
34
|
interface ConnectionState {
|
|
46
35
|
provider: any;
|
|
@@ -191,6 +180,29 @@ interface OwneyPosition {
|
|
|
191
180
|
* response later; undefined until then. */
|
|
192
181
|
liquidity?: number;
|
|
193
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Funds that have landed in the agent's wallet but are not yet deployed into a
|
|
185
|
+
* protocol. Sourced from Zyfai `staleBalances[].isPending`. Absent when nothing
|
|
186
|
+
* is pending, and for agents that do not report it (sail).
|
|
187
|
+
*/
|
|
188
|
+
interface OwneyPendingAllocation {
|
|
189
|
+
/** Deliberately loose (not OwneySupportedChainId) because Zyfai reports balances on unsupported chains. */
|
|
190
|
+
chainId: number;
|
|
191
|
+
/** Raw agent symbol, not normalized to OwneySupportedTokens; carries Zyfai's casing and "eth" alias for WETH. */
|
|
192
|
+
asset: string;
|
|
193
|
+
/** Decimal string, consistent with `OwneyToken.amount`. */
|
|
194
|
+
amount: string;
|
|
195
|
+
/**
|
|
196
|
+
* Zyfai's own `isPending` flag. TRUE means it is actively allocating. FALSE
|
|
197
|
+
* does NOT mean the entry is stale or safe to ignore: Zyfai flips it within
|
|
198
|
+
* minutes but leaves funds listed here indefinitely when it has not indexed
|
|
199
|
+
* the pool they landed in. Entries are surfaced regardless of this flag; use
|
|
200
|
+
* it only to decide wording, never to decide whether the money counts.
|
|
201
|
+
*/
|
|
202
|
+
isPending: boolean;
|
|
203
|
+
/** ISO timestamp from Zyfai's `updatedAt`, when the payload carries one. */
|
|
204
|
+
since?: string;
|
|
205
|
+
}
|
|
194
206
|
interface AgentBalance {
|
|
195
207
|
smartWallet?: `0x${string}`;
|
|
196
208
|
totalBalance: string;
|
|
@@ -202,6 +214,8 @@ interface AgentBalance {
|
|
|
202
214
|
* them (zyfai). Omitted for agents that don't expose positions (sail).
|
|
203
215
|
*/
|
|
204
216
|
positions?: OwneyPosition[];
|
|
217
|
+
/** Funds received but not yet deployed. Omitted when nothing is pending. */
|
|
218
|
+
pendingAllocations?: OwneyPendingAllocation[];
|
|
205
219
|
}
|
|
206
220
|
interface OwneyBalances {
|
|
207
221
|
totalBalance: string;
|
|
@@ -404,8 +418,6 @@ declare class OwneySDK {
|
|
|
404
418
|
private referralSource?;
|
|
405
419
|
private cachedSponsoredCallback;
|
|
406
420
|
private cachedWethSponsoredCallback;
|
|
407
|
-
private paymasterServiceUrl?;
|
|
408
|
-
private cachedSponsoredCallsCallbacks;
|
|
409
421
|
private initializingAgentsPromise;
|
|
410
422
|
constructor(config: OwneySDKConfig);
|
|
411
423
|
/**
|
|
@@ -446,13 +458,6 @@ declare class OwneySDK {
|
|
|
446
458
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
447
459
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
448
460
|
*/
|
|
449
|
-
private getDefaultSponsoredCallsCallback;
|
|
450
|
-
/**
|
|
451
|
-
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
452
|
-
* callback used when the caller omits `depositCallback` for a WETH deposit.
|
|
453
|
-
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
454
|
-
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
455
|
-
*/
|
|
456
461
|
private getDefaultWethSponsoredCallback;
|
|
457
462
|
private getAgent;
|
|
458
463
|
private getActiveAgents;
|
|
@@ -629,7 +634,7 @@ declare class OwneySDK {
|
|
|
629
634
|
getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
|
|
630
635
|
}
|
|
631
636
|
|
|
632
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "CHAIN_MISMATCH" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "DEPOSIT_INSUFFICIENT_BALANCE" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "PERMIT2_APPROVAL_REQUIRED" | "
|
|
637
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "CHAIN_MISMATCH" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "DEPOSIT_INSUFFICIENT_BALANCE" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
633
638
|
declare class OwneyError extends Error {
|
|
634
639
|
readonly code: OwneyErrorCode;
|
|
635
640
|
readonly details?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -30,17 +30,6 @@ interface OwneySDKConfig {
|
|
|
30
30
|
* already-deployed app: set `globalThis.__OWNEY_DEBUG__ = true` in devtools.
|
|
31
31
|
*/
|
|
32
32
|
debug?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Absolute URL of an ERC-7677 paymaster service. When set, deposits go out as
|
|
35
|
-
* an EIP-5792 `wallet_sendCalls` with `capabilities.paymasterService`, so a
|
|
36
|
-
* wallet that advertises sponsorship pays no native gas — the case EIP-3009
|
|
37
|
-
* cannot serve, because USDC verifies it with `ecrecover` and a smart account
|
|
38
|
-
* signs via ERC-1271.
|
|
39
|
-
*
|
|
40
|
-
* MUST be absolute: the wallet fetches this URL itself, so a relative path is
|
|
41
|
-
* unresolvable. Omit it and every rail behaves exactly as before.
|
|
42
|
-
*/
|
|
43
|
-
paymasterServiceUrl?: string;
|
|
44
33
|
}
|
|
45
34
|
interface ConnectionState {
|
|
46
35
|
provider: any;
|
|
@@ -191,6 +180,29 @@ interface OwneyPosition {
|
|
|
191
180
|
* response later; undefined until then. */
|
|
192
181
|
liquidity?: number;
|
|
193
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Funds that have landed in the agent's wallet but are not yet deployed into a
|
|
185
|
+
* protocol. Sourced from Zyfai `staleBalances[].isPending`. Absent when nothing
|
|
186
|
+
* is pending, and for agents that do not report it (sail).
|
|
187
|
+
*/
|
|
188
|
+
interface OwneyPendingAllocation {
|
|
189
|
+
/** Deliberately loose (not OwneySupportedChainId) because Zyfai reports balances on unsupported chains. */
|
|
190
|
+
chainId: number;
|
|
191
|
+
/** Raw agent symbol, not normalized to OwneySupportedTokens; carries Zyfai's casing and "eth" alias for WETH. */
|
|
192
|
+
asset: string;
|
|
193
|
+
/** Decimal string, consistent with `OwneyToken.amount`. */
|
|
194
|
+
amount: string;
|
|
195
|
+
/**
|
|
196
|
+
* Zyfai's own `isPending` flag. TRUE means it is actively allocating. FALSE
|
|
197
|
+
* does NOT mean the entry is stale or safe to ignore: Zyfai flips it within
|
|
198
|
+
* minutes but leaves funds listed here indefinitely when it has not indexed
|
|
199
|
+
* the pool they landed in. Entries are surfaced regardless of this flag; use
|
|
200
|
+
* it only to decide wording, never to decide whether the money counts.
|
|
201
|
+
*/
|
|
202
|
+
isPending: boolean;
|
|
203
|
+
/** ISO timestamp from Zyfai's `updatedAt`, when the payload carries one. */
|
|
204
|
+
since?: string;
|
|
205
|
+
}
|
|
194
206
|
interface AgentBalance {
|
|
195
207
|
smartWallet?: `0x${string}`;
|
|
196
208
|
totalBalance: string;
|
|
@@ -202,6 +214,8 @@ interface AgentBalance {
|
|
|
202
214
|
* them (zyfai). Omitted for agents that don't expose positions (sail).
|
|
203
215
|
*/
|
|
204
216
|
positions?: OwneyPosition[];
|
|
217
|
+
/** Funds received but not yet deployed. Omitted when nothing is pending. */
|
|
218
|
+
pendingAllocations?: OwneyPendingAllocation[];
|
|
205
219
|
}
|
|
206
220
|
interface OwneyBalances {
|
|
207
221
|
totalBalance: string;
|
|
@@ -404,8 +418,6 @@ declare class OwneySDK {
|
|
|
404
418
|
private referralSource?;
|
|
405
419
|
private cachedSponsoredCallback;
|
|
406
420
|
private cachedWethSponsoredCallback;
|
|
407
|
-
private paymasterServiceUrl?;
|
|
408
|
-
private cachedSponsoredCallsCallbacks;
|
|
409
421
|
private initializingAgentsPromise;
|
|
410
422
|
constructor(config: OwneySDKConfig);
|
|
411
423
|
/**
|
|
@@ -446,13 +458,6 @@ declare class OwneySDK {
|
|
|
446
458
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
447
459
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
448
460
|
*/
|
|
449
|
-
private getDefaultSponsoredCallsCallback;
|
|
450
|
-
/**
|
|
451
|
-
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
452
|
-
* callback used when the caller omits `depositCallback` for a WETH deposit.
|
|
453
|
-
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
454
|
-
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
455
|
-
*/
|
|
456
461
|
private getDefaultWethSponsoredCallback;
|
|
457
462
|
private getAgent;
|
|
458
463
|
private getActiveAgents;
|
|
@@ -629,7 +634,7 @@ declare class OwneySDK {
|
|
|
629
634
|
getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
|
|
630
635
|
}
|
|
631
636
|
|
|
632
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "CHAIN_MISMATCH" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "DEPOSIT_INSUFFICIENT_BALANCE" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "PERMIT2_APPROVAL_REQUIRED" | "
|
|
637
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "CHAIN_MISMATCH" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "DEPOSIT_INSUFFICIENT_BALANCE" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
633
638
|
declare class OwneyError extends Error {
|
|
634
639
|
readonly code: OwneyErrorCode;
|
|
635
640
|
readonly details?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -184,6 +184,32 @@ function resolveChainId(chain) {
|
|
|
184
184
|
if (Number.isFinite(asNum) && asNum > 0) return asNum;
|
|
185
185
|
return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
|
|
186
186
|
}
|
|
187
|
+
function mapPendingAllocations(raw) {
|
|
188
|
+
if (!Array.isArray(raw)) return void 0;
|
|
189
|
+
const pending = [];
|
|
190
|
+
for (const entry of raw) {
|
|
191
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
192
|
+
const e = entry;
|
|
193
|
+
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
194
|
+
if (typeof e.tokenSymbol !== "string" || e.tokenSymbol === "") continue;
|
|
195
|
+
if (typeof e.balance !== "string") continue;
|
|
196
|
+
let amount;
|
|
197
|
+
try {
|
|
198
|
+
amount = hexToDecimal(e.balance, tokenDecimals(e.tokenSymbol));
|
|
199
|
+
} catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (!Number.isFinite(amount) || amount <= 0) continue;
|
|
203
|
+
pending.push({
|
|
204
|
+
chainId: e.chainId,
|
|
205
|
+
asset: e.tokenSymbol,
|
|
206
|
+
amount: String(amount),
|
|
207
|
+
isPending: e.isPending === true,
|
|
208
|
+
...typeof e.updatedAt === "string" && e.updatedAt !== "" ? { since: e.updatedAt } : {}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return pending.length > 0 ? pending : void 0;
|
|
212
|
+
}
|
|
187
213
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
188
214
|
const portfolio = raw.portfolio;
|
|
189
215
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
@@ -235,12 +261,16 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
235
261
|
// structural read keeps it undefined today and auto-populates later.
|
|
236
262
|
liquidity: p.liquidity
|
|
237
263
|
}));
|
|
264
|
+
const pendingAllocations = mapPendingAllocations(
|
|
265
|
+
portfolio.staleBalances
|
|
266
|
+
);
|
|
238
267
|
return {
|
|
239
268
|
smartWallet,
|
|
240
269
|
totalBalance: String(totalBalance),
|
|
241
270
|
totalBalanceAsset: "usdc",
|
|
242
271
|
tokens,
|
|
243
|
-
positions
|
|
272
|
+
positions,
|
|
273
|
+
...pendingAllocations ? { pendingAllocations } : {}
|
|
244
274
|
};
|
|
245
275
|
}
|
|
246
276
|
function sumTokenValues(tokens) {
|
|
@@ -846,6 +876,12 @@ var ZyfaiAgent = class {
|
|
|
846
876
|
connectedAddress = null;
|
|
847
877
|
connectedChainId = null;
|
|
848
878
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
879
|
+
/**
|
|
880
|
+
* `${eoa}:${chainId}` keys we have already tried createSessionKey for. Guards
|
|
881
|
+
* against re-running it on every activation/deposit when Zyfai's
|
|
882
|
+
* `hasActiveSessionKey` does not flip to true — see ensureSessionKey.
|
|
883
|
+
*/
|
|
884
|
+
sessionKeyAttempts = /* @__PURE__ */ new Set();
|
|
849
885
|
connectAuthPromise = null;
|
|
850
886
|
rpcUrls;
|
|
851
887
|
publicClients = /* @__PURE__ */ new Map();
|
|
@@ -1303,10 +1339,74 @@ var ZyfaiAgent = class {
|
|
|
1303
1339
|
* recoverable (ensureWalletDeployed tries the other deploy call), but
|
|
1304
1340
|
* failing the deposit outright is not.
|
|
1305
1341
|
*/
|
|
1342
|
+
/**
|
|
1343
|
+
* Zyfai's own answer to "what kind of wallet is this, and can the agent act on
|
|
1344
|
+
* it", read from the positions payload (`GET /data/position`, which
|
|
1345
|
+
* `getPositions` wraps).
|
|
1346
|
+
*
|
|
1347
|
+
* `predeployed` and `hasActiveSessionKey` are both returned at runtime but
|
|
1348
|
+
* declared on neither `Portfolio` nor their docs, hence the cast. Verified
|
|
1349
|
+
* live: an old wallet reports `{predeployed: false, hasActiveSessionKey:
|
|
1350
|
+
* false}` while a pool wallet reports `{true, true}`.
|
|
1351
|
+
*
|
|
1352
|
+
* Preferred over the SDK's private `isPredeployed`, which is cached from the
|
|
1353
|
+
* login response and can go stale mid-session. Returns an empty object on any
|
|
1354
|
+
* failure so every caller degrades to its own fallback.
|
|
1355
|
+
*/
|
|
1356
|
+
async readWalletState(ownerAddress) {
|
|
1357
|
+
try {
|
|
1358
|
+
const { portfolio } = await this.sdk.getPositions(ownerAddress);
|
|
1359
|
+
const raw = portfolio;
|
|
1360
|
+
debugLog("zyfai:onboard", "wallet state from getPositions", {
|
|
1361
|
+
predeployed: raw?.predeployed,
|
|
1362
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1363
|
+
});
|
|
1364
|
+
return {
|
|
1365
|
+
predeployed: raw?.predeployed,
|
|
1366
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1367
|
+
};
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
console.warn(
|
|
1370
|
+
"[zyfai] getPositions wallet-state read failed (non-fatal):",
|
|
1371
|
+
error instanceof Error ? error.message : String(error)
|
|
1372
|
+
);
|
|
1373
|
+
return {};
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1306
1376
|
async isPredeployedPoolWallet(ownerAddress, smartWallet) {
|
|
1377
|
+
const { predeployed } = await this.readWalletState(ownerAddress);
|
|
1378
|
+
if (typeof predeployed === "boolean") {
|
|
1379
|
+
debugLog(
|
|
1380
|
+
"zyfai:onboard",
|
|
1381
|
+
`wallet class: ${predeployed ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1382
|
+
{ source: "getPositions.predeployed", predeployed }
|
|
1383
|
+
);
|
|
1384
|
+
return predeployed;
|
|
1385
|
+
}
|
|
1386
|
+
const internals = this.sdk;
|
|
1387
|
+
if (typeof internals.isPredeployed === "boolean") {
|
|
1388
|
+
debugLog(
|
|
1389
|
+
"zyfai:onboard",
|
|
1390
|
+
`wallet class: ${internals.isPredeployed ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1391
|
+
{
|
|
1392
|
+
source: "login response (cached)",
|
|
1393
|
+
predeployed: internals.isPredeployed
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
return internals.isPredeployed;
|
|
1397
|
+
}
|
|
1307
1398
|
try {
|
|
1308
1399
|
const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
|
|
1309
|
-
|
|
1400
|
+
const isPool = typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
|
|
1401
|
+
debugLog(
|
|
1402
|
+
"zyfai:onboard",
|
|
1403
|
+
`wallet class: ${isPool ? "PREDEPLOYED (new flow)" : "OLD (legacy flow)"}`,
|
|
1404
|
+
{
|
|
1405
|
+
source: "getSmartWalletByEOA fallback",
|
|
1406
|
+
poolRecord: byEoa?.smartWallet
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
return isPool;
|
|
1310
1410
|
} catch (error) {
|
|
1311
1411
|
console.warn(
|
|
1312
1412
|
"[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
|
|
@@ -1344,8 +1444,24 @@ var ZyfaiAgent = class {
|
|
|
1344
1444
|
ownerAddress,
|
|
1345
1445
|
chainId
|
|
1346
1446
|
);
|
|
1347
|
-
|
|
1348
|
-
|
|
1447
|
+
debugLog("zyfai:onboard", `activation check on chain ${chainId}`, {
|
|
1448
|
+
smartWallet: wallet.address,
|
|
1449
|
+
isDeployed: wallet.isDeployed
|
|
1450
|
+
});
|
|
1451
|
+
if (!wallet.isDeployed) {
|
|
1452
|
+
debugLog(
|
|
1453
|
+
"zyfai:onboard",
|
|
1454
|
+
"Safe not deployed on this chain; activation does nothing (deposit owns deploys)"
|
|
1455
|
+
);
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1459
|
+
await this.ensureSessionKey(
|
|
1460
|
+
ownerAddress,
|
|
1461
|
+
chainId,
|
|
1462
|
+
wallet.address,
|
|
1463
|
+
hasActiveSessionKey
|
|
1464
|
+
);
|
|
1349
1465
|
} catch (error) {
|
|
1350
1466
|
console.warn(
|
|
1351
1467
|
"[zyfai] session-key check at activation failed (non-fatal):",
|
|
@@ -1353,20 +1469,51 @@ var ZyfaiAgent = class {
|
|
|
1353
1469
|
);
|
|
1354
1470
|
}
|
|
1355
1471
|
}
|
|
1356
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1472
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet, hasActiveSessionKey) {
|
|
1473
|
+
const attemptKey = `${ownerAddress.toLowerCase()}:${chainId}`;
|
|
1474
|
+
if (this.sessionKeyAttempts.has(attemptKey)) {
|
|
1475
|
+
debugLog(
|
|
1476
|
+
"zyfai:onboard",
|
|
1477
|
+
"session key: already attempted this session, skipping",
|
|
1478
|
+
{ chainId }
|
|
1479
|
+
);
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1357
1482
|
try {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1483
|
+
if (hasActiveSessionKey === true) {
|
|
1484
|
+
debugLog(
|
|
1485
|
+
"zyfai:onboard",
|
|
1486
|
+
"session key: already on record -> nothing to do",
|
|
1487
|
+
{ chainId }
|
|
1488
|
+
);
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
if (hasActiveSessionKey === void 0) {
|
|
1492
|
+
const installed = await this.readSmartSessionsInstalled(
|
|
1493
|
+
chainId,
|
|
1494
|
+
smartWallet
|
|
1495
|
+
);
|
|
1496
|
+
debugLog(
|
|
1497
|
+
"zyfai:onboard",
|
|
1498
|
+
`session key: Zyfai state unavailable; on-chain validator ${installed ? "INSTALLED" : "MISSING"}`,
|
|
1499
|
+
{ smartWallet, chainId }
|
|
1500
|
+
);
|
|
1501
|
+
if (installed) return;
|
|
1502
|
+
}
|
|
1503
|
+
this.sessionKeyAttempts.add(attemptKey);
|
|
1366
1504
|
console.warn(
|
|
1367
|
-
`[zyfai]
|
|
1505
|
+
`[zyfai] no session key for ${smartWallet} on chain ${chainId}; creating one so the agent can allocate.`
|
|
1368
1506
|
);
|
|
1507
|
+
debugLog("zyfai:onboard", "session key: calling createSessionKey", {
|
|
1508
|
+
chainId,
|
|
1509
|
+
smartWallet,
|
|
1510
|
+
hasActiveSessionKey
|
|
1511
|
+
});
|
|
1369
1512
|
await this.sdk.createSessionKey(ownerAddress, chainId);
|
|
1513
|
+
debugLog("zyfai:onboard", "session key: createSessionKey succeeded", {
|
|
1514
|
+
chainId,
|
|
1515
|
+
smartWallet
|
|
1516
|
+
});
|
|
1370
1517
|
} catch (error) {
|
|
1371
1518
|
console.warn(
|
|
1372
1519
|
"[zyfai] createSessionKey skipped (non-fatal):",
|
|
@@ -1374,6 +1521,16 @@ var ZyfaiAgent = class {
|
|
|
1374
1521
|
);
|
|
1375
1522
|
}
|
|
1376
1523
|
}
|
|
1524
|
+
/** Ground truth for "can Zyfai's automation act on this Safe, on this chain". */
|
|
1525
|
+
async readSmartSessionsInstalled(chainId, smartWallet) {
|
|
1526
|
+
return this.getPublicClient(chainId).readContract({
|
|
1527
|
+
address: smartWallet,
|
|
1528
|
+
abi: ERC7579_IS_MODULE_INSTALLED_ABI,
|
|
1529
|
+
functionName: "isModuleInstalled",
|
|
1530
|
+
// moduleTypeId 1 = validator (ERC-7579)
|
|
1531
|
+
args: [1n, SMART_SESSIONS_VALIDATOR, "0x"]
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1377
1534
|
/**
|
|
1378
1535
|
* Guarantee the user's Safe has code on `chainId` before anything transfers
|
|
1379
1536
|
* funds into it, and return its address.
|
|
@@ -1394,8 +1551,24 @@ var ZyfaiAgent = class {
|
|
|
1394
1551
|
*/
|
|
1395
1552
|
async ensureWalletDeployed(ownerAddress, chainId) {
|
|
1396
1553
|
const wallet = await this.sdk.getSmartWalletAddress(ownerAddress, chainId);
|
|
1554
|
+
debugLog("zyfai:onboard", `--- deposit onboarding, chain ${chainId} ---`, {
|
|
1555
|
+
eoa: ownerAddress,
|
|
1556
|
+
smartWallet: wallet.address,
|
|
1557
|
+
isDeployed: wallet.isDeployed,
|
|
1558
|
+
isOwner: wallet.isOwner
|
|
1559
|
+
});
|
|
1397
1560
|
if (wallet.isDeployed) {
|
|
1398
|
-
|
|
1561
|
+
debugLog(
|
|
1562
|
+
"zyfai:onboard",
|
|
1563
|
+
"Safe already has code -> no deploy needed, checking the session key"
|
|
1564
|
+
);
|
|
1565
|
+
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1566
|
+
await this.ensureSessionKey(
|
|
1567
|
+
ownerAddress,
|
|
1568
|
+
chainId,
|
|
1569
|
+
wallet.address,
|
|
1570
|
+
hasActiveSessionKey
|
|
1571
|
+
);
|
|
1399
1572
|
return wallet.address;
|
|
1400
1573
|
}
|
|
1401
1574
|
const poolFirst = await this.isPredeployedPoolWallet(
|
|
@@ -1411,14 +1584,27 @@ var ZyfaiAgent = class {
|
|
|
1411
1584
|
this.sdk.deploySafe(ownerAddress, chainId, "aggressive", true)
|
|
1412
1585
|
);
|
|
1413
1586
|
const [first, second] = poolFirst ? [deployAsPool, deployAsLegacy] : [deployAsLegacy, deployAsPool];
|
|
1587
|
+
debugLog(
|
|
1588
|
+
"zyfai:onboard",
|
|
1589
|
+
`Safe has no code on chain ${chainId} -> deploying via ${poolFirst ? "deployOnChains (pool path)" : "deploySafe(createSessionKey=true) (legacy path)"}`
|
|
1590
|
+
);
|
|
1414
1591
|
try {
|
|
1415
1592
|
await first();
|
|
1593
|
+
debugLog(
|
|
1594
|
+
"zyfai:onboard",
|
|
1595
|
+
`${poolFirst ? "deployOnChains" : "deploySafe"} succeeded`
|
|
1596
|
+
);
|
|
1416
1597
|
} catch (error) {
|
|
1417
1598
|
console.warn(
|
|
1418
1599
|
`[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
|
|
1419
1600
|
error instanceof Error ? error.message : String(error)
|
|
1420
1601
|
);
|
|
1602
|
+
debugLog(
|
|
1603
|
+
"zyfai:onboard",
|
|
1604
|
+
`falling back to ${poolFirst ? "deploySafe (legacy path)" : "deployOnChains (pool path)"}`
|
|
1605
|
+
);
|
|
1421
1606
|
await second();
|
|
1607
|
+
debugLog("zyfai:onboard", "fallback deploy path succeeded");
|
|
1422
1608
|
}
|
|
1423
1609
|
const redeployed = await this.sdk.getSmartWalletAddress(
|
|
1424
1610
|
ownerAddress,
|
|
@@ -2240,97 +2426,6 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2240
2426
|
};
|
|
2241
2427
|
}
|
|
2242
2428
|
|
|
2243
|
-
// src/lib/sponsored-calls-deposit.ts
|
|
2244
|
-
import { encodeFunctionData, erc20Abi, toHex } from "viem";
|
|
2245
|
-
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
2246
|
-
var DEFAULT_MAX_POLLS = 30;
|
|
2247
|
-
async function paymasterSupported(provider, owner, chainId) {
|
|
2248
|
-
const caps = await provider.request({
|
|
2249
|
-
method: "wallet_getCapabilities",
|
|
2250
|
-
params: [owner]
|
|
2251
|
-
});
|
|
2252
|
-
const forChain = caps?.[toHex(chainId)] ?? caps?.[String(chainId)];
|
|
2253
|
-
return Boolean(forChain?.paymasterService?.supported);
|
|
2254
|
-
}
|
|
2255
|
-
function makeSponsoredCallsCallback(deps) {
|
|
2256
|
-
const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
2257
|
-
const maxPolls = deps.maxPolls ?? DEFAULT_MAX_POLLS;
|
|
2258
|
-
const absolutePaymasterUrl = () => {
|
|
2259
|
-
const configured = deps.paymasterServiceUrl;
|
|
2260
|
-
if (/^https?:\/\//i.test(configured)) return configured;
|
|
2261
|
-
const origin = globalThis.location?.origin;
|
|
2262
|
-
if (!origin) {
|
|
2263
|
-
throw new OwneyError(
|
|
2264
|
-
"SPONSORED_CALLS_UNSUPPORTED",
|
|
2265
|
-
`paymasterServiceUrl "${configured}" is relative and no page origin is available to resolve it.`
|
|
2266
|
-
);
|
|
2267
|
-
}
|
|
2268
|
-
return new URL(configured, origin).toString();
|
|
2269
|
-
};
|
|
2270
|
-
return async (smartWallet, chainId, amount) => {
|
|
2271
|
-
const cid = chainId;
|
|
2272
|
-
const token = deps.tokenAddressByChain[cid];
|
|
2273
|
-
if (!token) {
|
|
2274
|
-
throw new OwneyError(
|
|
2275
|
-
"CHAIN_UNSUPPORTED",
|
|
2276
|
-
`No sponsored token configured for chain ${chainId}`
|
|
2277
|
-
);
|
|
2278
|
-
}
|
|
2279
|
-
if (!await paymasterSupported(deps.provider, deps.ownerAddress, chainId)) {
|
|
2280
|
-
throw new OwneyError(
|
|
2281
|
-
"SPONSORED_CALLS_UNSUPPORTED",
|
|
2282
|
-
`Wallet does not advertise paymasterService on chain ${chainId}.`,
|
|
2283
|
-
{ chainId }
|
|
2284
|
-
);
|
|
2285
|
-
}
|
|
2286
|
-
const data = encodeFunctionData({
|
|
2287
|
-
abi: erc20Abi,
|
|
2288
|
-
functionName: "transfer",
|
|
2289
|
-
args: [smartWallet, BigInt(amount)]
|
|
2290
|
-
});
|
|
2291
|
-
const sendResult = await deps.provider.request({
|
|
2292
|
-
method: "wallet_sendCalls",
|
|
2293
|
-
params: [
|
|
2294
|
-
{
|
|
2295
|
-
version: "2.0.0",
|
|
2296
|
-
from: deps.ownerAddress,
|
|
2297
|
-
chainId: toHex(chainId),
|
|
2298
|
-
atomicRequired: false,
|
|
2299
|
-
calls: [{ to: token, value: "0x0", data }],
|
|
2300
|
-
capabilities: {
|
|
2301
|
-
paymasterService: { url: absolutePaymasterUrl() }
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
]
|
|
2305
|
-
});
|
|
2306
|
-
deps.onApproved?.();
|
|
2307
|
-
const callsId = typeof sendResult === "string" ? sendResult : sendResult?.id;
|
|
2308
|
-
if (!callsId) {
|
|
2309
|
-
throw new OwneyError(
|
|
2310
|
-
"SPONSORED_CALLS_NO_ID",
|
|
2311
|
-
"Wallet accepted wallet_sendCalls but returned no calls id.",
|
|
2312
|
-
{ chainId }
|
|
2313
|
-
);
|
|
2314
|
-
}
|
|
2315
|
-
for (let attempt = 0; attempt < maxPolls; attempt += 1) {
|
|
2316
|
-
const status = await deps.provider.request({
|
|
2317
|
-
method: "wallet_getCallsStatus",
|
|
2318
|
-
params: [callsId]
|
|
2319
|
-
});
|
|
2320
|
-
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
2321
|
-
if (txHash) return txHash;
|
|
2322
|
-
if (pollIntervalMs > 0) {
|
|
2323
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
throw new OwneyError(
|
|
2327
|
-
"SPONSORED_CALLS_NO_RECEIPT",
|
|
2328
|
-
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
2329
|
-
{ chainId, callsId }
|
|
2330
|
-
);
|
|
2331
|
-
};
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
2429
|
// src/client.ts
|
|
2335
2430
|
function encodeMultiAgentCursor(map) {
|
|
2336
2431
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -2392,15 +2487,12 @@ var OwneySDK = class {
|
|
|
2392
2487
|
referralSource;
|
|
2393
2488
|
cachedSponsoredCallback = null;
|
|
2394
2489
|
cachedWethSponsoredCallback = null;
|
|
2395
|
-
paymasterServiceUrl;
|
|
2396
|
-
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2397
2490
|
initializingAgentsPromise = null;
|
|
2398
2491
|
constructor(config) {
|
|
2399
2492
|
this.apiKey = config.apiKey;
|
|
2400
2493
|
if (config.debug) setOwneyDebug(true);
|
|
2401
2494
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2402
2495
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2403
|
-
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2404
2496
|
this.referralSource = config.referralSource;
|
|
2405
2497
|
}
|
|
2406
2498
|
/**
|
|
@@ -2423,7 +2515,6 @@ var OwneySDK = class {
|
|
|
2423
2515
|
this.state = { provider, walletAddress, chainId: null };
|
|
2424
2516
|
this.cachedSponsoredCallback = null;
|
|
2425
2517
|
this.cachedWethSponsoredCallback = null;
|
|
2426
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
2427
2518
|
}
|
|
2428
2519
|
/**
|
|
2429
2520
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2438,7 +2529,6 @@ var OwneySDK = class {
|
|
|
2438
2529
|
this.state = null;
|
|
2439
2530
|
this.cachedSponsoredCallback = null;
|
|
2440
2531
|
this.cachedWethSponsoredCallback = null;
|
|
2441
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
2442
2532
|
}
|
|
2443
2533
|
isAgentDisabled(agentId) {
|
|
2444
2534
|
return this.disabledAgents.has(agentId);
|
|
@@ -2520,26 +2610,6 @@ var OwneySDK = class {
|
|
|
2520
2610
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2521
2611
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2522
2612
|
*/
|
|
2523
|
-
getDefaultSponsoredCallsCallback(asset, onApproved) {
|
|
2524
|
-
const cached = this.cachedSponsoredCallsCallbacks.get(asset);
|
|
2525
|
-
if (!onApproved && cached) return cached;
|
|
2526
|
-
const provider = this.requireConnectedProvider();
|
|
2527
|
-
const callback = makeSponsoredCallsCallback({
|
|
2528
|
-
provider,
|
|
2529
|
-
ownerAddress: this.state.walletAddress,
|
|
2530
|
-
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
2531
|
-
onApproved,
|
|
2532
|
-
tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
|
|
2533
|
-
});
|
|
2534
|
-
if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
2535
|
-
return callback;
|
|
2536
|
-
}
|
|
2537
|
-
/**
|
|
2538
|
-
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
2539
|
-
* callback used when the caller omits `depositCallback` for a WETH deposit.
|
|
2540
|
-
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2541
|
-
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2542
|
-
*/
|
|
2543
2613
|
getDefaultWethSponsoredCallback(onApproved) {
|
|
2544
2614
|
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
2545
2615
|
return this.cachedWethSponsoredCallback;
|
|
@@ -2762,7 +2832,7 @@ var OwneySDK = class {
|
|
|
2762
2832
|
}
|
|
2763
2833
|
const state = this.requireState();
|
|
2764
2834
|
const chainId = this.requireChainId();
|
|
2765
|
-
const effectiveCallback = depositCallback ?? (
|
|
2835
|
+
const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2766
2836
|
if (agentId) {
|
|
2767
2837
|
if (this.isAgentDisabled(agentId)) {
|
|
2768
2838
|
throw new OwneyError(
|