Omniscia Alliance Block Audit

ERC20Permit Code Style Findings

ERC20Permit Code Style Findings

ERC-01C: Inefficient Usage of Counters

TypeSeverityLocation
Gas OptimizationInformationalERC20Permit.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 pointer
65 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 pointer
89 let memPtr := mload(64)
90
91 mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
92 mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
93 mstore(add(memPtr, 34), hashStruct) // Hash of struct
94
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.