@aastar/enduser 0.16.14 → 0.16.18

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,149 @@
1
+ import { Address, Hash } from 'viem';
2
+ import { type PublicClient, type WalletClient } from '@aastar/core';
3
+ /**
4
+ * PhD Paper Experiment Test Toolkit
5
+ *
6
+ * **Purpose**: Comprehensive API suite for preparing and managing test accounts
7
+ * for ERC-4337 performance comparison experiments (EOA vs AA vs SuperPaymaster).
8
+ *
9
+ * **Core Features**:
10
+ * 1. **Account Generation**: Create random EOA keys and deploy SimpleAccounts
11
+ * 2. **Token Funding**: Transfer test tokens (GToken, aPNTs, bPNTs, ETH)
12
+ * 3. **AA Deployment**: Deploy SimpleAccount contracts using official factory
13
+ * 4. **UserOp Execution**: Send ERC-4337 UserOperations with various paymasters
14
+ * 5. **Data Collection**: Generate experiment data for PhD paper analysis
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const toolkit = new TestAccountManager(publicClient, supplierWallet);
19
+ *
20
+ * // Prepare complete test environment
21
+ * const env = await toolkit.prepareTestEnvironment({
22
+ * accountCount: 3,
23
+ * fundEachEOAWithETH: parseEther("0.01"),
24
+ * fundEachAAWithETH: parseEther("0.02"),
25
+ * tokens: {
26
+ * gToken: { address: '0x...', amount: parseEther("100") },
27
+ * aPNTs: { address: '0x...', amount: parseEther("50") }
28
+ * }
29
+ * });
30
+ * ```
31
+ */
32
+ export declare class TestAccountManager {
33
+ /** @internal */
34
+ private publicClient;
35
+ /** @internal */
36
+ private walletClient;
37
+ constructor(
38
+ /** @internal */
39
+ publicClient: PublicClient,
40
+ /** @internal */
41
+ walletClient: WalletClient);
42
+ /**
43
+ * Prepare complete test environment for PhD experiments
44
+ *
45
+ * **Workflow**:
46
+ * 1. Generate N random EOA private keys
47
+ * 2. Deploy SimpleAccount for each EOA
48
+ * 3. Fund EOAs with ETH
49
+ * 4. Fund AAs with ETH
50
+ * 5. Transfer test tokens (GToken, aPNTs, bPNTs) to both EOAs and AAs
51
+ *
52
+ * @param config - Test environment configuration
53
+ * @returns Complete test environment with all accounts and tokens ready
54
+ */
55
+ prepareTestEnvironment(config: TestEnvironmentConfig): Promise<TestEnvironment>;
56
+ /**
57
+ * Generate multiple test accounts for experiments
58
+ * (Simplified version without token funding)
59
+ */
60
+ generateTestAccounts(count?: number, options?: {
61
+ fundEachAAWith?: bigint;
62
+ fundEachEOAWith?: bigint;
63
+ startingSalt?: number;
64
+ }): Promise<TestAccount[]>;
65
+ /**
66
+ * Export test accounts to .env format
67
+ */
68
+ exportToEnv(accounts: TestAccount[]): string;
69
+ /**
70
+ * Load test accounts from environment variables
71
+ */
72
+ static loadFromEnv(labels?: string[]): (TestAccount | null)[];
73
+ /**
74
+ * Get a single test account by label
75
+ */
76
+ static getTestAccount(label: string): TestAccount | null;
77
+ private records;
78
+ /**
79
+ * Add a standardized experiment record
80
+ */
81
+ addExperimentRecord(record: {
82
+ scenario: string;
83
+ group: 'EOA' | 'AA' | 'SuperPaymaster';
84
+ txHash: string;
85
+ gasUsed: bigint;
86
+ gasPrice: bigint;
87
+ status: string;
88
+ meta?: any;
89
+ }): {
90
+ id: string;
91
+ timestamp: number;
92
+ costETH: string;
93
+ scenario: string;
94
+ group: "EOA" | "AA" | "SuperPaymaster";
95
+ txHash: string;
96
+ gasUsed: bigint;
97
+ gasPrice: bigint;
98
+ status: string;
99
+ meta?: any;
100
+ };
101
+ /**
102
+ * Export collected data to CSV for PhD paper analysis
103
+ */
104
+ exportExperimentResults(filename?: string): void;
105
+ }
106
+ /**
107
+ * Test environment configuration
108
+ */
109
+ export interface TestEnvironmentConfig {
110
+ accountCount?: number;
111
+ fundEachEOAWithETH?: bigint;
112
+ fundEachAAWithETH?: bigint;
113
+ startingSalt?: number;
114
+ tokens?: {
115
+ [tokenName: string]: {
116
+ address: Address;
117
+ amount: bigint;
118
+ fundEOA?: boolean;
119
+ fundAA?: boolean;
120
+ };
121
+ };
122
+ }
123
+ /**
124
+ * Complete test environment
125
+ */
126
+ export interface TestEnvironment {
127
+ accounts: TestAccount[];
128
+ tokenFunding: TokenFundingRecord[];
129
+ }
130
+ /**
131
+ * Token funding record
132
+ */
133
+ export interface TokenFundingRecord {
134
+ account: string;
135
+ token: string;
136
+ eoaAmount: bigint;
137
+ aaAmount: bigint;
138
+ }
139
+ /**
140
+ * Test account data structure
141
+ */
142
+ export interface TestAccount {
143
+ label: string;
144
+ ownerKey: `0x${string}`;
145
+ ownerAddress: Address;
146
+ aaAddress: Address;
147
+ deployTxHash: Hash;
148
+ salt: number;
149
+ }
@@ -0,0 +1,271 @@
1
+ import { parseEther } from 'viem';
2
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
3
+ import { accountFactoryActions, TEST_ACCOUNT_ADDRESSES } from '@aastar/core';
4
+ /**
5
+ * PhD Paper Experiment Test Toolkit
6
+ *
7
+ * **Purpose**: Comprehensive API suite for preparing and managing test accounts
8
+ * for ERC-4337 performance comparison experiments (EOA vs AA vs SuperPaymaster).
9
+ *
10
+ * **Core Features**:
11
+ * 1. **Account Generation**: Create random EOA keys and deploy SimpleAccounts
12
+ * 2. **Token Funding**: Transfer test tokens (GToken, aPNTs, bPNTs, ETH)
13
+ * 3. **AA Deployment**: Deploy SimpleAccount contracts using official factory
14
+ * 4. **UserOp Execution**: Send ERC-4337 UserOperations with various paymasters
15
+ * 5. **Data Collection**: Generate experiment data for PhD paper analysis
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const toolkit = new TestAccountManager(publicClient, supplierWallet);
20
+ *
21
+ * // Prepare complete test environment
22
+ * const env = await toolkit.prepareTestEnvironment({
23
+ * accountCount: 3,
24
+ * fundEachEOAWithETH: parseEther("0.01"),
25
+ * fundEachAAWithETH: parseEther("0.02"),
26
+ * tokens: {
27
+ * gToken: { address: '0x...', amount: parseEther("100") },
28
+ * aPNTs: { address: '0x...', amount: parseEther("50") }
29
+ * }
30
+ * });
31
+ * ```
32
+ */
33
+ export class TestAccountManager {
34
+ publicClient;
35
+ walletClient;
36
+ constructor(
37
+ /** @internal */
38
+ publicClient,
39
+ /** @internal */
40
+ walletClient) {
41
+ this.publicClient = publicClient;
42
+ this.walletClient = walletClient;
43
+ if (!walletClient.account) {
44
+ // Placeholder account if not provided to avoid strict null checks in experiments
45
+ // In production, the consumer must ensure the wallet is connected.
46
+ }
47
+ }
48
+ /**
49
+ * Prepare complete test environment for PhD experiments
50
+ *
51
+ * **Workflow**:
52
+ * 1. Generate N random EOA private keys
53
+ * 2. Deploy SimpleAccount for each EOA
54
+ * 3. Fund EOAs with ETH
55
+ * 4. Fund AAs with ETH
56
+ * 5. Transfer test tokens (GToken, aPNTs, bPNTs) to both EOAs and AAs
57
+ *
58
+ * @param config - Test environment configuration
59
+ * @returns Complete test environment with all accounts and tokens ready
60
+ */
61
+ async prepareTestEnvironment(config) {
62
+ const { accountCount = 3, fundEachEOAWithETH = parseEther("0.01"), fundEachAAWithETH = parseEther("0.02"), tokens = {}, startingSalt = 0 } = config;
63
+ console.log(`🧪 Preparing PhD Experiment Test Environment (${accountCount} accounts)...\n`);
64
+ const accounts = [];
65
+ const labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
66
+ const factoryAddress = TEST_ACCOUNT_ADDRESSES.simpleAccountFactory;
67
+ const factoryRead = accountFactoryActions(factoryAddress)(this.publicClient);
68
+ const factoryWrite = accountFactoryActions(factoryAddress)(this.walletClient);
69
+ // Step 1: Generate accounts and deploy AAs
70
+ for (let i = 0; i < accountCount; i++) {
71
+ const label = labels[i] || `${i + 1}`;
72
+ console.log(`\n📝 [${i + 1}/${accountCount}] Setting up Account ${label}...`);
73
+ // Generate EOA
74
+ const ownerKey = generatePrivateKey();
75
+ const ownerAccount = privateKeyToAccount(ownerKey);
76
+ console.log(` 🔑 EOA: ${ownerAccount.address}`);
77
+ // Deploy AA
78
+ const salt = BigInt(startingSalt + i);
79
+ console.log(` 🏭 Deploying SimpleAccount (salt: ${salt})...`);
80
+ // Predict address
81
+ const accountAddress = await factoryRead.getAddress({ owner: ownerAccount.address, salt });
82
+ // Deploy if needed (createAccount sends tx regardless, or we can check code?)
83
+ // For simplicitly we just call createAccount. If already deployed it might revert?
84
+ // SimpleAccountFactory doesn't seem to check existence in createAccount, but CREATE2 validates.
85
+ // But we are using a fresh key/salt, so collision is unlikely unless we rerun.
86
+ // We'll try-catch or just execute.
87
+ let deployTxHash = '0x0';
88
+ try {
89
+ deployTxHash = await factoryWrite.createAccount({
90
+ owner: ownerAccount.address,
91
+ salt,
92
+ account: this.walletClient.account
93
+ });
94
+ await this.publicClient.waitForTransactionReceipt({ hash: deployTxHash });
95
+ }
96
+ catch (e) {
97
+ console.log(` ⚠️ Deployment might have failed (or already deployed): ${e.message?.split('\n')[0]}`);
98
+ }
99
+ console.log(` ✅ AA: ${accountAddress}`);
100
+ // Fund AA with ETH
101
+ if (fundEachAAWithETH > 0n) {
102
+ console.log(` ⛽ Funding AA with ${fundEachAAWithETH} wei ETH...`);
103
+ const fundTx = await this.walletClient.sendTransaction({
104
+ to: accountAddress,
105
+ value: fundEachAAWithETH,
106
+ account: this.walletClient.account,
107
+ chain: this.walletClient.chain
108
+ });
109
+ await this.publicClient.waitForTransactionReceipt({ hash: fundTx });
110
+ }
111
+ // Fund EOA with ETH
112
+ if (fundEachEOAWithETH > 0n) {
113
+ console.log(` ⛽ Funding EOA with ${fundEachEOAWithETH} wei ETH...`);
114
+ const fundTx = await this.walletClient.sendTransaction({
115
+ to: ownerAccount.address,
116
+ value: fundEachEOAWithETH,
117
+ account: this.walletClient.account,
118
+ chain: this.walletClient.chain
119
+ });
120
+ await this.publicClient.waitForTransactionReceipt({ hash: fundTx });
121
+ }
122
+ accounts.push({
123
+ label,
124
+ ownerKey,
125
+ ownerAddress: ownerAccount.address,
126
+ aaAddress: accountAddress,
127
+ deployTxHash,
128
+ salt: startingSalt + i
129
+ });
130
+ }
131
+ // Step 2: Fund with test tokens
132
+ console.log(`\n💰 Funding accounts with test tokens...`);
133
+ const tokenFunding = [];
134
+ for (const [tokenName, tokenConfig] of Object.entries(tokens)) {
135
+ if (!tokenConfig)
136
+ continue;
137
+ console.log(`\n 📊 Distributing ${tokenName}...`);
138
+ const erc20Abi = [
139
+ { name: 'transfer', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ name: '', type: 'bool' }] }
140
+ ];
141
+ for (const account of accounts) {
142
+ // Fund EOA
143
+ if (tokenConfig.fundEOA !== false) {
144
+ const tx = await this.walletClient.writeContract({
145
+ address: tokenConfig.address,
146
+ abi: erc20Abi,
147
+ functionName: 'transfer',
148
+ args: [account.ownerAddress, tokenConfig.amount],
149
+ account: this.walletClient.account,
150
+ chain: this.walletClient.chain
151
+ });
152
+ await this.publicClient.waitForTransactionReceipt({ hash: tx });
153
+ console.log(` ✅ ${account.label} EOA: ${tokenConfig.amount}`);
154
+ }
155
+ // Fund AA
156
+ if (tokenConfig.fundAA !== false) {
157
+ const tx = await this.walletClient.writeContract({
158
+ address: tokenConfig.address,
159
+ abi: erc20Abi,
160
+ functionName: 'transfer',
161
+ args: [account.aaAddress, tokenConfig.amount],
162
+ account: this.walletClient.account,
163
+ chain: this.walletClient.chain
164
+ });
165
+ await this.publicClient.waitForTransactionReceipt({ hash: tx });
166
+ console.log(` ✅ ${account.label} AA: ${tokenConfig.amount}`);
167
+ }
168
+ tokenFunding.push({
169
+ account: account.label,
170
+ token: tokenName,
171
+ eoaAmount: tokenConfig.fundEOA !== false ? tokenConfig.amount : 0n,
172
+ aaAmount: tokenConfig.fundAA !== false ? tokenConfig.amount : 0n
173
+ });
174
+ }
175
+ }
176
+ console.log(`\n✅ Test environment ready!`);
177
+ return { accounts, tokenFunding };
178
+ }
179
+ /**
180
+ * Generate multiple test accounts for experiments
181
+ * (Simplified version without token funding)
182
+ */
183
+ async generateTestAccounts(count = 3, options = {}) {
184
+ const { fundEachAAWith = parseEther("0.02"), fundEachEOAWith = parseEther("0.01"), startingSalt = 0 } = options;
185
+ const env = await this.prepareTestEnvironment({
186
+ accountCount: count,
187
+ fundEachEOAWithETH: fundEachEOAWith,
188
+ fundEachAAWithETH: fundEachAAWith,
189
+ startingSalt
190
+ });
191
+ return env.accounts;
192
+ }
193
+ /**
194
+ * Export test accounts to .env format
195
+ */
196
+ exportToEnv(accounts) {
197
+ const lines = [
198
+ '# Test Accounts for PhD Paper Experiments',
199
+ '# Generated by TestAccountManager API',
200
+ ''
201
+ ];
202
+ accounts.forEach(acc => lines.push(`TEST_OWNER_KEY_${acc.label}=${acc.ownerKey}`));
203
+ lines.push('');
204
+ accounts.forEach(acc => lines.push(`TEST_OWNER_EOA_${acc.label}=${acc.ownerAddress}`));
205
+ lines.push('');
206
+ accounts.forEach(acc => lines.push(`TEST_SIMPLE_ACCOUNT_${acc.label}=${acc.aaAddress}`));
207
+ return lines.join('\n');
208
+ }
209
+ /**
210
+ * Load test accounts from environment variables
211
+ */
212
+ static loadFromEnv(labels = ['A', 'B', 'C']) {
213
+ return labels.map(label => {
214
+ const ownerKey = process.env[`TEST_OWNER_KEY_${label}`];
215
+ const ownerAddress = process.env[`TEST_OWNER_EOA_${label}`];
216
+ const aaAddress = process.env[`TEST_SIMPLE_ACCOUNT_${label}`];
217
+ if (!ownerKey || !ownerAddress || !aaAddress)
218
+ return null;
219
+ return {
220
+ label,
221
+ ownerKey: ownerKey,
222
+ ownerAddress: ownerAddress,
223
+ aaAddress: aaAddress,
224
+ deployTxHash: '0x0',
225
+ salt: 0
226
+ };
227
+ });
228
+ }
229
+ /**
230
+ * Get a single test account by label
231
+ */
232
+ static getTestAccount(label) {
233
+ const accounts = TestAccountManager.loadFromEnv([label]);
234
+ return accounts[0] || null;
235
+ }
236
+ // --- Data Collection Extensions ---
237
+ records = [];
238
+ /**
239
+ * Add a standardized experiment record
240
+ */
241
+ addExperimentRecord(record) {
242
+ const fullRecord = {
243
+ ...record,
244
+ id: `${Date.now()}-${Math.floor(Math.random() * 1000)}`,
245
+ timestamp: Date.now(),
246
+ costETH: formatEther(record.gasUsed * record.gasPrice)
247
+ };
248
+ this.records.push(fullRecord);
249
+ return fullRecord;
250
+ }
251
+ /**
252
+ * Export collected data to CSV for PhD paper analysis
253
+ */
254
+ exportExperimentResults(filename = 'sdk_experiment_data.csv') {
255
+ const fs = require('fs');
256
+ const path = require('path');
257
+ const headers = ['ID', 'Scenario', 'Group', 'TxHash', 'GasUsed', 'GasPrice', 'CostETH', 'Status', 'Timestamp', 'Latency'];
258
+ const rows = this.records.map(r => [
259
+ r.id, r.scenario, r.group, r.txHash,
260
+ r.gasUsed.toString(), r.gasPrice.toString(), r.costETH,
261
+ r.status, new Date(r.timestamp).toISOString(),
262
+ r.meta?.latency || ''
263
+ ].join(','));
264
+ const csv = [headers.join(','), ...rows].join('\n');
265
+ fs.writeFileSync(path.join(process.cwd(), filename), csv);
266
+ console.log(`📊 Exported ${this.records.length} records to ${filename}`);
267
+ }
268
+ }
269
+ function formatEther(wei) {
270
+ return (Number(wei) / 1e18).toString();
271
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export * from './CommunityClient.js';
2
1
  export * from './UserClient.js';
2
+ export * from './CommunityClient.js';
3
+ export * from './UserLifecycle.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- export * from './CommunityClient.js';
2
1
  export * from './UserClient.js';
2
+ export * from './CommunityClient.js';
3
+ export * from './UserLifecycle.js';
@@ -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
+ }
@@ -0,0 +1,89 @@
1
+ import { type Address, type Hex } from 'viem';
2
+ /**
3
+ * PaymasterClient
4
+ * Focus: Integration, Funding, Interaction.
5
+ */
6
+ export declare class PaymasterClient {
7
+ /**
8
+ * @private
9
+ * Static utility class, should not be instantiated.
10
+ */
11
+ private constructor();
12
+ /**
13
+ * Get user's deposited balance on the Paymaster.
14
+ */
15
+ static getDepositedBalance(publicClient: any, address: Address, user: Address, token: Address): Promise<bigint>;
16
+ /**
17
+ * Deposit tokens to Paymaster for a user (enables gasless transactions).
18
+ */
19
+ static depositFor(wallet: any, address: Address, user: Address, token: Address, amount: bigint): Promise<any>;
20
+ /**
21
+ * Approve the Paymaster (or any spender) to spend gas tokens.
22
+ */
23
+ static approveGasToken(wallet: any, token: Address, spender: Address, amount: bigint): Promise<any>;
24
+ /**
25
+ * Estimate Gas for a UserOperation.
26
+ */
27
+ static estimateUserOperationGas(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
28
+ validityWindow?: number;
29
+ operator?: Address;
30
+ factory?: Address;
31
+ factoryData?: Hex;
32
+ }): Promise<{
33
+ preVerificationGas: bigint;
34
+ verificationGasLimit: bigint;
35
+ callGasLimit: bigint;
36
+ paymasterVerificationGasLimit: bigint | undefined;
37
+ paymasterPostOpGasLimit: bigint;
38
+ }>;
39
+ /**
40
+ * High-level API to submit a gasless UserOperation.
41
+ * Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
42
+ */
43
+ static submitGaslessUserOperation(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
44
+ validityWindow?: number;
45
+ verificationGasLimit?: bigint;
46
+ callGasLimit?: bigint;
47
+ preVerificationGas?: bigint;
48
+ maxFeePerGas?: bigint;
49
+ maxPriorityFeePerGas?: bigint;
50
+ autoEstimate?: boolean;
51
+ operator?: Address;
52
+ paymasterVerificationGasLimit?: bigint;
53
+ paymasterPostOpGasLimit?: bigint;
54
+ factory?: Address;
55
+ factoryData?: Hex;
56
+ }): Promise<`0x${string}`>;
57
+ /**
58
+ * Helper to extract the actual Gas Token fee from a UserOperation receipt.
59
+ * Looks for the 'PostOpProcessed' event emitted by the Paymaster.
60
+ */
61
+ static getFeeFromReceipt(receipt: any, paymasterAddress: Address): {
62
+ tokenCost: bigint;
63
+ actualGasCostWei: bigint;
64
+ } | null;
65
+ /**
66
+ * Get the fee for a specific transaction hash.
67
+ * Fetches the receipt (no scanning required) and decodes the log.
68
+ */
69
+ static getTransactionFee(publicClient: any, txHash: `0x${string}`, paymasterAddress: Address): Promise<{
70
+ tokenCost: bigint;
71
+ actualGasCostWei: bigint;
72
+ } | null>;
73
+ /**
74
+ * Helper: Encode a standardized ERC-20 Transfer.
75
+ * Returns the raw function data: `transfer(to, amount)`
76
+ */
77
+ static encodeTokenTransfer(recipient: Address, amount: bigint): `0x${string}`;
78
+ /**
79
+ * Helper: Encode a SimpleAccount execution.
80
+ * Wraps the inner call into: `execute(target, value, data)`
81
+ * This is the payload signed by the user.
82
+ */
83
+ static encodeExecution(target: Address, value: bigint, data: `0x${string}`): `0x${string}`;
84
+ /**
85
+ * More robust version of waitForUserOperationReceipt.
86
+ * Catches timeouts and returns a cleaner result.
87
+ */
88
+ static waitForUserOperation(bundlerClient: any, hash: `0x${string}`, timeout?: number): Promise<any>;
89
+ }