diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 15327c655..b409c84cd 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -504,6 +504,7 @@ public: std::vector definedFunctions() const { return filteredNodes(m_subNodes); } std::vector events() const { return filteredNodes(m_subNodes); } std::vector const& interfaceEvents() const; + std::vector errors() const { return filteredNodes(m_subNodes); } bool isInterface() const { return m_contractKind == ContractKind::Interface; } bool isLibrary() const { return m_contractKind == ContractKind::Library; } diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index 70dbc1b3a..5c2fb3416 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -121,6 +121,26 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) abi.emplace(std::move(event)); } + // TODO should use "used errors" once implemented, + // but should also include all errors defined in the contract. + for (ErrorDefinition const* error: _contractDef.errors()) + { + Json::Value event; + event["type"] = "error"; + event["name"] = error->name(); + Json::Value params(Json::arrayValue); + for (auto const& p: error->parameters()) + { + Type const* type = p->annotation().type->interfaceType(false); + solAssert(type, ""); + Json::Value input; + auto param = formatType(p->name(), *type, *p->annotation().type, false); + params.append(std::move(param)); + } + event["inputs"] = std::move(params); + abi.emplace(std::move(event)); + } + Json::Value abiJson{Json::arrayValue}; for (auto& f: abi) abiJson.append(std::move(f)); diff --git a/test/libsolidity/ABIJson/errors.sol b/test/libsolidity/ABIJson/errors.sol new file mode 100644 index 000000000..7c227b20d --- /dev/null +++ b/test/libsolidity/ABIJson/errors.sol @@ -0,0 +1,88 @@ +error FreeError(); +contract X { + error E(uint); + error E2(uint a, uint b); + error E4(uint a, bytes[][] c); + struct S { uint x; } + error E5(S t); + function f() public pure { + revert(FreeError()); + } +} +// ---- +// :X +// [ +// { +// "inputs": +// [ +// { +// "internalType": "uint256", +// "name": "", +// "type": "uint256" +// } +// ], +// "name": "E", +// "type": "error" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "uint256", +// "name": "a", +// "type": "uint256" +// }, +// { +// "internalType": "uint256", +// "name": "b", +// "type": "uint256" +// } +// ], +// "name": "E2", +// "type": "error" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "uint256", +// "name": "a", +// "type": "uint256" +// }, +// { +// "internalType": "bytes[][]", +// "name": "c", +// "type": "bytes[][]" +// } +// ], +// "name": "E4", +// "type": "error" +// }, +// { +// "inputs": +// [ +// { +// "components": +// [ +// { +// "internalType": "uint256", +// "name": "x", +// "type": "uint256" +// } +// ], +// "internalType": "struct X.S", +// "name": "t", +// "type": "tuple" +// } +// ], +// "name": "E5", +// "type": "error" +// }, +// { +// "inputs": [], +// "name": "f", +// "outputs": [], +// "stateMutability": "pure", +// "type": "function" +// } +// ]