diff options
author | Federico Bond <federicobond@gmail.com> | 2017-07-09 09:42:42 +0800 |
---|---|---|
committer | Federico Bond <federicobond@gmail.com> | 2017-07-13 10:57:53 +0800 |
commit | f20b150f3830d7a014258d92a26aba6a2bbdc8cb (patch) | |
tree | 1da74ae9b2a8c7b34f9be6ede23dc8980ec116a3 /libsolidity | |
parent | 757c500bda9a32cccc86e1ab24da31a99c0e6eac (diff) | |
download | dexon-solidity-f20b150f3830d7a014258d92a26aba6a2bbdc8cb.tar.gz dexon-solidity-f20b150f3830d7a014258d92a26aba6a2bbdc8cb.tar.zst dexon-solidity-f20b150f3830d7a014258d92a26aba6a2bbdc8cb.zip |
Add type error when attempting value transfer to a non-payable contract
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 19 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 6 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 4 |
3 files changed, 29 insertions, 0 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 90043b43..4e5a11ed 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -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())) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 6ecf509d..b54407c6 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -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(); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 66eb039f..bd5da30a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -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. |