Skip to content

Commit ac77d12

Browse files
authored
Merge pull request #16174 from argotorg/deprecation_warnings
Add deprecation warnings for `send()`, `transfer()`, ABI coder v1, contract comparisons, virtual modifiers and `memory-safe-assembly` comment
2 parents 5ef96c9 + b60f110 commit ac77d12

File tree

193 files changed

+1068
-152
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

193 files changed

+1068
-152
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ Language Features:
66
Compiler Features:
77
* ethdebug: Experimental support for instructions and source locations under EOF.
88
* EVM: Set default EVM Version to `osaka`.
9+
* DocString Parser: Warn about deprecation of inline assembly special comment `memory-safe-assembly`.
10+
* Syntax Checker: Warn about deprecation of ABI coder v1.
11+
* Syntax Checker: Warn about deprecation of virtual modifiers.
12+
* Type Checker: Warn about deprecation of `send` and `transfer` functions on instances of `address`.
13+
* Type Checker: Warn about deprecation of comparisons between variables of contract types.
914

1015
Bugfixes:
1116
* Assembler: Fix not using a fixed-width type for IDs being assigned to subassemblies nested more than one level away, resulting in inconsistent `--asm-json` output between target architectures.

docs/assembly.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,9 @@ of Solidity, you can use a special comment to annotate an assembly block as memo
381381
...
382382
}
383383
384-
Note that we will disallow the annotation via comment in a future breaking release; so, if you are not concerned with
385-
backward-compatibility with older compiler versions, prefer using the dialect string.
384+
.. warning::
385+
The ``memory-safe-assembly`` special comment is deprecated and scheduled for removal.
386+
In new code targeting recent compilers, use the assembly block annotation.
386387

387388
Advanced Safe Use of Memory
388389
---------------------------

docs/cheatsheet.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ Members of ``address``
5353
- ``<address>.staticcall(bytes memory) returns (bool, bytes memory)``: issue low-level ``STATICCALL`` with the given payload,
5454
returns success condition and return data
5555
- ``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`,
56-
returns ``false`` on failure
57-
- ``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
56+
returns ``false`` on failure (deprecated)
57+
- ``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure (deprecated)
5858

5959
.. index:: blockhash, blobhash, block, block;basefee, block;blobbasefee, block;chainid, block;coinbase, block;difficulty, block;gaslimit, block;number, block;prevrandao, block;timestamp
6060
.. index:: gasleft, msg;data, msg;sender, msg;sig, msg;value, tx;gasprice, tx;origin

docs/common-patterns.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ you receive the funds of the person who is now the richest.
5757
// Remember to zero the pending refund before
5858
// sending to prevent reentrancy attacks
5959
pendingWithdrawals[msg.sender] = 0;
60-
payable(msg.sender).transfer(amount);
60+
(bool success, ) = payable(msg.sender).call{value: amount}("");
61+
require(success);
6162
}
6263
}
6364
@@ -84,7 +85,8 @@ This is as opposed to the more intuitive sending pattern:
8485
function becomeRichest() public payable {
8586
if (msg.value <= mostSent) revert NotEnoughEther();
8687
// This line can cause problems (explained below).
87-
richest.transfer(msg.value);
88+
(bool success, ) = richest.call{value: msg.value}("");
89+
require(success);
8890
richest = payable(msg.sender);
8991
mostSent = msg.value;
9092
}
@@ -210,8 +212,10 @@ restrictions highly readable.
210212
revert NotEnoughEther();
211213
212214
_;
213-
if (msg.value > amount)
214-
payable(msg.sender).transfer(msg.value - amount);
215+
if (msg.value > amount) {
216+
(bool success, ) = payable(msg.sender).call{value: msg.value - amount}("");
217+
require(success);
218+
}
215219
}
216220
217221
function forceOwnerChange(address newOwner)

docs/contracts/functions.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ will consume more gas than the 2300 gas stipend:
310310
- Calling an external function which consumes a large amount of gas
311311
- Sending Ether
312312

313+
.. warning::
314+
``send()`` and ``transfer()`` are deprecated and scheduled for removal.
315+
See the section on :ref:`send <send-address-member>` and :ref:`transfer <balance-transfer-address-members>` for more information.
316+
313317
.. warning::
314318
When Ether is sent directly to a contract (without a function call, i.e. sender uses ``send`` or ``transfer``)
315319
but the receiving contract does not define a receive Ether function or a payable fallback function,
@@ -319,7 +323,6 @@ will consume more gas than the 2300 gas stipend:
319323
not recommended, since the fallback is invoked and would not fail for interface confusions
320324
on the part of the sender).
321325

322-
323326
.. warning::
324327
A contract without a receive Ether function can receive Ether as a
325328
recipient of a *coinbase transaction* (aka *miner block reward*)
@@ -440,6 +443,7 @@ operations as long as there is enough gas passed on to it.
440443
441444
// If someone sends Ether to that contract,
442445
// the transfer will fail, i.e. this returns false here.
446+
// This will report a warning (deprecation)
443447
return testPayable.send(2 ether);
444448
}
445449

docs/contracts/inheritance.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,8 @@ of the variable:
377377

378378
.. _modifier-overriding:
379379

380-
Modifier Overriding
381-
===================
380+
Modifier Overriding (deprecated)
381+
================================
382382

383383
Function modifiers can override each other. This works in the same way as
384384
:ref:`function overriding <function-overriding>` (except that there is no overloading for modifiers). The
@@ -392,6 +392,7 @@ and the ``override`` keyword must be used in the overriding modifier:
392392
393393
contract Base
394394
{
395+
// This will report a warning (deprecation)
395396
modifier foo() virtual {_;}
396397
}
397398
@@ -411,11 +412,13 @@ explicitly:
411412
412413
contract Base1
413414
{
415+
// This will report a warning (deprecation)
414416
modifier foo() virtual {_;}
415417
}
416418
417419
contract Base2
418420
{
421+
// This will report a warning (deprecation)
419422
modifier foo() virtual {_;}
420423
}
421424
@@ -424,6 +427,8 @@ explicitly:
424427
modifier foo() override(Base1, Base2) {_;}
425428
}
426429
430+
.. warning::
431+
``virtual`` modifiers are deprecated and scheduled for removal.
427432

428433

429434
.. index:: ! constructor

docs/control-structures.rst

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -692,16 +692,16 @@ and ``assert`` for internal error checking.
692692
:force:
693693
694694
// SPDX-License-Identifier: GPL-3.0
695-
pragma solidity >=0.5.0 <0.9.0;
695+
pragma solidity >=0.6.2 <0.9.0;
696696
697697
contract Sharer {
698698
function sendHalf(address payable addr) public payable returns (uint balance) {
699699
require(msg.value % 2 == 0, "Even value required.");
700700
uint balanceBeforeTransfer = address(this).balance;
701-
addr.transfer(msg.value / 2);
702-
// Since transfer throws an exception on failure and
703-
// cannot call back here, there should be no way for us to
704-
// still have half of the Ether.
701+
(bool success, ) = addr.call{value: msg.value / 2}("");
702+
require(success);
703+
// Since require will stop execution and revert if success is false,
704+
// there should be no way for us to still have half of the Ether.
705705
assert(address(this).balance == balanceBeforeTransfer - msg.value / 2);
706706
return address(this).balance;
707707
}
@@ -775,7 +775,8 @@ together with ``revert`` and the equivalent ``require``:
775775
if (msg.sender != owner)
776776
revert Unauthorized();
777777
778-
payable(msg.sender).transfer(address(this).balance);
778+
(bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
779+
require(success);
779780
}
780781
}
781782
@@ -914,4 +915,4 @@ in scope in the block that follows.
914915
out-of-gas situation and not a deliberate error condition:
915916
The caller always retains at least 1/64th of the gas in a call and thus
916917
even if the called contract goes out of gas, the caller still
917-
has some gas left.
918+
has some gas left.

docs/examples/blind-auction.rst

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,14 @@ to receive their Ether - contracts cannot activate themselves.
118118
if (amount > 0) {
119119
// It is important to set this to zero because the recipient
120120
// can call this function again as part of the receiving call
121-
// before `send` returns.
121+
// before `call` returns.
122122
pendingReturns[msg.sender] = 0;
123123
124124
// msg.sender is not of type `address payable` and must be
125125
// explicitly converted using `payable(msg.sender)` in order
126-
// use the member function `send()`.
127-
if (!payable(msg.sender).send(amount)) {
126+
// use the member function `call()`.
127+
(bool success, ) = payable(msg.sender).call{value: amount}("");
128+
if (!success) {
128129
// No need to call throw here, just reset the amount owing
129130
pendingReturns[msg.sender] = amount;
130131
return false;
@@ -160,7 +161,8 @@ to receive their Ether - contracts cannot activate themselves.
160161
emit AuctionEnded(highestBidder, highestBid);
161162
162163
// 3. Interaction
163-
beneficiary.transfer(highestBid);
164+
(bool success, ) = beneficiary.call{value: highestBid}("");
165+
require(success);
164166
}
165167
}
166168
@@ -310,7 +312,8 @@ invalid bids.
310312
// the same deposit.
311313
bidToCheck.blindedBid = bytes32(0);
312314
}
313-
payable(msg.sender).transfer(refund);
315+
(bool success, ) = payable(msg.sender).call{value: refund}("");
316+
require(success);
314317
}
315318
316319
/// Withdraw a bid that was overbid.
@@ -319,11 +322,12 @@ invalid bids.
319322
if (amount > 0) {
320323
// It is important to set this to zero because the recipient
321324
// can call this function again as part of the receiving call
322-
// before `transfer` returns (see the remark above about
325+
// before `call` returns (see the remark above about
323326
// conditions -> effects -> interaction).
324327
pendingReturns[msg.sender] = 0;
325328
326-
payable(msg.sender).transfer(amount);
329+
(bool success, ) = payable(msg.sender).call{value: amount}("");
330+
require(success);
327331
}
328332
}
329333
@@ -336,7 +340,8 @@ invalid bids.
336340
if (ended) revert AuctionEndAlreadyCalled();
337341
emit AuctionEnded(highestBidder, highestBid);
338342
ended = true;
339-
beneficiary.transfer(highestBid);
343+
(bool success, ) = beneficiary.call{value: highestBid}("");
344+
require(success);
340345
}
341346
342347
// This is an "internal" function which means that it

docs/examples/micropayment.rst

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ The full contract
185185
// this recreates the message that was signed on the client
186186
bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this)));
187187
require(recoverSigner(message, signature) == owner);
188-
payable(msg.sender).transfer(amount);
188+
(bool success, ) = payable(msg.sender).call{value: amount}("");
189+
require(success);
189190
}
190191
191192
/// freeze the contract and reclaim the leftover funds.
@@ -195,7 +196,8 @@ The full contract
195196
{
196197
require(msg.sender == owner);
197198
freeze();
198-
payable(msg.sender).transfer(address(this).balance);
199+
(bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
200+
require(success);
199201
}
200202
201203
/// signature methods.
@@ -406,9 +408,11 @@ The full contract
406408
require(msg.sender == recipient);
407409
require(isValidSignature(amount, signature));
408410
409-
recipient.transfer(amount);
411+
(bool success, ) = recipient.call{value: amount}("");
412+
require(success);
410413
freeze();
411-
sender.transfer(address(this).balance);
414+
(success, ) = sender.call{value: address(this).balance}("");
415+
require(success);
412416
}
413417
414418
/// the sender can extend the expiration at any time
@@ -430,7 +434,8 @@ The full contract
430434
{
431435
require(block.timestamp >= expiration);
432436
freeze();
433-
sender.transfer(address(this).balance);
437+
(bool success, ) = sender.call{value: address(this).balance}("");
438+
require(success);
434439
}
435440
436441
function isValidSignature(uint256 amount, bytes memory signature)

docs/examples/safe-remote.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ you can use state machine-like constructs inside a contract.
9393
{
9494
emit Aborted();
9595
state = State.Inactive;
96-
// We use transfer here directly. It is
96+
// We use call here directly. It is
9797
// reentrancy-safe, because it is the
9898
// last call in this function and we
9999
// already changed the state.
100-
seller.transfer(address(this).balance);
100+
(bool success, ) = seller.call{value: address(this).balance}("");
101+
require(success);
101102
}
102103
103104
/// Confirm the purchase as buyer.
@@ -124,11 +125,12 @@ you can use state machine-like constructs inside a contract.
124125
{
125126
emit ItemReceived();
126127
// It is important to change the state first because
127-
// otherwise, the contracts called using `send` below
128+
// otherwise, the contracts called using `call` below
128129
// can call in again here.
129130
state = State.Release;
130131
131-
buyer.transfer(value);
132+
(bool success, ) = buyer.call{value: value}("");
133+
require(success);
132134
}
133135
134136
/// This function refunds the seller, i.e.
@@ -140,10 +142,11 @@ you can use state machine-like constructs inside a contract.
140142
{
141143
emit SellerRefunded();
142144
// It is important to change the state first because
143-
// otherwise, the contracts called using `send` below
145+
// otherwise, the contracts called using `call` below
144146
// can call in again here.
145147
state = State.Inactive;
146148
147-
seller.transfer(3 * value);
149+
(bool success, ) = seller.call{value: 3 * value}("");
150+
require(success);
148151
}
149152
}

0 commit comments

Comments
 (0)