Add return data to bare calls.

This commit is contained in:
Daniel Kirchner 2018-08-15 23:30:09 +02:00
parent f27d7edfd6
commit 82f512a7d4
12 changed files with 269 additions and 119 deletions

View File

@ -617,11 +617,11 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
if (isAddress()) if (isAddress())
return { return {
{"balance", make_shared<IntegerType>(256)}, {"balance", make_shared<IntegerType>(256)},
{"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, {"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
{"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, {"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
{"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareDelegateCall, false)}, {"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
{"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)}, {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
}; };
else else
@ -2492,7 +2492,14 @@ TypePointers FunctionType::returnParameterTypesWithoutDynamicTypes() const
{ {
TypePointers returnParameterTypes = m_returnParameterTypes; TypePointers returnParameterTypes = m_returnParameterTypes;
if (m_kind == Kind::External || m_kind == Kind::DelegateCall) if (
m_kind == Kind::External ||
m_kind == Kind::DelegateCall ||
m_kind == Kind::BareCall ||
m_kind == Kind::BareCallCode ||
m_kind == Kind::BareDelegateCall ||
m_kind == Kind::BareStaticCall
)
for (auto& param: returnParameterTypes) for (auto& param: returnParameterTypes)
if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage)) if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage))
param = make_shared<InaccessibleDynamicType>(); param = make_shared<InaccessibleDynamicType>();

View File

@ -1827,33 +1827,34 @@ void ExpressionCompiler::appendExternalFunctionCall(
auto funKind = _functionType.kind(); auto funKind = _functionType.kind();
solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), "");
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall;
bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isCallCode = funKind == FunctionType::Kind::BareCallCode;
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall());
bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata();
unsigned retSize = 0; unsigned retSize = 0;
TypePointers returnTypes;
if (returnSuccessCondition)
retSize = 0; // return value actually is success condition
else if (haveReturndatacopy)
returnTypes = _functionType.returnParameterTypes();
else
returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes();
bool dynamicReturnSize = false; bool dynamicReturnSize = false;
for (auto const& retType: returnTypes) TypePointers returnTypes;
if (retType->isDynamicallyEncoded()) if (!returnSuccessConditionAndReturndata)
{ {
solAssert(haveReturndatacopy, ""); if (haveReturndatacopy)
dynamicReturnSize = true; returnTypes = _functionType.returnParameterTypes();
retSize = 0;
break;
}
else else
retSize += retType->calldataEncodedSize(); returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes();
for (auto const& retType: returnTypes)
if (retType->isDynamicallyEncoded())
{
solAssert(haveReturndatacopy, "");
dynamicReturnSize = true;
retSize = 0;
break;
}
else
retSize += retType->calldataEncodedSize();
}
// Evaluate arguments. // Evaluate arguments.
TypePointers argumentTypes; TypePointers argumentTypes;
@ -1997,7 +1998,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
(_functionType.gasSet() ? 1 : 0) + (_functionType.gasSet() ? 1 : 0) +
(!_functionType.isBareCall() ? 1 : 0); (!_functionType.isBareCall() ? 1 : 0);
if (returnSuccessCondition) if (returnSuccessConditionAndReturndata)
m_context << swapInstruction(remainsSize); m_context << swapInstruction(remainsSize);
else else
{ {
@ -2008,9 +2009,31 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().popStackSlots(remainsSize); utils().popStackSlots(remainsSize);
if (returnSuccessCondition) if (returnSuccessConditionAndReturndata)
{ {
// already there // success condition is already there
// The return parameter types can be empty, when this function is used as
// an internal helper function e.g. for ``send`` and ``transfer``. In that
// case we're only interested in the success condition, not the return data.
if (!_functionType.returnParameterTypes().empty())
{
if (haveReturndatacopy)
{
m_context << Instruction::RETURNDATASIZE;
m_context.appendInlineAssembly(R"({
switch v case 0 {
v := 0x60
} default {
v := mload(0x40)
mstore(0x40, add(v, and(add(returndatasize(), 0x3f), not(0x1f))))
mstore(v, returndatasize())
returndatacopy(add(v, 0x20), 0, returndatasize())
}
})", {"v"});
}
else
utils().pushZeroPointer();
}
} }
else if (funKind == FunctionType::Kind::RIPEMD160) else if (funKind == FunctionType::Kind::RIPEMD160)
{ {

View File

@ -3586,7 +3586,8 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws)
char const* sourceCode = R"YY( char const* sourceCode = R"YY(
contract A { contract A {
function f() public returns (bool) { function f() public returns (bool) {
return address(this).call(""); (bool success,) = address(this).call("");
return success;
} }
} }
)YY"; )YY";
@ -3598,7 +3599,9 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws)
char const* sourceCode = R"YY( char const* sourceCode = R"YY(
contract A { contract A {
function f() public returns (bool) { function f() public returns (bool) {
return address(this).staticcall(""); (bool success, bytes memory data) = address(this).staticcall("");
assert(data.length == 0);
return success;
} }
} }
)YY"; )YY";
@ -4408,7 +4411,8 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall)
function doSend(address rec) public payable function doSend(address rec) public payable
{ {
bytes4 signature = bytes4(bytes32(keccak256("receive(uint256)"))); bytes4 signature = bytes4(bytes32(keccak256("receive(uint256)")));
if (rec.delegatecall(abi.encodeWithSelector(signature, 23))) {} (bool success,) = rec.delegatecall(abi.encodeWithSelector(signature, 23));
success;
} }
} }
)**"; )**";
@ -4445,19 +4449,19 @@ BOOST_AUTO_TEST_CASE(generic_staticcall)
function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; } function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; }
} }
contract C { contract C {
function f(address a) public view returns (bool) function f(address a) public view returns (bool, bytes memory)
{ {
return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23)); return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23));
} }
function g(address a) public view returns (bool) function g(address a) public view returns (bool, bytes memory)
{ {
return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23)); return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23));
} }
function h(address a) public view returns (bool) function h(address a) public view returns (bool, bytes memory)
{ {
return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23)); return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23));
} }
function i(address a, uint256 v) public view returns (bool) function i(address a, uint256 v) public view returns (bool, bytes memory)
{ {
return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v)); return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v));
} }
@ -4466,11 +4470,11 @@ BOOST_AUTO_TEST_CASE(generic_staticcall)
compileAndRun(sourceCode, 0, "A"); compileAndRun(sourceCode, 0, "A");
u160 const c_addressA = m_contractAddress; u160 const c_addressA = m_contractAddress;
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true)); ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23));
ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true)); ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42));
ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false)); ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00));
ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true)); ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42));
ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false)); ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x00));
} }
} }
@ -4570,7 +4574,7 @@ BOOST_AUTO_TEST_CASE(call_forward_bytes)
contract sender { contract sender {
constructor() public { rec = new receiver(); } constructor() public { rec = new receiver(); }
function() external { savedData = msg.data; } function() external { savedData = msg.data; }
function forward() public returns (bool) { !address(rec).call(savedData); return true; } function forward() public returns (bool) { address(rec).call(savedData); return true; }
function clear() public returns (bool) { delete savedData; return true; } function clear() public returns (bool) { delete savedData; return true; }
function val() public returns (uint) { return rec.received(); } function val() public returns (uint) { return rec.received(); }
receiver rec; receiver rec;
@ -4599,18 +4603,21 @@ BOOST_AUTO_TEST_CASE(call_forward_bytes_length)
receiver rec; receiver rec;
constructor() public { rec = new receiver(); } constructor() public { rec = new receiver(); }
function viaCalldata() public returns (uint) { function viaCalldata() public returns (uint) {
require(address(rec).call(msg.data)); (bool success,) = address(rec).call(msg.data);
require(success);
return rec.calledLength(); return rec.calledLength();
} }
function viaMemory() public returns (uint) { function viaMemory() public returns (uint) {
bytes memory x = msg.data; bytes memory x = msg.data;
require(address(rec).call(x)); (bool success,) = address(rec).call(x);
require(success);
return rec.calledLength(); return rec.calledLength();
} }
bytes s; bytes s;
function viaStorage() public returns (uint) { function viaStorage() public returns (uint) {
s = msg.data; s = msg.data;
require(address(rec).call(s)); (bool success,) = address(rec).call(s);
require(success);
return rec.calledLength(); return rec.calledLength();
} }
} }
@ -10336,7 +10343,8 @@ BOOST_AUTO_TEST_CASE(mutex)
// NOTE: It is very bad practice to write this function this way. // NOTE: It is very bad practice to write this function this way.
// Please refer to the documentation of how to do this properly. // Please refer to the documentation of how to do this properly.
if (amount > shares) revert(); if (amount > shares) revert();
if (!msg.sender.call.value(amount)("")) revert(); (bool success,) = msg.sender.call.value(amount)("");
require(success);
shares -= amount; shares -= amount;
return shares; return shares;
} }
@ -10344,7 +10352,8 @@ BOOST_AUTO_TEST_CASE(mutex)
// NOTE: It is very bad practice to write this function this way. // NOTE: It is very bad practice to write this function this way.
// Please refer to the documentation of how to do this properly. // Please refer to the documentation of how to do this properly.
if (amount > shares) revert(); if (amount > shares) revert();
if (!msg.sender.call.value(amount)("")) revert(); (bool success,) = msg.sender.call.value(amount)("");
require(success);
shares -= amount; shares -= amount;
return shares; return shares;
} }
@ -12465,10 +12474,12 @@ BOOST_AUTO_TEST_CASE(bare_call_invalid_address)
contract C { contract C {
/// Calling into non-existant account is successful (creates the account) /// Calling into non-existant account is successful (creates the account)
function f() external returns (bool) { function f() external returns (bool) {
return address(0x4242).call(""); (bool success,) = address(0x4242).call("");
return success;
} }
function h() external returns (bool) { function h() external returns (bool) {
return address(0x4242).delegatecall(""); (bool success,) = address(0x4242).delegatecall("");
return success;
} }
} }
)YY"; )YY";
@ -12480,50 +12491,90 @@ BOOST_AUTO_TEST_CASE(bare_call_invalid_address)
{ {
char const* sourceCode = R"YY( char const* sourceCode = R"YY(
contract C { contract C {
function f() external returns (bool) { function f() external returns (bool, bytes memory) {
return address(0x4242).staticcall(""); return address(0x4242).staticcall("");
} }
} }
)YY"; )YY";
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), 0x40, 0x00));
} }
} }
BOOST_AUTO_TEST_CASE(delegatecall_return_value) BOOST_AUTO_TEST_CASE(delegatecall_return_value)
{ {
char const* sourceCode = R"DELIMITER( if (dev::test::Options::get().evmVersion().supportsReturndata())
contract C { {
uint value; char const* sourceCode = R"DELIMITER(
function set(uint _value) external { contract C {
value = _value; uint value;
function set(uint _value) external {
value = _value;
}
function get() external view returns (uint) {
return value;
}
function get_delegated() external returns (bool, bytes memory) {
return address(this).delegatecall(abi.encodeWithSignature("get()"));
}
function assert0() external view {
assert(value == 0);
}
function assert0_delegated() external returns (bool, bytes memory) {
return address(this).delegatecall(abi.encodeWithSignature("assert0()"));
}
} }
function get() external view returns (uint) { )DELIMITER";
return value; compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(1), 0x40, 0x00));
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 0x00));
ABI_CHECK(callContractFunction("set(uint256)", u256(1)), encodeArgs());
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(1)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0), 0x40, 0x00));
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 1));
ABI_CHECK(callContractFunction("set(uint256)", u256(42)), encodeArgs());
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(42)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0), 0x40, 0x00));
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 42));
}
else
{
char const* sourceCode = R"DELIMITER(
contract C {
uint value;
function set(uint _value) external {
value = _value;
}
function get() external view returns (uint) {
return value;
}
function get_delegated() external returns (bool) {
(bool success,) = address(this).delegatecall(abi.encodeWithSignature("get()"));
return success;
}
function assert0() external view {
assert(value == 0);
}
function assert0_delegated() external returns (bool) {
(bool success,) = address(this).delegatecall(abi.encodeWithSignature("assert0()"));
return success;
}
} }
function get_delegated() external returns (bool) { )DELIMITER";
return address(this).delegatecall(abi.encodeWithSignature("get()")); compileAndRun(sourceCode, 0, "C");
} ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0)));
function assert0() external view { ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(1)));
assert(value == 0); ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
} ABI_CHECK(callContractFunction("set(uint256)", u256(1)), encodeArgs());
function assert0_delegated() external returns (bool) { ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(1)));
return address(this).delegatecall(abi.encodeWithSignature("assert0()")); ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0)));
} ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
} ABI_CHECK(callContractFunction("set(uint256)", u256(42)), encodeArgs());
)DELIMITER"; ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(42)));
compileAndRun(sourceCode, 0, "C"); ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0)));
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0))); ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(1))); }
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
ABI_CHECK(callContractFunction("set(uint256)", u256(1)), encodeArgs());
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(1)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0)));
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
ABI_CHECK(callContractFunction("set(uint256)", u256(42)), encodeArgs());
ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(42)));
ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0)));
ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1)));
} }
BOOST_AUTO_TEST_CASE(function_types_sig) BOOST_AUTO_TEST_CASE(function_types_sig)
@ -13292,7 +13343,8 @@ BOOST_AUTO_TEST_CASE(abi_encode_call)
uint[] memory b = new uint[](2); uint[] memory b = new uint[](2);
b[0] = 6; b[0] = 6;
b[1] = 7; b[1] = 7;
require(address(this).call(abi.encodeWithSignature("c(uint256,uint256[])", a, b))); (bool success,) = address(this).call(abi.encodeWithSignature("c(uint256,uint256[])", a, b));
require(success);
return x; return x;
} }
} }

View File

@ -438,7 +438,8 @@ BOOST_AUTO_TEST_CASE(address_staticcall)
char const* sourceCode = R"( char const* sourceCode = R"(
contract C { contract C {
function f() public view returns(bool) { function f() public view returns(bool) {
return address(0x4242).staticcall(""); (bool success,) = address(0x4242).staticcall("");
return success;
} }
} }
)"; )";
@ -464,6 +465,58 @@ BOOST_AUTO_TEST_CASE(address_staticcall_value)
} }
} }
BOOST_AUTO_TEST_CASE(address_call_full_return_type)
{
char const* sourceCode = R"(
contract C {
function f() public {
(bool success, bytes memory m) = address(0x4242).call("");
success; m;
}
}
)";
if (dev::test::Options::get().evmVersion().supportsReturndata())
CHECK_SUCCESS_NO_WARNINGS(sourceCode);
else
CHECK_ERROR(sourceCode, TypeError, "Type inaccessible dynamic type is not implicitly convertible to expected type bytes memory.");
}
BOOST_AUTO_TEST_CASE(address_delegatecall_full_return_type)
{
char const* sourceCode = R"(
contract C {
function f() public {
(bool success, bytes memory m) = address(0x4242).delegatecall("");
success; m;
}
}
)";
if (dev::test::Options::get().evmVersion().supportsReturndata())
CHECK_SUCCESS_NO_WARNINGS(sourceCode);
else
CHECK_ERROR(sourceCode, TypeError, "Type inaccessible dynamic type is not implicitly convertible to expected type bytes memory.");
}
BOOST_AUTO_TEST_CASE(address_staticcall_full_return_type)
{
if (dev::test::Options::get().evmVersion().hasStaticCall())
{
char const* sourceCode = R"(
contract C {
function f() public view {
(bool success, bytes memory m) = address(0x4242).staticcall("");
success; m;
}
}
)";
CHECK_SUCCESS_NO_WARNINGS(sourceCode);
}
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -103,7 +103,8 @@ BOOST_AUTO_TEST_CASE(address_staticcall)
string text = R"( string text = R"(
contract C { contract C {
function i() view public returns (bool) { function i() view public returns (bool) {
return address(0x4242).staticcall(""); (bool success,) = address(0x4242).staticcall("");
return success;
} }
} }
)"; )";

View File

@ -1,13 +1,17 @@
contract C { contract C {
function f() public { function f() public {
require(address(this).call()); (bool success,) = address(this).call();
require(address(this).call(bytes4(0x12345678))); require(success);
require(address(this).call(uint(1))); (success,) = address(this).call(bytes4(0x12345678));
require(address(this).call(uint(1), uint(2))); require(success);
(success,) = address(this).call(uint(1));
require(success);
(success,) = address(this).call(uint(1), uint(2));
require(success);
} }
} }
// ---- // ----
// TypeError: (55-75): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata. // TypeError: (65-85): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata.
// TypeError: (113-131): Invalid type for argument in function call. Invalid implicit conversion from bytes4 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (153-171): Invalid type for argument in function call. Invalid implicit conversion from bytes4 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.
// TypeError: (170-177): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (240-247): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.
// TypeError: (197-233): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (297-333): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.

View File

@ -1,11 +1,14 @@
contract C { contract C {
function f() public { function f() public {
require(address(this).callcode()); (bool success,) = address(this).callcode();
require(address(this).callcode(uint(1))); require(success);
require(address(this).callcode(uint(1), uint(2))); (success,) = address(this).callcode(uint(1));
require(success);
(success,) = address(this).callcode(uint(1), uint(2));
require(success);
} }
} }
// ---- // ----
// TypeError: (55-79): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata. // TypeError: (65-89): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata.
// TypeError: (121-128): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (161-168): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.
// TypeError: (148-188): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (218-258): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.

View File

@ -1,11 +1,14 @@
contract C { contract C {
function f() public { function f() public {
require(address(this).delegatecall()); (bool success,) = address(this).delegatecall();
require(address(this).delegatecall(uint(1))); require(success);
require(address(this).delegatecall(uint(1), uint(2))); (success,) = address(this).delegatecall(uint(1));
require(success);
(success,) = address(this).delegatecall(uint(1), uint(2));
require(success);
} }
} }
// ---- // ----
// TypeError: (55-83): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata. // TypeError: (65-93): Wrong argument count for function call: 0 arguments given but expected 1. This function requires a single bytes argument. Use "" as argument to provide empty calldata.
// TypeError: (129-136): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (169-176): Invalid type for argument in function call. Invalid implicit conversion from uint256 to bytes memory requested. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.
// TypeError: (156-200): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it. // TypeError: (226-270): Wrong argument count for function call: 2 arguments given but expected 1. This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.

View File

@ -2,11 +2,11 @@ contract C {
function f() public { function f() public {
address addr; address addr;
uint balance = addr.balance; uint balance = addr.balance;
bool callRet = addr.call(""); (bool callSuc,) = addr.call("");
bool delegatecallRet = addr.delegatecall(""); (bool delegatecallSuc,) = addr.delegatecall("");
bool sendRet = addr.send(1); bool sendRet = addr.send(1);
addr.transfer(1); addr.transfer(1);
balance; callRet; delegatecallRet; sendRet; balance; callSuc; delegatecallSuc; sendRet;
} }
} }
// ---- // ----

View File

@ -1,13 +1,13 @@
contract C { contract C {
function f() public pure { function f() public pure {
bool a = address(this).call(abi.encode(address(this).delegatecall, super)); (bool a,) = address(this).call(abi.encode(address(this).delegatecall, super));
bool b = address(this).delegatecall(abi.encode(log0, tx, mulmod)); (a,) = address(this).delegatecall(abi.encode(log0, tx, mulmod));
a; b; a;
} }
} }
// ---- // ----
// TypeError: (91-117): This type cannot be encoded. // TypeError: (94-120): This type cannot be encoded.
// TypeError: (119-124): This type cannot be encoded. // TypeError: (122-127): This type cannot be encoded.
// TypeError: (183-187): This type cannot be encoded. // TypeError: (184-188): This type cannot be encoded.
// TypeError: (189-191): This type cannot be encoded. // TypeError: (190-192): This type cannot be encoded.
// TypeError: (193-199): This type cannot be encoded. // TypeError: (194-200): This type cannot be encoded.

View File

@ -3,8 +3,10 @@ contract C {
address(this).transfer(1); address(this).transfer(1);
require(address(this).send(2)); require(address(this).send(2));
selfdestruct(address(this)); selfdestruct(address(this));
require(address(this).delegatecall("")); (bool success,) = address(this).delegatecall("");
require(address(this).call("")); require(success);
(success,) = address(this).call("");
require(success);
} }
function g() pure public { function g() pure public {
bytes32 x = keccak256("abc"); bytes32 x = keccak256("abc");

View File

@ -9,15 +9,17 @@ contract C {
selfdestruct(address(this)); selfdestruct(address(this));
} }
function i() view public { function i() view public {
require(address(this).delegatecall("")); (bool success,) = address(this).delegatecall("");
require(success);
} }
function j() view public { function j() view public {
require(address(this).call("")); (bool success,) = address(this).call("");
require(success);
} }
} }
// ---- // ----
// TypeError: (52-77): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. // TypeError: (52-77): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
// TypeError: (132-153): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. // TypeError: (132-153): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
// TypeError: (201-228): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. // TypeError: (201-228): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
// TypeError: (283-313): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. // TypeError: (293-323): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
// TypeError: (369-391): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. // TypeError: (414-436): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.