40,000 USDC
View results
Submission Details
Severity: gas
Valid

Gas Optimizations

Gas Optimizations List

Number Optimization Details Instances
[G-01] Use assembly for address(0) comparison to save gas 4
[G-02] Use nested if and, avoid multiple check combinations using && 1
[G-03] Function calls can be cached rather than re calling , saves gas 1

Total 3 issues.

[G-01] Use assembly for address(0) comparison to save gas

4 instances - 1 file:

Instance#1-4 :

File: /src/Escrow.sol
40: if (address(tokenContract) == address(0)) revert Escrow__TokenZeroAddress();
41: if (buyer == address(0)) revert Escrow__BuyerZeroAddress();
42: if (seller == address(0)) revert Escrow__SellerZeroAddress();
...
103: if (i_arbiter == address(0)) revert Escrow__DisputeRequiresArbiter();

src/Escrow.sol#L40-L42 src/Escrow.sol#L103

Recommended Changes: Make a internal pure function and write assembly logic there. Call whenever
comparison with address(0) needed. It will make code modular and save some gas also during comparison.

- 40: if (address(tokenContract) == address(0)) revert Escrow__TokenZeroAddress();
+ 40: if (_checkAddressZero(address(tokenContract))) revert Escrow__TokenZeroAddress();
- 41: if (buyer == address(0)) revert Escrow__BuyerZeroAddress();
+ 41: if (_checkAddressZero(buyer)) revert Escrow__BuyerZeroAddress();
- 42: if (seller == address(0)) revert Escrow__SellerZeroAddress();
+ 42: if (_checkAddressZero(seller)) revert Escrow__SellerZeroAddress();
....
-103: if (i_arbiter == address(0)) revert Escrow__DisputeRequiresArbiter();
+103: if (_checkAddressZero(i_arbiter)) revert Escrow__DisputeRequiresArbiter();
....
//@audit adding 1 pure function to check for address(0) using assembly to save some gas
+ function _checkAddressZero(
+ address _address
+ ) internal pure returns (bool isAddressZero) {
+ assembly {
+ isAddressZero := eq(_address, 0)
+ }
+ }

[G-02] Use nested if and, avoid multiple check combinations using &&

Using nested if is cheaper gas wise than using && multiple check combinations. There are more advantages, such as easier
to read code and better coverage reports.

1 instance - 1 file:

Instance#1:

File: /src/Escrow.sol
67: if (msg.sender != i_buyer && msg.sender != i_seller) {
68: revert Escrow__OnlyBuyerOrSeller();
69: }

src/Escrow.sol#L67-L69

Recommended Changes: Use nested if

- 67: if (msg.sender != i_buyer && msg.sender != i_seller) {
+ if (msg.sender != i_buyer) {
+ if (msg.sender != i_seller) {
68: revert Escrow__OnlyBuyerOrSeller();
69: }
+ }

[G-03] Function calls can be cached rather than re calling save gas

1 instance - 1 file:

Instance#1 : External contract i_tokenContract.balanceOf(address(this)) can be called once to save gas instead of re-calling in line 125. We can use tokenBalance - totalFeeas remaining tokenBalance of this Escrow contract. Because from above only buyerAward and i_arbiterFee is transferred from this contract at line 120 and 123 whose total is totalFee at line 111.

File: /src/Escrow.sol
110: uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
111: uint256 totalFee = buyerAward + i_arbiterFee; // Reverts on overflow
if (totalFee > tokenBalance) {
revert Escrow__TotalFeeExceedsBalance(tokenBalance, totalFee);
}
s_state = State.Resolved;
emit Resolved(i_buyer, i_seller);
119: if (buyerAward > 0) {
i_tokenContract.safeTransfer(i_buyer, buyerAward);
}
122: if (i_arbiterFee > 0) {
i_tokenContract.safeTransfer(i_arbiter, i_arbiterFee);
}
125: tokenBalance = i_tokenContract.balanceOf(address(this));//@audit this call can be skipped by using above tokenBalance and totalFee

/src/Escrow.sol#L110-L125

Recommended Changes: Instead of re-calling replace it with tokenBalance - totalFee because totalFee is transferred from this contract in line 120 and 123 combined, remaining will be the token balance. This subtraction can be marked unchecked due to line 112 if condition it can't underflow.

110: uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
111: uint256 totalFee = buyerAward + i_arbiterFee; // Reverts on overflow
...
- 125: tokenBalance = i_tokenContract.balanceOf(address(this));
+ unchecked{
+ 125: tokenBalance = tokenBalance - totalFee;
+ }

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.