-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathBundler.error-mapping.test.js
More file actions
142 lines (129 loc) · 4.69 KB
/
Copy pathBundler.error-mapping.test.js
File metadata and controls
142 lines (129 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Unit tests for the BundlerErrorCodeDict translation that moved out of
// sendJsonRpcRequest into the Bundler class. Uses a mock Transport.
const ak = require("../../dist/index.cjs");
describe("Bundler error mapping (moved from sendJsonRpcRequest)", () => {
function rpcError(code, message) {
const err = new Error(message);
err.code = code;
err.name = "TransportRpcError";
return err;
}
function mockTransportThatThrows(err) {
return { request: async () => { throw err; } };
}
test("constructor wraps a URL in HttpTransport", () => {
const b = new ak.Bundler("https://example.test/rpc");
expect(ak.isHttpTransport(b.transport)).toBe(true);
});
test("from() returns same instance for existing Bundler", () => {
const b = new ak.Bundler("https://example.test/rpc");
expect(ak.Bundler.from(b)).toBe(b);
});
test("-32500 → outer BUNDLER_ERROR, inner SIMULATE_VALIDATION", async () => {
const t = mockTransportThatThrows(rpcError(-32500, "simulate validation failed"));
const b = new ak.Bundler(t);
try {
await b.chainId();
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.errno).toBe(-32500);
expect(err.cause).toBeDefined();
expect(err.cause.code).toBe("SIMULATE_VALIDATION");
expect(err.cause.errno).toBe(-32500);
}
});
test("-32601 → inner METHOD_NOT_FOUND (standard JSON-RPC meaning; an invalid userOpHash arrives as -32602 per bundler behavior, e.g. Voltaire)", async () => {
const t = mockTransportThatThrows(rpcError(-32601, "method not found"));
for (const call of [
(b) => b.getUserOperationReceipt("0xabc"),
(b) => b.chainId(),
]) {
const b = new ak.Bundler(t);
try {
await call(b);
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("METHOD_NOT_FOUND");
}
}
});
test("-32508 → inner PAYMASTER_DEPOSIT_TOO_LOW (ERC-7769; raised by Voltaire's mempool)", async () => {
const t = mockTransportThatThrows(
rpcError(-32508, "paymaster deposit too low for all mempool UserOperations"),
);
const b = new ak.Bundler(t);
try {
await b.chainId();
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("PAYMASTER_DEPOSIT_TOO_LOW");
expect(err.cause.errno).toBe(-32508);
}
});
test("-32603 → inner INTERNAL_ERROR (standard JSON-RPC meaning; bundler internal failure)", async () => {
const t = mockTransportThatThrows(rpcError(-32603, "unexpected internal error"));
const b = new ak.Bundler(t);
try {
await b.chainId();
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("INTERNAL_ERROR");
}
});
test("-32602 → inner INVALID_FIELDS (how an invalid userOpHash actually surfaces)", async () => {
const t = mockTransportThatThrows(rpcError(-32602, "Missing/invalid userOpHash"));
const b = new ak.Bundler(t);
try {
await b.getUserOperationReceipt("0xnothex");
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("INVALID_FIELDS");
}
});
test("unknown JSON-RPC code → outer BUNDLER_ERROR, inner UNKNOWN_ERROR", async () => {
const t = mockTransportThatThrows(rpcError(-99999, "wat"));
const b = new ak.Bundler(t);
try {
await b.chainId();
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("UNKNOWN_ERROR");
expect(err.cause.errno).toBe(-99999);
}
});
test("each Bundler method goes through the same translation (sample)", async () => {
const methods = [
() => b.chainId(),
() => b.supportedEntryPoints(),
() =>
b.estimateUserOperationGas(
{ sender: "0x0", nonce: 0n, callData: "0x", initCode: "0x", callGasLimit: 0n, verificationGasLimit: 0n, preVerificationGas: 0n, maxFeePerGas: 0n, maxPriorityFeePerGas: 0n, paymasterAndData: "0x", signature: "0x" },
"0x0",
),
() =>
b.sendUserOperation(
{ sender: "0x0", nonce: 0n, callData: "0x", initCode: "0x", callGasLimit: 0n, verificationGasLimit: 0n, preVerificationGas: 0n, maxFeePerGas: 0n, maxPriorityFeePerGas: 0n, paymasterAndData: "0x", signature: "0x" },
"0x0",
),
() => b.getUserOperationReceipt("0xhash"),
() => b.getUserOperationByHash("0xhash"),
];
const t = mockTransportThatThrows(rpcError(-32500, "test"));
const b = new ak.Bundler(t);
for (const m of methods) {
try {
await m();
throw new Error("expected throw");
} catch (err) {
expect(err.code).toBe("BUNDLER_ERROR");
expect(err.cause.code).toBe("SIMULATE_VALIDATION");
}
}
});
});