hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
279 lines • 14.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.SolidityError = exports.encodeSolidityStackTrace = exports.wrapWithSolidityErrorsCorrection = exports.getCurrentStack = void 0;
const ethereumjs_util_1 = require("@nomicfoundation/ethereumjs-util");
const panic_errors_1 = require("./panic-errors");
const solidity_stack_trace_1 = require("./solidity-stack-trace");
const inspect = Symbol.for("nodejs.util.inspect.custom");
function getCurrentStack() {
const previousPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (e, s) => s;
const error = new Error();
const stack = error.stack;
Error.prepareStackTrace = previousPrepareStackTrace;
return stack;
}
exports.getCurrentStack = getCurrentStack;
async function wrapWithSolidityErrorsCorrection(f, stackFramesToRemove) {
const stackTraceAtCall = getCurrentStack().slice(stackFramesToRemove);
try {
return await f();
}
catch (error) {
if (error.stackTrace === undefined) {
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw error;
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw encodeSolidityStackTrace(error.message, error.stackTrace, stackTraceAtCall);
}
}
exports.wrapWithSolidityErrorsCorrection = wrapWithSolidityErrorsCorrection;
function encodeSolidityStackTrace(fallbackMessage, stackTrace, previousStack) {
if (Error.prepareStackTrace === undefined) {
// Node 12 doesn't have a default Error.prepareStackTrace
require("source-map-support/register");
}
const previousPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (error, stack) => {
if (previousStack !== undefined) {
stack = previousStack;
}
else {
// We remove error management related stack traces
stack.splice(0, 1);
}
for (const entry of stackTrace) {
const callsite = encodeStackTraceEntry(entry);
if (callsite === undefined) {
continue;
}
stack.unshift(callsite);
}
return previousPrepareStackTrace(error, stack);
};
const msg = getMessageFromLastStackTraceEntry(stackTrace[stackTrace.length - 1]);
const solidityError = new SolidityError(msg !== undefined ? msg : fallbackMessage, stackTrace);
// This hack is here because prepare stack is lazy
solidityError.stack = solidityError.stack;
Error.prepareStackTrace = previousPrepareStackTrace;
return solidityError;
}
exports.encodeSolidityStackTrace = encodeSolidityStackTrace;
function encodeStackTraceEntry(stackTraceEntry) {
switch (stackTraceEntry.type) {
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.MISSING_FALLBACK_OR_RECEIVE_ERROR:
return sourceReferenceToSolidityCallsite({
...stackTraceEntry.sourceReference,
function: solidity_stack_trace_1.UNRECOGNIZED_FUNCTION_NAME,
});
case solidity_stack_trace_1.StackTraceEntryType.CALLSTACK_ENTRY:
case solidity_stack_trace_1.StackTraceEntryType.REVERT_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.CUSTOM_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.INVALID_PARAMS_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.FALLBACK_NOT_PAYABLE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.RETURNDATA_SIZE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.CALL_FAILED_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR:
return sourceReferenceToSolidityCallsite(stackTraceEntry.sourceReference);
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CREATE_CALLSTACK_ENTRY:
return new SolidityCallSite(undefined, solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.CONSTRUCTOR_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY:
return new SolidityCallSite((0, ethereumjs_util_1.bytesToHex)(stackTraceEntry.address), solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.UNKNOWN_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.PRECOMPILE_ERROR:
return new SolidityCallSite(undefined, `<PrecompileContract ${stackTraceEntry.precompile}>`, solidity_stack_trace_1.PRECOMPILE_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR:
return new SolidityCallSite(undefined, solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.CONSTRUCTOR_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR:
return new SolidityCallSite((0, ethereumjs_util_1.bytesToHex)(stackTraceEntry.address), solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.UNKNOWN_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.INTERNAL_FUNCTION_CALLSTACK_ENTRY:
return new SolidityCallSite(stackTraceEntry.sourceReference.sourceName, stackTraceEntry.sourceReference.contract, `internal@${stackTraceEntry.pc}`, undefined);
case solidity_stack_trace_1.StackTraceEntryType.CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR:
if (stackTraceEntry.sourceReference !== undefined) {
return sourceReferenceToSolidityCallsite(stackTraceEntry.sourceReference);
}
return new SolidityCallSite(undefined, solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.UNKNOWN_FUNCTION_NAME, undefined);
case solidity_stack_trace_1.StackTraceEntryType.OTHER_EXECUTION_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.CONTRACT_TOO_LARGE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.PANIC_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR:
if (stackTraceEntry.sourceReference === undefined) {
return new SolidityCallSite(undefined, solidity_stack_trace_1.UNRECOGNIZED_CONTRACT_NAME, solidity_stack_trace_1.UNKNOWN_FUNCTION_NAME, undefined);
}
return sourceReferenceToSolidityCallsite(stackTraceEntry.sourceReference);
}
}
function sourceReferenceToSolidityCallsite(sourceReference) {
return new SolidityCallSite(sourceReference.sourceName, sourceReference.contract, sourceReference.function !== undefined
? sourceReference.function
: solidity_stack_trace_1.UNKNOWN_FUNCTION_NAME, sourceReference.line);
}
function getMessageFromLastStackTraceEntry(stackTraceEntry) {
switch (stackTraceEntry.type) {
case solidity_stack_trace_1.StackTraceEntryType.PRECOMPILE_ERROR:
return `Transaction reverted: call to precompile ${stackTraceEntry.precompile} failed`;
case solidity_stack_trace_1.StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR:
return `Transaction reverted: non-payable function was called with value ${stackTraceEntry.value.toString(10)}`;
case solidity_stack_trace_1.StackTraceEntryType.INVALID_PARAMS_ERROR:
return `Transaction reverted: function was called with incorrect parameters`;
case solidity_stack_trace_1.StackTraceEntryType.FALLBACK_NOT_PAYABLE_ERROR:
return `Transaction reverted: fallback function is not payable and was called with value ${stackTraceEntry.value.toString(10)}`;
case solidity_stack_trace_1.StackTraceEntryType.FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR:
return `Transaction reverted: there's no receive function, fallback function is not payable and was called with value ${stackTraceEntry.value.toString(10)}`;
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR:
return `Transaction reverted: function selector was not recognized and there's no fallback function`;
case solidity_stack_trace_1.StackTraceEntryType.MISSING_FALLBACK_OR_RECEIVE_ERROR:
return `Transaction reverted: function selector was not recognized and there's no fallback nor receive function`;
case solidity_stack_trace_1.StackTraceEntryType.RETURNDATA_SIZE_ERROR:
return `Transaction reverted: function returned an unexpected amount of data`;
case solidity_stack_trace_1.StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR:
return `Transaction reverted: function call to a non-contract account`;
case solidity_stack_trace_1.StackTraceEntryType.CALL_FAILED_ERROR:
return `Transaction reverted: function call failed to execute`;
case solidity_stack_trace_1.StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR:
return `Transaction reverted: library was called directly`;
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR:
case solidity_stack_trace_1.StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR:
if (stackTraceEntry.message.isErrorReturnData()) {
return `VM Exception while processing transaction: reverted with reason string '${stackTraceEntry.message.decodeError()}'`;
}
if (stackTraceEntry.message.isPanicReturnData()) {
const message = (0, panic_errors_1.panicErrorCodeToMessage)(stackTraceEntry.message.decodePanic());
return `VM Exception while processing transaction: ${message}`;
}
if (!stackTraceEntry.message.isEmpty()) {
const returnData = Buffer.from(stackTraceEntry.message.value).toString("hex");
return `VM Exception while processing transaction: reverted with an unrecognized custom error (return data: 0x${returnData})`;
}
if (stackTraceEntry.isInvalidOpcodeError) {
return "VM Exception while processing transaction: invalid opcode";
}
return "Transaction reverted without a reason string";
case solidity_stack_trace_1.StackTraceEntryType.REVERT_ERROR:
if (stackTraceEntry.message.isErrorReturnData()) {
return `VM Exception while processing transaction: reverted with reason string '${stackTraceEntry.message.decodeError()}'`;
}
if (stackTraceEntry.isInvalidOpcodeError) {
return "VM Exception while processing transaction: invalid opcode";
}
return "Transaction reverted without a reason string";
case solidity_stack_trace_1.StackTraceEntryType.PANIC_ERROR:
const panicMessage = (0, panic_errors_1.panicErrorCodeToMessage)(stackTraceEntry.errorCode);
return `VM Exception while processing transaction: ${panicMessage}`;
case solidity_stack_trace_1.StackTraceEntryType.CUSTOM_ERROR:
return `VM Exception while processing transaction: ${stackTraceEntry.message}`;
case solidity_stack_trace_1.StackTraceEntryType.OTHER_EXECUTION_ERROR:
// TODO: What if there was returnData?
return `Transaction reverted and Hardhat couldn't infer the reason.`;
case solidity_stack_trace_1.StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR:
return "Transaction reverted without a reason string and without a valid sourcemap provided by the compiler. Some line numbers may be off. We strongly recommend upgrading solc and always using revert reasons.";
case solidity_stack_trace_1.StackTraceEntryType.CONTRACT_TOO_LARGE_ERROR:
return "Transaction reverted: trying to deploy a contract whose code is too large";
case solidity_stack_trace_1.StackTraceEntryType.CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR:
return "Transaction reverted: contract call run out of gas and made the transaction revert";
}
}
// Note: This error class MUST NOT extend ProviderError, as libraries
// use the code property to detect if they are dealing with a JSON-RPC error,
// and take control of errors.
class SolidityError extends Error {
constructor(message, stackTrace) {
super(message);
this.stackTrace = stackTrace;
}
[inspect]() {
return this.inspect();
}
inspect() {
return this.stack !== undefined
? this.stack
: "Internal error when encoding SolidityError";
}
}
exports.SolidityError = SolidityError;
class SolidityCallSite {
constructor(_sourceName, _contract, _functionName, _line) {
this._sourceName = _sourceName;
this._contract = _contract;
this._functionName = _functionName;
this._line = _line;
}
getColumnNumber() {
return null;
}
getEvalOrigin() {
return undefined;
}
getFileName() {
return this._sourceName ?? "unknown";
}
getFunction() {
return undefined;
}
getFunctionName() {
// if it's a top-level function, we print its name
if (this._contract === undefined) {
return this._functionName ?? null;
}
return null;
}
getLineNumber() {
return this._line !== undefined ? this._line : null;
}
getMethodName() {
if (this._contract !== undefined) {
return this._functionName ?? null;
}
return null;
}
getPosition() {
return 0;
}
getPromiseIndex() {
return 0;
}
getScriptNameOrSourceURL() {
return "";
}
getThis() {
return undefined;
}
getTypeName() {
return this._contract ?? null;
}
isAsync() {
return false;
}
isConstructor() {
return false;
}
isEval() {
return false;
}
isNative() {
return false;
}
isPromiseAll() {
return false;
}
isToplevel() {
return false;
}
getScriptHash() {
return "";
}
getEnclosingColumnNumber() {
return 0;
}
getEnclosingLineNumber() {
return 0;
}
toString() {
return "[SolidityCallSite]";
}
}
//# sourceMappingURL=solidity-errors.js.map
;