Optimize array access in ERC1155 (#4300)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com> Co-authored-by: Francisco Giordano <fg@frang.io>
This commit is contained in:
5
.changeset/hot-coins-judge.md
Normal file
5
.changeset/hot-coins-judge.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Arrays`: Add `unsafeMemoryAccess` helpers to read from a memory array without checking the length.
|
||||
5
.changeset/tough-drinks-hammer.md
Normal file
5
.changeset/tough-drinks-hammer.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`ERC1155`: Optimize array accesses by skipping bounds checking when unnecessary.
|
||||
@ -8,6 +8,7 @@ import "./IERC1155Receiver.sol";
|
||||
import "./extensions/IERC1155MetadataURI.sol";
|
||||
import "../../utils/Context.sol";
|
||||
import "../../utils/introspection/ERC165.sol";
|
||||
import "../../utils/Arrays.sol";
|
||||
import "../../interfaces/draft-IERC6093.sol";
|
||||
|
||||
/**
|
||||
@ -18,6 +19,9 @@ import "../../interfaces/draft-IERC6093.sol";
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
|
||||
using Arrays for uint256[];
|
||||
using Arrays for address[];
|
||||
|
||||
// Mapping from token ID to account balances
|
||||
mapping(uint256 => mapping(address => uint256)) private _balances;
|
||||
|
||||
@ -87,7 +91,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
uint256[] memory batchBalances = new uint256[](accounts.length);
|
||||
|
||||
for (uint256 i = 0; i < accounts.length; ++i) {
|
||||
batchBalances[i] = balanceOf(accounts[i], ids[i]);
|
||||
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
|
||||
}
|
||||
|
||||
return batchBalances;
|
||||
@ -157,8 +161,8 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
address operator = _msgSender();
|
||||
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 id = ids[i];
|
||||
uint256 amount = amounts[i];
|
||||
uint256 id = ids.unsafeMemoryAccess(i);
|
||||
uint256 amount = amounts.unsafeMemoryAccess(i);
|
||||
|
||||
if (from != address(0)) {
|
||||
uint256 fromBalance = _balances[id][from];
|
||||
@ -176,8 +180,8 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
}
|
||||
|
||||
if (ids.length == 1) {
|
||||
uint256 id = ids[0];
|
||||
uint256 amount = amounts[0];
|
||||
uint256 id = ids.unsafeMemoryAccess(0);
|
||||
uint256 amount = amounts.unsafeMemoryAccess(0);
|
||||
emit TransferSingle(operator, from, to, id, amount);
|
||||
if (to != address(0)) {
|
||||
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
|
||||
|
||||
@ -102,4 +102,26 @@ library Arrays {
|
||||
}
|
||||
return slot.getUint256Slot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user