Open code423n4 opened 2 years ago
2022-02-jpyc gas optimization
1 use initial value for uint256 variable.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L58
uint256 internal totalSupply_;
2 use function param to emit an event instead of storage to save gas. https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L383
masterMinter is storage, so it costs extra gas. In this case, you can use _newMasterMinter instead of masterMinter.
emit MasterMinterChanged(_newMasterMinter);
3 Use unchecked for calculations in which over/underflow is checked.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L146 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L276 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L316 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L372 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L449
Wrap with
unchecked {
}
4 Using the cache is gas efficient.
You can use the cache for allowed[owner][spender] in _decreaseAllowance. Also allowed[from][msg.sender] in transferForm too.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L440-L450 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L272-L276 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L457-L460 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L281-L285
function _decreaseAllowance( address owner, address spender, uint256 decrement ) internal override { uint _allowed = allowance(owner, spender); require(decrement <= _allowed, “ERC20: decreased allowance below zero”); unchecked { _approve(owner, spender, allowed - dcrement); } }
You need to change the visibility of allowance to public if you call allowance() in _decreaseAllowance().
5 Use cache for balances[from]in _transfer.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L322-L326 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L312-L317
uint256 balanceFrom = balances[from]; require(value <= balanceFrom, “ERC20: transfer amount exceeds balance”); balances[from] = balanceFrom - value;
6 delete the unnecessary variable.
In my opinion, you can delete minters because onlyMinters which uses minters can also use minterAllowed to execute his task and onlyMinters for burn function must not be checked(because burn has not directly to do with minter)
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L59 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L59
and you can also delete the following function
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L182-L184
Modifier onlyMinters() { require(minterAllowed[msg.sender] != 0, “FiatToken: Mint is not available”); _; }
7 use custom errors instead of require to save gas.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L78-L94 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L135-L136 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L139-L142 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L156-L159 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L245-L246 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L271-L274 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L309-L314 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L368-L369 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L378-L381 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L445-L448 https://.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L122 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L142-L149 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L163-L166 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L253-L254 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L280-L283 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L319-L324 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L378-L379 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L388-L391 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L456-L459 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L611-L614 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L625-L628 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L660-L663
No. 1 and 2 is valid. But there are a lot of duplicates about this. e.g. #27
No. 3 and 4 can be valid too. Although there are duplicates. #27
Fixed and thanks!
Final change can be viewed here.
2022-02-jpyc gas optimization
1 use initial value for uint256 variable.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L58
uint256 internal totalSupply_;
2 use function param to emit an event instead of storage to save gas. https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L383
masterMinter is storage, so it costs extra gas. In this case, you can use _newMasterMinter instead of masterMinter.
emit MasterMinterChanged(_newMasterMinter);
3 Use unchecked for calculations in which over/underflow is checked.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L146 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L276 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L316 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L372 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L449
Wrap with
unchecked {
}
4 Using the cache is gas efficient.
You can use the cache for allowed[owner][spender] in _decreaseAllowance. Also allowed[from][msg.sender] in transferForm too.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L440-L450 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L272-L276 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L457-L460 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L281-L285
function _decreaseAllowance( address owner, address spender, uint256 decrement ) internal override { uint _allowed = allowance(owner, spender); require(decrement <= _allowed, “ERC20: decreased allowance below zero”); unchecked { _approve(owner, spender, allowed - dcrement); } }
You need to change the visibility of allowance to public if you call allowance() in _decreaseAllowance().
5 Use cache for balances[from]in _transfer.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L322-L326 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L312-L317
uint256 balanceFrom = balances[from]; require(value <= balanceFrom, “ERC20: transfer amount exceeds balance”); balances[from] = balanceFrom - value;
6 delete the unnecessary variable.
In my opinion, you can delete minters because onlyMinters which uses minters can also use minterAllowed to execute his task and onlyMinters for burn function must not be checked(because burn has not directly to do with minter)
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L59 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L59
and you can also delete the following function
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L182-L184
Modifier onlyMinters() { require(minterAllowed[msg.sender] != 0, “FiatToken: Mint is not available”); _; }
7 use custom errors instead of require to save gas.
https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L78-L94 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L135-L136 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L139-L142 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L156-L159 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L245-L246 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L271-L274 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L309-L314 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L368-L369 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L378-L381 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v1/FiatTokenV1.sol#L445-L448 https://.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L122 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L142-L149 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L163-L166 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L253-L254 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L280-L283 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L319-L324 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L378-L379 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L388-L391 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L456-L459 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L611-L614 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L625-L628 https://github.com/code-423n4/2022-02-jpyc/blob/main/contracts/v2/FiatTokenV2.sol#L660-L663