@aastar/dapp 0.16.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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/dist/core/src/abis/BLSAggregator.json +686 -0
  3. package/dist/core/src/abis/BLSValidator.json +42 -0
  4. package/dist/core/src/abis/DVTValidator.json +368 -0
  5. package/dist/core/src/abis/EntryPoint.json +1382 -0
  6. package/dist/core/src/abis/GToken.json +513 -0
  7. package/dist/core/src/abis/GTokenStaking.json +949 -0
  8. package/dist/core/src/abis/MySBT.json +1518 -0
  9. package/dist/core/src/abis/Paymaster.json +1143 -0
  10. package/dist/core/src/abis/PaymasterFactory.json +640 -0
  11. package/dist/core/src/abis/Registry.json +1942 -0
  12. package/dist/core/src/abis/ReputationSystem.json +699 -0
  13. package/dist/core/src/abis/SimpleAccount.json +560 -0
  14. package/dist/core/src/abis/SimpleAccountFactory.json +111 -0
  15. package/dist/core/src/abis/SuperPaymaster.json +1781 -0
  16. package/dist/core/src/abis/index.d.ts +1126 -0
  17. package/dist/core/src/abis/index.js +91 -0
  18. package/dist/core/src/abis/xPNTsFactory.json +718 -0
  19. package/dist/core/src/abis/xPNTsToken.json +1280 -0
  20. package/dist/core/src/actions/StateValidator.d.ts +68 -0
  21. package/dist/core/src/actions/StateValidator.js +187 -0
  22. package/dist/core/src/actions/account.d.ts +55 -0
  23. package/dist/core/src/actions/account.js +133 -0
  24. package/dist/core/src/actions/aggregator.d.ts +17 -0
  25. package/dist/core/src/actions/aggregator.js +31 -0
  26. package/dist/core/src/actions/dvt.d.ts +30 -0
  27. package/dist/core/src/actions/dvt.js +41 -0
  28. package/dist/core/src/actions/entryPoint.d.ts +90 -0
  29. package/dist/core/src/actions/entryPoint.js +211 -0
  30. package/dist/core/src/actions/factory.d.ts +215 -0
  31. package/dist/core/src/actions/factory.js +442 -0
  32. package/dist/core/src/actions/faucet.d.ts +48 -0
  33. package/dist/core/src/actions/faucet.js +337 -0
  34. package/dist/core/src/actions/gtokenExtended.d.ts +39 -0
  35. package/dist/core/src/actions/gtokenExtended.js +115 -0
  36. package/dist/core/src/actions/index.d.ts +15 -0
  37. package/dist/core/src/actions/index.js +17 -0
  38. package/dist/core/src/actions/paymasterV4.d.ts +170 -0
  39. package/dist/core/src/actions/paymasterV4.js +334 -0
  40. package/dist/core/src/actions/registry.d.ts +246 -0
  41. package/dist/core/src/actions/registry.js +667 -0
  42. package/dist/core/src/actions/reputation.d.ts +129 -0
  43. package/dist/core/src/actions/reputation.js +281 -0
  44. package/dist/core/src/actions/sbt.d.ts +191 -0
  45. package/dist/core/src/actions/sbt.js +533 -0
  46. package/dist/core/src/actions/staking.d.ts +132 -0
  47. package/dist/core/src/actions/staking.js +330 -0
  48. package/dist/core/src/actions/superPaymaster.d.ts +237 -0
  49. package/dist/core/src/actions/superPaymaster.js +644 -0
  50. package/dist/core/src/actions/tokens.d.ts +229 -0
  51. package/dist/core/src/actions/tokens.js +415 -0
  52. package/dist/core/src/branding.d.ts +30 -0
  53. package/dist/core/src/branding.js +30 -0
  54. package/dist/core/src/clients/BaseClient.d.ts +25 -0
  55. package/dist/core/src/clients/BaseClient.js +66 -0
  56. package/dist/core/src/clients/types.d.ts +60 -0
  57. package/dist/core/src/clients/types.js +1 -0
  58. package/dist/core/src/clients.d.ts +5 -0
  59. package/dist/core/src/clients.js +11 -0
  60. package/dist/core/src/communities.d.ts +52 -0
  61. package/dist/core/src/communities.js +73 -0
  62. package/dist/core/src/config/ContractConfigManager.d.ts +20 -0
  63. package/dist/core/src/config/ContractConfigManager.js +48 -0
  64. package/dist/core/src/constants.d.ts +88 -0
  65. package/dist/core/src/constants.js +125 -0
  66. package/dist/core/src/contract-addresses.d.ts +110 -0
  67. package/dist/core/src/contract-addresses.js +99 -0
  68. package/dist/core/src/contracts.d.ts +424 -0
  69. package/dist/core/src/contracts.js +343 -0
  70. package/dist/core/src/crypto/blsSigner.d.ts +64 -0
  71. package/dist/core/src/crypto/blsSigner.js +98 -0
  72. package/dist/core/src/crypto/index.d.ts +1 -0
  73. package/dist/core/src/crypto/index.js +1 -0
  74. package/dist/core/src/index.d.ts +21 -0
  75. package/dist/core/src/index.js +21 -0
  76. package/dist/core/src/networks.d.ts +127 -0
  77. package/dist/core/src/networks.js +118 -0
  78. package/dist/core/src/requirementChecker.d.ts +38 -0
  79. package/dist/core/src/requirementChecker.js +139 -0
  80. package/dist/core/src/roles.d.ts +204 -0
  81. package/dist/core/src/roles.js +211 -0
  82. package/dist/core/src/utils/validation.d.ts +24 -0
  83. package/dist/core/src/utils/validation.js +56 -0
  84. package/dist/dapp/src/index.d.ts +3 -0
  85. package/dist/dapp/src/index.js +3 -0
  86. package/dist/dapp/src/ui/components/EvaluationPanel.d.ts +11 -0
  87. package/dist/dapp/src/ui/components/EvaluationPanel.js +37 -0
  88. package/dist/dapp/src/ui/hooks/useCreditScore.d.ts +13 -0
  89. package/dist/dapp/src/ui/hooks/useCreditScore.js +32 -0
  90. package/dist/dapp/src/ui/hooks/useSuperPaymaster.d.ts +8 -0
  91. package/dist/dapp/src/ui/hooks/useSuperPaymaster.js +23 -0
  92. package/dist/dapp/src/ui/index.d.ts +4 -0
  93. package/dist/dapp/src/ui/index.js +17 -0
  94. package/dist/paymaster/src/SuperPaymaster/index.d.ts +44 -0
  95. package/dist/paymaster/src/SuperPaymaster/index.js +133 -0
  96. package/dist/paymaster/src/V4/PaymasterClient.d.ts +79 -0
  97. package/dist/paymaster/src/V4/PaymasterClient.js +315 -0
  98. package/dist/paymaster/src/V4/PaymasterOperator.d.ts +41 -0
  99. package/dist/paymaster/src/V4/PaymasterOperator.js +241 -0
  100. package/dist/paymaster/src/V4/PaymasterUtils.d.ts +55 -0
  101. package/dist/paymaster/src/V4/PaymasterUtils.js +124 -0
  102. package/dist/paymaster/src/V4/SuperPaymasterClient.d.ts +21 -0
  103. package/dist/paymaster/src/V4/SuperPaymasterClient.js +73 -0
  104. package/dist/paymaster/src/V4/index.d.ts +4 -0
  105. package/dist/paymaster/src/V4/index.js +4 -0
  106. package/dist/paymaster/src/index.d.ts +2 -0
  107. package/dist/paymaster/src/index.js +4 -0
  108. package/package.json +31 -0
@@ -0,0 +1,79 @@
1
+ import { type Address, type Hex } from 'viem';
2
+ /**
3
+ * PaymasterClient
4
+ * Focus: Integration, Funding, Interaction.
5
+ */
6
+ export declare class PaymasterClient {
7
+ /**
8
+ * Get user's deposited balance on the Paymaster.
9
+ */
10
+ static getDepositedBalance(publicClient: any, address: Address, user: Address, token: Address): Promise<bigint>;
11
+ /**
12
+ * Deposit tokens to Paymaster for a user (enables gasless transactions).
13
+ */
14
+ static depositFor(wallet: any, address: Address, user: Address, token: Address, amount: bigint): Promise<any>;
15
+ /**
16
+ * Approve the Paymaster (or any spender) to spend gas tokens.
17
+ */
18
+ static approveGasToken(wallet: any, token: Address, spender: Address, amount: bigint): Promise<any>;
19
+ /**
20
+ * Estimate Gas for a UserOperation.
21
+ */
22
+ static estimateUserOperationGas(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
23
+ validityWindow?: number;
24
+ operator?: Address;
25
+ factory?: Address;
26
+ factoryData?: Hex;
27
+ }): Promise<{
28
+ preVerificationGas: bigint;
29
+ verificationGasLimit: bigint;
30
+ callGasLimit: bigint;
31
+ paymasterVerificationGasLimit: bigint | undefined;
32
+ paymasterPostOpGasLimit: bigint;
33
+ }>;
34
+ /**
35
+ * High-level API to submit a gasless UserOperation.
36
+ * Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
37
+ */
38
+ static submitGaslessUserOperation(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
39
+ validityWindow?: number;
40
+ verificationGasLimit?: bigint;
41
+ callGasLimit?: bigint;
42
+ preVerificationGas?: bigint;
43
+ maxFeePerGas?: bigint;
44
+ maxPriorityFeePerGas?: bigint;
45
+ autoEstimate?: boolean;
46
+ operator?: Address;
47
+ paymasterVerificationGasLimit?: bigint;
48
+ paymasterPostOpGasLimit?: bigint;
49
+ factory?: Address;
50
+ factoryData?: Hex;
51
+ }): Promise<`0x${string}`>;
52
+ /**
53
+ * Helper to extract the actual Gas Token fee from a UserOperation receipt.
54
+ * Looks for the 'PostOpProcessed' event emitted by the Paymaster.
55
+ */
56
+ static getFeeFromReceipt(receipt: any, paymasterAddress: Address): {
57
+ tokenCost: bigint;
58
+ actualGasCostWei: bigint;
59
+ } | null;
60
+ /**
61
+ * Get the fee for a specific transaction hash.
62
+ * Fetches the receipt (no scanning required) and decodes the log.
63
+ */
64
+ static getTransactionFee(publicClient: any, txHash: `0x${string}`, paymasterAddress: Address): Promise<{
65
+ tokenCost: bigint;
66
+ actualGasCostWei: bigint;
67
+ } | null>;
68
+ /**
69
+ * Helper: Encode a standardized ERC-20 Transfer.
70
+ * Returns the raw function data: `transfer(to, amount)`
71
+ */
72
+ static encodeTokenTransfer(recipient: Address, amount: bigint): `0x${string}`;
73
+ /**
74
+ * Helper: Encode a SimpleAccount execution.
75
+ * Wraps the inner call into: `execute(target, value, data)`
76
+ * This is the payload signed by the user.
77
+ */
78
+ static encodeExecution(target: Address, value: bigint, data: `0x${string}`): `0x${string}`;
79
+ }
@@ -0,0 +1,315 @@
1
+ import { concat, pad, toHex, parseAbi, encodeFunctionData } from 'viem';
2
+ import { buildPaymasterData, buildSuperPaymasterData, formatUserOpV07, getUserOpHashV07 } from './PaymasterUtils';
3
+ /**
4
+ * PaymasterClient
5
+ * Focus: Integration, Funding, Interaction.
6
+ */
7
+ export class PaymasterClient {
8
+ /**
9
+ * Get user's deposited balance on the Paymaster.
10
+ */
11
+ static async getDepositedBalance(publicClient, address, user, token) {
12
+ return publicClient.readContract({
13
+ address,
14
+ abi: [{
15
+ name: 'balances',
16
+ type: 'function',
17
+ inputs: [
18
+ { name: 'user', type: 'address' },
19
+ { name: 'token', type: 'address' }
20
+ ],
21
+ outputs: [{ name: '', type: 'uint256' }],
22
+ stateMutability: 'view'
23
+ }],
24
+ functionName: 'balances',
25
+ args: [user, token]
26
+ });
27
+ }
28
+ /**
29
+ * Deposit tokens to Paymaster for a user (enables gasless transactions).
30
+ */
31
+ static async depositFor(wallet, address, user, token, amount) {
32
+ return wallet.writeContract({
33
+ address,
34
+ abi: parseAbi(['function depositFor(address user, address token, uint256 amount) external']),
35
+ functionName: 'depositFor',
36
+ args: [user, token, amount],
37
+ chain: wallet.chain
38
+ });
39
+ }
40
+ /**
41
+ * Approve the Paymaster (or any spender) to spend gas tokens.
42
+ */
43
+ static async approveGasToken(wallet, token, spender, amount) {
44
+ return wallet.writeContract({
45
+ address: token,
46
+ abi: parseAbi(['function approve(address spender, uint256 amount) external returns (bool)']),
47
+ functionName: 'approve',
48
+ args: [spender, amount],
49
+ chain: wallet.chain
50
+ });
51
+ }
52
+ /**
53
+ * Estimate Gas for a UserOperation.
54
+ */
55
+ static async estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
56
+ // 1. Construct a dummy UserOp for estimation
57
+ let paymasterAndData;
58
+ if (options?.operator) {
59
+ paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
60
+ verificationGasLimit: 300000n,
61
+ postOpGasLimit: 300000n
62
+ });
63
+ }
64
+ else {
65
+ paymasterAndData = buildPaymasterData(paymasterAddress, token, {
66
+ validityWindow: options?.validityWindow,
67
+ verificationGasLimit: 60000n, // Placeholder
68
+ postOpGasLimit: 60000n // Placeholder
69
+ });
70
+ }
71
+ // 1.5. Get dynamic gas prices from network
72
+ let maxFeePerGas = 30000000000n; // 30 Gwei default
73
+ let maxPriorityFeePerGas = 1000000000n; // 1 Gwei default
74
+ try {
75
+ const feeData = await client.estimateFeesPerGas();
76
+ maxFeePerGas = (feeData.maxFeePerGas ?? 30000000000n) * 150n / 100n; // 1.5x buffer
77
+ maxPriorityFeePerGas = (feeData.maxPriorityFeePerGas ?? 1000000000n) * 150n / 100n;
78
+ if (maxPriorityFeePerGas < 500000000n)
79
+ maxPriorityFeePerGas = 500000000n; // Min 0.5 Gwei
80
+ }
81
+ catch (e) {
82
+ // Use defaults if estimation fails
83
+ }
84
+ const partialUserOp = {
85
+ sender: aaAddress,
86
+ nonce: 0n,
87
+ initCode: (options?.factory && options?.factoryData)
88
+ ? concat([options.factory, options.factoryData])
89
+ : '0x',
90
+ callData,
91
+ accountGasLimits: concat([pad(toHex(60000n), { size: 16 }), pad(toHex(100000n), { size: 16 })]), // 60k verification, 100k call
92
+ preVerificationGas: 50000n, // 50k PVG
93
+ gasFees: concat([pad(toHex(maxPriorityFeePerGas), { size: 16 }), pad(toHex(maxFeePerGas), { size: 16 })]),
94
+ paymasterAndData,
95
+ signature: '0x'
96
+ };
97
+ // Get actual nonce
98
+ try {
99
+ const nonce = await client.readContract({
100
+ address: aaAddress,
101
+ abi: parseAbi(['function getNonce() view returns (uint256)']),
102
+ functionName: 'getNonce'
103
+ });
104
+ partialUserOp.nonce = BigInt(nonce);
105
+ }
106
+ catch (e) { }
107
+ const userOpHash = getUserOpHashV07(partialUserOp, entryPoint, BigInt(client.chain.id));
108
+ partialUserOp.signature = (await wallet.account.signMessage({ message: { raw: userOpHash } }));
109
+ const payload = {
110
+ jsonrpc: '2.0',
111
+ id: 1,
112
+ method: 'eth_estimateUserOperationGas',
113
+ params: [formatUserOpV07(partialUserOp), entryPoint]
114
+ };
115
+ const response = await fetch(bundlerUrl, {
116
+ method: 'POST',
117
+ headers: { 'Content-Type': 'application/json' },
118
+ body: JSON.stringify(payload, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
119
+ });
120
+ const result = await response.json();
121
+ if (result.error)
122
+ throw new Error(`Estimation Error: ${JSON.stringify(result.error)}`);
123
+ const data = result.result;
124
+ // Dynamic tuning based on "Efficiency Guard" formulas
125
+ return {
126
+ preVerificationGas: BigInt(data.preVerificationGas),
127
+ verificationGasLimit: BigInt(data.verificationGasLimit),
128
+ callGasLimit: (BigInt(data.callGasLimit) * 110n) / 100n, // 1.1x safety buffer
129
+ paymasterVerificationGasLimit: data.paymasterVerificationGasLimit ? BigInt(data.paymasterVerificationGasLimit) : undefined,
130
+ paymasterPostOpGasLimit: data.paymasterPostOpGasLimit ? BigInt(data.paymasterPostOpGasLimit) : 100000n
131
+ };
132
+ }
133
+ /**
134
+ * High-level API to submit a gasless UserOperation.
135
+ * Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
136
+ */
137
+ static async submitGaslessUserOperation(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
138
+ // 0. Auto-Estimate if requested or if limits missing
139
+ let gasLimits = {
140
+ preVerificationGas: options?.preVerificationGas,
141
+ verificationGasLimit: options?.verificationGasLimit,
142
+ callGasLimit: options?.callGasLimit,
143
+ paymasterVerificationGasLimit: options?.paymasterVerificationGasLimit,
144
+ paymasterPostOpGasLimit: options?.paymasterPostOpGasLimit ?? 100000n
145
+ };
146
+ if (options?.autoEstimate !== false && (!gasLimits.verificationGasLimit || !gasLimits.callGasLimit)) {
147
+ const est = await this.estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, {
148
+ validityWindow: options?.validityWindow,
149
+ operator: options?.operator,
150
+ factory: options?.factory,
151
+ factoryData: options?.factoryData
152
+ });
153
+ gasLimits.preVerificationGas = options?.preVerificationGas ?? est.preVerificationGas;
154
+ gasLimits.verificationGasLimit = options?.verificationGasLimit ?? est.verificationGasLimit;
155
+ gasLimits.callGasLimit = options?.callGasLimit ?? est.callGasLimit;
156
+ gasLimits.paymasterVerificationGasLimit = options?.paymasterVerificationGasLimit ?? est.paymasterVerificationGasLimit;
157
+ gasLimits.paymasterPostOpGasLimit = options?.paymasterPostOpGasLimit ?? est.paymasterPostOpGasLimit;
158
+ }
159
+ // 1. Get Nonce
160
+ const nonce = await client.readContract({
161
+ address: aaAddress,
162
+ abi: parseAbi(['function getNonce() view returns (uint256)']),
163
+ functionName: 'getNonce'
164
+ });
165
+ // 1.5 Get Gas Prices from Network if not provided
166
+ let maxFeePerGas = options?.maxFeePerGas;
167
+ let maxPriorityFeePerGas = options?.maxPriorityFeePerGas;
168
+ if (!maxFeePerGas || !maxPriorityFeePerGas) {
169
+ try {
170
+ const feeData = await client.estimateFeesPerGas();
171
+ // Apply 1.5x buffer for network volatility
172
+ maxFeePerGas = maxFeePerGas ?? ((feeData.maxFeePerGas ?? 30000000000n) * 150n) / 100n;
173
+ maxPriorityFeePerGas = maxPriorityFeePerGas ?? ((feeData.maxPriorityFeePerGas ?? 1000000000n) * 150n) / 100n;
174
+ if (maxPriorityFeePerGas < 500000000n) {
175
+ console.log(`[PaymasterClient] Priority Fee ${maxPriorityFeePerGas} too low, clamping to 0.5 Gwei`);
176
+ maxPriorityFeePerGas = 500000000n; // Min 0.5 Gwei
177
+ }
178
+ // Ensure MaxFee >= Priority
179
+ if (maxFeePerGas < maxPriorityFeePerGas) {
180
+ maxFeePerGas = maxPriorityFeePerGas + 1000000n; // Add small buffer
181
+ console.log(`[PaymasterClient] MaxFee bumped to accommodate Priority Fee`);
182
+ }
183
+ console.log(`[PaymasterClient] Fees Set: MaxFee=${maxFeePerGas}, Priority=${maxPriorityFeePerGas}`);
184
+ }
185
+ catch (e) {
186
+ console.log('[PaymasterClient] Fee Estimation Failed:', e);
187
+ // Fallback to safer defaults if estimation fails
188
+ maxFeePerGas = maxFeePerGas ?? 50000000000n; // 50 Gwei
189
+ maxPriorityFeePerGas = maxPriorityFeePerGas ?? 2000000000n; // 2 Gwei
190
+ }
191
+ }
192
+ // 2. Build paymasterAndData
193
+ let paymasterAndData;
194
+ if (options?.operator) {
195
+ paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
196
+ verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n,
197
+ postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
198
+ });
199
+ }
200
+ else {
201
+ paymasterAndData = buildPaymasterData(paymasterAddress, token, {
202
+ validityWindow: options?.validityWindow,
203
+ verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n, // Use tuned value
204
+ postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
205
+ });
206
+ }
207
+ // 3. Construct UserOp
208
+ const userOp = {
209
+ sender: aaAddress,
210
+ nonce: BigInt(nonce),
211
+ initCode: (options?.factory && options?.factoryData)
212
+ ? concat([options.factory, options.factoryData])
213
+ : '0x',
214
+ callData,
215
+ 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)
218
+ ]),
219
+ preVerificationGas: gasLimits.preVerificationGas ?? 50000n,
220
+ gasFees: concat([
221
+ pad(toHex(maxPriorityFeePerGas), { size: 16 }),
222
+ pad(toHex(maxFeePerGas), { size: 16 })
223
+ ]),
224
+ paymasterAndData,
225
+ signature: '0x'
226
+ };
227
+ // Debug logs (Commented out for production)
228
+ /*
229
+ console.log("DEBUG: UserOp Gas Limits:", {
230
+ accountGasLimits: userOp.accountGasLimits,
231
+ preVerificationGas: userOp.preVerificationGas,
232
+ gasFees: userOp.gasFees,
233
+ paymasterAndData: userOp.paymasterAndData
234
+ });
235
+ */
236
+ // 4. Final Hashing and Signing
237
+ const userOpHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
238
+ const signature = (await wallet.account.signMessage({ message: { raw: userOpHash } }));
239
+ userOp.signature = signature;
240
+ // 6. Submit to Bundler
241
+ const response = await fetch(bundlerUrl, {
242
+ method: 'POST',
243
+ headers: { 'Content-Type': 'application/json' },
244
+ body: JSON.stringify({
245
+ jsonrpc: '2.0',
246
+ id: 1,
247
+ method: 'eth_sendUserOperation',
248
+ params: [formatUserOpV07(userOp), entryPoint]
249
+ }, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
250
+ });
251
+ const result = await response.json();
252
+ if (result.error)
253
+ throw new Error(`Bundler Error: ${JSON.stringify(result.error)}`);
254
+ return result.result;
255
+ }
256
+ /**
257
+ * Helper to extract the actual Gas Token fee from a UserOperation receipt.
258
+ * Looks for the 'PostOpProcessed' event emitted by the Paymaster.
259
+ */
260
+ static getFeeFromReceipt(receipt, paymasterAddress) {
261
+ // Event Signature: PostOpProcessed(address indexed user, address indexed token, uint256 actualGasCostWei, uint256 tokenCost, uint256 protocolRevenue)
262
+ // Topic0: 0x62544d7f48b11c32334310ebd306b47224fca220163218d4a7264322c52ae073
263
+ const TOPIC_POST_OP = '0x62544d7f48b11c32334310ebd306b47224fca220163218d4a7264322c52ae073';
264
+ for (const log of receipt.logs) {
265
+ if (log.address.toLowerCase() === paymasterAddress.toLowerCase() && log.topics[0] === TOPIC_POST_OP) {
266
+ // Decode Data: actualGasCostWei, tokenCost, protocolRevenue (3x uint256)
267
+ // We manually decode or use viem's decodeEventLog if available.
268
+ // Here we use a lightweight manual decode for the data part (non-indexed).
269
+ // Data is 3 * 32 bytes.
270
+ const data = log.data.replace('0x', '');
271
+ if (data.length >= 192) { // 3 * 64 hex chars = 192
272
+ const actualGasCostWei = BigInt('0x' + data.slice(0, 64));
273
+ const tokenCost = BigInt('0x' + data.slice(64, 128));
274
+ // const protocolRevenue = BigInt('0x' + data.slice(128, 192));
275
+ return { tokenCost, actualGasCostWei };
276
+ }
277
+ }
278
+ }
279
+ return null;
280
+ }
281
+ /**
282
+ * Get the fee for a specific transaction hash.
283
+ * Fetches the receipt (no scanning required) and decodes the log.
284
+ */
285
+ static async getTransactionFee(publicClient, txHash, paymasterAddress) {
286
+ const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
287
+ return this.getFeeFromReceipt(receipt, paymasterAddress);
288
+ }
289
+ // ===========================================
290
+ // 🛠️ Semantic CallData Builders (For DX)
291
+ // ===========================================
292
+ /**
293
+ * Helper: Encode a standardized ERC-20 Transfer.
294
+ * Returns the raw function data: `transfer(to, amount)`
295
+ */
296
+ static encodeTokenTransfer(recipient, amount) {
297
+ return encodeFunctionData({
298
+ abi: parseAbi(['function transfer(address to, uint256 amount) external returns (bool)']),
299
+ functionName: 'transfer',
300
+ args: [recipient, amount]
301
+ });
302
+ }
303
+ /**
304
+ * Helper: Encode a SimpleAccount execution.
305
+ * Wraps the inner call into: `execute(target, value, data)`
306
+ * This is the payload signed by the user.
307
+ */
308
+ static encodeExecution(target, value, data) {
309
+ return encodeFunctionData({
310
+ abi: parseAbi(['function execute(address dest, uint256 value, bytes func) external']),
311
+ functionName: 'execute',
312
+ args: [target, value, data]
313
+ });
314
+ }
315
+ }
@@ -0,0 +1,41 @@
1
+ import { type Address } from 'viem';
2
+ import { type GaslessReadinessReport } from './PaymasterUtils';
3
+ /**
4
+ * PaymasterOperator
5
+ * Focus: Deployment, Configuration, Maintenance, Keeper Bots.
6
+ */
7
+ export declare class PaymasterOperator {
8
+ /**
9
+ * Update the cached ETH/USD price from Chainlink Oracle.
10
+ * Must be called if cachedPrice is 0 (uninitialized).
11
+ */
12
+ static updatePrice(wallet: any, address: Address): Promise<any>;
13
+ /**
14
+ * Set the token price (in 8 decimals, e.g., 1e8 = $1 USD).
15
+ */
16
+ static setTokenPrice(wallet: any, address: Address, token: Address, priceUSD: bigint): Promise<any>;
17
+ static getCachedPrice(publicClient: any, address: Address): Promise<{
18
+ price: bigint;
19
+ updatedAt: bigint;
20
+ }>;
21
+ static getTokenPrice(publicClient: any, address: Address, token: Address): Promise<bigint>;
22
+ static getDepositedBalance(publicClient: any, address: Address, user: Address, token: Address): Promise<bigint>;
23
+ static ensurePriceInitialized(wallet: any, publicClient: any, address: Address): Promise<boolean>;
24
+ static addStake(wallet: any, address: Address, amount: bigint, unstakeDelaySec: number): Promise<any>;
25
+ static addDeposit(wallet: any, address: Address, amount: bigint): Promise<any>;
26
+ static addGasToken(wallet: any, address: Address, token: Address): Promise<any>;
27
+ static removeGasToken(wallet: any, address: Address, token: Address): Promise<any>;
28
+ static setServiceFeeRate(wallet: any, address: Address, rate: bigint): Promise<any>;
29
+ static setMaxGasCostCap(wallet: any, address: Address, cap: bigint): Promise<any>;
30
+ static withdrawPNT(wallet: any, address: Address, to: Address, token: Address, amount: bigint): Promise<any>;
31
+ static checkGaslessReadiness(publicClient: any, entryPoint: Address, paymasterAddress: Address, user: Address, token: Address): Promise<GaslessReadinessReport>;
32
+ static prepareGaslessEnvironment(operatorWallet: any, publicClient: any, entryPoint: Address, paymasterAddress: Address, token: Address, options?: {
33
+ minStake?: bigint;
34
+ minDeposit?: bigint;
35
+ tokenPriceUSD?: bigint;
36
+ }): Promise<{
37
+ step: string;
38
+ hash?: string;
39
+ status: string;
40
+ }[]>;
41
+ }
@@ -0,0 +1,241 @@
1
+ import { parseAbi } from 'viem';
2
+ /**
3
+ * PaymasterOperator
4
+ * Focus: Deployment, Configuration, Maintenance, Keeper Bots.
5
+ */
6
+ export class PaymasterOperator {
7
+ /**
8
+ * Update the cached ETH/USD price from Chainlink Oracle.
9
+ * Must be called if cachedPrice is 0 (uninitialized).
10
+ */
11
+ static async updatePrice(wallet, address) {
12
+ return wallet.writeContract({
13
+ address,
14
+ abi: parseAbi(['function updatePrice() external']),
15
+ functionName: 'updatePrice',
16
+ chain: wallet.chain
17
+ });
18
+ }
19
+ /**
20
+ * Set the token price (in 8 decimals, e.g., 1e8 = $1 USD).
21
+ */
22
+ static async setTokenPrice(wallet, address, token, priceUSD) {
23
+ return wallet.writeContract({
24
+ address,
25
+ abi: parseAbi(['function setTokenPrice(address token, uint256 price) external']),
26
+ functionName: 'setTokenPrice',
27
+ args: [token, priceUSD],
28
+ chain: wallet.chain
29
+ });
30
+ }
31
+ static async getCachedPrice(publicClient, address) {
32
+ const result = await publicClient.readContract({
33
+ address,
34
+ abi: [{
35
+ name: 'cachedPrice',
36
+ type: 'function',
37
+ inputs: [],
38
+ outputs: [
39
+ { name: 'price', type: 'uint208' },
40
+ { name: 'updatedAt', type: 'uint48' }
41
+ ],
42
+ stateMutability: 'view'
43
+ }],
44
+ functionName: 'cachedPrice'
45
+ });
46
+ return { price: result[0], updatedAt: result[1] };
47
+ }
48
+ static async getTokenPrice(publicClient, address, token) {
49
+ return publicClient.readContract({
50
+ address,
51
+ abi: [{
52
+ name: 'tokenPrices',
53
+ type: 'function',
54
+ inputs: [{ name: 'token', type: 'address' }],
55
+ outputs: [{ name: '', type: 'uint256' }],
56
+ stateMutability: 'view'
57
+ }],
58
+ functionName: 'tokenPrices',
59
+ args: [token]
60
+ });
61
+ }
62
+ static async getDepositedBalance(publicClient, address, user, token) {
63
+ return publicClient.readContract({
64
+ address,
65
+ abi: [{
66
+ name: 'balances',
67
+ type: 'function',
68
+ inputs: [
69
+ { name: 'user', type: 'address' },
70
+ { name: 'token', type: 'address' }
71
+ ],
72
+ outputs: [{ name: '', type: 'uint256' }],
73
+ stateMutability: 'view'
74
+ }],
75
+ functionName: 'balances',
76
+ args: [user, token]
77
+ });
78
+ }
79
+ static async ensurePriceInitialized(wallet, publicClient, address) {
80
+ const { price } = await this.getCachedPrice(publicClient, address);
81
+ if (price === 0n) {
82
+ await this.updatePrice(wallet, address);
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ static async addStake(wallet, address, amount, unstakeDelaySec) {
88
+ return wallet.writeContract({
89
+ address,
90
+ abi: parseAbi(['function addStake(uint32 unstakeDelaySec) external payable']),
91
+ functionName: 'addStake',
92
+ args: [unstakeDelaySec],
93
+ value: amount,
94
+ chain: wallet.chain
95
+ });
96
+ }
97
+ static async addDeposit(wallet, address, amount) {
98
+ return wallet.writeContract({
99
+ address,
100
+ abi: parseAbi(['function addDeposit() external payable']),
101
+ functionName: 'addDeposit',
102
+ value: amount,
103
+ chain: wallet.chain
104
+ });
105
+ }
106
+ static async addGasToken(wallet, address, token) {
107
+ return wallet.writeContract({
108
+ address,
109
+ abi: ['function addGasToken(address token)'],
110
+ functionName: 'addGasToken',
111
+ args: [token],
112
+ chain: wallet.chain
113
+ });
114
+ }
115
+ static async removeGasToken(wallet, address, token) {
116
+ return wallet.writeContract({
117
+ address,
118
+ abi: ['function removeGasToken(address token)'],
119
+ functionName: 'removeGasToken',
120
+ args: [token],
121
+ chain: wallet.chain
122
+ });
123
+ }
124
+ static async setServiceFeeRate(wallet, address, rate) {
125
+ return wallet.writeContract({
126
+ address,
127
+ abi: ['function setServiceFeeRate(uint256 rate)'],
128
+ functionName: 'setServiceFeeRate',
129
+ args: [rate],
130
+ chain: wallet.chain
131
+ });
132
+ }
133
+ static async setMaxGasCostCap(wallet, address, cap) {
134
+ return wallet.writeContract({
135
+ address,
136
+ abi: ['function setMaxGasCostCap(uint256 cap)'],
137
+ functionName: 'setMaxGasCostCap',
138
+ args: [cap],
139
+ chain: wallet.chain
140
+ });
141
+ }
142
+ static async withdrawPNT(wallet, address, to, token, amount) {
143
+ return wallet.writeContract({
144
+ address,
145
+ abi: ['function withdrawPNT(address to, address token, uint256 amount)'],
146
+ functionName: 'withdrawPNT',
147
+ args: [to, token, amount],
148
+ chain: wallet.chain
149
+ });
150
+ }
151
+ // --- Diagnostics & Automation ---
152
+ static async checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, user, token) {
153
+ const issues = [];
154
+ // 1. EntryPoint Stake/Deposit
155
+ const depositInfo = await publicClient.readContract({
156
+ address: entryPoint,
157
+ abi: parseAbi(['function getDepositInfo(address account) external view returns (uint256 deposit, bool staked, uint256 stake, uint32 unstakeDelaySec, uint48 withdrawTime)']),
158
+ functionName: 'getDepositInfo',
159
+ args: [paymasterAddress]
160
+ });
161
+ if (depositInfo[2] < 50000000000000000n)
162
+ issues.push('Paymaster stake in EntryPoint is less than 0.05 ETH');
163
+ if (depositInfo[3] < 86400)
164
+ issues.push('Paymaster unstake delay is less than 1 day');
165
+ if (depositInfo[0] < 100000000000000000n)
166
+ issues.push('Paymaster deposit in EntryPoint is less than 0.1 ETH');
167
+ // 2. Oracle Price
168
+ const ethPrice = await publicClient.readContract({
169
+ address: paymasterAddress,
170
+ abi: parseAbi(['function cachedPrice() external view returns (uint208 price, uint48 updatedAt)']),
171
+ functionName: 'cachedPrice'
172
+ }).catch(() => [0n, 0n]);
173
+ if (ethPrice[0] === 0n)
174
+ issues.push('Paymaster ETH/USD price not initialized');
175
+ // 3. Token Support & Price
176
+ const [tokenPrice, userTokenBal, userPMDeposit] = await Promise.all([
177
+ this.getTokenPrice(publicClient, paymasterAddress, token),
178
+ publicClient.readContract({
179
+ address: token,
180
+ abi: parseAbi(['function balanceOf(address account) external view returns (uint256)']),
181
+ functionName: 'balanceOf',
182
+ args: [user]
183
+ }),
184
+ this.getDepositedBalance(publicClient, paymasterAddress, user, token)
185
+ ]);
186
+ if (tokenPrice === 0n)
187
+ issues.push('Token price not set in Paymaster');
188
+ if (userPMDeposit === 0n)
189
+ issues.push('User has no deposit in Paymaster');
190
+ return {
191
+ isReady: issues.length === 0,
192
+ issues,
193
+ details: {
194
+ paymasterStake: depositInfo[2],
195
+ paymasterDeposit: depositInfo[0],
196
+ ethUsdPrice: ethPrice.price,
197
+ tokenSupported: true,
198
+ tokenPrice: tokenPrice,
199
+ userTokenBalance: userTokenBal,
200
+ userPaymasterDeposit: userPMDeposit
201
+ }
202
+ };
203
+ }
204
+ static async prepareGaslessEnvironment(operatorWallet, publicClient, entryPoint, paymasterAddress, token, options = {}) {
205
+ const report = await this.checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, operatorWallet.account.address, token);
206
+ const results = [];
207
+ // 1. Stake
208
+ if (report.details.paymasterStake < (options.minStake || 50000000000000000n)) {
209
+ const hash = await this.addStake(operatorWallet, paymasterAddress, options.minStake || 50000000000000000n, 86400);
210
+ await publicClient.waitForTransactionReceipt({ hash });
211
+ results.push({ step: 'Stake', hash, status: 'Confirmed' });
212
+ }
213
+ // 2. Deposit (EntryPoint)
214
+ if (report.details.paymasterDeposit < (options.minDeposit || 100000000000000000n)) {
215
+ const hash = await this.addDeposit(operatorWallet, paymasterAddress, options.minDeposit || 300000000000000000n);
216
+ await publicClient.waitForTransactionReceipt({ hash });
217
+ results.push({ step: 'Deposit', hash, status: 'Confirmed' });
218
+ }
219
+ // 3. Oracle Price
220
+ if (report.details.ethUsdPrice === 0n) {
221
+ const hash = await this.updatePrice(operatorWallet, paymasterAddress);
222
+ await publicClient.waitForTransactionReceipt({ hash });
223
+ results.push({ step: 'OraclePrice', hash, status: 'Confirmed' });
224
+ }
225
+ // 4. Token Support & Price
226
+ if (report.details.tokenPrice === 0n) {
227
+ try {
228
+ const hash = await this.addGasToken(operatorWallet, paymasterAddress, token);
229
+ await publicClient.waitForTransactionReceipt({ hash });
230
+ results.push({ step: 'AddGasToken', hash, status: 'Confirmed' });
231
+ }
232
+ catch (e) { }
233
+ if (options.tokenPriceUSD) {
234
+ const hash = await this.setTokenPrice(operatorWallet, paymasterAddress, token, options.tokenPriceUSD);
235
+ await publicClient.waitForTransactionReceipt({ hash });
236
+ results.push({ step: 'TokenPrice', hash, status: 'Confirmed' });
237
+ }
238
+ }
239
+ return results;
240
+ }
241
+ }