mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10604 from ethereum/strict-address-payable
[BREAKING] Strict address payable
This commit is contained in:
commit
53368eff9b
@ -89,6 +89,10 @@ This section lists changes that might cause existing contracts to not compile an
|
|||||||
|
|
||||||
- ``address(uint)`` and ``uint(address)``: converting both type-category and width. Replace this by
|
- ``address(uint)`` and ``uint(address)``: converting both type-category and width. Replace this by
|
||||||
``address(uint160(uint))`` and ``uint(uint160(address))`` respectively.
|
``address(uint160(uint))`` and ``uint(uint160(address))`` respectively.
|
||||||
|
- ``payable(uint160)``, ``payable(bytes20)`` and ``payable(integer-literal)``: converting both
|
||||||
|
type-category and state-mutability. Replace this by ``payable(address(uint160))``,
|
||||||
|
``payable(address(bytes20))`` and ``payable(address(integer-literal))`` respectively. Note that
|
||||||
|
``payable(0)`` is valid and is an exception to the rule.
|
||||||
- ``int80(bytes10)`` and ``bytes10(int80)``: converting both type-category and sign. Replace this by
|
- ``int80(bytes10)`` and ``bytes10(int80)``: converting both type-category and sign. Replace this by
|
||||||
``int80(uint80(bytes10))`` and ``bytes10(uint80(int80)`` respectively.
|
``int80(uint80(bytes10))`` and ``bytes10(uint80(int80)`` respectively.
|
||||||
- ``Contract(uint)``: converting both type-category and width. Replace this by
|
- ``Contract(uint)``: converting both type-category and width. Replace this by
|
||||||
@ -125,11 +129,13 @@ This section lists changes that might cause existing contracts to not compile an
|
|||||||
particular, the following explicit conversions have the type ``address`` instead of ``address
|
particular, the following explicit conversions have the type ``address`` instead of ``address
|
||||||
payable``:
|
payable``:
|
||||||
|
|
||||||
- ``address(u)`` where ``u`` is an arbitrary variable of type ``uint160``. One can convert ``u``
|
- ``address(u)`` where ``u`` is a variable of type ``uint160``. One can convert ``u``
|
||||||
into the type ``address payable`` by using an explicit conversion, i.e., ``payable(u)``.
|
into the type ``address payable`` by using two explicit conversions, i.e.,
|
||||||
- ``address(b)`` where ``b`` is an arbitrary variable of type ``bytes20``. One can convert ``b``
|
``payable(address(u))``.
|
||||||
into the type ``address payable`` by using an explicit conversion, i.e., ``payable(bytes20)``.
|
- ``address(b)`` where ``b`` is a variable of type ``bytes20``. One can convert ``b``
|
||||||
- ``address(c)`` where ``c`` is an arbitrary contract. Previously, the return type of this
|
into the type ``address payable`` by using two explicit conversions, i.e.,
|
||||||
|
``payable(address(b))``.
|
||||||
|
- ``address(c)`` where ``c`` is a contract. Previously, the return type of this
|
||||||
conversion depended on whether the contract can receive Ether (either by having a receive
|
conversion depended on whether the contract can receive Ether (either by having a receive
|
||||||
function or a payable fallback function). The conversion ``payable(c)`` has the type ``address
|
function or a payable fallback function). The conversion ``payable(c)`` has the type ``address
|
||||||
payable`` and is only allowed when the contract ``c`` can receive Ether. In general, one can
|
payable`` and is only allowed when the contract ``c`` can receive Ether. In general, one can
|
||||||
|
@ -188,17 +188,14 @@ Type conversions:
|
|||||||
Implicit conversions from ``address payable`` to ``address`` are allowed, whereas conversions from ``address`` to ``address payable``
|
Implicit conversions from ``address payable`` to ``address`` are allowed, whereas conversions from ``address`` to ``address payable``
|
||||||
must be explicit via ``payable(<address>)``.
|
must be explicit via ``payable(<address>)``.
|
||||||
|
|
||||||
Explicit conversions to and from ``address`` are allowed for integers, integer literals, ``bytes20`` and contract types with the following
|
Explicit conversions to and from ``address`` are allowed for ``uint160``, integer literals,
|
||||||
caveat:
|
``bytes20`` and contract types.
|
||||||
The result of a conversion of the form ``address(x)``
|
|
||||||
has the type ``address payable``, if ``x`` is of integer or fixed bytes type,
|
|
||||||
or a contract with a receive or payable fallback function.
|
|
||||||
If ``x`` is a contract without a receive or payable fallback function,
|
|
||||||
then ``address(x)`` will be of type ``address``.
|
|
||||||
Similarly, if ``x`` is a literal, then ``address(x)`` will also be of type ``address``.
|
|
||||||
In external function signatures ``address`` is used for both the ``address`` and the ``address payable`` type.
|
|
||||||
|
|
||||||
Only expressions of type ``address`` can be converted to type ``address payable`` via ``payable(<address>)``.
|
Only expressions of type ``address`` and contract-type can be converted to the type ``address
|
||||||
|
payable`` via the explicit conversion ``payable(...)``. For contract-type, this conversion is only
|
||||||
|
allowed if the contract can receive Ether, i.e., the contract either has a :ref:`receive
|
||||||
|
<receive-ether-function>` or a payable fallback function. Note that ``payable(0)`` is valid and is
|
||||||
|
an exception to this rule.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If you need a variable of type ``address`` and plan to send Ether to it, then
|
If you need a variable of type ``address`` and plan to send Ether to it, then
|
||||||
|
@ -399,13 +399,13 @@ BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
return true;
|
return true;
|
||||||
else if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
|
else if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
|
||||||
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
|
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
|
||||||
else if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
else if (m_stateMutability == StateMutability::NonPayable)
|
||||||
return (!integerType->isSigned() && integerType->numBits() == 160);
|
{
|
||||||
else if (
|
if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
||||||
(_convertTo.category() == Category::FixedBytes) &&
|
return (!integerType->isSigned() && integerType->numBits() == 160);
|
||||||
(160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8)
|
else if (auto fixedBytesType = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
||||||
)
|
return (fixedBytesType->numBytes() == 20);
|
||||||
return true;
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -530,8 +530,11 @@ BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
return true;
|
return true;
|
||||||
else if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
else if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
||||||
return (numBits() == integerType->numBits()) || (isSigned() == integerType->isSigned());
|
return (numBits() == integerType->numBits()) || (isSigned() == integerType->isSigned());
|
||||||
else if (_convertTo.category() == Category::Address)
|
else if (auto addressType = dynamic_cast<AddressType const*>(&_convertTo))
|
||||||
return (!isSigned() && numBits() == 160);
|
return
|
||||||
|
(addressType->stateMutability() != StateMutability::Payable) &&
|
||||||
|
!isSigned() &&
|
||||||
|
(numBits() == 160);
|
||||||
else if (auto fixedBytesType = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
else if (auto fixedBytesType = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
||||||
return (!isSigned() && (numBits() == fixedBytesType->numBytes() * 8));
|
return (!isSigned() && (numBits() == fixedBytesType->numBytes() * 8));
|
||||||
else if (dynamic_cast<EnumType const*>(&_convertTo))
|
else if (dynamic_cast<EnumType const*>(&_convertTo))
|
||||||
@ -939,8 +942,13 @@ BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo)
|
|||||||
auto category = _convertTo.category();
|
auto category = _convertTo.category();
|
||||||
if (category == Category::FixedBytes)
|
if (category == Category::FixedBytes)
|
||||||
return false;
|
return false;
|
||||||
else if (category == Category::Address)
|
else if (auto addressType = dynamic_cast<AddressType const*>(&_convertTo))
|
||||||
return !(isNegative() || isFractional() || !integerType() || integerType()->numBits() > 160);
|
return (m_value == 0) ||
|
||||||
|
((addressType->stateMutability() != StateMutability::Payable) &&
|
||||||
|
!isNegative() &&
|
||||||
|
!isFractional() &&
|
||||||
|
integerType() &&
|
||||||
|
(integerType()->numBits() <= 160));
|
||||||
else if (category == Category::Integer)
|
else if (category == Category::Integer)
|
||||||
return false;
|
return false;
|
||||||
else if (auto enumType = dynamic_cast<EnumType const*>(&_convertTo))
|
else if (auto enumType = dynamic_cast<EnumType const*>(&_convertTo))
|
||||||
@ -1250,8 +1258,10 @@ BoolResult FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) con
|
|||||||
return true;
|
return true;
|
||||||
else if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
else if (auto integerType = dynamic_cast<IntegerType const*>(&_convertTo))
|
||||||
return (!integerType->isSigned() && integerType->numBits() == numBytes() * 8);
|
return (!integerType->isSigned() && integerType->numBits() == numBytes() * 8);
|
||||||
else if (_convertTo.category() == Category::Address && numBytes() == 20)
|
else if (auto addressType = dynamic_cast<AddressType const*>(&_convertTo))
|
||||||
return true;
|
return
|
||||||
|
(addressType->stateMutability() != StateMutability::Payable) &&
|
||||||
|
(numBytes() == 20);
|
||||||
else if (auto fixedPointType = dynamic_cast<FixedPointType const*>(&_convertTo))
|
else if (auto fixedPointType = dynamic_cast<FixedPointType const*>(&_convertTo))
|
||||||
return fixedPointType->numBits() == numBytes() * 8;
|
return fixedPointType->numBits() == numBytes() * 8;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ contract C {
|
|||||||
assembly {
|
assembly {
|
||||||
y := x
|
y := x
|
||||||
}
|
}
|
||||||
address payable z = payable(y);
|
address payable z = payable(address(y));
|
||||||
assembly {
|
assembly {
|
||||||
r := z
|
r := z
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
contract test {
|
contract test {
|
||||||
function f() public {
|
function f() public {
|
||||||
payable(0x12).send(1);
|
payable(address(0x12)).send(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 5878: (50-71): Failure condition of 'send' ignored. Consider using 'transfer' instead.
|
// Warning 5878: (50-80): Failure condition of 'send' ignored. Consider using 'transfer' instead.
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure returns (C c) {
|
function f() public pure returns (C c) {
|
||||||
c = C(payable(2));
|
c = C(payable(address(2)));
|
||||||
}
|
}
|
||||||
fallback() external payable {
|
fallback() external payable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 3628: (0-120): This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.
|
// Warning 3628: (0-129): This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.
|
||||||
|
@ -4,16 +4,12 @@ contract C {
|
|||||||
address a2 = address(bytes20(0));
|
address a2 = address(bytes20(0));
|
||||||
address a3 = address(this);
|
address a3 = address(this);
|
||||||
|
|
||||||
address payable a4 = payable(uint160(0));
|
|
||||||
address payable a5 = payable(bytes20(0));
|
|
||||||
address payable a6 = payable(this);
|
|
||||||
|
|
||||||
// Trivial conversions
|
// Trivial conversions
|
||||||
address payable a7 = payable(address(uint160(0)));
|
address payable a4 = payable(address(uint160(0)));
|
||||||
address payable a8 = payable(address(bytes20(0)));
|
address payable a5 = payable(address(bytes20(0)));
|
||||||
address payable a9 = payable(address(this));
|
address payable a6 = payable(address(this));
|
||||||
|
|
||||||
a1; a2; a3; a4; a5; a6; a7; a8; a9;
|
a1; a2; a3; a4; a5; a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// to make payable(this) work
|
// to make payable(this) work
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address payable a = address(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9574: (52-82): Type address is not implicitly convertible to expected type address payable.
|
@ -1,5 +1,5 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f(bytes20 x) public pure returns (address payable) {
|
function f(bytes20 x) public pure returns (address payable) {
|
||||||
return payable(x);
|
return payable(address(x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
|
// We allow an exception for 0
|
||||||
address payable a = payable(0);
|
address payable a = payable(0);
|
||||||
a = payable(1);
|
a = payable(address(1));
|
||||||
address payable b = payable(0x0123456789012345678901234567890123456789);
|
address payable b = payable(0x0123456789012345678901234567890123456789);
|
||||||
b = payable(0x9876543210987654321098765432109876543210);
|
b = payable(0x9876543210987654321098765432109876543210);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address payable a = payable(address(uint160(0)));
|
||||||
|
address payable b = payable(address(bytes20(0)));
|
||||||
|
address payable c = payable(address(2));
|
||||||
|
// hex literal that is only 15 bytes long
|
||||||
|
address payable d = payable(address(0x002190356cBB839Cbe05303d7705Fa));
|
||||||
|
|
||||||
|
uint160 a1 = uint160(address(payable(0)));
|
||||||
|
bytes20 b1 = bytes20(address(payable(0)));
|
||||||
|
|
||||||
|
a; b; c; d; a1; b1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address payable a = payable(uint160(0));
|
||||||
|
address payable b = payable(bytes20(0));
|
||||||
|
address payable c = payable(2);
|
||||||
|
// hex literal that is only 15 bytes long
|
||||||
|
address payable d = payable(0x002190356cBB839Cbe05303d7705Fa);
|
||||||
|
|
||||||
|
// The opposite should also be disallowed
|
||||||
|
uint160 a1 = uint160(payable(0));
|
||||||
|
bytes20 b1 = bytes20(payable(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9640: (72-91): Explicit type conversion not allowed from "uint160" to "address payable".
|
||||||
|
// TypeError 9640: (121-140): Explicit type conversion not allowed from "bytes20" to "address payable".
|
||||||
|
// TypeError 9640: (170-180): Explicit type conversion not allowed from "int_const 2" to "address payable".
|
||||||
|
// TypeError 9640: (260-301): Explicit type conversion not allowed from "int_const 6807...(25 digits omitted)...4970" to "address payable".
|
||||||
|
// TypeError 9640: (375-394): Explicit type conversion not allowed from "address payable" to "uint160".
|
||||||
|
// TypeError 9640: (417-436): Explicit type conversion not allowed from "address payable" to "bytes20".
|
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
// 0 is okay, because it's an exception
|
||||||
|
address payable a = payable(0);
|
||||||
|
|
||||||
|
// address literals have type address
|
||||||
|
address payable b = payable(0x00000000219ab540356cBB839Cbe05303d7705Fa);
|
||||||
|
|
||||||
|
address payable c = payable(address(2));
|
||||||
|
|
||||||
|
a; b; c;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure returns (C c) {
|
function f() public pure returns (C c) {
|
||||||
c = C(payable(2));
|
c = C(payable(address(2)));
|
||||||
}
|
}
|
||||||
receive() external payable {
|
receive() external payable {
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f(uint x) public pure returns (address payable) {
|
function f(uint x) public pure returns (address payable) {
|
||||||
return payable(uint160(x));
|
return payable(address(uint160(x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user