Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cuddly-cycles-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hardhat": patch
---

Fixed bug to preserve revert data in JSON-RPC responses for non-ProviderErrors ([8061](https://github.com/NomicFoundation/hardhat/pull/8061)).
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ const _readWsRequest = (msg: string): JsonRpcRequest | JsonRpcRequest[] => {
};

const _handleError = (error: Error): JsonRpcResponse => {
// Extract revert data from the original error before potentially wrapping it.
// Non-ProviderError errors (e.g. SolidityError) carry .data and .transactionHash
// that would be lost when wrapped in InternalError below.
const txHash = extractTxHash(error);
const returnData = extractReturnData(error);

// In case of non-hardhat error, treat it as internal and associate the appropriate error code.
if (!ProviderError.isProviderError(error)) {
error = new InternalError(undefined, error);
Expand All @@ -266,8 +272,8 @@ const _handleError = (error: Error): JsonRpcResponse => {
message: error.message,
data: {
message: error.message,
txHash: extractTxHash(error),
data: extractReturnData(error),
txHash,
data: returnData,
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ describe("JSON-RPC handler", async function () {
};
throw err;
},
nonProviderErrorWithRevertData: () => {
// Simulates SolidityError: a non-ProviderError with .data and .transactionHash
const err = new Error("revert Unauthorized");
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- allow in test
(err as any).data = "0xdeadbeef";
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- allow in test
(err as any).transactionHash = "0xabc123";
throw err;
},
});
const server = new JsonRpcServerImplementation({
hostname,
Expand Down Expand Up @@ -298,6 +307,29 @@ describe("JSON-RPC handler", async function () {
assert.equal(rpcRes.error.data.txHash, "0xbeef");
assert.equal(rpcRes.error.data.data, "0xabad1dea");
});

it("should preserve revert data from non-ProviderError errors", async function () {
// Simulates SolidityError which has .data and .transactionHash but is NOT a ProviderError
const rpcReq: JsonRpcRequest = {
jsonrpc: "2.0",
method: "nonProviderErrorWithRevertData",
id: 1,
};

const rpcRes = await postRawJsonRpc(hostname, port, JSON.stringify(rpcReq));

assert.ok(
isJsonRpcResponse(rpcRes) && isFailedJsonRpcResponse(rpcRes),
"Expected a failed JSON-RPC response",
);
assert.equal(rpcRes.error.code, InternalError.CODE);
assert.ok(
isObject(rpcRes.error.data),
"Expected error data to be an object",
);
assert.equal(rpcRes.error.data.txHash, "0xabc123");
assert.equal(rpcRes.error.data.data, "0xdeadbeef");
});
});

async function postRawJsonRpc(
Expand Down
Loading