From 5d9652ed10243029e7b77a8f5b32b4c676d71422 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 28 Jun 2022 22:07:26 +0300 Subject: [PATCH 1/8] Use unchecked arithmetic in "_transfer" and "_mint" --- contracts/token/ERC20/ERC20.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index ed2cd5dec5f..ad081e09121 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -237,8 +237,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata { require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; + _balances[to] += amount; } - _balances[to] += amount; emit Transfer(from, to, amount); @@ -260,7 +260,9 @@ contract ERC20 is Context, IERC20, IERC20Metadata { _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; - _balances[account] += amount; + unchecked { + _balances[account] += amount; + } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); From 4cc291e78d6bbfdb1f1d3a67f94026c7125d01e3 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 1 Jul 2022 09:56:32 +0300 Subject: [PATCH 2/8] docs: mention erc20 unchecked optimization in changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa3c9e478b..270650f78b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) * `GovernorCompatibilityBravo`: remove unused `using` statements ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) - + * `ERC20`: optimize `_transfer_` and `_mint_` by wrapping arithmetic calculations in an `unchecked` block. + ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) ## 4.7.0 (2022-06-29) * `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) @@ -26,7 +27,7 @@ * `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) * `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) - * `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + * `Proxies`: remove runtime check of ERC1967 storage slots.([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) ### Breaking changes From a7f638cd0bd0b5d756b05aa04919ab5f9289e512 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 1 Jul 2022 16:44:32 +0200 Subject: [PATCH 3/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 270650f78b6..4809296ebb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) * `GovernorCompatibilityBravo`: remove unused `using` statements ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) - * `ERC20`: optimize `_transfer_` and `_mint_` by wrapping arithmetic calculations in an `unchecked` block. - ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) + * `ERC20`: optimize `_transfer_` and `_mint_` by wrapping arithmetic calculations in an `unchecked` block. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) + ## 4.7.0 (2022-06-29) * `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) From d7b06ee9dc0b30bddd7773f791a140f2643fa1d0 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 1 Jul 2022 16:46:43 +0200 Subject: [PATCH 4/8] Update ERC20.sol --- contracts/token/ERC20/ERC20.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index ad081e09121..1e9e2205888 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -288,8 +288,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata { require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; + _totalSupply -= amount; } - _totalSupply -= amount; emit Transfer(account, address(0), amount); From 43e931f33486a9be144757b8e21dd0d611b9acc7 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 1 Jul 2022 16:47:21 +0200 Subject: [PATCH 5/8] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4809296ebb8..29182382243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) * `GovernorCompatibilityBravo`: remove unused `using` statements ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) - * `ERC20`: optimize `_transfer_` and `_mint_` by wrapping arithmetic calculations in an `unchecked` block. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) + * `ERC20`: optimize `_transfer_`, `_mint_` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) ## 4.7.0 (2022-06-29) From 36e625fa68d36defdf30a53ec490f405539d1014 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 1 Jul 2022 16:05:18 -0300 Subject: [PATCH 6/8] add comments explaining lack of overflow --- contracts/token/ERC20/ERC20.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 1e9e2205888..083b58c7197 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -237,6 +237,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata { require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. _balances[to] += amount; } @@ -261,6 +263,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { _totalSupply += amount; unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); @@ -288,6 +291,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } From 69efce9dd4297057b1eb03783b6de203d1f2c710 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 1 Jul 2022 16:06:02 -0300 Subject: [PATCH 7/8] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29182382243..8234f8ee46b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ * `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) * `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) - * `Proxies`: remove runtime check of ERC1967 storage slots.([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + * `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) ### Breaking changes From cb8aa1cd78c194186102f5a89fbb38b115d96a6f Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 1 Jul 2022 16:06:35 -0300 Subject: [PATCH 8/8] fix function names in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8234f8ee46b..8c2edb59785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) * `GovernorCompatibilityBravo`: remove unused `using` statements ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) - * `ERC20`: optimize `_transfer_`, `_mint_` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) + * `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) ## 4.7.0 (2022-06-29)