mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4829 from ethereum/callBytesReturn
Add return data to bare calls.
This commit is contained in:
commit
cc7daf7b47
@ -406,7 +406,8 @@ inheritable properties of contracts and may be overridden by derived contracts.
|
|||||||
/// The `return 7` statement assigns 7 to the return value but still
|
/// The `return 7` statement assigns 7 to the return value but still
|
||||||
/// executes the statement `locked = false` in the modifier.
|
/// executes the statement `locked = false` in the modifier.
|
||||||
function f() public noReentrancy returns (uint) {
|
function f() public noReentrancy returns (uint) {
|
||||||
require(msg.sender.call(""));
|
(bool success,) = msg.sender.call("");
|
||||||
|
require(success);
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -645,7 +646,8 @@ Like any function, the fallback function can execute complex operations as long
|
|||||||
|
|
||||||
contract Caller {
|
contract Caller {
|
||||||
function callTest(Test test) public returns (bool) {
|
function callTest(Test test) public returns (bool) {
|
||||||
require(address(test).call(abi.encodeWithSignature("nonExistingFunction()")));
|
(bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
|
||||||
|
require(success);
|
||||||
// results in test.x becoming == 1.
|
// results in test.x becoming == 1.
|
||||||
|
|
||||||
// If someone sends ether to that contract,
|
// If someone sends ether to that contract,
|
||||||
|
@ -86,7 +86,8 @@ as it uses ``call`` which forwards all remaining gas by default:
|
|||||||
mapping(address => uint) shares;
|
mapping(address => uint) shares;
|
||||||
/// Withdraw your share.
|
/// Withdraw your share.
|
||||||
function withdraw() public {
|
function withdraw() public {
|
||||||
if (msg.sender.call.value(shares[msg.sender])(""))
|
(bool success,) = msg.sender.call.value(shares[msg.sender])("");
|
||||||
|
if (success)
|
||||||
shares[msg.sender] = 0;
|
shares[msg.sender] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>();
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -226,13 +226,11 @@ contract MultiSigWallet {
|
|||||||
{
|
{
|
||||||
if (isConfirmed(transactionId)) {
|
if (isConfirmed(transactionId)) {
|
||||||
Transaction storage tx = transactions[transactionId];
|
Transaction storage tx = transactions[transactionId];
|
||||||
tx.executed = true;
|
(tx.executed,) = tx.destination.call.value(tx.value)(tx.data);
|
||||||
if (tx.destination.call.value(tx.value)(tx.data))
|
if (tx.executed)
|
||||||
emit Execution(transactionId);
|
emit Execution(transactionId);
|
||||||
else {
|
else
|
||||||
emit ExecutionFailure(transactionId);
|
emit ExecutionFailure(transactionId);
|
||||||
tx.executed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,14 +45,13 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet {
|
|||||||
Transaction storage tx = transactions[transactionId];
|
Transaction storage tx = transactions[transactionId];
|
||||||
bool confirmed = isConfirmed(transactionId);
|
bool confirmed = isConfirmed(transactionId);
|
||||||
if (confirmed || tx.data.length == 0 && isUnderLimit(tx.value)) {
|
if (confirmed || tx.data.length == 0 && isUnderLimit(tx.value)) {
|
||||||
tx.executed = true;
|
|
||||||
if (!confirmed)
|
if (!confirmed)
|
||||||
spentToday += tx.value;
|
spentToday += tx.value;
|
||||||
if (tx.destination.call.value(tx.value)(tx.data))
|
(tx.executed,) = tx.destination.call.value(tx.value)(tx.data);
|
||||||
|
if (tx.executed)
|
||||||
emit Execution(transactionId);
|
emit Execution(transactionId);
|
||||||
else {
|
else {
|
||||||
emit ExecutionFailure(transactionId);
|
emit ExecutionFailure(transactionId);
|
||||||
tx.executed = false;
|
|
||||||
if (!confirmed)
|
if (!confirmed)
|
||||||
spentToday -= tx.value;
|
spentToday -= tx.value;
|
||||||
}
|
}
|
||||||
|
@ -360,8 +360,8 @@ contract MilestoneTracker {
|
|||||||
// Recheck again to not pay twice
|
// Recheck again to not pay twice
|
||||||
if (milestone.status == MilestoneStatus.AuthorizedForPayment) revert();
|
if (milestone.status == MilestoneStatus.AuthorizedForPayment) revert();
|
||||||
milestone.status = MilestoneStatus.AuthorizedForPayment;
|
milestone.status = MilestoneStatus.AuthorizedForPayment;
|
||||||
if (!milestone.paymentSource.call.value(0)(milestone.payData))
|
(bool success,) = milestone.paymentSource.call.value(0)(milestone.payData);
|
||||||
revert();
|
require(success);
|
||||||
emit ProposalStatusChanged(_idMilestone, milestone.status);
|
emit ProposalStatusChanged(_idMilestone, milestone.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,8 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
|||||||
if (underLimit(_value)) {
|
if (underLimit(_value)) {
|
||||||
emit SingleTransact(msg.sender, _value, _to, _data);
|
emit SingleTransact(msg.sender, _value, _to, _data);
|
||||||
// yes - just execute the call.
|
// yes - just execute the call.
|
||||||
if (!_to.call.value(_value)(_data)) {
|
(bool success,) = _to.call.value(_value)(_data);
|
||||||
revert();
|
require(success);
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// determine our operation hash.
|
// determine our operation hash.
|
||||||
@ -82,9 +81,8 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
|||||||
*/
|
*/
|
||||||
function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) {
|
function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) {
|
||||||
if (txs[_h].to != address(0)) {
|
if (txs[_h].to != address(0)) {
|
||||||
if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
|
(bool success,) = txs[_h].to.call.value(txs[_h].value)(txs[_h].data);
|
||||||
revert();
|
require(success);
|
||||||
}
|
|
||||||
emit MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
|
emit MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
|
||||||
delete txs[_h];
|
delete txs[_h];
|
||||||
return true;
|
return true;
|
||||||
|
@ -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,217 @@ 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(bare_call_return_data)
|
||||||
|
{
|
||||||
|
if (dev::test::Options::get().evmVersion().supportsReturndata())
|
||||||
|
{
|
||||||
|
vector<string> calltypes = {"call", "delegatecall"};
|
||||||
|
if (dev::test::Options::get().evmVersion().hasStaticCall())
|
||||||
|
calltypes.emplace_back("staticcall");
|
||||||
|
for (string const& calltype: calltypes)
|
||||||
|
{
|
||||||
|
string sourceCode = R"DELIMITER(
|
||||||
|
contract A {
|
||||||
|
constructor() public {
|
||||||
|
}
|
||||||
|
function return_bool() public pure returns(bool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function return_int32() public pure returns(int32) {
|
||||||
|
return -32;
|
||||||
|
}
|
||||||
|
function return_uint32() public pure returns(uint32) {
|
||||||
|
return 0x3232;
|
||||||
|
}
|
||||||
|
function return_int256() public pure returns(int256) {
|
||||||
|
return -256;
|
||||||
|
}
|
||||||
|
function return_uint256() public pure returns(uint256) {
|
||||||
|
return 0x256256;
|
||||||
|
}
|
||||||
|
function return_bytes4() public pure returns(bytes4) {
|
||||||
|
return 0xabcd0012;
|
||||||
|
}
|
||||||
|
function return_multi() public pure returns(bool, uint32, bytes4) {
|
||||||
|
return (false, 0x3232, 0xabcd0012);
|
||||||
|
}
|
||||||
|
function return_bytes() public pure returns(bytes memory b) {
|
||||||
|
b = new bytes(2);
|
||||||
|
b[0] = 0x42;
|
||||||
|
b[1] = 0x21;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
A addr;
|
||||||
|
constructor() public {
|
||||||
|
addr = new A();
|
||||||
|
}
|
||||||
|
function f(string memory signature) public returns (bool, bytes memory) {
|
||||||
|
return address(addr).)DELIMITER" + calltype + R"DELIMITER((abi.encodeWithSignature(signature));
|
||||||
|
}
|
||||||
|
function check_bool() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_bool()");
|
||||||
|
assert(success);
|
||||||
|
bool a = abi.decode(data, (bool));
|
||||||
|
assert(a);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_int32() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_int32()");
|
||||||
|
assert(success);
|
||||||
|
int32 a = abi.decode(data, (int32));
|
||||||
|
assert(a == -32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_uint32() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_uint32()");
|
||||||
|
assert(success);
|
||||||
|
uint32 a = abi.decode(data, (uint32));
|
||||||
|
assert(a == 0x3232);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_int256() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_int256()");
|
||||||
|
assert(success);
|
||||||
|
int256 a = abi.decode(data, (int256));
|
||||||
|
assert(a == -256);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_uint256() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_uint256()");
|
||||||
|
assert(success);
|
||||||
|
uint256 a = abi.decode(data, (uint256));
|
||||||
|
assert(a == 0x256256);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_bytes4() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_bytes4()");
|
||||||
|
assert(success);
|
||||||
|
bytes4 a = abi.decode(data, (bytes4));
|
||||||
|
assert(a == 0xabcd0012);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_multi() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_multi()");
|
||||||
|
assert(success);
|
||||||
|
(bool a, uint32 b, bytes4 c) = abi.decode(data, (bool, uint32, bytes4));
|
||||||
|
assert(a == false && b == 0x3232 && c == 0xabcd0012);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function check_bytes() external returns (bool) {
|
||||||
|
(bool success, bytes memory data) = f("return_bytes()");
|
||||||
|
assert(success);
|
||||||
|
(bytes memory d) = abi.decode(data, (bytes));
|
||||||
|
assert(d.length == 2 && d[0] == 0x42 && d[1] == 0x21);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)DELIMITER";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bool()"))), encodeArgs(true, 0x40, 0x20, true));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_int32()"))), encodeArgs(true, 0x40, 0x20, u256(-32)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_uint32()"))), encodeArgs(true, 0x40, 0x20, u256(0x3232)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_int256()"))), encodeArgs(true, 0x40, 0x20, u256(-256)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_uint256()"))), encodeArgs(true, 0x40, 0x20, u256(0x256256)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bytes4()"))), encodeArgs(true, 0x40, 0x20, u256(0xabcd0012) << (28*8)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_multi()"))), encodeArgs(true, 0x40, 0x60, false, u256(0x3232), u256(0xabcd0012) << (28*8)));
|
||||||
|
ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bytes()"))), encodeArgs(true, 0x40, 0x60, 0x20, 0x02, encode(bytes{0x42,0x21}, false)));
|
||||||
|
ABI_CHECK(callContractFunction("check_bool()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_int32()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_uint32()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_int256()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_uint256()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_bytes4()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_multi()"), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("check_bytes()"), encodeArgs(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +13470,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
@ -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.
|
||||||
|
@ -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");
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user