@arcenpay/react 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1174 @@
1
+ import {
2
+ getChain
3
+ } from "./chunk-GY2HMODH.mjs";
4
+
5
+ // src/lib/zerodev.ts
6
+ import {
7
+ createKernelAccount,
8
+ createKernelAccountClient,
9
+ createZeroDevPaymasterClient,
10
+ constants as zeroDevConstants
11
+ } from "@zerodev/sdk";
12
+ import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator";
13
+ import {
14
+ createPublicClient as createPublicClient2,
15
+ http as http2,
16
+ encodeFunctionData
17
+ } from "viem";
18
+ import { sepolia as sepolia2, baseSepolia as baseSepolia2, base } from "viem/chains";
19
+
20
+ // src/internal/sdk-core/addresses.ts
21
+ var ADDRESSES = {
22
+ // Ethereum Sepolia (Testnet) — Deployed 2026-03-19
23
+ 11155111: {
24
+ subscriptionRegistry: "0xE206C519076535A9d24c852093860CFD780908C1",
25
+ autopayModule: "0xc82417e378b23AD9Ae73229EF08a4BA7896a4351",
26
+ planFactory: "0x4F97E0c2Ac053b735640fEb164a08Cb45ba83db1",
27
+ feeCollector: "0xa8A0D3007e5680D387A50C1a1E2Eb0AD092ca396",
28
+ sessionVault: "0xd68b9C0a34d61CC3b3F982A5EC6Cc5a5739e46D9",
29
+ zkUsageVerifier: "0x1f75d66692416cE880d51Baf6CdcBeE98E5837c0",
30
+ mirrorRegistry: "0xC187CD32d569ec0E84B9b378f8E63f3a74afac74"
31
+ },
32
+ // Base Sepolia (Testnet) — Deployed 2026-04-23
33
+ 84532: {
34
+ subscriptionRegistry: "0xF9610c064FFD64255A1d509d17b2Af8733084e50",
35
+ autopayModule: "0x69Ac04bFdC045A99A2D31bb141A74da354a94c19",
36
+ planFactory: "0x66775Af13C63781AAd28203CC5d3E9eE5d5eB83d",
37
+ feeCollector: "0x5F32fBfF19385A78c3F721007758E9924FAD4133",
38
+ sessionVault: "0x96BcE2d49e3e4EddBBF3aa07354E66615BC2623c",
39
+ zkUsageVerifier: "0x03290b6988F87925A4939d974895bC30981aA90D",
40
+ mirrorRegistry: "0xe7E0dFfa82596ee6Ba1755bc25c29376a07236dE"
41
+ },
42
+ // Base Mainnet — set ARCENPAY_CONTRACT_8453_* env vars after audit + deployment
43
+ 8453: {
44
+ subscriptionRegistry: "0x0000000000000000000000000000000000000000",
45
+ autopayModule: "0x0000000000000000000000000000000000000000",
46
+ planFactory: "0x0000000000000000000000000000000000000000",
47
+ feeCollector: "0x0000000000000000000000000000000000000000",
48
+ sessionVault: "0x0000000000000000000000000000000000000000",
49
+ zkUsageVerifier: "0x0000000000000000000000000000000000000000",
50
+ mirrorRegistry: "0x0000000000000000000000000000000000000000"
51
+ }
52
+ };
53
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
54
+ var CONTRACT_KEYS = [
55
+ "subscriptionRegistry",
56
+ "autopayModule",
57
+ "planFactory",
58
+ "feeCollector",
59
+ "sessionVault",
60
+ "zkUsageVerifier"
61
+ ];
62
+ function applyEnvOverrides(chainId, base2) {
63
+ if (typeof process === "undefined") return base2;
64
+ const result = { ...base2 };
65
+ for (const key of CONTRACT_KEYS) {
66
+ const envKey = `ARCENPAY_CONTRACT_${chainId}_${key}`;
67
+ const legacyKey = `MEAP_CONTRACT_${chainId}_${key}`;
68
+ const override = process.env[envKey] ?? process.env[legacyKey];
69
+ if (override && override.startsWith("0x")) {
70
+ result[key] = override;
71
+ }
72
+ }
73
+ const mirrorOverride = process.env[`ARCENPAY_CONTRACT_${chainId}_mirrorRegistry`] ?? process.env[`MEAP_CONTRACT_${chainId}_mirrorRegistry`];
74
+ if (mirrorOverride && mirrorOverride.startsWith("0x")) {
75
+ result.mirrorRegistry = mirrorOverride;
76
+ }
77
+ const yieldOverride = process.env[`ARCENPAY_CONTRACT_${chainId}_yieldSessionVault`] ?? process.env[`MEAP_CONTRACT_${chainId}_yieldSessionVault`];
78
+ if (yieldOverride && yieldOverride.startsWith("0x")) {
79
+ result.yieldSessionVault = yieldOverride;
80
+ }
81
+ return result;
82
+ }
83
+ function getContractAddresses(chainId) {
84
+ const base2 = ADDRESSES[chainId];
85
+ if (!base2) {
86
+ throw new Error(`No contract addresses configured for chain ${chainId}`);
87
+ }
88
+ const addresses = applyEnvOverrides(chainId, base2);
89
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
90
+ const allZero = CONTRACT_KEYS.every(
91
+ (k) => addresses[k] === ZERO_ADDRESS
92
+ );
93
+ if (allZero) {
94
+ throw new Error(
95
+ `[getContractAddresses] Chain ${chainId} has no deployed contracts. Set ARCENPAY_CONTRACT_${chainId}_<key> env vars or deploy contracts before using this chain in production.`
96
+ );
97
+ }
98
+ }
99
+ return addresses;
100
+ }
101
+
102
+ // src/internal/sdk-core/environment.ts
103
+ var ZERO_ADDRESS2 = "0x0000000000000000000000000000000000000000";
104
+ var REQUIRED_CONTRACT_KEYS = [
105
+ "subscriptionRegistry",
106
+ "autopayModule",
107
+ "planFactory",
108
+ "feeCollector",
109
+ "sessionVault",
110
+ "zkUsageVerifier"
111
+ ];
112
+ var DEFAULT_SERVICES = {
113
+ 11155111: {
114
+ rpcUrl: "https://ethereum-sepolia-rpc.publicnode.com"
115
+ },
116
+ 84532: {
117
+ rpcUrl: "https://sepolia.base.org"
118
+ },
119
+ 8453: {
120
+ rpcUrl: "https://mainnet.base.org"
121
+ }
122
+ };
123
+ var LEGACY_RPC_ENV_KEYS = {
124
+ 11155111: ["SEPOLIA_RPC_URL"],
125
+ 84532: ["BASE_SEPOLIA_RPC_URL"],
126
+ 8453: ["BASE_MAINNET_RPC_URL"]
127
+ };
128
+ var SERVICE_ENV_KEYS = {
129
+ rpcUrl: (chainId) => [
130
+ `ARCENPAY_RPC_URL_${chainId}`,
131
+ `MEAP_RPC_URL_${chainId}`,
132
+ `RPC_URL_${chainId}`,
133
+ `NEXT_PUBLIC_RPC_URL_${chainId}`,
134
+ ...LEGACY_RPC_ENV_KEYS[chainId] || [],
135
+ "ARCENPAY_RPC_URL",
136
+ "MEAP_RPC_URL",
137
+ "RPC_URL",
138
+ "NEXT_PUBLIC_RPC_URL"
139
+ ],
140
+ subgraphUrl: (chainId) => [
141
+ `ARCENPAY_SUBGRAPH_URL_${chainId}`,
142
+ `MEAP_SUBGRAPH_URL_${chainId}`,
143
+ `NEXT_PUBLIC_GRAPH_URL_${chainId}`,
144
+ "ARCENPAY_SUBGRAPH_URL",
145
+ "MEAP_SUBGRAPH_URL",
146
+ "NEXT_PUBLIC_GRAPH_URL"
147
+ ],
148
+ facilitatorUrl: (chainId) => [
149
+ `ARCENPAY_FACILITATOR_URL_${chainId}`,
150
+ `MEAP_FACILITATOR_URL_${chainId}`,
151
+ `FACILITATOR_BASE_URL_${chainId}`,
152
+ `FACILITATOR_URL_${chainId}`,
153
+ `NEXT_PUBLIC_FACILITATOR_BASE_URL_${chainId}`,
154
+ `NEXT_PUBLIC_FACILITATOR_URL_${chainId}`,
155
+ "ARCENPAY_FACILITATOR_URL",
156
+ "MEAP_FACILITATOR_URL",
157
+ "FACILITATOR_BASE_URL",
158
+ "FACILITATOR_URL",
159
+ "NEXT_PUBLIC_FACILITATOR_BASE_URL",
160
+ "NEXT_PUBLIC_FACILITATOR_URL"
161
+ ]
162
+ };
163
+ function getEnv(keys) {
164
+ if (typeof process === "undefined") return void 0;
165
+ for (const key of keys) {
166
+ const value = process.env[key]?.trim();
167
+ if (value) return value;
168
+ }
169
+ return void 0;
170
+ }
171
+ function resolveServiceUrl(chainId, service, fallback) {
172
+ return getEnv(SERVICE_ENV_KEYS[service](chainId)) || fallback || "";
173
+ }
174
+ function isZeroAddress(value) {
175
+ return (value || "").toLowerCase() === ZERO_ADDRESS2;
176
+ }
177
+ function getChainEnvironment(chainId) {
178
+ const chain = getChain(chainId);
179
+ const defaults = DEFAULT_SERVICES[chainId] || {
180
+ rpcUrl: chain.rpcUrls.default.http[0] || ""
181
+ };
182
+ return {
183
+ chainId,
184
+ chainName: chain.name,
185
+ isTestnet: Boolean(chain.testnet),
186
+ contracts: getContractAddresses(chainId),
187
+ services: {
188
+ rpcUrl: resolveServiceUrl(chainId, "rpcUrl", defaults.rpcUrl),
189
+ subgraphUrl: resolveServiceUrl(chainId, "subgraphUrl", defaults.subgraphUrl),
190
+ facilitatorUrl: resolveServiceUrl(
191
+ chainId,
192
+ "facilitatorUrl",
193
+ defaults.facilitatorUrl
194
+ )
195
+ }
196
+ };
197
+ }
198
+ function isValidHttpUrl(url) {
199
+ try {
200
+ const parsed = new URL(url);
201
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
202
+ } catch {
203
+ return false;
204
+ }
205
+ }
206
+ function validateChainEnvironment(chainId, options = {}) {
207
+ const env = getChainEnvironment(chainId);
208
+ const production = options.production ?? (typeof process !== "undefined" ? process.env.NODE_ENV === "production" : false);
209
+ const requiredContracts = options.requiredContracts || REQUIRED_CONTRACT_KEYS;
210
+ const requiredServices = options.requiredServices || ["rpcUrl"];
211
+ const contractErrors = requiredContracts.filter((key) => isZeroAddress(env.contracts[key])).map((key) => `${String(key)} is zero-address`);
212
+ if (production && contractErrors.length > 0) {
213
+ throw new Error(
214
+ `[validateChainEnvironment] Chain ${chainId} invalid contracts: ${contractErrors.join(", ")}`
215
+ );
216
+ }
217
+ const serviceErrors = requiredServices.filter((key) => !env.services[key] || !isValidHttpUrl(env.services[key] || "")).map((key) => `${String(key)} is missing or invalid`);
218
+ if (serviceErrors.length > 0) {
219
+ throw new Error(
220
+ `[validateChainEnvironment] Chain ${chainId} invalid services: ${serviceErrors.join(", ")}`
221
+ );
222
+ }
223
+ return { ok: true };
224
+ }
225
+
226
+ // src/internal/sdk-core/app-origin.ts
227
+ var ARCENPAY_LOCAL_APP_URL = "http://localhost:3000";
228
+ var ARCENPAY_PRODUCTION_APP_URL = "https://app.arcenpay.com";
229
+ var DEFAULT_ENV_KEYS = [
230
+ "ARCENPAY_BASE_URL",
231
+ "NEXT_PUBLIC_ARCENPAY_BASE_URL"
232
+ ];
233
+ function trimTrailingSlash(value) {
234
+ return value.replace(/\/$/, "");
235
+ }
236
+ function getRuntimeEnv() {
237
+ if (typeof process === "undefined") return void 0;
238
+ return process.env;
239
+ }
240
+ function readEnvValue(env, keys) {
241
+ if (!env) return void 0;
242
+ for (const key of keys) {
243
+ const value = env[key]?.trim();
244
+ if (value) return value;
245
+ }
246
+ return void 0;
247
+ }
248
+ function resolveArcenPayBaseUrl(options = {}) {
249
+ if (options.explicit?.trim()) {
250
+ return trimTrailingSlash(options.explicit.trim());
251
+ }
252
+ const env = options.env ?? getRuntimeEnv();
253
+ const envOverride = readEnvValue(env, options.envKeys ?? DEFAULT_ENV_KEYS);
254
+ if (envOverride) {
255
+ return trimTrailingSlash(envOverride);
256
+ }
257
+ const localDevUrl = options.localDevUrl ?? ARCENPAY_LOCAL_APP_URL;
258
+ const productionUrl = options.productionUrl ?? ARCENPAY_PRODUCTION_APP_URL;
259
+ const nodeEnv = env?.NODE_ENV;
260
+ if (nodeEnv && nodeEnv !== "production") {
261
+ return localDevUrl;
262
+ }
263
+ return productionUrl;
264
+ }
265
+
266
+ // src/internal/sdk-core/abis.ts
267
+ var SubscriptionRegistryABI = [
268
+ // Core functions
269
+ {
270
+ type: "function",
271
+ name: "mint",
272
+ inputs: [
273
+ { name: "to", type: "address" },
274
+ { name: "planId", type: "uint256" },
275
+ { name: "duration", type: "uint64" }
276
+ ],
277
+ outputs: [{ name: "tokenId", type: "uint256" }],
278
+ stateMutability: "nonpayable"
279
+ },
280
+ {
281
+ type: "function",
282
+ name: "renew",
283
+ inputs: [
284
+ { name: "tokenId", type: "uint256" },
285
+ { name: "extension", type: "uint64" }
286
+ ],
287
+ outputs: [],
288
+ stateMutability: "nonpayable"
289
+ },
290
+ {
291
+ type: "function",
292
+ name: "cancel",
293
+ inputs: [{ name: "tokenId", type: "uint256" }],
294
+ outputs: [],
295
+ stateMutability: "nonpayable"
296
+ },
297
+ {
298
+ type: "function",
299
+ name: "changePlan",
300
+ inputs: [
301
+ { name: "tokenId", type: "uint256" },
302
+ { name: "newPlanId", type: "uint256" }
303
+ ],
304
+ outputs: [],
305
+ stateMutability: "nonpayable"
306
+ },
307
+ {
308
+ type: "function",
309
+ name: "isValid",
310
+ inputs: [{ name: "tokenId", type: "uint256" }],
311
+ outputs: [{ name: "", type: "bool" }],
312
+ stateMutability: "view"
313
+ },
314
+ {
315
+ type: "function",
316
+ name: "expiresAt",
317
+ inputs: [{ name: "tokenId", type: "uint256" }],
318
+ outputs: [{ name: "", type: "uint64" }],
319
+ stateMutability: "view"
320
+ },
321
+ {
322
+ type: "function",
323
+ name: "getPlanFeatures",
324
+ inputs: [{ name: "tokenId", type: "uint256" }],
325
+ outputs: [
326
+ { name: "planId", type: "uint256" },
327
+ { name: "planTier", type: "string" }
328
+ ],
329
+ stateMutability: "view"
330
+ },
331
+ {
332
+ type: "function",
333
+ name: "getWalletSubscription",
334
+ inputs: [{ name: "wallet", type: "address" }],
335
+ outputs: [{ name: "", type: "uint256" }],
336
+ stateMutability: "view"
337
+ },
338
+ {
339
+ type: "function",
340
+ name: "importSubscription",
341
+ inputs: [
342
+ { name: "to", type: "address" },
343
+ { name: "tokenId", type: "uint256" },
344
+ { name: "planId", type: "uint256" },
345
+ { name: "expiration", type: "uint64" }
346
+ ],
347
+ outputs: [],
348
+ stateMutability: "nonpayable"
349
+ },
350
+ {
351
+ type: "function",
352
+ name: "finalizeMigration",
353
+ inputs: [],
354
+ outputs: [],
355
+ stateMutability: "nonpayable"
356
+ },
357
+ {
358
+ type: "function",
359
+ name: "hasActiveSubscription",
360
+ inputs: [{ name: "wallet", type: "address" }],
361
+ outputs: [{ name: "", type: "bool" }],
362
+ stateMutability: "view"
363
+ },
364
+ {
365
+ type: "function",
366
+ name: "authorizedBillers",
367
+ inputs: [{ name: "biller", type: "address" }],
368
+ outputs: [{ name: "isAuthorized", type: "bool" }],
369
+ stateMutability: "view"
370
+ },
371
+ {
372
+ type: "function",
373
+ name: "setCrossChainTransports",
374
+ inputs: [
375
+ { name: "axelarTransport", type: "address" },
376
+ { name: "ccipTransport", type: "address" }
377
+ ],
378
+ outputs: [],
379
+ stateMutability: "nonpayable"
380
+ },
381
+ {
382
+ type: "function",
383
+ name: "dispatchCrossChainUpdate",
384
+ inputs: [
385
+ { name: "tokenId", type: "uint256" },
386
+ { name: "destinationChainId", type: "uint256" },
387
+ { name: "refundAddress", type: "address" }
388
+ ],
389
+ outputs: [
390
+ { name: "messageId", type: "bytes32" },
391
+ { name: "routeUsed", type: "uint8" }
392
+ ],
393
+ stateMutability: "payable"
394
+ },
395
+ // Events
396
+ {
397
+ type: "event",
398
+ name: "SubscriptionMinted",
399
+ inputs: [
400
+ { name: "subscriber", type: "address", indexed: true },
401
+ { name: "tokenId", type: "uint256", indexed: true },
402
+ { name: "planId", type: "uint256", indexed: true },
403
+ { name: "expiration", type: "uint64", indexed: false }
404
+ ]
405
+ },
406
+ {
407
+ type: "event",
408
+ name: "SubscriptionRenewed",
409
+ inputs: [
410
+ { name: "tokenId", type: "uint256", indexed: true },
411
+ { name: "newExpiration", type: "uint64", indexed: false },
412
+ { name: "amountPaid", type: "uint256", indexed: false }
413
+ ]
414
+ },
415
+ {
416
+ type: "event",
417
+ name: "SubscriptionCancelled",
418
+ inputs: [{ name: "tokenId", type: "uint256", indexed: true }]
419
+ },
420
+ {
421
+ type: "event",
422
+ name: "SubscriptionPlanChanged",
423
+ inputs: [
424
+ { name: "tokenId", type: "uint256", indexed: true },
425
+ { name: "previousPlanId", type: "uint256", indexed: true },
426
+ { name: "newPlanId", type: "uint256", indexed: true },
427
+ { name: "expiration", type: "uint64", indexed: false }
428
+ ]
429
+ },
430
+ {
431
+ type: "event",
432
+ name: "BillingSuccess",
433
+ inputs: [
434
+ { name: "tokenId", type: "uint256", indexed: true },
435
+ { name: "planId", type: "uint256", indexed: true },
436
+ { name: "amount", type: "uint256", indexed: false },
437
+ { name: "timestamp", type: "uint256", indexed: false }
438
+ ]
439
+ },
440
+ {
441
+ type: "event",
442
+ name: "CrossChainDispatchRequested",
443
+ inputs: [
444
+ { name: "tokenId", type: "uint256", indexed: true },
445
+ { name: "destinationChainId", type: "uint256", indexed: true },
446
+ { name: "route", type: "uint8", indexed: true },
447
+ { name: "messageId", type: "bytes32", indexed: false }
448
+ ]
449
+ },
450
+ {
451
+ type: "event",
452
+ name: "CrossChainFallbackTriggered",
453
+ inputs: [
454
+ { name: "tokenId", type: "uint256", indexed: true },
455
+ { name: "destinationChainId", type: "uint256", indexed: true },
456
+ { name: "primaryError", type: "bytes", indexed: false }
457
+ ]
458
+ },
459
+ {
460
+ type: "event",
461
+ name: "SubscriptionImported",
462
+ inputs: [
463
+ { name: "subscriber", type: "address", indexed: true },
464
+ { name: "tokenId", type: "uint256", indexed: true },
465
+ { name: "planId", type: "uint256", indexed: true },
466
+ { name: "expiration", type: "uint64", indexed: false }
467
+ ]
468
+ },
469
+ {
470
+ type: "event",
471
+ name: "RegistryMigrationFinalized",
472
+ inputs: []
473
+ },
474
+ {
475
+ type: "event",
476
+ name: "Transfer",
477
+ inputs: [
478
+ { name: "from", type: "address", indexed: true },
479
+ { name: "to", type: "address", indexed: true },
480
+ { name: "tokenId", type: "uint256", indexed: true }
481
+ ]
482
+ }
483
+ ];
484
+ var PlanFactoryABI = [
485
+ {
486
+ type: "function",
487
+ name: "createPlan",
488
+ inputs: [
489
+ { name: "name", type: "string" },
490
+ { name: "tier", type: "string" },
491
+ { name: "price", type: "uint256" },
492
+ { name: "billingInterval", type: "uint32" },
493
+ { name: "acceptedToken", type: "address" },
494
+ { name: "metadataURI", type: "string" }
495
+ ],
496
+ outputs: [{ name: "planId", type: "uint256" }],
497
+ stateMutability: "nonpayable"
498
+ },
499
+ {
500
+ type: "function",
501
+ name: "getPlan",
502
+ inputs: [{ name: "planId", type: "uint256" }],
503
+ outputs: [
504
+ {
505
+ name: "plan",
506
+ type: "tuple",
507
+ components: [
508
+ { name: "id", type: "uint256" },
509
+ { name: "provider", type: "address" },
510
+ { name: "name", type: "string" },
511
+ { name: "tier", type: "string" },
512
+ { name: "price", type: "uint256" },
513
+ { name: "billingInterval", type: "uint32" },
514
+ { name: "acceptedToken", type: "address" },
515
+ { name: "active", type: "bool" },
516
+ { name: "metadataURI", type: "string" }
517
+ ]
518
+ }
519
+ ],
520
+ stateMutability: "view"
521
+ },
522
+ {
523
+ type: "function",
524
+ name: "getProviderPlans",
525
+ inputs: [{ name: "provider", type: "address" }],
526
+ outputs: [{ name: "planIds", type: "uint256[]" }],
527
+ stateMutability: "view"
528
+ },
529
+ {
530
+ type: "function",
531
+ name: "isProvider",
532
+ inputs: [{ name: "provider", type: "address" }],
533
+ outputs: [{ name: "", type: "bool" }],
534
+ stateMutability: "view"
535
+ },
536
+ {
537
+ type: "event",
538
+ name: "PlanCreated",
539
+ inputs: [
540
+ { name: "planId", type: "uint256", indexed: true },
541
+ { name: "provider", type: "address", indexed: true },
542
+ { name: "name", type: "string", indexed: false },
543
+ { name: "price", type: "uint256", indexed: false },
544
+ { name: "billingInterval", type: "uint32", indexed: false }
545
+ ]
546
+ },
547
+ {
548
+ type: "function",
549
+ name: "deactivatePlan",
550
+ inputs: [{ name: "planId", type: "uint256" }],
551
+ outputs: [],
552
+ stateMutability: "nonpayable"
553
+ },
554
+ {
555
+ type: "function",
556
+ name: "updatePlan",
557
+ inputs: [
558
+ { name: "planId", type: "uint256" },
559
+ { name: "price", type: "uint256" },
560
+ { name: "metadataURI", type: "string" }
561
+ ],
562
+ outputs: [],
563
+ stateMutability: "nonpayable"
564
+ },
565
+ {
566
+ type: "event",
567
+ name: "PlanDeactivated",
568
+ inputs: [{ name: "planId", type: "uint256", indexed: true }]
569
+ }
570
+ ];
571
+ var ERC7579AutopayModuleABI = [
572
+ {
573
+ type: "function",
574
+ name: "onInstall",
575
+ inputs: [{ name: "data", type: "bytes" }],
576
+ outputs: [],
577
+ stateMutability: "nonpayable"
578
+ },
579
+ {
580
+ type: "function",
581
+ name: "onUninstall",
582
+ inputs: [{ name: "data", type: "bytes" }],
583
+ outputs: [],
584
+ stateMutability: "nonpayable"
585
+ },
586
+ {
587
+ type: "function",
588
+ name: "execute",
589
+ inputs: [
590
+ { name: "account", type: "address" },
591
+ { name: "amount", type: "uint256" }
592
+ ],
593
+ outputs: [],
594
+ stateMutability: "nonpayable"
595
+ },
596
+ {
597
+ type: "function",
598
+ name: "isInitialized",
599
+ inputs: [{ name: "smartAccount", type: "address" }],
600
+ outputs: [{ name: "", type: "bool" }],
601
+ stateMutability: "view"
602
+ },
603
+ {
604
+ type: "function",
605
+ name: "getConfig",
606
+ inputs: [{ name: "account", type: "address" }],
607
+ outputs: [
608
+ {
609
+ name: "config",
610
+ type: "tuple",
611
+ components: [
612
+ { name: "merchant", type: "address" },
613
+ { name: "maxAmount", type: "uint256" },
614
+ { name: "token", type: "address" },
615
+ { name: "interval", type: "uint32" },
616
+ { name: "startTime", type: "uint64" },
617
+ { name: "planId", type: "uint256" },
618
+ { name: "maxTotalAmount", type: "uint256" }
619
+ ]
620
+ }
621
+ ],
622
+ stateMutability: "view"
623
+ },
624
+ {
625
+ type: "function",
626
+ name: "updateConfig",
627
+ inputs: [
628
+ {
629
+ name: "config",
630
+ type: "tuple",
631
+ components: [
632
+ { name: "merchant", type: "address" },
633
+ { name: "maxAmount", type: "uint256" },
634
+ { name: "token", type: "address" },
635
+ { name: "interval", type: "uint32" },
636
+ { name: "startTime", type: "uint64" },
637
+ { name: "planId", type: "uint256" },
638
+ { name: "maxTotalAmount", type: "uint256" }
639
+ ]
640
+ }
641
+ ],
642
+ outputs: [],
643
+ stateMutability: "nonpayable"
644
+ },
645
+ {
646
+ type: "function",
647
+ name: "canExecute",
648
+ inputs: [{ name: "account", type: "address" }],
649
+ outputs: [{ name: "", type: "bool" }],
650
+ stateMutability: "view"
651
+ },
652
+ {
653
+ type: "function",
654
+ name: "lastPullTime",
655
+ inputs: [{ name: "account", type: "address" }],
656
+ outputs: [{ name: "", type: "uint64" }],
657
+ stateMutability: "view"
658
+ },
659
+ {
660
+ type: "function",
661
+ name: "mirrorDestinationChainId",
662
+ inputs: [{ name: "account", type: "address" }],
663
+ outputs: [{ name: "", type: "uint256" }],
664
+ stateMutability: "view"
665
+ },
666
+ {
667
+ type: "function",
668
+ name: "isAccountPaused",
669
+ inputs: [{ name: "account", type: "address" }],
670
+ outputs: [{ name: "", type: "bool" }],
671
+ stateMutability: "view"
672
+ },
673
+ {
674
+ type: "function",
675
+ name: "importAccountState",
676
+ inputs: [
677
+ { name: "account", type: "address" },
678
+ {
679
+ name: "config",
680
+ type: "tuple",
681
+ components: [
682
+ { name: "merchant", type: "address" },
683
+ { name: "maxAmount", type: "uint256" },
684
+ { name: "token", type: "address" },
685
+ { name: "interval", type: "uint32" },
686
+ { name: "startTime", type: "uint64" },
687
+ { name: "planId", type: "uint256" },
688
+ { name: "maxTotalAmount", type: "uint256" }
689
+ ]
690
+ },
691
+ { name: "lastPullTime_", type: "uint64" },
692
+ { name: "totalPulled_", type: "uint256" },
693
+ { name: "mirrorDestinationChainId_", type: "uint256" },
694
+ { name: "accountPaused_", type: "bool" }
695
+ ],
696
+ outputs: [],
697
+ stateMutability: "nonpayable"
698
+ },
699
+ {
700
+ type: "function",
701
+ name: "finalizeMigration",
702
+ inputs: [],
703
+ outputs: [],
704
+ stateMutability: "nonpayable"
705
+ },
706
+ {
707
+ type: "event",
708
+ name: "AutopayConfigured",
709
+ inputs: [
710
+ { name: "account", type: "address", indexed: true },
711
+ { name: "merchant", type: "address", indexed: true },
712
+ { name: "maxAmount", type: "uint256", indexed: false },
713
+ { name: "token", type: "address", indexed: false },
714
+ { name: "interval", type: "uint32", indexed: false }
715
+ ]
716
+ },
717
+ {
718
+ type: "event",
719
+ name: "AutopayConfigUpdated",
720
+ inputs: [
721
+ { name: "account", type: "address", indexed: true },
722
+ { name: "previousPlanId", type: "uint256", indexed: true },
723
+ { name: "newPlanId", type: "uint256", indexed: true },
724
+ { name: "maxAmount", type: "uint256", indexed: false },
725
+ { name: "interval", type: "uint32", indexed: false }
726
+ ]
727
+ },
728
+ {
729
+ type: "event",
730
+ name: "PaymentExecuted",
731
+ inputs: [
732
+ { name: "account", type: "address", indexed: true },
733
+ { name: "merchant", type: "address", indexed: true },
734
+ { name: "amount", type: "uint256", indexed: false },
735
+ { name: "timestamp", type: "uint256", indexed: false }
736
+ ]
737
+ },
738
+ {
739
+ type: "event",
740
+ name: "BillingExecuted",
741
+ inputs: [
742
+ { name: "account", type: "address", indexed: true },
743
+ { name: "merchant", type: "address", indexed: true },
744
+ { name: "tokenId", type: "uint256", indexed: true },
745
+ { name: "planId", type: "uint256", indexed: false },
746
+ { name: "reason", type: "uint8", indexed: false },
747
+ { name: "grossAmount", type: "uint256", indexed: false },
748
+ { name: "merchantAmount", type: "uint256", indexed: false },
749
+ { name: "protocolFee", type: "uint256", indexed: false },
750
+ { name: "timestamp", type: "uint256", indexed: false }
751
+ ]
752
+ },
753
+ {
754
+ type: "event",
755
+ name: "AutopayRevoked",
756
+ inputs: [{ name: "account", type: "address", indexed: true }]
757
+ },
758
+ {
759
+ type: "event",
760
+ name: "AccountStateImported",
761
+ inputs: [
762
+ { name: "account", type: "address", indexed: true },
763
+ { name: "planId", type: "uint256", indexed: true },
764
+ { name: "lastPullTime", type: "uint64", indexed: false }
765
+ ]
766
+ },
767
+ {
768
+ type: "event",
769
+ name: "MigrationFinalized",
770
+ inputs: []
771
+ }
772
+ ];
773
+
774
+ // src/internal/sdk-core/accounts.ts
775
+ import { createPublicClient, http } from "viem";
776
+
777
+ // src/lib/zerodev.ts
778
+ var CHAIN_MAP = {
779
+ 11155111: sepolia2,
780
+ 84532: baseSepolia2,
781
+ 8453: base
782
+ };
783
+ var ENTRY_POINT = zeroDevConstants.getEntryPoint("0.7");
784
+ var ENTRY_POINT_ADDRESS = ENTRY_POINT.address;
785
+ var KERNEL_VERSION = zeroDevConstants.KERNEL_V3_1;
786
+ function getZeroDevChainLabel(chainId) {
787
+ if (chainId === 84532) return "Base Sepolia";
788
+ if (chainId === 8453) return "Base";
789
+ if (chainId === 11155111) return "Sepolia";
790
+ return `Chain ${chainId}`;
791
+ }
792
+ function resolveZeroDevUrls(params) {
793
+ const specificUnified = process.env[`NEXT_PUBLIC_ZERODEV_RPC_${params.chainId}`];
794
+ const specificBundler = process.env[`NEXT_PUBLIC_ZERODEV_BUNDLER_RPC_${params.chainId}`];
795
+ const specificPaymaster = process.env[`NEXT_PUBLIC_ZERODEV_PAYMASTER_RPC_${params.chainId}`];
796
+ const genericUnified = process.env.NEXT_PUBLIC_ZERODEV_RPC;
797
+ const genericBundler = process.env.NEXT_PUBLIC_ZERODEV_BUNDLER_RPC;
798
+ const genericPaymaster = process.env.NEXT_PUBLIC_ZERODEV_PAYMASTER_RPC;
799
+ const defaultUnifiedV3 = `https://rpc.zerodev.app/api/v3/${params.projectId}/chain/${params.chainId}`;
800
+ const hasConfiguredUrls = !!(params.bundlerUrl || params.paymasterUrl || specificUnified || specificBundler || specificPaymaster || genericUnified || genericBundler || genericPaymaster);
801
+ return {
802
+ bundlerUrl: params.bundlerUrl || specificUnified || specificBundler || genericUnified || genericBundler || defaultUnifiedV3 || `https://rpc.zerodev.app/api/v2/bundler/${params.projectId}`,
803
+ paymasterUrl: params.paymasterUrl || specificUnified || specificPaymaster || genericUnified || genericPaymaster || defaultUnifiedV3 || `https://rpc.zerodev.app/api/v2/paymaster/${params.projectId}`,
804
+ hasConfiguredUrls
805
+ };
806
+ }
807
+ function normalizeZeroDevError(error, params) {
808
+ const message = error instanceof Error ? error.message : String(error ?? "");
809
+ const chainLabel = getZeroDevChainLabel(params.chainId);
810
+ const usingDefaultUrls = !params.hasConfiguredUrls;
811
+ if (message.includes("ChainId not found")) {
812
+ const nextStep = usingDefaultUrls ? `Enable ${chainLabel} for ZeroDev project ${params.projectId}, or set NEXT_PUBLIC_ZERODEV_BUNDLER_RPC_${params.chainId} and NEXT_PUBLIC_ZERODEV_PAYMASTER_RPC_${params.chainId} to chain-specific endpoints.` : `The configured ZeroDev endpoint does not recognize ${chainLabel} for project ${params.projectId}. Verify the project supports chain ${params.chainId} or replace the override URLs. Bundler URL: ${params.bundlerUrl ?? "n/a"}. Paymaster URL: ${params.paymasterUrl ?? "n/a"}.`;
813
+ return new Error(
814
+ `ZeroDev project ${params.projectId} is not configured for ${chainLabel} (chain ${params.chainId}). ${nextStep}`
815
+ );
816
+ }
817
+ return error instanceof Error ? error : new Error(message);
818
+ }
819
+ function isRecoverableSmartAccountFundingError(error) {
820
+ const message = error instanceof Error ? error.message : String(error ?? "");
821
+ const lower = message.toLowerCase();
822
+ return lower.includes("smart account does not have sufficient funds") || lower.includes("sufficient funds to execute the user operation") || lower.includes("insufficient funds") || lower.includes("user operation") && lower.includes("paymaster");
823
+ }
824
+ async function createKernelExecutionContext(config) {
825
+ const chain = CHAIN_MAP[config.chainId] || baseSepolia2;
826
+ const { bundlerUrl, paymasterUrl, hasConfiguredUrls } = resolveZeroDevUrls({
827
+ projectId: config.projectId,
828
+ chainId: config.chainId,
829
+ bundlerUrl: config.bundlerUrl,
830
+ paymasterUrl: config.paymasterUrl
831
+ });
832
+ const publicClient = createPublicClient2({
833
+ chain,
834
+ transport: http2()
835
+ });
836
+ const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
837
+ signer: config.walletClient,
838
+ entryPoint: ENTRY_POINT,
839
+ kernelVersion: KERNEL_VERSION
840
+ });
841
+ const kernelAccount = await createKernelAccount(publicClient, {
842
+ plugins: { sudo: ecdsaValidator },
843
+ entryPoint: ENTRY_POINT,
844
+ kernelVersion: KERNEL_VERSION
845
+ });
846
+ const paymasterClient = createZeroDevPaymasterClient({
847
+ chain,
848
+ transport: http2(paymasterUrl)
849
+ });
850
+ const kernelClient = createKernelAccountClient({
851
+ account: kernelAccount,
852
+ chain,
853
+ bundlerTransport: http2(bundlerUrl),
854
+ middleware: {
855
+ sponsorUserOperation: async ({
856
+ userOperation
857
+ }) => {
858
+ return paymasterClient.sponsorUserOperation({
859
+ userOperation,
860
+ entryPoint: ENTRY_POINT_ADDRESS
861
+ });
862
+ }
863
+ }
864
+ });
865
+ return {
866
+ publicClient,
867
+ kernelAccount,
868
+ kernelClient,
869
+ bundlerUrl,
870
+ paymasterUrl,
871
+ hasConfiguredUrls
872
+ };
873
+ }
874
+ async function deploySmartAccount(config) {
875
+ const chain = CHAIN_MAP[config.chainId] || baseSepolia2;
876
+ const contracts = getContractAddresses(config.chainId);
877
+ const { bundlerUrl, paymasterUrl, hasConfiguredUrls } = resolveZeroDevUrls({
878
+ projectId: config.projectId,
879
+ chainId: config.chainId,
880
+ bundlerUrl: config.bundlerUrl,
881
+ paymasterUrl: config.paymasterUrl
882
+ });
883
+ const publicClient = createPublicClient2({
884
+ chain,
885
+ transport: http2()
886
+ });
887
+ const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
888
+ signer: config.walletClient,
889
+ entryPoint: ENTRY_POINT,
890
+ kernelVersion: KERNEL_VERSION
891
+ });
892
+ const kernelAccount = await createKernelAccount(publicClient, {
893
+ plugins: {
894
+ sudo: ecdsaValidator
895
+ },
896
+ entryPoint: ENTRY_POINT,
897
+ kernelVersion: KERNEL_VERSION
898
+ });
899
+ const smartAccountAddress = kernelAccount.address;
900
+ const code = await publicClient.getCode({ address: smartAccountAddress });
901
+ const alreadyDeployed = !!code && code !== "0x";
902
+ const paymasterClient = createZeroDevPaymasterClient({
903
+ chain,
904
+ transport: http2(paymasterUrl)
905
+ });
906
+ const kernelClient = createKernelAccountClient({
907
+ account: kernelAccount,
908
+ chain,
909
+ bundlerTransport: http2(bundlerUrl),
910
+ middleware: {
911
+ sponsorUserOperation: async ({
912
+ userOperation
913
+ }) => {
914
+ return paymasterClient.sponsorUserOperation({
915
+ userOperation,
916
+ entryPoint: ENTRY_POINT_ADDRESS
917
+ });
918
+ }
919
+ }
920
+ });
921
+ let installTxHash;
922
+ if (contracts.autopayModule) {
923
+ try {
924
+ const initialized = await publicClient.readContract({
925
+ address: contracts.autopayModule,
926
+ abi: ERC7579AutopayModuleABI,
927
+ functionName: "isInitialized",
928
+ args: [smartAccountAddress]
929
+ });
930
+ if (initialized) {
931
+ console.log(
932
+ `[ZeroDev] AutopayModule already initialized for ${smartAccountAddress}`
933
+ );
934
+ return {
935
+ smartAccountAddress,
936
+ installTxHash,
937
+ alreadyDeployed
938
+ };
939
+ }
940
+ const installData = encodeFunctionData({
941
+ abi: [
942
+ {
943
+ type: "function",
944
+ name: "installModule",
945
+ inputs: [
946
+ { name: "moduleType", type: "uint256" },
947
+ { name: "module", type: "address" },
948
+ { name: "initData", type: "bytes" }
949
+ ],
950
+ outputs: [],
951
+ stateMutability: "nonpayable"
952
+ }
953
+ ],
954
+ functionName: "installModule",
955
+ args: [
956
+ 2n,
957
+ // Module type 2 = Executor
958
+ contracts.autopayModule,
959
+ "0x"
960
+ // Empty init data
961
+ ]
962
+ });
963
+ installTxHash = await kernelClient.sendTransaction({
964
+ to: smartAccountAddress,
965
+ data: installData,
966
+ value: 0n
967
+ });
968
+ console.log(
969
+ `[ZeroDev] AutopayModule installed on ${smartAccountAddress} \u2014 tx: ${installTxHash}`
970
+ );
971
+ } catch (err) {
972
+ if (err?.message?.includes("already installed") || err?.message?.includes("AlreadyInitialized")) {
973
+ console.log(
974
+ `[ZeroDev] AutopayModule already installed on ${smartAccountAddress}`
975
+ );
976
+ } else {
977
+ const normalizedError = normalizeZeroDevError(err, {
978
+ projectId: config.projectId,
979
+ chainId: config.chainId,
980
+ bundlerUrl,
981
+ paymasterUrl,
982
+ hasConfiguredUrls
983
+ });
984
+ if (isRecoverableSmartAccountFundingError(normalizedError)) {
985
+ console.warn(
986
+ "[ZeroDev] Module installation needs prefund or sponsorship; callers may fall back to the connected wallet:",
987
+ normalizedError.message
988
+ );
989
+ } else {
990
+ console.error(
991
+ "[ZeroDev] Module installation failed:",
992
+ normalizedError.message
993
+ );
994
+ }
995
+ throw normalizedError;
996
+ }
997
+ }
998
+ }
999
+ return {
1000
+ smartAccountAddress,
1001
+ installTxHash,
1002
+ alreadyDeployed
1003
+ };
1004
+ }
1005
+ async function revokeAutopayModule(config) {
1006
+ const chain = CHAIN_MAP[config.chainId] || baseSepolia2;
1007
+ const contracts = getContractAddresses(config.chainId);
1008
+ if (!contracts.autopayModule) {
1009
+ throw new Error("Autopay module address not configured for this chain.");
1010
+ }
1011
+ const { bundlerUrl, paymasterUrl, hasConfiguredUrls } = resolveZeroDevUrls({
1012
+ projectId: config.projectId,
1013
+ chainId: config.chainId,
1014
+ bundlerUrl: config.bundlerUrl,
1015
+ paymasterUrl: config.paymasterUrl
1016
+ });
1017
+ const publicClient = createPublicClient2({
1018
+ chain,
1019
+ transport: http2()
1020
+ });
1021
+ const initialized = await publicClient.readContract({
1022
+ address: contracts.autopayModule,
1023
+ abi: ERC7579AutopayModuleABI,
1024
+ functionName: "isInitialized",
1025
+ args: [config.smartAccountAddress]
1026
+ });
1027
+ if (!initialized) {
1028
+ return { alreadyRevoked: true };
1029
+ }
1030
+ const { kernelAccount, kernelClient } = await createKernelExecutionContext({
1031
+ projectId: config.projectId,
1032
+ chainId: config.chainId,
1033
+ walletClient: config.walletClient,
1034
+ bundlerUrl,
1035
+ paymasterUrl
1036
+ });
1037
+ if (kernelAccount.address.toLowerCase() !== config.smartAccountAddress.toLowerCase()) {
1038
+ throw new Error(
1039
+ `Kernel account mismatch. Expected ${config.smartAccountAddress}, got ${kernelAccount.address}.`
1040
+ );
1041
+ }
1042
+ const revokeData = encodeFunctionData({
1043
+ abi: ERC7579AutopayModuleABI,
1044
+ functionName: "onUninstall",
1045
+ args: ["0x"]
1046
+ });
1047
+ try {
1048
+ const txHash = await kernelClient.sendTransaction({
1049
+ to: contracts.autopayModule,
1050
+ data: revokeData,
1051
+ value: 0n
1052
+ });
1053
+ return { txHash, alreadyRevoked: false };
1054
+ } catch (error) {
1055
+ throw normalizeZeroDevError(error, {
1056
+ projectId: config.projectId,
1057
+ chainId: config.chainId,
1058
+ bundlerUrl,
1059
+ paymasterUrl,
1060
+ hasConfiguredUrls
1061
+ });
1062
+ }
1063
+ }
1064
+ async function sendSmartAccountTransaction(config) {
1065
+ const {
1066
+ publicClient,
1067
+ kernelAccount,
1068
+ kernelClient,
1069
+ bundlerUrl,
1070
+ paymasterUrl,
1071
+ hasConfiguredUrls
1072
+ } = await createKernelExecutionContext({
1073
+ projectId: config.projectId,
1074
+ chainId: config.chainId,
1075
+ walletClient: config.walletClient,
1076
+ bundlerUrl: config.bundlerUrl,
1077
+ paymasterUrl: config.paymasterUrl
1078
+ });
1079
+ if (config.smartAccountAddress && kernelAccount.address.toLowerCase() !== config.smartAccountAddress.toLowerCase()) {
1080
+ throw new Error(
1081
+ `Kernel account mismatch. Expected ${config.smartAccountAddress}, got ${kernelAccount.address}.`
1082
+ );
1083
+ }
1084
+ try {
1085
+ const txHash = await kernelClient.sendTransaction({
1086
+ to: config.to,
1087
+ data: config.data,
1088
+ value: config.value ?? 0n
1089
+ });
1090
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
1091
+ return {
1092
+ smartAccountAddress: kernelAccount.address,
1093
+ txHash
1094
+ };
1095
+ } catch (error) {
1096
+ throw normalizeZeroDevError(error, {
1097
+ projectId: config.projectId,
1098
+ chainId: config.chainId,
1099
+ bundlerUrl,
1100
+ paymasterUrl,
1101
+ hasConfiguredUrls
1102
+ });
1103
+ }
1104
+ }
1105
+ async function updateAutopayConfig(config) {
1106
+ const contracts = getContractAddresses(config.chainId);
1107
+ if (!contracts.autopayModule) {
1108
+ throw new Error("Autopay module address is not configured for this chain.");
1109
+ }
1110
+ const data = encodeFunctionData({
1111
+ abi: ERC7579AutopayModuleABI,
1112
+ functionName: "updateConfig",
1113
+ args: [
1114
+ {
1115
+ merchant: config.merchant,
1116
+ maxAmount: config.maxAmount,
1117
+ token: config.token,
1118
+ interval: config.interval,
1119
+ startTime: config.startTime,
1120
+ planId: config.planId,
1121
+ maxTotalAmount: config.maxTotalAmount ?? 0n
1122
+ }
1123
+ ]
1124
+ });
1125
+ return sendSmartAccountTransaction({
1126
+ projectId: config.projectId,
1127
+ chainId: config.chainId,
1128
+ walletClient: config.walletClient,
1129
+ smartAccountAddress: config.smartAccountAddress,
1130
+ to: contracts.autopayModule,
1131
+ data,
1132
+ bundlerUrl: config.bundlerUrl,
1133
+ paymasterUrl: config.paymasterUrl
1134
+ });
1135
+ }
1136
+ async function cancelSubscription(config) {
1137
+ const contracts = getContractAddresses(config.chainId);
1138
+ if (!contracts.subscriptionRegistry) {
1139
+ throw new Error(
1140
+ "Subscription registry address is not configured for this chain."
1141
+ );
1142
+ }
1143
+ const data = encodeFunctionData({
1144
+ abi: SubscriptionRegistryABI,
1145
+ functionName: "cancelSubscription",
1146
+ args: [config.tokenId]
1147
+ });
1148
+ return sendSmartAccountTransaction({
1149
+ projectId: config.projectId,
1150
+ chainId: config.chainId,
1151
+ walletClient: config.walletClient,
1152
+ smartAccountAddress: config.smartAccountAddress,
1153
+ to: contracts.subscriptionRegistry,
1154
+ data,
1155
+ bundlerUrl: config.bundlerUrl,
1156
+ paymasterUrl: config.paymasterUrl
1157
+ });
1158
+ }
1159
+
1160
+ export {
1161
+ getContractAddresses,
1162
+ getChainEnvironment,
1163
+ validateChainEnvironment,
1164
+ resolveArcenPayBaseUrl,
1165
+ SubscriptionRegistryABI,
1166
+ PlanFactoryABI,
1167
+ ERC7579AutopayModuleABI,
1168
+ isRecoverableSmartAccountFundingError,
1169
+ deploySmartAccount,
1170
+ revokeAutopayModule,
1171
+ sendSmartAccountTransaction,
1172
+ updateAutopayConfig,
1173
+ cancelSubscription
1174
+ };