@owney/sdk 0.7.7-beta.6 → 0.7.7

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 CHANGED
@@ -2025,7 +2025,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2025
2025
  }
2026
2026
 
2027
2027
  // src/client.ts
2028
- var import_viem5 = require("viem");
2028
+ var import_viem6 = require("viem");
2029
2029
  var import_chains2 = require("viem/chains");
2030
2030
 
2031
2031
  // src/lib/transfer-auth.ts
@@ -2455,6 +2455,97 @@ function makeSponsoredWethCallback(deps) {
2455
2455
  };
2456
2456
  }
2457
2457
 
2458
+ // src/lib/sponsored-calls-deposit.ts
2459
+ var import_viem5 = require("viem");
2460
+ var DEFAULT_POLL_INTERVAL_MS = 1500;
2461
+ var DEFAULT_MAX_POLLS = 30;
2462
+ async function paymasterSupported(provider, owner, chainId) {
2463
+ const caps = await provider.request({
2464
+ method: "wallet_getCapabilities",
2465
+ params: [owner]
2466
+ });
2467
+ const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
2468
+ return Boolean(forChain?.paymasterService?.supported);
2469
+ }
2470
+ function makeSponsoredCallsCallback(deps) {
2471
+ const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
2472
+ const maxPolls = deps.maxPolls ?? DEFAULT_MAX_POLLS;
2473
+ const absolutePaymasterUrl = () => {
2474
+ const configured = deps.paymasterServiceUrl;
2475
+ if (/^https?:\/\//i.test(configured)) return configured;
2476
+ const origin = globalThis.location?.origin;
2477
+ if (!origin) {
2478
+ throw new OwneyError(
2479
+ "SPONSORED_CALLS_UNSUPPORTED",
2480
+ `paymasterServiceUrl "${configured}" is relative and no page origin is available to resolve it.`
2481
+ );
2482
+ }
2483
+ return new URL(configured, origin).toString();
2484
+ };
2485
+ return async (smartWallet, chainId, amount) => {
2486
+ const cid = chainId;
2487
+ const token = deps.tokenAddressByChain[cid];
2488
+ if (!token) {
2489
+ throw new OwneyError(
2490
+ "CHAIN_UNSUPPORTED",
2491
+ `No sponsored token configured for chain ${chainId}`
2492
+ );
2493
+ }
2494
+ if (!await paymasterSupported(deps.provider, deps.ownerAddress, chainId)) {
2495
+ throw new OwneyError(
2496
+ "SPONSORED_CALLS_UNSUPPORTED",
2497
+ `Wallet does not advertise paymasterService on chain ${chainId}.`,
2498
+ { chainId }
2499
+ );
2500
+ }
2501
+ const data = (0, import_viem5.encodeFunctionData)({
2502
+ abi: import_viem5.erc20Abi,
2503
+ functionName: "transfer",
2504
+ args: [smartWallet, BigInt(amount)]
2505
+ });
2506
+ const sendResult = await deps.provider.request({
2507
+ method: "wallet_sendCalls",
2508
+ params: [
2509
+ {
2510
+ version: "2.0.0",
2511
+ from: deps.ownerAddress,
2512
+ chainId: (0, import_viem5.toHex)(chainId),
2513
+ atomicRequired: false,
2514
+ calls: [{ to: token, value: "0x0", data }],
2515
+ capabilities: {
2516
+ paymasterService: { url: absolutePaymasterUrl() }
2517
+ }
2518
+ }
2519
+ ]
2520
+ });
2521
+ deps.onApproved?.();
2522
+ const callsId = typeof sendResult === "string" ? sendResult : sendResult?.id;
2523
+ if (!callsId) {
2524
+ throw new OwneyError(
2525
+ "SPONSORED_CALLS_NO_ID",
2526
+ "Wallet accepted wallet_sendCalls but returned no calls id.",
2527
+ { chainId }
2528
+ );
2529
+ }
2530
+ for (let attempt = 0; attempt < maxPolls; attempt += 1) {
2531
+ const status = await deps.provider.request({
2532
+ method: "wallet_getCallsStatus",
2533
+ params: [callsId]
2534
+ });
2535
+ const txHash = status?.receipts?.[0]?.transactionHash;
2536
+ if (txHash) return txHash;
2537
+ if (pollIntervalMs > 0) {
2538
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2539
+ }
2540
+ }
2541
+ throw new OwneyError(
2542
+ "SPONSORED_CALLS_NO_RECEIPT",
2543
+ `No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
2544
+ { chainId, callsId }
2545
+ );
2546
+ };
2547
+ }
2548
+
2458
2549
  // src/client.ts
2459
2550
  function encodeMultiAgentCursor(map) {
2460
2551
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -2516,12 +2607,15 @@ var OwneySDK = class {
2516
2607
  referralSource;
2517
2608
  cachedSponsoredCallback = null;
2518
2609
  cachedWethSponsoredCallback = null;
2610
+ paymasterServiceUrl;
2611
+ cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
2519
2612
  initializingAgentsPromise = null;
2520
2613
  constructor(config) {
2521
2614
  this.apiKey = config.apiKey;
2522
2615
  if (config.debug) setOwneyDebug(true);
2523
2616
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
2524
2617
  this.routingApiBaseUrl = config.routingApiBaseUrl;
2618
+ this.paymasterServiceUrl = config.paymasterServiceUrl;
2525
2619
  this.referralSource = config.referralSource;
2526
2620
  }
2527
2621
  /**
@@ -2544,6 +2638,7 @@ var OwneySDK = class {
2544
2638
  this.state = { provider, walletAddress, chainId: null };
2545
2639
  this.cachedSponsoredCallback = null;
2546
2640
  this.cachedWethSponsoredCallback = null;
2641
+ this.cachedSponsoredCallsCallbacks.clear();
2547
2642
  }
2548
2643
  /**
2549
2644
  * Disconnect from all agents and clear connection state.
@@ -2558,6 +2653,7 @@ var OwneySDK = class {
2558
2653
  this.state = null;
2559
2654
  this.cachedSponsoredCallback = null;
2560
2655
  this.cachedWethSponsoredCallback = null;
2656
+ this.cachedSponsoredCallsCallbacks.clear();
2561
2657
  }
2562
2658
  isAgentDisabled(agentId) {
2563
2659
  return this.disabledAgents.has(agentId);
@@ -2620,14 +2716,14 @@ var OwneySDK = class {
2620
2716
  // Casts work around viem's chain-narrowed Client vs the generic
2621
2717
  // PublicClient/WalletClient param types — structurally identical at
2622
2718
  // runtime, but the two share a name TS treats as unrelated.
2623
- getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2719
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
2624
2720
  chain: VIEM_CHAIN2[cid],
2625
- transport: (0, import_viem5.custom)(provider)
2721
+ transport: (0, import_viem6.custom)(provider)
2626
2722
  }),
2627
- getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2723
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
2628
2724
  account: owner,
2629
2725
  chain: VIEM_CHAIN2[cid],
2630
- transport: (0, import_viem5.custom)(provider)
2726
+ transport: (0, import_viem6.custom)(provider)
2631
2727
  })
2632
2728
  });
2633
2729
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -2639,6 +2735,26 @@ var OwneySDK = class {
2639
2735
  * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
2640
2736
  * `PermitTransferFrom` instead of an EIP-3009 authorization.
2641
2737
  */
2738
+ getDefaultSponsoredCallsCallback(asset, onApproved) {
2739
+ const cached = this.cachedSponsoredCallsCallbacks.get(asset);
2740
+ if (!onApproved && cached) return cached;
2741
+ const provider = this.requireConnectedProvider();
2742
+ const callback = makeSponsoredCallsCallback({
2743
+ provider,
2744
+ ownerAddress: this.state.walletAddress,
2745
+ paymasterServiceUrl: this.paymasterServiceUrl,
2746
+ onApproved,
2747
+ tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
2748
+ });
2749
+ if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
2750
+ return callback;
2751
+ }
2752
+ /**
2753
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
2754
+ * callback used when the caller omits `depositCallback` for a WETH deposit.
2755
+ * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
2756
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
2757
+ */
2642
2758
  getDefaultWethSponsoredCallback(onApproved) {
2643
2759
  if (!onApproved && this.cachedWethSponsoredCallback)
2644
2760
  return this.cachedWethSponsoredCallback;
@@ -2653,14 +2769,14 @@ var OwneySDK = class {
2653
2769
  // Casts work around viem's chain-narrowed Client vs the generic
2654
2770
  // PublicClient/WalletClient param types — structurally identical at
2655
2771
  // runtime, but the two share a name TS treats as unrelated.
2656
- getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2772
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
2657
2773
  chain: VIEM_CHAIN2[cid],
2658
- transport: (0, import_viem5.custom)(provider)
2774
+ transport: (0, import_viem6.custom)(provider)
2659
2775
  }),
2660
- getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2776
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
2661
2777
  account: owner,
2662
2778
  chain: VIEM_CHAIN2[cid],
2663
- transport: (0, import_viem5.custom)(provider)
2779
+ transport: (0, import_viem6.custom)(provider)
2664
2780
  })
2665
2781
  });
2666
2782
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -2861,7 +2977,7 @@ var OwneySDK = class {
2861
2977
  }
2862
2978
  const state = this.requireState();
2863
2979
  const chainId = this.requireChainId();
2864
- const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
2980
+ const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
2865
2981
  if (agentId) {
2866
2982
  if (this.isAgentDisabled(agentId)) {
2867
2983
  throw new OwneyError(
@@ -3504,10 +3620,10 @@ var OwneySDK = class {
3504
3620
  );
3505
3621
  }
3506
3622
  const provider = this.requireConnectedProvider();
3507
- const wallet = (0, import_viem5.createWalletClient)({
3623
+ const wallet = (0, import_viem6.createWalletClient)({
3508
3624
  account: state.walletAddress,
3509
3625
  chain: VIEM_CHAIN2[chainId],
3510
- transport: (0, import_viem5.custom)(provider)
3626
+ transport: (0, import_viem6.custom)(provider)
3511
3627
  });
3512
3628
  const hash = await wallet.writeContract({
3513
3629
  address: token,
@@ -3517,9 +3633,9 @@ var OwneySDK = class {
3517
3633
  account: state.walletAddress,
3518
3634
  chain: VIEM_CHAIN2[chainId]
3519
3635
  });
3520
- const publicClient = (0, import_viem5.createPublicClient)({
3636
+ const publicClient = (0, import_viem6.createPublicClient)({
3521
3637
  chain: VIEM_CHAIN2[chainId],
3522
- transport: (0, import_viem5.custom)(provider)
3638
+ transport: (0, import_viem6.custom)(provider)
3523
3639
  });
3524
3640
  const receipt = await publicClient.waitForTransactionReceipt({
3525
3641
  hash,
@@ -3628,7 +3744,7 @@ var OwneySDK = class {
3628
3744
  };
3629
3745
 
3630
3746
  // src/agents/zyfai/zyfai.siwx.ts
3631
- var import_viem6 = require("viem");
3747
+ var import_viem7 = require("viem");
3632
3748
  var import_siwe = require("siwe");
3633
3749
  var import_sdk2 = require("@zyfai/sdk");
3634
3750
 
@@ -3755,7 +3871,7 @@ function buildSIWXConfig(deps) {
3755
3871
  issuedAt,
3756
3872
  toString() {
3757
3873
  return new import_siwe.SiweMessage({
3758
- address: (0, import_viem6.getAddress)(accountAddress),
3874
+ address: (0, import_viem7.getAddress)(accountAddress),
3759
3875
  chainId: numericChainId(chainId),
3760
3876
  domain,
3761
3877
  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;
@@ -418,6 +429,8 @@ declare class OwneySDK {
418
429
  private referralSource?;
419
430
  private cachedSponsoredCallback;
420
431
  private cachedWethSponsoredCallback;
432
+ private paymasterServiceUrl?;
433
+ private cachedSponsoredCallsCallbacks;
421
434
  private initializingAgentsPromise;
422
435
  constructor(config: OwneySDKConfig);
423
436
  /**
@@ -458,6 +471,13 @@ declare class OwneySDK {
458
471
  * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
459
472
  * `PermitTransferFrom` instead of an EIP-3009 authorization.
460
473
  */
474
+ private getDefaultSponsoredCallsCallback;
475
+ /**
476
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
477
+ * callback used when the caller omits `depositCallback` for a WETH deposit.
478
+ * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
479
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
480
+ */
461
481
  private getDefaultWethSponsoredCallback;
462
482
  private getAgent;
463
483
  private getActiveAgents;
@@ -634,7 +654,7 @@ declare class OwneySDK {
634
654
  getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
635
655
  }
636
656
 
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";
657
+ 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";
638
658
  declare class OwneyError extends Error {
639
659
  readonly code: OwneyErrorCode;
640
660
  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;
@@ -418,6 +429,8 @@ declare class OwneySDK {
418
429
  private referralSource?;
419
430
  private cachedSponsoredCallback;
420
431
  private cachedWethSponsoredCallback;
432
+ private paymasterServiceUrl?;
433
+ private cachedSponsoredCallsCallbacks;
421
434
  private initializingAgentsPromise;
422
435
  constructor(config: OwneySDKConfig);
423
436
  /**
@@ -458,6 +471,13 @@ declare class OwneySDK {
458
471
  * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
459
472
  * `PermitTransferFrom` instead of an EIP-3009 authorization.
460
473
  */
474
+ private getDefaultSponsoredCallsCallback;
475
+ /**
476
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
477
+ * callback used when the caller omits `depositCallback` for a WETH deposit.
478
+ * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
479
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
480
+ */
461
481
  private getDefaultWethSponsoredCallback;
462
482
  private getAgent;
463
483
  private getActiveAgents;
@@ -634,7 +654,7 @@ declare class OwneySDK {
634
654
  getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
635
655
  }
636
656
 
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";
657
+ 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";
638
658
  declare class OwneyError extends Error {
639
659
  readonly code: OwneyErrorCode;
640
660
  readonly details?: Record<string, unknown>;
package/dist/index.js CHANGED
@@ -2426,6 +2426,97 @@ function makeSponsoredWethCallback(deps) {
2426
2426
  };
2427
2427
  }
2428
2428
 
2429
+ // src/lib/sponsored-calls-deposit.ts
2430
+ import { encodeFunctionData, erc20Abi, toHex } from "viem";
2431
+ var DEFAULT_POLL_INTERVAL_MS = 1500;
2432
+ var DEFAULT_MAX_POLLS = 30;
2433
+ async function paymasterSupported(provider, owner, chainId) {
2434
+ const caps = await provider.request({
2435
+ method: "wallet_getCapabilities",
2436
+ params: [owner]
2437
+ });
2438
+ const forChain = caps?.[toHex(chainId)] ?? caps?.[String(chainId)];
2439
+ return Boolean(forChain?.paymasterService?.supported);
2440
+ }
2441
+ function makeSponsoredCallsCallback(deps) {
2442
+ const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
2443
+ const maxPolls = deps.maxPolls ?? DEFAULT_MAX_POLLS;
2444
+ const absolutePaymasterUrl = () => {
2445
+ const configured = deps.paymasterServiceUrl;
2446
+ if (/^https?:\/\//i.test(configured)) return configured;
2447
+ const origin = globalThis.location?.origin;
2448
+ if (!origin) {
2449
+ throw new OwneyError(
2450
+ "SPONSORED_CALLS_UNSUPPORTED",
2451
+ `paymasterServiceUrl "${configured}" is relative and no page origin is available to resolve it.`
2452
+ );
2453
+ }
2454
+ return new URL(configured, origin).toString();
2455
+ };
2456
+ return async (smartWallet, chainId, amount) => {
2457
+ const cid = chainId;
2458
+ const token = deps.tokenAddressByChain[cid];
2459
+ if (!token) {
2460
+ throw new OwneyError(
2461
+ "CHAIN_UNSUPPORTED",
2462
+ `No sponsored token configured for chain ${chainId}`
2463
+ );
2464
+ }
2465
+ if (!await paymasterSupported(deps.provider, deps.ownerAddress, chainId)) {
2466
+ throw new OwneyError(
2467
+ "SPONSORED_CALLS_UNSUPPORTED",
2468
+ `Wallet does not advertise paymasterService on chain ${chainId}.`,
2469
+ { chainId }
2470
+ );
2471
+ }
2472
+ const data = encodeFunctionData({
2473
+ abi: erc20Abi,
2474
+ functionName: "transfer",
2475
+ args: [smartWallet, BigInt(amount)]
2476
+ });
2477
+ const sendResult = await deps.provider.request({
2478
+ method: "wallet_sendCalls",
2479
+ params: [
2480
+ {
2481
+ version: "2.0.0",
2482
+ from: deps.ownerAddress,
2483
+ chainId: toHex(chainId),
2484
+ atomicRequired: false,
2485
+ calls: [{ to: token, value: "0x0", data }],
2486
+ capabilities: {
2487
+ paymasterService: { url: absolutePaymasterUrl() }
2488
+ }
2489
+ }
2490
+ ]
2491
+ });
2492
+ deps.onApproved?.();
2493
+ const callsId = typeof sendResult === "string" ? sendResult : sendResult?.id;
2494
+ if (!callsId) {
2495
+ throw new OwneyError(
2496
+ "SPONSORED_CALLS_NO_ID",
2497
+ "Wallet accepted wallet_sendCalls but returned no calls id.",
2498
+ { chainId }
2499
+ );
2500
+ }
2501
+ for (let attempt = 0; attempt < maxPolls; attempt += 1) {
2502
+ const status = await deps.provider.request({
2503
+ method: "wallet_getCallsStatus",
2504
+ params: [callsId]
2505
+ });
2506
+ const txHash = status?.receipts?.[0]?.transactionHash;
2507
+ if (txHash) return txHash;
2508
+ if (pollIntervalMs > 0) {
2509
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2510
+ }
2511
+ }
2512
+ throw new OwneyError(
2513
+ "SPONSORED_CALLS_NO_RECEIPT",
2514
+ `No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
2515
+ { chainId, callsId }
2516
+ );
2517
+ };
2518
+ }
2519
+
2429
2520
  // src/client.ts
2430
2521
  function encodeMultiAgentCursor(map) {
2431
2522
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -2487,12 +2578,15 @@ var OwneySDK = class {
2487
2578
  referralSource;
2488
2579
  cachedSponsoredCallback = null;
2489
2580
  cachedWethSponsoredCallback = null;
2581
+ paymasterServiceUrl;
2582
+ cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
2490
2583
  initializingAgentsPromise = null;
2491
2584
  constructor(config) {
2492
2585
  this.apiKey = config.apiKey;
2493
2586
  if (config.debug) setOwneyDebug(true);
2494
2587
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
2495
2588
  this.routingApiBaseUrl = config.routingApiBaseUrl;
2589
+ this.paymasterServiceUrl = config.paymasterServiceUrl;
2496
2590
  this.referralSource = config.referralSource;
2497
2591
  }
2498
2592
  /**
@@ -2515,6 +2609,7 @@ var OwneySDK = class {
2515
2609
  this.state = { provider, walletAddress, chainId: null };
2516
2610
  this.cachedSponsoredCallback = null;
2517
2611
  this.cachedWethSponsoredCallback = null;
2612
+ this.cachedSponsoredCallsCallbacks.clear();
2518
2613
  }
2519
2614
  /**
2520
2615
  * Disconnect from all agents and clear connection state.
@@ -2529,6 +2624,7 @@ var OwneySDK = class {
2529
2624
  this.state = null;
2530
2625
  this.cachedSponsoredCallback = null;
2531
2626
  this.cachedWethSponsoredCallback = null;
2627
+ this.cachedSponsoredCallsCallbacks.clear();
2532
2628
  }
2533
2629
  isAgentDisabled(agentId) {
2534
2630
  return this.disabledAgents.has(agentId);
@@ -2610,6 +2706,26 @@ var OwneySDK = class {
2610
2706
  * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
2611
2707
  * `PermitTransferFrom` instead of an EIP-3009 authorization.
2612
2708
  */
2709
+ getDefaultSponsoredCallsCallback(asset, onApproved) {
2710
+ const cached = this.cachedSponsoredCallsCallbacks.get(asset);
2711
+ if (!onApproved && cached) return cached;
2712
+ const provider = this.requireConnectedProvider();
2713
+ const callback = makeSponsoredCallsCallback({
2714
+ provider,
2715
+ ownerAddress: this.state.walletAddress,
2716
+ paymasterServiceUrl: this.paymasterServiceUrl,
2717
+ onApproved,
2718
+ tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
2719
+ });
2720
+ if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
2721
+ return callback;
2722
+ }
2723
+ /**
2724
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
2725
+ * callback used when the caller omits `depositCallback` for a WETH deposit.
2726
+ * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
2727
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
2728
+ */
2613
2729
  getDefaultWethSponsoredCallback(onApproved) {
2614
2730
  if (!onApproved && this.cachedWethSponsoredCallback)
2615
2731
  return this.cachedWethSponsoredCallback;
@@ -2832,7 +2948,7 @@ var OwneySDK = class {
2832
2948
  }
2833
2949
  const state = this.requireState();
2834
2950
  const chainId = this.requireChainId();
2835
- const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
2951
+ const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
2836
2952
  if (agentId) {
2837
2953
  if (this.isAgentDisabled(agentId)) {
2838
2954
  throw new OwneyError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.7-beta.6",
3
+ "version": "0.7.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",