@owney/sdk 0.7.7-beta.4 → 0.7.7-beta.5
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 +147 -217
- package/dist/index.d.cts +21 -18
- package/dist/index.d.ts +21 -18
- package/dist/index.js +132 -202
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -217,32 +217,6 @@ 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 (e.isPending !== true) continue;
|
|
227
|
-
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
228
|
-
if (typeof e.tokenSymbol !== "string" || e.tokenSymbol === "") continue;
|
|
229
|
-
if (typeof e.balance !== "string") continue;
|
|
230
|
-
let amount;
|
|
231
|
-
try {
|
|
232
|
-
amount = hexToDecimal(e.balance, tokenDecimals(e.tokenSymbol));
|
|
233
|
-
} catch {
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
if (!Number.isFinite(amount) || amount <= 0) continue;
|
|
237
|
-
pending.push({
|
|
238
|
-
chainId: e.chainId,
|
|
239
|
-
asset: e.tokenSymbol,
|
|
240
|
-
amount: String(amount),
|
|
241
|
-
...typeof e.updatedAt === "string" && e.updatedAt !== "" ? { since: e.updatedAt } : {}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
return pending.length > 0 ? pending : void 0;
|
|
245
|
-
}
|
|
246
220
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
247
221
|
const portfolio = raw.portfolio;
|
|
248
222
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
@@ -294,16 +268,12 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
294
268
|
// structural read keeps it undefined today and auto-populates later.
|
|
295
269
|
liquidity: p.liquidity
|
|
296
270
|
}));
|
|
297
|
-
const pendingAllocations = mapPendingAllocations(
|
|
298
|
-
portfolio.staleBalances
|
|
299
|
-
);
|
|
300
271
|
return {
|
|
301
272
|
smartWallet,
|
|
302
273
|
totalBalance: String(totalBalance),
|
|
303
274
|
totalBalanceAsset: "usdc",
|
|
304
275
|
tokens,
|
|
305
|
-
positions
|
|
306
|
-
...pendingAllocations ? { pendingAllocations } : {}
|
|
276
|
+
positions
|
|
307
277
|
};
|
|
308
278
|
}
|
|
309
279
|
function sumTokenValues(tokens) {
|
|
@@ -909,12 +879,6 @@ var ZyfaiAgent = class {
|
|
|
909
879
|
connectedAddress = null;
|
|
910
880
|
connectedChainId = null;
|
|
911
881
|
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();
|
|
918
882
|
connectAuthPromise = null;
|
|
919
883
|
rpcUrls;
|
|
920
884
|
publicClients = /* @__PURE__ */ new Map();
|
|
@@ -1372,74 +1336,10 @@ var ZyfaiAgent = class {
|
|
|
1372
1336
|
* recoverable (ensureWalletDeployed tries the other deploy call), but
|
|
1373
1337
|
* failing the deposit outright is not.
|
|
1374
1338
|
*/
|
|
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
|
-
}
|
|
1409
1339
|
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
|
-
}
|
|
1431
1340
|
try {
|
|
1432
1341
|
const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
|
|
1433
|
-
|
|
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;
|
|
1342
|
+
return typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
|
|
1443
1343
|
} catch (error) {
|
|
1444
1344
|
console.warn(
|
|
1445
1345
|
"[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
|
|
@@ -1477,24 +1377,8 @@ var ZyfaiAgent = class {
|
|
|
1477
1377
|
ownerAddress,
|
|
1478
1378
|
chainId
|
|
1479
1379
|
);
|
|
1480
|
-
|
|
1481
|
-
|
|
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
|
-
);
|
|
1380
|
+
if (!wallet.isDeployed) return;
|
|
1381
|
+
await this.ensureSessionKey(ownerAddress, chainId, wallet.address);
|
|
1498
1382
|
} catch (error) {
|
|
1499
1383
|
console.warn(
|
|
1500
1384
|
"[zyfai] session-key check at activation failed (non-fatal):",
|
|
@@ -1502,51 +1386,20 @@ var ZyfaiAgent = class {
|
|
|
1502
1386
|
);
|
|
1503
1387
|
}
|
|
1504
1388
|
}
|
|
1505
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet
|
|
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
|
-
}
|
|
1389
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1515
1390
|
try {
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
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);
|
|
1391
|
+
const installed = await this.getPublicClient(chainId).readContract({
|
|
1392
|
+
address: smartWallet,
|
|
1393
|
+
abi: ERC7579_IS_MODULE_INSTALLED_ABI,
|
|
1394
|
+
functionName: "isModuleInstalled",
|
|
1395
|
+
// moduleTypeId 1 = validator (ERC-7579)
|
|
1396
|
+
args: [1n, import_sdk.SMART_SESSIONS_VALIDATOR, "0x"]
|
|
1397
|
+
});
|
|
1398
|
+
if (installed) return;
|
|
1537
1399
|
console.warn(
|
|
1538
|
-
`[zyfai]
|
|
1400
|
+
`[zyfai] Safe ${smartWallet} has no smart-sessions validator on chain ${chainId}; creating a session key so the agent can allocate.`
|
|
1539
1401
|
);
|
|
1540
|
-
debugLog("zyfai:onboard", "session key: calling createSessionKey", {
|
|
1541
|
-
chainId,
|
|
1542
|
-
smartWallet,
|
|
1543
|
-
hasActiveSessionKey
|
|
1544
|
-
});
|
|
1545
1402
|
await this.sdk.createSessionKey(ownerAddress, chainId);
|
|
1546
|
-
debugLog("zyfai:onboard", "session key: createSessionKey succeeded", {
|
|
1547
|
-
chainId,
|
|
1548
|
-
smartWallet
|
|
1549
|
-
});
|
|
1550
1403
|
} catch (error) {
|
|
1551
1404
|
console.warn(
|
|
1552
1405
|
"[zyfai] createSessionKey skipped (non-fatal):",
|
|
@@ -1554,16 +1407,6 @@ var ZyfaiAgent = class {
|
|
|
1554
1407
|
);
|
|
1555
1408
|
}
|
|
1556
1409
|
}
|
|
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
|
-
}
|
|
1567
1410
|
/**
|
|
1568
1411
|
* Guarantee the user's Safe has code on `chainId` before anything transfers
|
|
1569
1412
|
* funds into it, and return its address.
|
|
@@ -1584,24 +1427,8 @@ var ZyfaiAgent = class {
|
|
|
1584
1427
|
*/
|
|
1585
1428
|
async ensureWalletDeployed(ownerAddress, chainId) {
|
|
1586
1429
|
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
|
-
});
|
|
1593
1430
|
if (wallet.isDeployed) {
|
|
1594
|
-
|
|
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
|
-
);
|
|
1431
|
+
await this.ensureSessionKey(ownerAddress, chainId, wallet.address);
|
|
1605
1432
|
return wallet.address;
|
|
1606
1433
|
}
|
|
1607
1434
|
const poolFirst = await this.isPredeployedPoolWallet(
|
|
@@ -1617,27 +1444,14 @@ var ZyfaiAgent = class {
|
|
|
1617
1444
|
this.sdk.deploySafe(ownerAddress, chainId, "aggressive", true)
|
|
1618
1445
|
);
|
|
1619
1446
|
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
|
-
);
|
|
1624
1447
|
try {
|
|
1625
1448
|
await first();
|
|
1626
|
-
debugLog(
|
|
1627
|
-
"zyfai:onboard",
|
|
1628
|
-
`${poolFirst ? "deployOnChains" : "deploySafe"} succeeded`
|
|
1629
|
-
);
|
|
1630
1449
|
} catch (error) {
|
|
1631
1450
|
console.warn(
|
|
1632
1451
|
`[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
|
|
1633
1452
|
error instanceof Error ? error.message : String(error)
|
|
1634
1453
|
);
|
|
1635
|
-
debugLog(
|
|
1636
|
-
"zyfai:onboard",
|
|
1637
|
-
`falling back to ${poolFirst ? "deploySafe (legacy path)" : "deployOnChains (pool path)"}`
|
|
1638
|
-
);
|
|
1639
1454
|
await second();
|
|
1640
|
-
debugLog("zyfai:onboard", "fallback deploy path succeeded");
|
|
1641
1455
|
}
|
|
1642
1456
|
const redeployed = await this.sdk.getSmartWalletAddress(
|
|
1643
1457
|
ownerAddress,
|
|
@@ -2025,7 +1839,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
2025
1839
|
}
|
|
2026
1840
|
|
|
2027
1841
|
// src/client.ts
|
|
2028
|
-
var
|
|
1842
|
+
var import_viem6 = require("viem");
|
|
2029
1843
|
var import_chains2 = require("viem/chains");
|
|
2030
1844
|
|
|
2031
1845
|
// src/lib/transfer-auth.ts
|
|
@@ -2455,6 +2269,97 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2455
2269
|
};
|
|
2456
2270
|
}
|
|
2457
2271
|
|
|
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
|
+
|
|
2458
2363
|
// src/client.ts
|
|
2459
2364
|
function encodeMultiAgentCursor(map) {
|
|
2460
2365
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -2516,12 +2421,15 @@ var OwneySDK = class {
|
|
|
2516
2421
|
referralSource;
|
|
2517
2422
|
cachedSponsoredCallback = null;
|
|
2518
2423
|
cachedWethSponsoredCallback = null;
|
|
2424
|
+
paymasterServiceUrl;
|
|
2425
|
+
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2519
2426
|
initializingAgentsPromise = null;
|
|
2520
2427
|
constructor(config) {
|
|
2521
2428
|
this.apiKey = config.apiKey;
|
|
2522
2429
|
if (config.debug) setOwneyDebug(true);
|
|
2523
2430
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2524
2431
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2432
|
+
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2525
2433
|
this.referralSource = config.referralSource;
|
|
2526
2434
|
}
|
|
2527
2435
|
/**
|
|
@@ -2544,6 +2452,7 @@ var OwneySDK = class {
|
|
|
2544
2452
|
this.state = { provider, walletAddress, chainId: null };
|
|
2545
2453
|
this.cachedSponsoredCallback = null;
|
|
2546
2454
|
this.cachedWethSponsoredCallback = null;
|
|
2455
|
+
this.cachedSponsoredCallsCallbacks.clear();
|
|
2547
2456
|
}
|
|
2548
2457
|
/**
|
|
2549
2458
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2558,6 +2467,7 @@ var OwneySDK = class {
|
|
|
2558
2467
|
this.state = null;
|
|
2559
2468
|
this.cachedSponsoredCallback = null;
|
|
2560
2469
|
this.cachedWethSponsoredCallback = null;
|
|
2470
|
+
this.cachedSponsoredCallsCallbacks.clear();
|
|
2561
2471
|
}
|
|
2562
2472
|
isAgentDisabled(agentId) {
|
|
2563
2473
|
return this.disabledAgents.has(agentId);
|
|
@@ -2620,14 +2530,14 @@ var OwneySDK = class {
|
|
|
2620
2530
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2621
2531
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2622
2532
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2623
|
-
getPublicClient: (cid) => (0,
|
|
2533
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
2624
2534
|
chain: VIEM_CHAIN2[cid],
|
|
2625
|
-
transport: (0,
|
|
2535
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2626
2536
|
}),
|
|
2627
|
-
getWalletClient: (cid) => (0,
|
|
2537
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
2628
2538
|
account: owner,
|
|
2629
2539
|
chain: VIEM_CHAIN2[cid],
|
|
2630
|
-
transport: (0,
|
|
2540
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2631
2541
|
})
|
|
2632
2542
|
});
|
|
2633
2543
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -2639,6 +2549,26 @@ var OwneySDK = class {
|
|
|
2639
2549
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2640
2550
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2641
2551
|
*/
|
|
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
|
+
*/
|
|
2642
2572
|
getDefaultWethSponsoredCallback(onApproved) {
|
|
2643
2573
|
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
2644
2574
|
return this.cachedWethSponsoredCallback;
|
|
@@ -2653,14 +2583,14 @@ var OwneySDK = class {
|
|
|
2653
2583
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2654
2584
|
// PublicClient/WalletClient param types — structurally identical at
|
|
2655
2585
|
// runtime, but the two share a name TS treats as unrelated.
|
|
2656
|
-
getPublicClient: (cid) => (0,
|
|
2586
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
2657
2587
|
chain: VIEM_CHAIN2[cid],
|
|
2658
|
-
transport: (0,
|
|
2588
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2659
2589
|
}),
|
|
2660
|
-
getWalletClient: (cid) => (0,
|
|
2590
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
2661
2591
|
account: owner,
|
|
2662
2592
|
chain: VIEM_CHAIN2[cid],
|
|
2663
|
-
transport: (0,
|
|
2593
|
+
transport: (0, import_viem6.custom)(provider)
|
|
2664
2594
|
})
|
|
2665
2595
|
});
|
|
2666
2596
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -2861,7 +2791,7 @@ var OwneySDK = class {
|
|
|
2861
2791
|
}
|
|
2862
2792
|
const state = this.requireState();
|
|
2863
2793
|
const chainId = this.requireChainId();
|
|
2864
|
-
const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2794
|
+
const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2865
2795
|
if (agentId) {
|
|
2866
2796
|
if (this.isAgentDisabled(agentId)) {
|
|
2867
2797
|
throw new OwneyError(
|
|
@@ -3504,10 +3434,10 @@ var OwneySDK = class {
|
|
|
3504
3434
|
);
|
|
3505
3435
|
}
|
|
3506
3436
|
const provider = this.requireConnectedProvider();
|
|
3507
|
-
const wallet = (0,
|
|
3437
|
+
const wallet = (0, import_viem6.createWalletClient)({
|
|
3508
3438
|
account: state.walletAddress,
|
|
3509
3439
|
chain: VIEM_CHAIN2[chainId],
|
|
3510
|
-
transport: (0,
|
|
3440
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3511
3441
|
});
|
|
3512
3442
|
const hash = await wallet.writeContract({
|
|
3513
3443
|
address: token,
|
|
@@ -3517,9 +3447,9 @@ var OwneySDK = class {
|
|
|
3517
3447
|
account: state.walletAddress,
|
|
3518
3448
|
chain: VIEM_CHAIN2[chainId]
|
|
3519
3449
|
});
|
|
3520
|
-
const publicClient = (0,
|
|
3450
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
3521
3451
|
chain: VIEM_CHAIN2[chainId],
|
|
3522
|
-
transport: (0,
|
|
3452
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3523
3453
|
});
|
|
3524
3454
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3525
3455
|
hash,
|
|
@@ -3628,7 +3558,7 @@ var OwneySDK = class {
|
|
|
3628
3558
|
};
|
|
3629
3559
|
|
|
3630
3560
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
3631
|
-
var
|
|
3561
|
+
var import_viem7 = require("viem");
|
|
3632
3562
|
var import_siwe = require("siwe");
|
|
3633
3563
|
var import_sdk2 = require("@zyfai/sdk");
|
|
3634
3564
|
|
|
@@ -3755,7 +3685,7 @@ function buildSIWXConfig(deps) {
|
|
|
3755
3685
|
issuedAt,
|
|
3756
3686
|
toString() {
|
|
3757
3687
|
return new import_siwe.SiweMessage({
|
|
3758
|
-
address: (0,
|
|
3688
|
+
address: (0, import_viem7.getAddress)(accountAddress),
|
|
3759
3689
|
chainId: numericChainId(chainId),
|
|
3760
3690
|
domain,
|
|
3761
3691
|
uri,
|
package/dist/index.d.cts
CHANGED
|
@@ -30,6 +30,17 @@ 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;
|
|
33
44
|
}
|
|
34
45
|
interface ConnectionState {
|
|
35
46
|
provider: any;
|
|
@@ -180,21 +191,6 @@ interface OwneyPosition {
|
|
|
180
191
|
* response later; undefined until then. */
|
|
181
192
|
liquidity?: number;
|
|
182
193
|
}
|
|
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
|
-
/** ISO timestamp from Zyfai's `updatedAt`, when the payload carries one. */
|
|
196
|
-
since?: string;
|
|
197
|
-
}
|
|
198
194
|
interface AgentBalance {
|
|
199
195
|
smartWallet?: `0x${string}`;
|
|
200
196
|
totalBalance: string;
|
|
@@ -206,8 +202,6 @@ interface AgentBalance {
|
|
|
206
202
|
* them (zyfai). Omitted for agents that don't expose positions (sail).
|
|
207
203
|
*/
|
|
208
204
|
positions?: OwneyPosition[];
|
|
209
|
-
/** Funds received but not yet deployed. Omitted when nothing is pending. */
|
|
210
|
-
pendingAllocations?: OwneyPendingAllocation[];
|
|
211
205
|
}
|
|
212
206
|
interface OwneyBalances {
|
|
213
207
|
totalBalance: string;
|
|
@@ -410,6 +404,8 @@ declare class OwneySDK {
|
|
|
410
404
|
private referralSource?;
|
|
411
405
|
private cachedSponsoredCallback;
|
|
412
406
|
private cachedWethSponsoredCallback;
|
|
407
|
+
private paymasterServiceUrl?;
|
|
408
|
+
private cachedSponsoredCallsCallbacks;
|
|
413
409
|
private initializingAgentsPromise;
|
|
414
410
|
constructor(config: OwneySDKConfig);
|
|
415
411
|
/**
|
|
@@ -450,6 +446,13 @@ declare class OwneySDK {
|
|
|
450
446
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
451
447
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
452
448
|
*/
|
|
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
|
+
*/
|
|
453
456
|
private getDefaultWethSponsoredCallback;
|
|
454
457
|
private getAgent;
|
|
455
458
|
private getActiveAgents;
|
|
@@ -626,7 +629,7 @@ declare class OwneySDK {
|
|
|
626
629
|
getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
|
|
627
630
|
}
|
|
628
631
|
|
|
629
|
-
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";
|
|
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" | "SPONSORED_CALLS_UNSUPPORTED" | "SPONSORED_CALLS_NO_ID" | "SPONSORED_CALLS_NO_RECEIPT" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
630
633
|
declare class OwneyError extends Error {
|
|
631
634
|
readonly code: OwneyErrorCode;
|
|
632
635
|
readonly details?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,17 @@ 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;
|
|
33
44
|
}
|
|
34
45
|
interface ConnectionState {
|
|
35
46
|
provider: any;
|
|
@@ -180,21 +191,6 @@ interface OwneyPosition {
|
|
|
180
191
|
* response later; undefined until then. */
|
|
181
192
|
liquidity?: number;
|
|
182
193
|
}
|
|
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
|
-
/** ISO timestamp from Zyfai's `updatedAt`, when the payload carries one. */
|
|
196
|
-
since?: string;
|
|
197
|
-
}
|
|
198
194
|
interface AgentBalance {
|
|
199
195
|
smartWallet?: `0x${string}`;
|
|
200
196
|
totalBalance: string;
|
|
@@ -206,8 +202,6 @@ interface AgentBalance {
|
|
|
206
202
|
* them (zyfai). Omitted for agents that don't expose positions (sail).
|
|
207
203
|
*/
|
|
208
204
|
positions?: OwneyPosition[];
|
|
209
|
-
/** Funds received but not yet deployed. Omitted when nothing is pending. */
|
|
210
|
-
pendingAllocations?: OwneyPendingAllocation[];
|
|
211
205
|
}
|
|
212
206
|
interface OwneyBalances {
|
|
213
207
|
totalBalance: string;
|
|
@@ -410,6 +404,8 @@ declare class OwneySDK {
|
|
|
410
404
|
private referralSource?;
|
|
411
405
|
private cachedSponsoredCallback;
|
|
412
406
|
private cachedWethSponsoredCallback;
|
|
407
|
+
private paymasterServiceUrl?;
|
|
408
|
+
private cachedSponsoredCallsCallbacks;
|
|
413
409
|
private initializingAgentsPromise;
|
|
414
410
|
constructor(config: OwneySDKConfig);
|
|
415
411
|
/**
|
|
@@ -450,6 +446,13 @@ declare class OwneySDK {
|
|
|
450
446
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
451
447
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
452
448
|
*/
|
|
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
|
+
*/
|
|
453
456
|
private getDefaultWethSponsoredCallback;
|
|
454
457
|
private getAgent;
|
|
455
458
|
private getActiveAgents;
|
|
@@ -626,7 +629,7 @@ declare class OwneySDK {
|
|
|
626
629
|
getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
|
|
627
630
|
}
|
|
628
631
|
|
|
629
|
-
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";
|
|
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" | "SPONSORED_CALLS_UNSUPPORTED" | "SPONSORED_CALLS_NO_ID" | "SPONSORED_CALLS_NO_RECEIPT" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
630
633
|
declare class OwneyError extends Error {
|
|
631
634
|
readonly code: OwneyErrorCode;
|
|
632
635
|
readonly details?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -184,32 +184,6 @@ 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 (e.isPending !== true) continue;
|
|
194
|
-
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
195
|
-
if (typeof e.tokenSymbol !== "string" || e.tokenSymbol === "") continue;
|
|
196
|
-
if (typeof e.balance !== "string") continue;
|
|
197
|
-
let amount;
|
|
198
|
-
try {
|
|
199
|
-
amount = hexToDecimal(e.balance, tokenDecimals(e.tokenSymbol));
|
|
200
|
-
} catch {
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
if (!Number.isFinite(amount) || amount <= 0) continue;
|
|
204
|
-
pending.push({
|
|
205
|
-
chainId: e.chainId,
|
|
206
|
-
asset: e.tokenSymbol,
|
|
207
|
-
amount: String(amount),
|
|
208
|
-
...typeof e.updatedAt === "string" && e.updatedAt !== "" ? { since: e.updatedAt } : {}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return pending.length > 0 ? pending : void 0;
|
|
212
|
-
}
|
|
213
187
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
214
188
|
const portfolio = raw.portfolio;
|
|
215
189
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
@@ -261,16 +235,12 @@ function mapBalances(raw, _chainId, smartWallet) {
|
|
|
261
235
|
// structural read keeps it undefined today and auto-populates later.
|
|
262
236
|
liquidity: p.liquidity
|
|
263
237
|
}));
|
|
264
|
-
const pendingAllocations = mapPendingAllocations(
|
|
265
|
-
portfolio.staleBalances
|
|
266
|
-
);
|
|
267
238
|
return {
|
|
268
239
|
smartWallet,
|
|
269
240
|
totalBalance: String(totalBalance),
|
|
270
241
|
totalBalanceAsset: "usdc",
|
|
271
242
|
tokens,
|
|
272
|
-
positions
|
|
273
|
-
...pendingAllocations ? { pendingAllocations } : {}
|
|
243
|
+
positions
|
|
274
244
|
};
|
|
275
245
|
}
|
|
276
246
|
function sumTokenValues(tokens) {
|
|
@@ -876,12 +846,6 @@ var ZyfaiAgent = class {
|
|
|
876
846
|
connectedAddress = null;
|
|
877
847
|
connectedChainId = null;
|
|
878
848
|
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();
|
|
885
849
|
connectAuthPromise = null;
|
|
886
850
|
rpcUrls;
|
|
887
851
|
publicClients = /* @__PURE__ */ new Map();
|
|
@@ -1339,74 +1303,10 @@ var ZyfaiAgent = class {
|
|
|
1339
1303
|
* recoverable (ensureWalletDeployed tries the other deploy call), but
|
|
1340
1304
|
* failing the deposit outright is not.
|
|
1341
1305
|
*/
|
|
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
|
-
}
|
|
1376
1306
|
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
|
-
}
|
|
1398
1307
|
try {
|
|
1399
1308
|
const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
|
|
1400
|
-
|
|
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;
|
|
1309
|
+
return typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
|
|
1410
1310
|
} catch (error) {
|
|
1411
1311
|
console.warn(
|
|
1412
1312
|
"[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
|
|
@@ -1444,24 +1344,8 @@ var ZyfaiAgent = class {
|
|
|
1444
1344
|
ownerAddress,
|
|
1445
1345
|
chainId
|
|
1446
1346
|
);
|
|
1447
|
-
|
|
1448
|
-
|
|
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
|
-
);
|
|
1347
|
+
if (!wallet.isDeployed) return;
|
|
1348
|
+
await this.ensureSessionKey(ownerAddress, chainId, wallet.address);
|
|
1465
1349
|
} catch (error) {
|
|
1466
1350
|
console.warn(
|
|
1467
1351
|
"[zyfai] session-key check at activation failed (non-fatal):",
|
|
@@ -1469,51 +1353,20 @@ var ZyfaiAgent = class {
|
|
|
1469
1353
|
);
|
|
1470
1354
|
}
|
|
1471
1355
|
}
|
|
1472
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet
|
|
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
|
-
}
|
|
1356
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1482
1357
|
try {
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
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);
|
|
1358
|
+
const installed = await this.getPublicClient(chainId).readContract({
|
|
1359
|
+
address: smartWallet,
|
|
1360
|
+
abi: ERC7579_IS_MODULE_INSTALLED_ABI,
|
|
1361
|
+
functionName: "isModuleInstalled",
|
|
1362
|
+
// moduleTypeId 1 = validator (ERC-7579)
|
|
1363
|
+
args: [1n, SMART_SESSIONS_VALIDATOR, "0x"]
|
|
1364
|
+
});
|
|
1365
|
+
if (installed) return;
|
|
1504
1366
|
console.warn(
|
|
1505
|
-
`[zyfai]
|
|
1367
|
+
`[zyfai] Safe ${smartWallet} has no smart-sessions validator on chain ${chainId}; creating a session key so the agent can allocate.`
|
|
1506
1368
|
);
|
|
1507
|
-
debugLog("zyfai:onboard", "session key: calling createSessionKey", {
|
|
1508
|
-
chainId,
|
|
1509
|
-
smartWallet,
|
|
1510
|
-
hasActiveSessionKey
|
|
1511
|
-
});
|
|
1512
1369
|
await this.sdk.createSessionKey(ownerAddress, chainId);
|
|
1513
|
-
debugLog("zyfai:onboard", "session key: createSessionKey succeeded", {
|
|
1514
|
-
chainId,
|
|
1515
|
-
smartWallet
|
|
1516
|
-
});
|
|
1517
1370
|
} catch (error) {
|
|
1518
1371
|
console.warn(
|
|
1519
1372
|
"[zyfai] createSessionKey skipped (non-fatal):",
|
|
@@ -1521,16 +1374,6 @@ var ZyfaiAgent = class {
|
|
|
1521
1374
|
);
|
|
1522
1375
|
}
|
|
1523
1376
|
}
|
|
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
|
-
}
|
|
1534
1377
|
/**
|
|
1535
1378
|
* Guarantee the user's Safe has code on `chainId` before anything transfers
|
|
1536
1379
|
* funds into it, and return its address.
|
|
@@ -1551,24 +1394,8 @@ var ZyfaiAgent = class {
|
|
|
1551
1394
|
*/
|
|
1552
1395
|
async ensureWalletDeployed(ownerAddress, chainId) {
|
|
1553
1396
|
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
|
-
});
|
|
1560
1397
|
if (wallet.isDeployed) {
|
|
1561
|
-
|
|
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
|
-
);
|
|
1398
|
+
await this.ensureSessionKey(ownerAddress, chainId, wallet.address);
|
|
1572
1399
|
return wallet.address;
|
|
1573
1400
|
}
|
|
1574
1401
|
const poolFirst = await this.isPredeployedPoolWallet(
|
|
@@ -1584,27 +1411,14 @@ var ZyfaiAgent = class {
|
|
|
1584
1411
|
this.sdk.deploySafe(ownerAddress, chainId, "aggressive", true)
|
|
1585
1412
|
);
|
|
1586
1413
|
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
|
-
);
|
|
1591
1414
|
try {
|
|
1592
1415
|
await first();
|
|
1593
|
-
debugLog(
|
|
1594
|
-
"zyfai:onboard",
|
|
1595
|
-
`${poolFirst ? "deployOnChains" : "deploySafe"} succeeded`
|
|
1596
|
-
);
|
|
1597
1416
|
} catch (error) {
|
|
1598
1417
|
console.warn(
|
|
1599
1418
|
`[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
|
|
1600
1419
|
error instanceof Error ? error.message : String(error)
|
|
1601
1420
|
);
|
|
1602
|
-
debugLog(
|
|
1603
|
-
"zyfai:onboard",
|
|
1604
|
-
`falling back to ${poolFirst ? "deploySafe (legacy path)" : "deployOnChains (pool path)"}`
|
|
1605
|
-
);
|
|
1606
1421
|
await second();
|
|
1607
|
-
debugLog("zyfai:onboard", "fallback deploy path succeeded");
|
|
1608
1422
|
}
|
|
1609
1423
|
const redeployed = await this.sdk.getSmartWalletAddress(
|
|
1610
1424
|
ownerAddress,
|
|
@@ -2426,6 +2240,97 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2426
2240
|
};
|
|
2427
2241
|
}
|
|
2428
2242
|
|
|
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
|
+
|
|
2429
2334
|
// src/client.ts
|
|
2430
2335
|
function encodeMultiAgentCursor(map) {
|
|
2431
2336
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -2487,12 +2392,15 @@ var OwneySDK = class {
|
|
|
2487
2392
|
referralSource;
|
|
2488
2393
|
cachedSponsoredCallback = null;
|
|
2489
2394
|
cachedWethSponsoredCallback = null;
|
|
2395
|
+
paymasterServiceUrl;
|
|
2396
|
+
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2490
2397
|
initializingAgentsPromise = null;
|
|
2491
2398
|
constructor(config) {
|
|
2492
2399
|
this.apiKey = config.apiKey;
|
|
2493
2400
|
if (config.debug) setOwneyDebug(true);
|
|
2494
2401
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
2495
2402
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2403
|
+
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2496
2404
|
this.referralSource = config.referralSource;
|
|
2497
2405
|
}
|
|
2498
2406
|
/**
|
|
@@ -2515,6 +2423,7 @@ var OwneySDK = class {
|
|
|
2515
2423
|
this.state = { provider, walletAddress, chainId: null };
|
|
2516
2424
|
this.cachedSponsoredCallback = null;
|
|
2517
2425
|
this.cachedWethSponsoredCallback = null;
|
|
2426
|
+
this.cachedSponsoredCallsCallbacks.clear();
|
|
2518
2427
|
}
|
|
2519
2428
|
/**
|
|
2520
2429
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2529,6 +2438,7 @@ var OwneySDK = class {
|
|
|
2529
2438
|
this.state = null;
|
|
2530
2439
|
this.cachedSponsoredCallback = null;
|
|
2531
2440
|
this.cachedWethSponsoredCallback = null;
|
|
2441
|
+
this.cachedSponsoredCallsCallbacks.clear();
|
|
2532
2442
|
}
|
|
2533
2443
|
isAgentDisabled(agentId) {
|
|
2534
2444
|
return this.disabledAgents.has(agentId);
|
|
@@ -2610,6 +2520,26 @@ var OwneySDK = class {
|
|
|
2610
2520
|
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
2611
2521
|
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
2612
2522
|
*/
|
|
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
|
+
*/
|
|
2613
2543
|
getDefaultWethSponsoredCallback(onApproved) {
|
|
2614
2544
|
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
2615
2545
|
return this.cachedWethSponsoredCallback;
|
|
@@ -2832,7 +2762,7 @@ var OwneySDK = class {
|
|
|
2832
2762
|
}
|
|
2833
2763
|
const state = this.requireState();
|
|
2834
2764
|
const chainId = this.requireChainId();
|
|
2835
|
-
const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2765
|
+
const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
2836
2766
|
if (agentId) {
|
|
2837
2767
|
if (this.isAgentDisabled(agentId)) {
|
|
2838
2768
|
throw new OwneyError(
|