@aastar/paymaster 0.16.7 → 0.16.11

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.
Files changed (107) hide show
  1. package/dist/V4/BundlerCompat.d.ts +28 -0
  2. package/dist/V4/BundlerCompat.js +37 -0
  3. package/dist/{paymaster/src/V4 → V4}/PaymasterClient.d.ts +5 -0
  4. package/dist/{paymaster/src/V4 → V4}/PaymasterClient.js +108 -15
  5. package/dist/{paymaster/src/V4 → V4}/PaymasterUtils.d.ts +11 -0
  6. package/dist/{paymaster/src/V4 → V4}/PaymasterUtils.js +36 -19
  7. package/dist/{paymaster/src/V4 → V4}/SuperPaymasterClient.js +16 -10
  8. package/package.json +5 -8
  9. package/dist/core/src/abis/BLSAggregator.json +0 -686
  10. package/dist/core/src/abis/BLSValidator.json +0 -42
  11. package/dist/core/src/abis/DVTValidator.json +0 -368
  12. package/dist/core/src/abis/EntryPoint.json +0 -1382
  13. package/dist/core/src/abis/GToken.json +0 -513
  14. package/dist/core/src/abis/GTokenStaking.json +0 -949
  15. package/dist/core/src/abis/MySBT.json +0 -1518
  16. package/dist/core/src/abis/Paymaster.json +0 -1143
  17. package/dist/core/src/abis/PaymasterFactory.json +0 -640
  18. package/dist/core/src/abis/Registry.json +0 -1942
  19. package/dist/core/src/abis/ReputationSystem.json +0 -699
  20. package/dist/core/src/abis/SimpleAccount.json +0 -560
  21. package/dist/core/src/abis/SimpleAccountFactory.json +0 -111
  22. package/dist/core/src/abis/SuperPaymaster.json +0 -1781
  23. package/dist/core/src/abis/index.d.ts +0 -1126
  24. package/dist/core/src/abis/index.js +0 -91
  25. package/dist/core/src/abis/xPNTsFactory.json +0 -718
  26. package/dist/core/src/abis/xPNTsToken.json +0 -1280
  27. package/dist/core/src/actions/StateValidator.d.ts +0 -68
  28. package/dist/core/src/actions/StateValidator.js +0 -187
  29. package/dist/core/src/actions/account.d.ts +0 -55
  30. package/dist/core/src/actions/account.js +0 -133
  31. package/dist/core/src/actions/aggregator.d.ts +0 -17
  32. package/dist/core/src/actions/aggregator.js +0 -31
  33. package/dist/core/src/actions/dvt.d.ts +0 -30
  34. package/dist/core/src/actions/dvt.js +0 -41
  35. package/dist/core/src/actions/entryPoint.d.ts +0 -90
  36. package/dist/core/src/actions/entryPoint.js +0 -211
  37. package/dist/core/src/actions/factory.d.ts +0 -215
  38. package/dist/core/src/actions/factory.js +0 -442
  39. package/dist/core/src/actions/faucet.d.ts +0 -48
  40. package/dist/core/src/actions/faucet.js +0 -337
  41. package/dist/core/src/actions/gtokenExtended.d.ts +0 -39
  42. package/dist/core/src/actions/gtokenExtended.js +0 -115
  43. package/dist/core/src/actions/index.d.ts +0 -15
  44. package/dist/core/src/actions/index.js +0 -17
  45. package/dist/core/src/actions/paymasterV4.d.ts +0 -170
  46. package/dist/core/src/actions/paymasterV4.js +0 -334
  47. package/dist/core/src/actions/registry.d.ts +0 -246
  48. package/dist/core/src/actions/registry.js +0 -667
  49. package/dist/core/src/actions/reputation.d.ts +0 -129
  50. package/dist/core/src/actions/reputation.js +0 -281
  51. package/dist/core/src/actions/sbt.d.ts +0 -191
  52. package/dist/core/src/actions/sbt.js +0 -533
  53. package/dist/core/src/actions/staking.d.ts +0 -132
  54. package/dist/core/src/actions/staking.js +0 -330
  55. package/dist/core/src/actions/superPaymaster.d.ts +0 -237
  56. package/dist/core/src/actions/superPaymaster.js +0 -644
  57. package/dist/core/src/actions/tokens.d.ts +0 -229
  58. package/dist/core/src/actions/tokens.js +0 -415
  59. package/dist/core/src/branding.d.ts +0 -30
  60. package/dist/core/src/branding.js +0 -30
  61. package/dist/core/src/clients/BaseClient.d.ts +0 -25
  62. package/dist/core/src/clients/BaseClient.js +0 -66
  63. package/dist/core/src/clients/types.d.ts +0 -60
  64. package/dist/core/src/clients/types.js +0 -1
  65. package/dist/core/src/clients.d.ts +0 -5
  66. package/dist/core/src/clients.js +0 -11
  67. package/dist/core/src/communities.d.ts +0 -52
  68. package/dist/core/src/communities.js +0 -73
  69. package/dist/core/src/config/ContractConfigManager.d.ts +0 -20
  70. package/dist/core/src/config/ContractConfigManager.js +0 -48
  71. package/dist/core/src/constants.d.ts +0 -88
  72. package/dist/core/src/constants.js +0 -125
  73. package/dist/core/src/contract-addresses.d.ts +0 -110
  74. package/dist/core/src/contract-addresses.js +0 -99
  75. package/dist/core/src/contracts.d.ts +0 -424
  76. package/dist/core/src/contracts.js +0 -343
  77. package/dist/core/src/crypto/blsSigner.d.ts +0 -64
  78. package/dist/core/src/crypto/blsSigner.js +0 -98
  79. package/dist/core/src/crypto/index.d.ts +0 -1
  80. package/dist/core/src/crypto/index.js +0 -1
  81. package/dist/core/src/index.d.ts +0 -21
  82. package/dist/core/src/index.js +0 -21
  83. package/dist/core/src/networks.d.ts +0 -127
  84. package/dist/core/src/networks.js +0 -118
  85. package/dist/core/src/requirementChecker.d.ts +0 -38
  86. package/dist/core/src/requirementChecker.js +0 -139
  87. package/dist/core/src/roles.d.ts +0 -204
  88. package/dist/core/src/roles.js +0 -211
  89. package/dist/core/src/utils/validation.d.ts +0 -24
  90. package/dist/core/src/utils/validation.js +0 -56
  91. /package/dist/{paymaster/src/SuperPaymaster → SuperPaymaster}/index.d.ts +0 -0
  92. /package/dist/{paymaster/src/SuperPaymaster → SuperPaymaster}/index.js +0 -0
  93. /package/dist/{paymaster/src/V4 → V4}/PaymasterClient.test.d.ts +0 -0
  94. /package/dist/{paymaster/src/V4 → V4}/PaymasterClient.test.js +0 -0
  95. /package/dist/{paymaster/src/V4 → V4}/PaymasterOperator.d.ts +0 -0
  96. /package/dist/{paymaster/src/V4 → V4}/PaymasterOperator.js +0 -0
  97. /package/dist/{paymaster/src/V4 → V4}/PaymasterOperator.test.d.ts +0 -0
  98. /package/dist/{paymaster/src/V4 → V4}/PaymasterOperator.test.js +0 -0
  99. /package/dist/{paymaster/src/V4 → V4}/PaymasterUtils.test.d.ts +0 -0
  100. /package/dist/{paymaster/src/V4 → V4}/PaymasterUtils.test.js +0 -0
  101. /package/dist/{paymaster/src/V4 → V4}/SuperPaymasterClient.d.ts +0 -0
  102. /package/dist/{paymaster/src/V4 → V4}/SuperPaymasterClient.test.d.ts +0 -0
  103. /package/dist/{paymaster/src/V4 → V4}/SuperPaymasterClient.test.js +0 -0
  104. /package/dist/{paymaster/src/V4 → V4}/index.d.ts +0 -0
  105. /package/dist/{paymaster/src/V4 → V4}/index.js +0 -0
  106. /package/dist/{paymaster/src/index.d.ts → index.d.ts} +0 -0
  107. /package/dist/{paymaster/src/index.js → index.js} +0 -0
@@ -0,0 +1,28 @@
1
+ import { type Address } from 'viem';
2
+ /**
3
+ * Bundler types we support
4
+ */
5
+ export declare enum BundlerType {
6
+ ALCHEMY = "alchemy",
7
+ PIMLICO = "pimlico",
8
+ STACKUP = "stackup",
9
+ CANDIDE = "candide",
10
+ UNKNOWN = "unknown"
11
+ }
12
+ /**
13
+ * Detect bundler type from URL
14
+ */
15
+ export declare function detectBundlerType(bundlerUrl: string): BundlerType;
16
+ /**
17
+ * Minimal interface to satisfy basic Pimlico/Bundler needs
18
+ * without bringing in heavy permissionless types that might conflict
19
+ */
20
+ export interface BundlerConfig {
21
+ type: BundlerType;
22
+ url: string;
23
+ entryPoint: Address;
24
+ }
25
+ /**
26
+ * Create a bundler client config
27
+ */
28
+ export declare function createBundlerClient(bundlerUrl: string, entryPoint: Address): BundlerConfig;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Bundler types we support
3
+ */
4
+ export var BundlerType;
5
+ (function (BundlerType) {
6
+ BundlerType["ALCHEMY"] = "alchemy";
7
+ BundlerType["PIMLICO"] = "pimlico";
8
+ BundlerType["STACKUP"] = "stackup";
9
+ BundlerType["CANDIDE"] = "candide";
10
+ BundlerType["UNKNOWN"] = "unknown";
11
+ })(BundlerType || (BundlerType = {}));
12
+ /**
13
+ * Detect bundler type from URL
14
+ */
15
+ export function detectBundlerType(bundlerUrl) {
16
+ const url = bundlerUrl.toLowerCase();
17
+ if (url.includes('alchemy.com'))
18
+ return BundlerType.ALCHEMY;
19
+ if (url.includes('pimlico.io'))
20
+ return BundlerType.PIMLICO;
21
+ if (url.includes('stackup'))
22
+ return BundlerType.STACKUP;
23
+ if (url.includes('candide.dev'))
24
+ return BundlerType.CANDIDE;
25
+ return BundlerType.UNKNOWN;
26
+ }
27
+ /**
28
+ * Create a bundler client config
29
+ */
30
+ export function createBundlerClient(bundlerUrl, entryPoint) {
31
+ const bundlerType = detectBundlerType(bundlerUrl);
32
+ return {
33
+ type: bundlerType,
34
+ url: bundlerUrl,
35
+ entryPoint
36
+ };
37
+ }
@@ -76,4 +76,9 @@ export declare class PaymasterClient {
76
76
  * This is the payload signed by the user.
77
77
  */
78
78
  static encodeExecution(target: Address, value: bigint, data: `0x${string}`): `0x${string}`;
79
+ /**
80
+ * More robust version of waitForUserOperationReceipt.
81
+ * Catches timeouts and returns a cleaner result.
82
+ */
83
+ static waitForUserOperation(bundlerClient: any, hash: `0x${string}`, timeout?: number): Promise<any>;
79
84
  }
@@ -1,5 +1,6 @@
1
- import { concat, pad, toHex, parseAbi, encodeFunctionData } from 'viem';
2
- import { buildPaymasterData, buildSuperPaymasterData, formatUserOpV07, getUserOpHashV07 } from './PaymasterUtils';
1
+ import { parseAbi, concat, pad, toHex, encodeFunctionData } from 'viem';
2
+ import { buildPaymasterData, buildSuperPaymasterData, formatUserOpV07, getUserOpHashV07 } from './PaymasterUtils.js';
3
+ import { detectBundlerType } from './BundlerCompat.js';
3
4
  /**
4
5
  * PaymasterClient
5
6
  * Focus: Integration, Funding, Interaction.
@@ -53,6 +54,44 @@ export class PaymasterClient {
53
54
  * Estimate Gas for a UserOperation.
54
55
  */
55
56
  static async estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
57
+ // 0. Check cachedPrice (Critical for Paymaster V4)
58
+ if (!options?.operator) { // Only for Paymaster V4, not SuperPaymaster
59
+ try {
60
+ const cache = await client.readContract({
61
+ address: paymasterAddress,
62
+ abi: parseAbi(['function cachedPrice() view returns (uint208 price, uint48 updatedAt)']),
63
+ functionName: 'cachedPrice'
64
+ });
65
+ if (!cache || cache.price === 0n || cache[0] === 0n) {
66
+ console.log('[PaymasterClient] ⚠️ cachedPrice is 0! Auto-initializing...');
67
+ // Check if we're on testnet (chainId 11155111 = Sepolia, 11155420 = OP Sepolia)
68
+ const chainId = client.chain?.id || await client.getChainId();
69
+ const isTestnet = [11155111, 11155420, 31337].includes(chainId);
70
+ if (isTestnet) {
71
+ // Auto-call updatePrice on testnet
72
+ const updateHash = await wallet.writeContract({
73
+ address: paymasterAddress,
74
+ abi: parseAbi(['function updatePrice() external']),
75
+ functionName: 'updatePrice'
76
+ });
77
+ await client.waitForTransactionReceipt({ hash: updateHash });
78
+ console.log('[PaymasterClient] ✅ cachedPrice initialized via updatePrice()');
79
+ }
80
+ else {
81
+ // Mainnet: throw error, require Keeper
82
+ throw new Error(`Paymaster cachedPrice is 0 on Mainnet (chainId: ${chainId}). ` +
83
+ `This requires Keeper to call updatePrice(). Please ensure Keeper is running.`);
84
+ }
85
+ }
86
+ }
87
+ catch (e) {
88
+ // If error is our mainnet check, re-throw
89
+ if (e.message?.includes('requires Keeper'))
90
+ throw e;
91
+ // Otherwise log and continue (might be old Paymaster without cachedPrice)
92
+ console.log('[PaymasterClient] ⚠️ Failed to check cachedPrice:', e.message?.slice(0, 50));
93
+ }
94
+ }
56
95
  // 1. Construct a dummy UserOp for estimation
57
96
  let paymasterAndData;
58
97
  if (options?.operator) {
@@ -64,8 +103,8 @@ export class PaymasterClient {
64
103
  else {
65
104
  paymasterAndData = buildPaymasterData(paymasterAddress, token, {
66
105
  validityWindow: options?.validityWindow,
67
- verificationGasLimit: 60000n, // Placeholder
68
- postOpGasLimit: 60000n // Placeholder
106
+ verificationGasLimit: 250000n,
107
+ postOpGasLimit: 150000n
69
108
  });
70
109
  }
71
110
  // 1.5. Get dynamic gas prices from network
@@ -88,8 +127,8 @@ export class PaymasterClient {
88
127
  ? concat([options.factory, options.factoryData])
89
128
  : '0x',
90
129
  callData,
91
- accountGasLimits: concat([pad(toHex(60000n), { size: 16 }), pad(toHex(100000n), { size: 16 })]), // 60k verification, 100k call
92
- preVerificationGas: 50000n, // 50k PVG
130
+ accountGasLimits: concat([pad(toHex(250000n), { size: 16 }), pad(toHex(500000n), { size: 16 })]),
131
+ preVerificationGas: 100000n,
93
132
  gasFees: concat([pad(toHex(maxPriorityFeePerGas), { size: 16 }), pad(toHex(maxFeePerGas), { size: 16 })]),
94
133
  paymasterAndData,
95
134
  signature: '0x'
@@ -118,14 +157,33 @@ export class PaymasterClient {
118
157
  body: JSON.stringify(payload, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
119
158
  });
120
159
  const result = await response.json();
160
+ // Debug logging for Candide
161
+ if (bundlerUrl.includes('candide')) {
162
+ console.log('[PaymasterClient] Candide Request:', JSON.stringify(payload.params[0], null, 2));
163
+ console.log('[PaymasterClient] Candide Response:', JSON.stringify(result, null, 2));
164
+ }
165
+ const data = result.result;
166
+ // Debug logging for estimation
167
+ console.log('[PaymasterClient] Gas Estimation Result:', JSON.stringify(data, null, 2));
168
+ // Anvil Fallback for Estimation
169
+ if (result.error && (result.error.code === -32601 || result.error.message?.includes('Method not found'))) {
170
+ console.log('[PaymasterClient] EstimateUserOp failed (Method not found). Using Anvil defaults.');
171
+ return {
172
+ preVerificationGas: 100000n,
173
+ verificationGasLimit: 1000000n,
174
+ callGasLimit: 2000000n,
175
+ paymasterVerificationGasLimit: 100000n,
176
+ paymasterPostOpGasLimit: 100000n
177
+ };
178
+ }
121
179
  if (result.error)
122
180
  throw new Error(`Estimation Error: ${JSON.stringify(result.error)}`);
123
- const data = result.result;
124
- // Dynamic tuning based on "Efficiency Guard" formulas
181
+ // Dynamic tuning: use estimated values directly to maintain efficiency
182
+ // Bundler efficiency check: actual_used / limit >= 0.4
125
183
  return {
126
184
  preVerificationGas: BigInt(data.preVerificationGas),
127
- verificationGasLimit: BigInt(data.verificationGasLimit),
128
- callGasLimit: (BigInt(data.callGasLimit) * 110n) / 100n, // 1.1x safety buffer
185
+ verificationGasLimit: BigInt(data.verificationGasLimit), // Use estimate as-is for efficiency
186
+ callGasLimit: (BigInt(data.callGasLimit) * 110n) / 100n, // Small 1.1x buffer
129
187
  paymasterVerificationGasLimit: data.paymasterVerificationGasLimit ? BigInt(data.paymasterVerificationGasLimit) : undefined,
130
188
  paymasterPostOpGasLimit: data.paymasterPostOpGasLimit ? BigInt(data.paymasterPostOpGasLimit) : 100000n
131
189
  };
@@ -141,7 +199,7 @@ export class PaymasterClient {
141
199
  verificationGasLimit: options?.verificationGasLimit,
142
200
  callGasLimit: options?.callGasLimit,
143
201
  paymasterVerificationGasLimit: options?.paymasterVerificationGasLimit,
144
- paymasterPostOpGasLimit: options?.paymasterPostOpGasLimit ?? 100000n
202
+ paymasterPostOpGasLimit: options?.paymasterPostOpGasLimit ?? 150000n
145
203
  };
146
204
  if (options?.autoEstimate !== false && (!gasLimits.verificationGasLimit || !gasLimits.callGasLimit)) {
147
205
  const est = await this.estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, {
@@ -198,9 +256,13 @@ export class PaymasterClient {
198
256
  });
199
257
  }
200
258
  else {
259
+ // MATH: Target Efficiency = PVG / (PVG + VGL + PMVGL) >= 0.4
260
+ // Since PVG is ~100k, (VGL + PMVGL) must be <= 150k.
261
+ // We set each to 75k to safely pass the 0.4 efficiency guard.
262
+ const pmVerGas = 75000n;
201
263
  paymasterAndData = buildPaymasterData(paymasterAddress, token, {
202
264
  validityWindow: options?.validityWindow,
203
- verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n, // Use tuned value
265
+ verificationGasLimit: pmVerGas,
204
266
  postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
205
267
  });
206
268
  }
@@ -213,8 +275,8 @@ export class PaymasterClient {
213
275
  : '0x',
214
276
  callData,
215
277
  accountGasLimits: concat([
216
- pad(toHex(gasLimits.verificationGasLimit ?? 150000n), { size: 16 }), // Verification (Tuned or Default)
217
- pad(toHex(gasLimits.callGasLimit ?? 500000n), { size: 16 }) // Call (Tuned or Default)
278
+ pad(toHex(75000n), { size: 16 }), // Verification (Tuned for 0.4 efficiency)
279
+ pad(toHex(gasLimits.callGasLimit ?? 500000n), { size: 16 }) // Call
218
280
  ]),
219
281
  preVerificationGas: gasLimits.preVerificationGas ?? 50000n,
220
282
  gasFees: concat([
@@ -237,7 +299,10 @@ export class PaymasterClient {
237
299
  const userOpHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
238
300
  const signature = (await wallet.account.signMessage({ message: { raw: userOpHash } }));
239
301
  userOp.signature = signature;
240
- // 6. Submit to Bundler
302
+ // 6. Submit to Bundler (Unified JSON-RPC)
303
+ const bundlerType = detectBundlerType(bundlerUrl);
304
+ console.log(`[PaymasterClient] Using ${bundlerType} Bundler`);
305
+ // Use standard JSON-RPC for all bundlers (Pimlico/Alchemy/Stackup/etc)
241
306
  const response = await fetch(bundlerUrl, {
242
307
  method: 'POST',
243
308
  headers: { 'Content-Type': 'application/json' },
@@ -249,8 +314,21 @@ export class PaymasterClient {
249
314
  }, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
250
315
  });
251
316
  const result = await response.json();
317
+ if (result.error && (result.error.code === -32601 || result.error.message?.includes('Method not found'))) {
318
+ console.log('[PaymasterClient] SendUserOp failed (Method not found). Falling back to direct handleOps...');
319
+ const caller = wallet.account?.address ? wallet.account.address : wallet.account;
320
+ return await wallet.writeContract({
321
+ address: entryPoint,
322
+ abi: parseAbi(['function handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[], address) external']),
323
+ functionName: 'handleOps',
324
+ args: [[userOp], caller],
325
+ chain: wallet.chain,
326
+ account: wallet.account
327
+ });
328
+ }
252
329
  if (result.error)
253
330
  throw new Error(`Bundler Error: ${JSON.stringify(result.error)}`);
331
+ console.log('[PaymasterClient] ✅ Submitted via', bundlerType, 'hash:', result.result);
254
332
  return result.result;
255
333
  }
256
334
  /**
@@ -312,4 +390,19 @@ export class PaymasterClient {
312
390
  args: [target, value, data]
313
391
  });
314
392
  }
393
+ /**
394
+ * More robust version of waitForUserOperationReceipt.
395
+ * Catches timeouts and returns a cleaner result.
396
+ */
397
+ static async waitForUserOperation(bundlerClient, hash, timeout = 60000) {
398
+ try {
399
+ return await bundlerClient.waitForUserOperationReceipt({ hash, timeout });
400
+ }
401
+ catch (error) {
402
+ if (error.name === 'TimeoutError' || error.message?.includes('timed out')) {
403
+ return { timeout: true, hash };
404
+ }
405
+ throw error;
406
+ }
407
+ }
315
408
  }
@@ -43,13 +43,24 @@ export declare function buildPaymasterData(paymasterAddress: Address, token: Add
43
43
  /**
44
44
  * Build paymasterAndData for SuperPaymaster V3.
45
45
  * Layout: [Paymaster(20)] [verGas(16)] [postGas(16)] [operator(20)] [maxRate(32)]
46
+ * Total: 104 bytes
47
+ *
48
+ * IMPORTANT: SuperPaymaster contract generates validUntil internally using:
49
+ * validUntil = cachedPrice.updatedAt + priceStalenessThreshold
50
+ * Do NOT include validUntil/validAfter in paymasterAndData!
46
51
  */
47
52
  export declare function buildSuperPaymasterData(paymasterAddress: Address, operator: Address, options?: {
48
53
  verificationGasLimit?: bigint;
49
54
  postOpGasLimit?: bigint;
55
+ maxRate?: bigint;
50
56
  }): `0x${string}`;
51
57
  /**
52
58
  * Helper to format UserOp for Alchemy/Standard Bundlers (v0.7 Decomposed)
53
59
  */
54
60
  export declare function formatUserOpV07(userOp: any): any;
55
61
  export declare function getUserOpHashV07(userOp: any, entryPoint: Address, chainId: bigint): Hex;
62
+ /**
63
+ * Tune gas limit using a dynamic nominal ceiling to satisfy Bundler efficiency (0.4)
64
+ * Target: Actual / Limit >= targetEfficiency
65
+ */
66
+ export declare function tuneGasLimit(estimate: bigint, nominalActual: bigint, targetEfficiency?: number): bigint;
@@ -1,7 +1,6 @@
1
1
  import { concat, pad, toHex, keccak256, encodeAbiParameters, toBytes } from 'viem';
2
- import { validateAddress, validateUint128 } from '@aastar/core';
3
- const DEFAULT_VERIFICATION_GAS_V4 = 80000n;
4
- const DEFAULT_POSTOP_GAS_V4 = 100000n;
2
+ const DEFAULT_VERIFICATION_GAS_V4 = 1500000n; // ~1.5M for safety
3
+ const DEFAULT_POSTOP_GAS_V4 = 300000n; // ~300k for postOp logic
5
4
  /**
6
5
  * Constructs the middleware for Paymaster V4.
7
6
  * Returns the `paymasterAndData` hex string.
@@ -32,11 +31,8 @@ export function getPaymasterV4Middleware(config) {
32
31
  */
33
32
  export function buildPaymasterData(paymasterAddress, token, options) {
34
33
  const validityWindow = options?.validityWindow ?? 3600;
35
- const verGas = options?.verificationGasLimit ?? 80000n;
34
+ const verGas = options?.verificationGasLimit ?? 200000n; // Increased for estimation
36
35
  const postGas = options?.postOpGasLimit ?? 100000n;
37
- // Hardening: uint128 bounds check
38
- validateUint128(verGas, 'verificationGasLimit');
39
- validateUint128(postGas, 'postOpGasLimit');
40
36
  const now = Math.floor(Date.now() / 1000);
41
37
  const validUntil = now + validityWindow;
42
38
  const validAfter = now - 100; // 100 seconds grace period
@@ -52,20 +48,22 @@ export function buildPaymasterData(paymasterAddress, token, options) {
52
48
  /**
53
49
  * Build paymasterAndData for SuperPaymaster V3.
54
50
  * Layout: [Paymaster(20)] [verGas(16)] [postGas(16)] [operator(20)] [maxRate(32)]
51
+ * Total: 104 bytes
52
+ *
53
+ * IMPORTANT: SuperPaymaster contract generates validUntil internally using:
54
+ * validUntil = cachedPrice.updatedAt + priceStalenessThreshold
55
+ * Do NOT include validUntil/validAfter in paymasterAndData!
55
56
  */
56
57
  export function buildSuperPaymasterData(paymasterAddress, operator, options) {
57
58
  const verGas = options?.verificationGasLimit ?? 80000n;
58
59
  const postGas = options?.postOpGasLimit ?? 100000n;
59
- // Hardening
60
- validateAddress(paymasterAddress, 'Paymaster Address');
61
- validateAddress(operator, 'Operator Address');
62
- validateUint128(verGas, 'verificationGasLimit');
63
- validateUint128(postGas, 'postOpGasLimit');
60
+ const maxRate = options?.maxRate ?? ((1n << 256n) - 1n); // Default: max uint256, no rate limit
64
61
  return concat([
65
62
  paymasterAddress,
66
63
  pad(toHex(verGas), { size: 16 }),
67
64
  pad(toHex(postGas), { size: 16 }),
68
- operator
65
+ operator,
66
+ pad(toHex(maxRate), { size: 32 }) // Optional rate commitment (rug pull protection)
69
67
  ]);
70
68
  }
71
69
  /**
@@ -77,14 +75,21 @@ export function formatUserOpV07(userOp) {
77
75
  nonce: toHex(userOp.nonce),
78
76
  callData: userOp.callData,
79
77
  preVerificationGas: toHex(userOp.preVerificationGas),
80
- signature: userOp.signature,
81
- initCode: userOp.initCode
78
+ signature: userOp.signature
82
79
  };
83
- // Extract Factory/FactoryData if present
84
- if (userOp.initCode && userOp.initCode !== '0x') {
85
- result.factory = userOp.initCode.slice(0, 42);
86
- result.factoryData = '0x' + userOp.initCode.slice(42);
80
+ // Only include factory/factoryData if account is NOT deployed (initCode not empty)
81
+ if (userOp.initCode && userOp.initCode !== '0x' && userOp.initCode.length > 2) {
82
+ result.initCode = userOp.initCode;
83
+ if (userOp.initCode.length > 42) {
84
+ result.factory = userOp.initCode.slice(0, 42);
85
+ result.factoryData = '0x' + userOp.initCode.slice(42);
86
+ }
87
+ else {
88
+ result.factory = '0x0000000000000000000000000000000000000000';
89
+ result.factoryData = '0x';
90
+ }
87
91
  }
92
+ // If account is deployed, don't include any factory fields at all
88
93
  // Unpack accountGasLimits: [verificationGasLimit(16)][callGasLimit(16)]
89
94
  if (userOp.accountGasLimits && userOp.accountGasLimits !== '0x') {
90
95
  const packed = userOp.accountGasLimits.replace('0x', '').padStart(64, '0');
@@ -122,3 +127,15 @@ export function getUserOpHashV07(userOp, entryPoint, chainId) {
122
127
  ]));
123
128
  return keccak256(encodeAbiParameters(['bytes32', 'address', 'uint256'].map(t => ({ type: t })), [hashedUserOp, entryPoint, chainId]));
124
129
  }
130
+ /**
131
+ * Tune gas limit using a dynamic nominal ceiling to satisfy Bundler efficiency (0.4)
132
+ * Target: Actual / Limit >= targetEfficiency
133
+ */
134
+ export function tuneGasLimit(estimate, nominalActual, targetEfficiency = 0.45) {
135
+ if (estimate === 0n)
136
+ return 0n;
137
+ // targetEfficiency = actual / ceiling => ceiling = actual / targetEfficiency
138
+ const ceiling = (nominalActual * 100n) / BigInt(Math.floor(targetEfficiency * 100));
139
+ // Return the more restrictive limit to ensure efficiency ratio is met
140
+ return estimate < ceiling ? estimate : ceiling;
141
+ }
@@ -1,6 +1,6 @@
1
1
  import { encodeFunctionData, parseAbi } from 'viem';
2
2
  import { PaymasterClient } from './PaymasterClient';
3
- import { validateAddress, validateAmount } from '@aastar/core';
3
+ import { tuneGasLimit } from './PaymasterUtils';
4
4
  /**
5
5
  * SuperPaymasterClient
6
6
  * High-level API for SuperPaymaster operations, including dynamic gas estimation.
@@ -11,12 +11,6 @@ export class SuperPaymasterClient {
11
11
  * Automatically handles gas estimation with a smart efficiency buffer.
12
12
  */
13
13
  static async submitGaslessTransaction(client, wallet, aaAddress, entryPoint, bundlerUrl, config) {
14
- // Validation (Phase 0 Hardening)
15
- validateAddress(config.token, 'Token Address');
16
- validateAddress(config.recipient, 'Recipient Address');
17
- validateAddress(config.operator, 'Operator Address');
18
- validateAddress(config.paymasterAddress, 'Paymaster Address');
19
- validateAmount(config.amount, 'Amount', 1n); // Must be > 0
20
14
  // 1. Prepare Calldata (Standard ERC20 Transfer)
21
15
  const callData = encodeFunctionData({
22
16
  abi: parseAbi(['function execute(address dest, uint256 value, bytes func) external']),
@@ -53,18 +47,30 @@ export class SuperPaymasterClient {
53
47
  // Safety Floor: If estimate is suspiciously low (e.g. < 50k), bump it for PM logic
54
48
  // But if we bump it too high, we hit "Efficiency too low".
55
49
  // Let's trust the bundler's estimate but add a fixed safety pad for dynamic storage
56
- const SAFETY_PAD = 20000n;
50
+ const SAFETY_PAD = 80000n;
57
51
  const tunedVGL = vgl + SAFETY_PAD;
52
+ // CRITICAL FIX: Set paymasterVerificationGasLimit for optimal efficiency
53
+ // Bundler requires efficiency ratio >= 0.4 (actual_gas_used / gas_limit >= 0.4)
54
+ // SuperPaymaster validatePaymasterUserOp uses ~110-120k gas (measured)
55
+ // Test results:
56
+ // Analysis (Jan 19 Update-Final-Final):
57
+ // Instead of fixed percentage, use "Dynamic Nominal Gas Tuning".
58
+ // SuperPaymaster validation common case is ~58k-66k. Worst case (refresh) 115k.
59
+ // Setting nominal benchmark to 60k gives Ceiling = 60k / 0.45 = 133,333.
60
+ // This satisfies 0.4 efficiency (58/133=0.43) AND execution (115 < 133).
61
+ const bundlerEstimate = est.paymasterVerificationGasLimit || 100000n;
62
+ const tunedPMVerificationGas = tuneGasLimit(bundlerEstimate, 60000n, 0.45);
58
63
  // Same for PostOp
59
64
  const tunedPostOp = est.paymasterPostOpGasLimit + 10000n;
60
- console.log(`[SuperPaymasterClient] 🔧 Tuned Limits: VGL=${tunedVGL}, PostOp=${tunedPostOp}`);
65
+ console.log(`[SuperPaymasterClient] 🔧 Tuned Limits: VGL=${tunedVGL}, PMVGL=${tunedPMVerificationGas}, PostOp=${tunedPostOp}`);
61
66
  // 4. Submit with Tuned Limits
62
67
  return PaymasterClient.submitGaslessUserOperation(client, wallet, aaAddress, entryPoint, config.paymasterAddress, config.token, bundlerUrl, callData, {
63
68
  operator: config.operator,
64
69
  verificationGasLimit: tunedVGL,
65
70
  callGasLimit: est.callGasLimit,
66
71
  preVerificationGas: est.preVerificationGas,
67
- paymasterPostOpGasLimit: tunedPostOp, // Pass specific PM limits if supported
72
+ paymasterVerificationGasLimit: tunedPMVerificationGas, // EXPLICIT PM LIMIT
73
+ paymasterPostOpGasLimit: tunedPostOp,
68
74
  autoEstimate: false, // We did it ourselves
69
75
  factory: config.factory,
70
76
  factoryData: config.factoryData
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aastar/paymaster",
3
- "version": "0.16.7",
3
+ "version": "0.16.11",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,18 +9,15 @@
9
9
  ],
10
10
  "dependencies": {
11
11
  "viem": "2.43.3",
12
- "@aastar/core": "0.16.7"
12
+ "@aastar/core": "0.16.11"
13
13
  },
14
14
  "devDependencies": {
15
- "typescript": "5.7.2"
15
+ "typescript": "5.6.3"
16
16
  },
17
- "publishConfig": {
18
- "access": "public"
19
- },
20
- "license": "MIT",
21
17
  "scripts": {
22
18
  "clean": "find src -name '*.js' -o -name '*.d.ts' -o -name '*.map' | xargs rm -f",
23
19
  "prebuild": "pnpm clean",
24
- "build": "tsc"
20
+ "build": "tsc",
21
+ "test": "vitest run"
25
22
  }
26
23
  }