@privacy-paymasters/sdk 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.
package/dist/index.js CHANGED
@@ -111,7 +111,8 @@ class UserOperationBuilder {
111
111
  }
112
112
  }
113
113
  // src/bundlerClient.ts
114
- import { http, toHex } from "viem";
114
+ import { decodeErrorResult, http, toHex } from "viem";
115
+ import { entryPoint08Abi } from "viem/account-abstraction";
115
116
  import { createBundlerClient as createViemBundlerClient } from "viem/account-abstraction";
116
117
 
117
118
  class BundlerClient {
@@ -119,7 +120,9 @@ class BundlerClient {
119
120
  client;
120
121
  constructor(bundlerUrl, entryPoint) {
121
122
  this.entryPoint = entryPoint;
122
- this.client = createViemBundlerClient({ transport: http(bundlerUrl) });
123
+ this.client = createViemBundlerClient({
124
+ transport: http(bundlerUrl)
125
+ });
123
126
  }
124
127
  async estimateUserOperationGas(op) {
125
128
  this.client.estimateUserOperationGas;
@@ -162,28 +165,42 @@ class BundlerClient {
162
165
  };
163
166
  }
164
167
  async sendUserOperation(op) {
165
- return this.client.request({
166
- method: "eth_sendUserOperation",
167
- params: [
168
- {
169
- sender: op.sender,
170
- nonce: toHex(op.nonce),
171
- callData: op.callData,
172
- callGasLimit: toHex(op.callGasLimit),
173
- verificationGasLimit: toHex(op.verificationGasLimit),
174
- preVerificationGas: toHex(op.preVerificationGas),
175
- maxFeePerGas: toHex(op.maxFeePerGas),
176
- maxPriorityFeePerGas: toHex(op.maxPriorityFeePerGas),
177
- paymaster: op.paymaster,
178
- paymasterVerificationGasLimit: op.paymasterVerificationGasLimit ? toHex(op.paymasterVerificationGasLimit) : undefined,
179
- paymasterPostOpGasLimit: op.paymasterPostOpGasLimit ? toHex(op.paymasterPostOpGasLimit) : undefined,
180
- paymasterData: op.paymasterData,
181
- signature: op.signature,
182
- eip7702Auth: op.authorization ? serializeAuth(op.authorization) : undefined
183
- },
184
- this.entryPoint
185
- ]
186
- });
168
+ try {
169
+ const _r = await this.client.request({
170
+ method: "eth_sendUserOperation",
171
+ params: [
172
+ {
173
+ sender: op.sender,
174
+ nonce: toHex(op.nonce),
175
+ callData: op.callData,
176
+ callGasLimit: toHex(op.callGasLimit),
177
+ verificationGasLimit: toHex(op.verificationGasLimit),
178
+ preVerificationGas: toHex(op.preVerificationGas),
179
+ maxFeePerGas: toHex(op.maxFeePerGas),
180
+ maxPriorityFeePerGas: toHex(op.maxPriorityFeePerGas),
181
+ paymaster: op.paymaster,
182
+ paymasterVerificationGasLimit: op.paymasterVerificationGasLimit ? toHex(op.paymasterVerificationGasLimit) : undefined,
183
+ paymasterPostOpGasLimit: op.paymasterPostOpGasLimit ? toHex(op.paymasterPostOpGasLimit) : undefined,
184
+ paymasterData: op.paymasterData,
185
+ signature: op.signature,
186
+ eip7702Auth: op.authorization ? serializeAuth(op.authorization) : undefined
187
+ },
188
+ this.entryPoint
189
+ ]
190
+ });
191
+ return _r;
192
+ } catch (error) {
193
+ console.error(error);
194
+ let _error = error;
195
+ if (_error?.data) {
196
+ const parsedError = decodeErrorResult({
197
+ abi: entryPoint08Abi,
198
+ data: _error.data
199
+ });
200
+ throw parsedError;
201
+ }
202
+ throw error;
203
+ }
187
204
  }
188
205
  async waitForUserOperationReceipt(hash) {
189
206
  return this.client.waitForUserOperationReceipt({ hash });
@@ -0,0 +1,18 @@
1
+ import type { Address, Hex } from "viem";
2
+ export interface StartServersOptions {
3
+ execRpcUrl?: string;
4
+ forkUrl?: string;
5
+ forkBlockNumber?: bigint | number;
6
+ entrypoint: Address;
7
+ executorPrivateKey?: Hex;
8
+ utilityPrivateKey?: Hex;
9
+ port?: number;
10
+ fundedPrivateKeys?: Hex[];
11
+ safeMode?: boolean;
12
+ }
13
+ export interface ServersResult {
14
+ execRpcUrl: string;
15
+ bundlerRpcUrl: string;
16
+ stop: () => Promise<void>;
17
+ }
18
+ export declare function startServers(options: StartServersOptions): Promise<ServersResult>;
@@ -0,0 +1,61 @@
1
+ // src/bundler-server.ts
2
+ import { Instance } from "prool";
3
+ import { createTestClient, http, parseEther } from "viem";
4
+ import { privateKeyToAddress } from "viem/accounts";
5
+ import { anvil } from "viem/chains";
6
+ var DEFAULT_EXECUTOR_PK = "0x4a3a02862ddcb260ed52d40ef03f8e3d78fa3d174b0ef333afdf1ffb4a648cd5";
7
+ var DEFAULT_UTILITY_PK = "0xdd4b2564c83ff7de602c39ffda1146055dc1814b07c083d7971722384f1f01a6";
8
+ async function startServers(options) {
9
+ const {
10
+ forkUrl,
11
+ forkBlockNumber,
12
+ entrypoint,
13
+ executorPrivateKey = DEFAULT_EXECUTOR_PK,
14
+ utilityPrivateKey = DEFAULT_UTILITY_PK,
15
+ fundedPrivateKeys = [],
16
+ safeMode = false,
17
+ port = 8545
18
+ } = options;
19
+ if (!options.execRpcUrl && !forkUrl)
20
+ throw new Error("Either execRpcUrl or forkUrl must be provided");
21
+ let execRpcUrl;
22
+ let stopExec;
23
+ if (options.execRpcUrl) {
24
+ execRpcUrl = options.execRpcUrl;
25
+ } else {
26
+ const execServer = Instance.anvil({
27
+ forkUrl,
28
+ forkBlockNumber,
29
+ chainId: anvil.id,
30
+ port
31
+ });
32
+ await execServer.start();
33
+ execRpcUrl = `http://localhost:${execServer.port}`;
34
+ stopExec = () => execServer.stop();
35
+ const allPks = [executorPrivateKey, utilityPrivateKey, ...fundedPrivateKeys];
36
+ const testClient = createTestClient({ chain: anvil, mode: "anvil", transport: http(execRpcUrl) });
37
+ for (const pk of allPks) {
38
+ await testClient.setBalance({ address: privateKeyToAddress(pk), value: parseEther("1000") });
39
+ }
40
+ }
41
+ const bundlerServer = Instance.alto({
42
+ rpcUrl: execRpcUrl,
43
+ entrypoints: [entrypoint],
44
+ executorPrivateKeys: [executorPrivateKey],
45
+ utilityPrivateKey,
46
+ safeMode
47
+ });
48
+ await bundlerServer.start();
49
+ const bundlerRpcUrl = `http://127.0.0.1:${bundlerServer.port}`;
50
+ return {
51
+ execRpcUrl,
52
+ bundlerRpcUrl,
53
+ stop: async () => {
54
+ await stopExec?.();
55
+ await bundlerServer.stop();
56
+ }
57
+ };
58
+ }
59
+ export {
60
+ startServers
61
+ };
@@ -0,0 +1,14 @@
1
+ import type { Hex } from "viem";
2
+ export interface DeployPaymasterOptions {
3
+ forkUrl: string;
4
+ privateKey: Hex;
5
+ deployEnv?: string;
6
+ stakeAmount?: string;
7
+ unstakeDelay?: string;
8
+ depositAmount?: string;
9
+ }
10
+ export interface DeploymentResult {
11
+ paymasterAddress: `0x${string}`;
12
+ tornadoAccountAddress: `0x${string}`;
13
+ }
14
+ export declare function deployPaymaster(options: DeployPaymasterOptions): Promise<DeploymentResult>;
@@ -0,0 +1,64 @@
1
+ // src/deploy-paymaster.ts
2
+ import { spawn } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { readFile, writeFile } from "node:fs/promises";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ function findProjectRoot(startDir) {
8
+ let dir = startDir;
9
+ while (true) {
10
+ if (existsSync(join(dir, "foundry.toml")))
11
+ return dir;
12
+ const parent = dirname(dir);
13
+ if (parent === dir)
14
+ throw new Error("Could not find foundry.toml — run from inside the privacy-paymaster project");
15
+ dir = parent;
16
+ }
17
+ }
18
+ function forge(args, env, cwd) {
19
+ return new Promise((resolve, reject) => {
20
+ console.log(`Running: forge ${args.join(" ")}`);
21
+ const proc = spawn("forge", args, { env, cwd, stdio: ["ignore", "ignore", "pipe"] });
22
+ let stderr = "";
23
+ proc.stderr.on("data", (chunk) => {
24
+ stderr += chunk.toString();
25
+ });
26
+ proc.on("close", (code) => {
27
+ if (code !== 0)
28
+ reject(new Error(`forge ${args.join(" ")} failed:
29
+ ${stderr}`));
30
+ else
31
+ resolve();
32
+ });
33
+ });
34
+ }
35
+ async function deployPaymaster(options) {
36
+ const {
37
+ forkUrl,
38
+ privateKey,
39
+ deployEnv = "anvil-test",
40
+ stakeAmount = "100000000000000000",
41
+ unstakeDelay = "3600",
42
+ depositAmount = "100000000000000000"
43
+ } = options;
44
+ const projectRoot = findProjectRoot(dirname(fileURLToPath(import.meta.url)));
45
+ const deploymentsPath = join(projectRoot, `config/deployments/${deployEnv}.json`);
46
+ await writeFile(deploymentsPath, "{}");
47
+ const env = { ...process.env, DEPLOY_ENV: deployEnv, PRIVATE_KEY: privateKey };
48
+ await forge(["script", "DeployPaymaster", "--fork-url", forkUrl, "--broadcast"], env, projectRoot);
49
+ await forge(["script", "StakePaymaster", "--fork-url", forkUrl, "--broadcast"], {
50
+ ...env,
51
+ STAKE_AMOUNT: stakeAmount,
52
+ UNSTAKE_DELAY: unstakeDelay,
53
+ DEPOSIT_AMOUNT: depositAmount
54
+ }, projectRoot);
55
+ await forge(["script", "DeployTornado", "--fork-url", forkUrl, "--broadcast"], env, projectRoot);
56
+ const deployments = JSON.parse(await readFile(deploymentsPath, "utf-8"));
57
+ return {
58
+ paymasterAddress: deployments.paymaster.address,
59
+ tornadoAccountAddress: deployments.tornado_eth_1.tornadoAccount
60
+ };
61
+ }
62
+ export {
63
+ deployPaymaster
64
+ };
package/package.json CHANGED
@@ -3,25 +3,36 @@
3
3
  "module": "dist/index.js",
4
4
  "types": "dist/index.d.ts",
5
5
  "type": "module",
6
- "version": "0.0.1",
6
+ "version": "0.0.2",
7
7
  "private": false,
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
+ },
13
+ "./bundler-server": {
14
+ "types": "./dist/src/bundler-server.d.ts",
15
+ "import": "./dist/src/bundler-server.js"
16
+ },
17
+ "./deploy-paymaster": {
18
+ "types": "./dist/src/deploy-paymaster.d.ts",
19
+ "import": "./dist/src/deploy-paymaster.js"
12
20
  }
13
21
  },
14
22
  "files": [
15
23
  "dist"
16
24
  ],
17
25
  "devDependencies": {
18
- "@types/bun": "latest"
26
+ "@types/bun": "latest",
27
+ "@types/node": "^25.8.0"
19
28
  },
20
29
  "peerDependencies": {
21
30
  "typescript": "^5.9.0"
22
31
  },
23
32
  "scripts": {
24
- "build": "bun build ./index.ts --outdir ./dist --target node --format esm --packages external && tsc -p tsconfig.build.json",
33
+ "build": "bun build ./index.ts ./src/bundler-server.ts ./src/deploy-paymaster.ts --outdir ./dist --target node --format esm --packages external && tsc -p tsconfig.build.json",
34
+ "serve-bundler": "bun scripts/start-bundler.ts",
35
+ "deploy": "bun scripts/deploy-paymaster.ts",
25
36
  "test": "bun test",
26
37
  "test:e2e": "bun test tests/e2e.test.ts"
27
38
  },