@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 +41 -24
- package/dist/src/bundler-server.d.ts +18 -0
- package/dist/src/bundler-server.js +61 -0
- package/dist/src/deploy-paymaster.d.ts +14 -0
- package/dist/src/deploy-paymaster.js +64 -0
- package/package.json +14 -3
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({
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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.
|
|
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
|
},
|