mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add type error when attempting value transfer to a non-payable contract
This commit is contained in:
parent
757c500bda
commit
f20b150f38
@ -2,6 +2,7 @@
|
||||
|
||||
Features:
|
||||
* Inline Assembly: Show useful error message if trying to access calldata variables.
|
||||
* Type Checker: Disallow value transfers to contracts without a payable fallback function
|
||||
|
||||
Bugfixes:
|
||||
* Type Checker: Fix invalid "specify storage keyword" warning for reference members of structs.
|
||||
|
@ -1631,6 +1631,25 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||
}
|
||||
|
||||
if (exprType->category() == Type::Category::Contract)
|
||||
{
|
||||
if (auto callType = dynamic_cast<FunctionType const*>(type(_memberAccess).get()))
|
||||
{
|
||||
auto kind = callType->kind();
|
||||
auto contractType = dynamic_cast<ContractType const*>(exprType.get());
|
||||
solAssert(!!contractType, "Should be contract type.");
|
||||
|
||||
if (
|
||||
(kind == FunctionType::Kind::Send || kind == FunctionType::Kind::Transfer) &&
|
||||
!contractType->isPayable()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
_memberAccess.location(),
|
||||
"Value transfer to a contract without a payable fallback function."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
||||
// although every subexpression is, so leaving this limited for now.
|
||||
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
|
||||
|
@ -1230,6 +1230,12 @@ bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
_convertTo.category() == Category::Contract;
|
||||
}
|
||||
|
||||
bool ContractType::isPayable() const
|
||||
{
|
||||
auto fallbackFunction = m_contract.fallbackFunction();
|
||||
return fallbackFunction && fallbackFunction->isPayable();
|
||||
}
|
||||
|
||||
TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
|
||||
{
|
||||
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
|
||||
|
@ -675,6 +675,10 @@ public:
|
||||
}
|
||||
|
||||
bool isSuper() const { return m_super; }
|
||||
|
||||
// @returns true if and only if the contract has a payable fallback function
|
||||
bool isPayable() const;
|
||||
|
||||
ContractDefinition const& contractDefinition() const { return m_contract; }
|
||||
|
||||
/// Returns the function type of the constructor modified to return an object of the contract's type.
|
||||
|
@ -6146,6 +6146,76 @@ BOOST_AUTO_TEST_CASE(callable_crash)
|
||||
CHECK_ERROR(text, TypeError, "Type is not callable");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_transfer_non_payable_fallback)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
function() {}
|
||||
}
|
||||
|
||||
contract B {
|
||||
A a;
|
||||
|
||||
function() {
|
||||
a.transfer(100);
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_transfer_no_fallback)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {}
|
||||
|
||||
contract B {
|
||||
A a;
|
||||
|
||||
function() {
|
||||
a.transfer(100);
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_send_non_payable_fallback)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
function() {}
|
||||
}
|
||||
|
||||
contract B {
|
||||
A a;
|
||||
|
||||
function() {
|
||||
require(a.send(100));
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(does_not_error_transfer_payable_fallback)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
function() payable {}
|
||||
}
|
||||
|
||||
contract B {
|
||||
A a;
|
||||
|
||||
function() {
|
||||
a.transfer(100);
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
|
||||
{
|
||||
char const* text = R"(
|
||||
|
Loading…
Reference in New Issue
Block a user