Omniscia Alliance Block Audit
ERC20Permit Code Style Findings
ERC20Permit Code Style Findings
ERC-01C: Inefficient Usage of Counters
Type | Severity | Location |
---|---|---|
Gas Optimization | Informational | ERC20Permit.sol:L61, L102 |
Description:
The usage of the Counters.Counter
wrapper for a counter causes a gas overhead that can be avoided.
Example:
contracts/ERC20Permit.sol
60bytes32 hashStruct;61uint256 nonce = _nonces[owner].current();62
63assembly {64 // Load free memory pointer65 let memPtr := mload(64)66
67 // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")68 mstore(memPtr, 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9)69 mstore(add(memPtr, 32), owner)70 mstore(add(memPtr, 64), spender)71 mstore(add(memPtr, 96), amount)72 mstore(add(memPtr, 128), nonce)73 mstore(add(memPtr, 160), deadline)74
75 hashStruct := keccak256(memPtr, 192)76}77
78bytes32 eip712DomainHash = _domainSeparator();79
80// Assembly for more efficient computing:81// bytes32 hash = keccak256(82// abi.encodePacked(uint16(0x1901), eip712DomainHash, hashStruct)83// );84
85bytes32 hash;86
87assembly {88 // Load free memory pointer89 let memPtr := mload(64)90
91 mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header92 mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash93 mstore(add(memPtr, 34), hashStruct) // Hash of struct94
95 hash := keccak256(memPtr, 66)96}97
98address signer = _recover(hash, v, r, s);99
100require(signer == owner, "ERC20Permit: invalid signature");101
102_nonces[owner].increment();103_approve(owner, spender, amount);
Recommendation:
We advise the implementation to be replaced by a literal uint256
or, if the implementation is desired to be kept, another optimization to be applied whereby the _nonces[owner]
lookup is stored to an in-memory variable to prevent calculating the keccak256
hash twice and reducing gas cost by a keccak256
operation.
Alleviation:
The latter of our recommendation was applied to the codebase whereby the pointer to the Counter
implementation is retained in memory thus optimizing the function.