diff options
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | docs/abi-spec.rst | 3 | ||||
-rw-r--r-- | libsolidity/interface/ABI.cpp | 3 | ||||
-rw-r--r-- | test/libsolidity/SolidityABIJSON.cpp | 54 |
4 files changed, 60 insertions, 1 deletions
diff --git a/Changelog.md b/Changelog.md index 256198f9..9bc0b354 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.4.16 (unreleased) Features: + * ABI JSON: Include new field ``statemutability`` with values ``view``, ``nonpayable`` and ``payable``. * Parser: Display previous visibility specifier in error if multiple are found. * Syntax Checker: Support ``pragma experimental <feature>;`` to turn on experimental features. * Static Analyzer: Warn about large storage structures. diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 2cf57427..7a1a9af0 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -294,7 +294,8 @@ The JSON format for a contract's interface is given by an array of function and/ * `type`: the canonical type of the parameter. - `outputs`: an array of objects similar to `inputs`, can be omitted if function doesn't return anything; - `constant`: `true` if function is :ref:`specified to not modify blockchain state <constant-functions>`); -- `payable`: `true` if function accepts ether, defaults to `false`. +- `payable`: `true` if function accepts ether, defaults to `false`; +- `statemutability`: a string with one of the following values: `view` (same as `constant` above), `nonpayable` and `payable` (same as `payable` above). `type` can be omitted, defaulting to `"function"`. diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index 12f958fc..9fc2f4e8 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -38,6 +38,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) method["name"] = it.second->declaration().name(); method["constant"] = it.second->isConstant(); method["payable"] = it.second->isPayable(); + method["statemutability"] = stateMutabilityToString(it.second->stateMutability()); method["inputs"] = formatTypeList( externalFunctionType->parameterNames(), externalFunctionType->parameterTypes(), @@ -57,6 +58,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); solAssert(!!externalFunction, ""); method["payable"] = externalFunction->isPayable(); + method["statemutability"] = stateMutabilityToString(externalFunction->stateMutability()); method["inputs"] = formatTypeList( externalFunction->parameterNames(), externalFunction->parameterTypes(), @@ -71,6 +73,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) Json::Value method; method["type"] = "fallback"; method["payable"] = externalFunctionType->isPayable(); + method["statemutability"] = stateMutabilityToString(externalFunctionType->stateMutability()); abi.append(method); } for (auto const& it: _contractDef.interfaceEvents()) diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index 452a2662..80b4b6ad 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -76,6 +76,7 @@ BOOST_AUTO_TEST_CASE(basic_test) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -119,6 +120,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -137,6 +139,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) "name": "g", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -169,6 +172,7 @@ BOOST_AUTO_TEST_CASE(multiple_params) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -207,6 +211,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) "name": "c", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -225,6 +230,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -258,6 +264,7 @@ BOOST_AUTO_TEST_CASE(const_function) "name": "foo", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -280,6 +287,7 @@ BOOST_AUTO_TEST_CASE(const_function) "name": "boo", "constant": true, "payable" : false, + "statemutability": "view", "type": "function", "inputs": [{ "name": "a", @@ -311,6 +319,7 @@ BOOST_AUTO_TEST_CASE(events) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -392,6 +401,7 @@ BOOST_AUTO_TEST_CASE(inherited) "name": "baseFunction", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [{ @@ -408,6 +418,7 @@ BOOST_AUTO_TEST_CASE(inherited) "name": "derivedFunction", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [{ @@ -463,6 +474,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -505,6 +517,7 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter) "name": "f", "constant": false, "payable" : false, + "statemutability": "nonpayable", "type": "function", "inputs": [ { @@ -548,12 +561,44 @@ BOOST_AUTO_TEST_CASE(constructor_abi) } ], "payable": false, + "statemutability": "nonpayable", "type": "constructor" } ])"; checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(payable_constructor_abi) +{ + char const* sourceCode = R"( + contract test { + function test(uint param1, test param2, bool param3) payable {} + } + )"; + + char const* interface = R"([ + { + "inputs": [ + { + "name": "param1", + "type": "uint256" + }, + { + "name": "param2", + "type": "address" + }, + { + "name": "param3", + "type": "bool" + } + ], + "payable": true, + "statemutability": "payable", + "type": "constructor" + } + ])"; + checkInterface(sourceCode, interface); +} BOOST_AUTO_TEST_CASE(return_param_in_abi) { @@ -574,6 +619,7 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi) { "constant" : false, "payable" : false, + "statemutability": "nonpayable", "inputs" : [], "name" : "ret", "outputs" : [ @@ -592,6 +638,7 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi) } ], "payable": false, + "statemutability": "nonpayable", "type": "constructor" } ] @@ -613,6 +660,7 @@ BOOST_AUTO_TEST_CASE(strings_and_arrays) { "constant" : false, "payable" : false, + "statemutability": "nonpayable", "name": "f", "inputs": [ { "name": "a", "type": "string" }, @@ -641,6 +689,7 @@ BOOST_AUTO_TEST_CASE(library_function) { "constant" : false, "payable" : false, + "statemutability": "nonpayable", "name": "f", "inputs": [ { "name": "b", "type": "test.StructType storage" }, @@ -670,6 +719,7 @@ BOOST_AUTO_TEST_CASE(include_fallback_function) [ { "payable": false, + "statemutability": "nonpayable", "type" : "fallback" } ] @@ -691,6 +741,7 @@ BOOST_AUTO_TEST_CASE(payable_function) { "constant" : false, "payable": false, + "statemutability": "nonpayable", "inputs": [], "name": "f", "outputs": [], @@ -699,6 +750,7 @@ BOOST_AUTO_TEST_CASE(payable_function) { "constant" : false, "payable": true, + "statemutability": "payable", "inputs": [], "name": "g", "outputs": [], @@ -721,6 +773,7 @@ BOOST_AUTO_TEST_CASE(payable_fallback_function) [ { "payable": true, + "statemutability": "payable", "type" : "fallback" } ] @@ -741,6 +794,7 @@ BOOST_AUTO_TEST_CASE(function_type) { "constant" : false, "payable": false, + "statemutability": "nonpayable", "inputs": [{ "name": "x", "type": "function" |